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