001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.cluster.session;
018:
019: /**
020: * Title: Tomcat Session Replication for Tomcat 4.0 <BR>
021: * Description: A very simple straight forward implementation of
022: * session replication of servers in a cluster.<BR>
023: * This session replication is implemented "live". By live
024: * I mean, when a session attribute is added into a session on Node A
025: * a message is broadcasted to other messages and setAttribute is called on the replicated
026: * sessions.<BR>
027: * A full description of this implementation can be found under
028: * <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
029: *
030: * Copyright: See apache license
031: * Company: www.filip.net
032: * @author <a href="mailto:mail@filip.net">Filip Hanik</a>
033: * @version 1.0 for TC 4.0
034: * Description:<BR>
035: * The ReplicatedSession class is a simple extension of the StandardSession class
036: * It overrides a few methods (setAttribute, removeAttribute, expire, access) and has
037: * hooks into the InMemoryReplicationManager to broadcast and receive events from the cluster.<BR>
038: * This class inherits the readObjectData and writeObject data methods from the StandardSession
039: * and does not contain any serializable elements in addition to the inherited ones from the StandardSession
040: *
041: */
042: import org.apache.catalina.Manager;
043: import org.apache.catalina.session.ManagerBase;
044: import org.apache.catalina.realm.GenericPrincipal;
045: import org.apache.catalina.SessionListener;
046: import java.io.IOException;
047: import java.io.ObjectInputStream;
048: import java.io.ObjectOutputStream;
049: import java.security.Principal;
050: import java.io.PrintWriter;
051: import java.io.StringWriter;
052:
053: public class ReplicatedSession extends
054: org.apache.catalina.session.StandardSession implements
055: org.apache.catalina.cluster.ClusterSession {
056:
057: private transient Manager mManager = null;
058: protected boolean isDirty = false;
059: private transient long lastAccessWasDistributed = System
060: .currentTimeMillis();
061: private boolean isPrimarySession = true;
062:
063: public ReplicatedSession(Manager manager) {
064: super (manager);
065: mManager = manager;
066: }
067:
068: public boolean isDirty() {
069: return isDirty;
070: }
071:
072: public void setIsDirty(boolean dirty) {
073: isDirty = dirty;
074: }
075:
076: public void setLastAccessWasDistributed(long time) {
077: lastAccessWasDistributed = time;
078: }
079:
080: public long getLastAccessWasDistributed() {
081: return lastAccessWasDistributed;
082: }
083:
084: public void removeAttribute(String name) {
085: setIsDirty(true);
086: super .removeAttribute(name);
087: }
088:
089: /**
090: * see parent description,
091: * plus we also notify other nodes in the cluster
092: */
093: public void removeAttribute(String name, boolean notify) {
094: setIsDirty(true);
095: super .removeAttribute(name, notify);
096: }
097:
098: /**
099: * Sets an attribute and notifies the other nodes in the cluster
100: */
101: public void setAttribute(String name, Object value) {
102: if (value == null) {
103: removeAttribute(name);
104: return;
105: }
106: if (!(value instanceof java.io.Serializable))
107: throw new java.lang.IllegalArgumentException(
108: "Value for attribute " + name
109: + " is not serializable.");
110: setIsDirty(true);
111: super .setAttribute(name, value);
112: }
113:
114: public void setMaxInactiveInterval(int interval) {
115: setIsDirty(true);
116: super .setMaxInactiveInterval(interval);
117: }
118:
119: /**
120: * Sets the manager for this session
121: * @param mgr - the servers InMemoryReplicationManager
122: */
123: public void setManager(SimpleTcpReplicationManager mgr) {
124: mManager = mgr;
125: super .setManager(mgr);
126: }
127:
128: /**
129: * Set the authenticated Principal that is associated with this Session.
130: * This provides an <code>Authenticator</code> with a means to cache a
131: * previously authenticated Principal, and avoid potentially expensive
132: * <code>Realm.authenticate()</code> calls on every request.
133: *
134: * @param principal The new Principal, or <code>null</code> if none
135: */
136: public void setPrincipal(Principal principal) {
137: super .setPrincipal(principal);
138: setIsDirty(true);
139: }
140:
141: public void expire() {
142: SimpleTcpReplicationManager mgr = (SimpleTcpReplicationManager) getManager();
143: mgr.sessionInvalidated(getId());
144: setIsDirty(true);
145: super .expire();
146: }
147:
148: public void invalidate() {
149: SimpleTcpReplicationManager mgr = (SimpleTcpReplicationManager) getManager();
150: mgr.sessionInvalidated(getId());
151: setIsDirty(true);
152: super .invalidate();
153: }
154:
155: /**
156: * Read a serialized version of the contents of this session object from
157: * the specified object input stream, without requiring that the
158: * StandardSession itself have been serialized.
159: *
160: * @param stream The object input stream to read from
161: *
162: * @exception ClassNotFoundException if an unknown class is specified
163: * @exception IOException if an input/output error occurs
164: */
165: public void readObjectData(ObjectInputStream stream)
166: throws ClassNotFoundException, IOException {
167:
168: super .readObjectData(stream);
169:
170: }
171:
172: /**
173: * Write a serialized version of the contents of this session object to
174: * the specified object output stream, without requiring that the
175: * StandardSession itself have been serialized.
176: *
177: * @param stream The object output stream to write to
178: *
179: * @exception IOException if an input/output error occurs
180: */
181: public void writeObjectData(ObjectOutputStream stream)
182: throws IOException {
183:
184: super .writeObjectData(stream);
185:
186: }
187:
188: public void setId(String id, boolean tellNew) {
189:
190: if ((this .id != null) && (manager != null))
191: manager.remove(this );
192:
193: this .id = id;
194:
195: if (manager != null)
196: manager.add(this );
197: if (tellNew)
198: tellNew();
199: }
200:
201: /**
202: * returns true if this session is the primary session, if that is the
203: * case, the manager can expire it upon timeout.
204: */
205: public boolean isPrimarySession() {
206: return isPrimarySession;
207: }
208:
209: /**
210: * Sets whether this is the primary session or not.
211: * @param primarySession Flag value
212: */
213: public void setPrimarySession(boolean primarySession) {
214: this .isPrimarySession = primarySession;
215: }
216:
217: /**
218: * Implements a log method to log through the manager
219: */
220: protected void log(String message) {
221:
222: if ((mManager != null)
223: && (mManager instanceof SimpleTcpReplicationManager)) {
224: ((SimpleTcpReplicationManager) mManager).log
225: .debug("ReplicatedSession: " + message);
226: } else {
227: System.out.println("ReplicatedSession: " + message);
228: }
229:
230: }
231:
232: protected void log(String message, Throwable x) {
233:
234: if ((mManager != null)
235: && (mManager instanceof SimpleTcpReplicationManager)) {
236: ((SimpleTcpReplicationManager) mManager).log.error(
237: "ReplicatedSession: " + message, x);
238: } else {
239: System.out.println("ReplicatedSession: " + message);
240: x.printStackTrace();
241: }
242:
243: }
244:
245: public String toString() {
246: StringBuffer buf = new StringBuffer("ReplicatedSession id=");
247: buf.append(getId()).append(" ref=").append(super .toString())
248: .append("\n");
249: java.util.Enumeration e = getAttributeNames();
250: while (e.hasMoreElements()) {
251: String name = (String) e.nextElement();
252: Object value = getAttribute(name);
253: buf.append("\tname=").append(name).append("; value=")
254: .append(value).append("\n");
255: }
256: buf.append("\tLastAccess=").append(getLastAccessedTime())
257: .append("\n");
258: return buf.toString();
259: }
260:
261: public int getAccessCount() {
262: return accessCount;
263: }
264:
265: public void setAccessCount(int accessCount) {
266: this .accessCount = accessCount;
267: }
268:
269: public long getLastAccessedTime() {
270: return lastAccessedTime;
271: }
272:
273: public void setLastAccessedTime(long lastAccessedTime) {
274: this .lastAccessedTime = lastAccessedTime;
275: }
276:
277: public long getThisAccessedTime() {
278: return this AccessedTime;
279: }
280:
281: public void setThisAccessedTime(long thisAccessedTime) {
282: this.thisAccessedTime = thisAccessedTime;
283: }
284:
285: }
|