/** * Reinstantiates a serialized session from the data passed in. This will first call * createSession() so that we get a fresh instance with all the managers set and all the transient * fields validated. Then it calls Session.readObjectData(byte[]) to deserialize the object * * @param data - a byte array containing session data * @return a valid Session object, null if an error occurs */ protected Session readSession(byte[] data, String sessionId) { try { ReplicationStream session_in = getReplicationStream(data); Session session = sessionId != null ? this.findSession(sessionId) : null; boolean isNew = (session == null); // clear the old values from the existing session if (session != null) { ReplicatedSession rs = (ReplicatedSession) session; rs.expire(false); // cleans up the previous values, since we are not doing removes session = null; } // end if if (session == null) { session = createSession(null, false, false); sessions.remove(session.getIdInternal()); } boolean hasPrincipal = session_in.readBoolean(); SerializablePrincipal p = null; if (hasPrincipal) p = (SerializablePrincipal) session_in.readObject(); ((ReplicatedSession) session).readObjectData(session_in); if (hasPrincipal) session.setPrincipal(p.getPrincipal(getContainer().getRealm())); ((ReplicatedSession) session).setId(sessionId, isNew); ReplicatedSession rsession = (ReplicatedSession) session; rsession.setAccessCount(1); session.setManager(this); session.setValid(true); rsession.setLastAccessedTime(System.currentTimeMillis()); rsession.setThisAccessedTime(System.currentTimeMillis()); ((ReplicatedSession) session).setAccessCount(0); session.setNew(false); if (log.isTraceEnabled()) log.trace( "Session loaded id=" + sessionId + " actualId=" + session.getId() + " exists=" + this.sessions.containsKey(sessionId) + " valid=" + rsession.isValid()); return session; } catch (Exception x) { log.error("Failed to deserialize the session!", x); } return null; }
public ClusterMessage requestCompleted(String sessionId) { if (!getDistributable()) { log.warn( "Received requestCompleted message, although this context[" + getName() + "] is not distributable. Ignoring message"); return null; } try { if (invalidatedSessions.get(sessionId) != null) { synchronized (invalidatedSessions) { invalidatedSessions.remove(sessionId); SessionMessage msg = new SessionMessageImpl( name, SessionMessage.EVT_SESSION_EXPIRED, null, sessionId, sessionId); return msg; } } else { ReplicatedSession session = (ReplicatedSession) findSession(sessionId); if (session != null) { // return immediately if the session is not dirty if (useDirtyFlag && (!session.isDirty())) { // but before we return doing nothing, // see if we should send // an updated last access message so that // sessions across cluster dont expire long interval = session.getMaxInactiveInterval(); long lastaccdist = System.currentTimeMillis() - session.getLastAccessWasDistributed(); if (((interval * 1000) / lastaccdist) < 3) { SessionMessage accmsg = new SessionMessageImpl( name, SessionMessage.EVT_SESSION_ACCESSED, null, sessionId, sessionId); session.setLastAccessWasDistributed(System.currentTimeMillis()); return accmsg; } return null; } session.setIsDirty(false); if (log.isDebugEnabled()) { try { log.debug("Sending session to cluster=" + session); } catch (Exception ignore) { } } SessionMessage msg = new SessionMessageImpl( name, SessionMessage.EVT_SESSION_CREATED, writeSession(session), session.getIdInternal(), session.getIdInternal()); return msg; } // end if } // end if } catch (Exception x) { log.error("Unable to replicate session", x); } return null; }
/** * Serialize a session into a byte array<br> * This method simple calls the writeObjectData method on the session and returns the byte data * from that call * * @param session - the session to be serialized * @return a byte array containing the session data, null if the serialization failed */ protected byte[] writeSession(Session session) { try { java.io.ByteArrayOutputStream session_data = new java.io.ByteArrayOutputStream(); java.io.ObjectOutputStream session_out = new java.io.ObjectOutputStream(session_data); session_out.flush(); boolean hasPrincipal = session.getPrincipal() != null; session_out.writeBoolean(hasPrincipal); if (hasPrincipal) { session_out.writeObject( SerializablePrincipal.createPrincipal((GenericPrincipal) session.getPrincipal())); } // end if ((ReplicatedSession) session).writeObjectData(session_out); return session_data.toByteArray(); } catch (Exception x) { log.error("Failed to serialize the session!", x); } return null; }
/** * Creates a HTTP session. Most of the code in here is copied from the StandardManager. This is * not pretty, yeah I know, but it was necessary since the StandardManager had hard coded the * session instantiation to the a StandardSession, when we actually want to instantiate a * ReplicatedSession<br> * If the call comes from the Tomcat servlet engine, a SessionMessage goes out to the other nodes * in the cluster that this session has been created. * * @param notify - if set to true the other nodes in the cluster will be notified. This flag is * needed so that we can create a session before we deserialize a replicated one * @see ReplicatedSession */ protected Session createSession(String sessionId, boolean notify, boolean setId) { // inherited from the basic manager if ((getMaxActiveSessions() >= 0) && (sessions.size() >= getMaxActiveSessions())) { throw new TooManyActiveSessionsException( sm.getString("standardManager.createSession.ise"), getMaxActiveSessions()); } Session session = new ReplicatedSession(this); // Initialize the properties of the new session and return it session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); if (sessionId == null) sessionId = generateSessionId(); if (setId) session.setId(sessionId); if (notify && (cluster != null)) { ((ReplicatedSession) session).setIsDirty(true); } return (session); } // createSession
/** * This method is called by the received thread when a SessionMessage has been received from one * of the other nodes in the cluster. * * @param msg - the message received * @param sender - the sender of the message, this is used if we receive a EVT_GET_ALL_SESSION * message, so that we only reply to the requesting node */ protected void messageReceived(SessionMessage msg, Member sender) { try { if (log.isInfoEnabled()) { log.debug("Received SessionMessage of type=" + msg.getEventTypeString()); log.debug("Received SessionMessage sender=" + sender); } switch (msg.getEventType()) { case SessionMessage.EVT_GET_ALL_SESSIONS: { // get a list of all the session from this manager Object[] sessions = findSessions(); java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); java.io.ObjectOutputStream oout = new java.io.ObjectOutputStream(bout); oout.writeInt(sessions.length); for (int i = 0; i < sessions.length; i++) { ReplicatedSession ses = (ReplicatedSession) sessions[i]; oout.writeUTF(ses.getIdInternal()); byte[] data = writeSession(ses); oout.writeObject(data); } // for // don't send a message if we don't have to oout.flush(); oout.close(); byte[] data = bout.toByteArray(); SessionMessage newmsg = new SessionMessageImpl( name, SessionMessage.EVT_ALL_SESSION_DATA, data, "SESSION-STATE", "SESSION-STATE-" + getName()); cluster.send(newmsg, sender); break; } case SessionMessage.EVT_ALL_SESSION_DATA: { java.io.ByteArrayInputStream bin = new java.io.ByteArrayInputStream(msg.getSession()); java.io.ObjectInputStream oin = new java.io.ObjectInputStream(bin); int size = oin.readInt(); for (int i = 0; i < size; i++) { String id = oin.readUTF(); byte[] data = (byte[]) oin.readObject(); Session session = readSession(data, id); } // for stateTransferred = true; break; } case SessionMessage.EVT_SESSION_CREATED: { Session session = this.readSession(msg.getSession(), msg.getSessionID()); if (log.isDebugEnabled()) { log.debug("Received replicated session=" + session + " isValid=" + session.isValid()); } break; } case SessionMessage.EVT_SESSION_EXPIRED: { Session session = findSession(msg.getSessionID()); if (session != null) { session.expire(); this.remove(session); } // end if break; } case SessionMessage.EVT_SESSION_ACCESSED: { Session session = findSession(msg.getSessionID()); if (session != null) { session.access(); session.endAccess(); } break; } default: { // we didn't recognize the message type, do nothing break; } } // switch } catch (Exception x) { log.error("Unable to receive message through TCP channel", x); } }