1
2 /*
3 * Copyright 1999,2004 The Apache Software Foundation.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.catalina.cluster.session;
19
20 /**
21 * Title: Tomcat Session Replication for Tomcat 4.0 <BR>
22 * Description: A very simple straight forward implementation of
23 * session replication of servers in a cluster.<BR>
24 * This session replication is implemented "live". By live
25 * I mean, when a session attribute is added into a session on Node A
26 * a message is broadcasted to other messages and setAttribute is called on the replicated
27 * sessions.<BR>
28 * A full description of this implementation can be found under
29 * <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
30 *
31 * Copyright: See apache license
32 * @author Filip Hanik
33 * @version $Revision: 303842 $ $Date: 2005-04-10 12:20:46 -0400 (Sun, 10 Apr 2005) $
34 * Description:<BR>
35 * The ReplicatedSession class is a simple extension of the StandardSession class
36 * It overrides a few methods (setAttribute, removeAttribute, expire, access) and has
37 * hooks into the InMemoryReplicationManager to broadcast and receive events from the cluster.<BR>
38 * This class inherits the readObjectData and writeObject data methods from the StandardSession
39 * and does not contain any serializable elements in addition to the inherited ones from the StandardSession
40 *
41 */
42 import org.apache.catalina.Manager;
43 import java.io.IOException;
44 import java.io.ObjectInputStream;
45 import java.io.ObjectOutputStream;
46 import java.security.Principal;
47
48 public class ReplicatedSession extends org.apache.catalina.session.StandardSession
49 implements org.apache.catalina.cluster.ClusterSession{
50
51 private transient Manager mManager = null;
52 protected boolean isDirty = false;
53 private transient long lastAccessWasDistributed = System.currentTimeMillis();
54 private boolean isPrimarySession=true;
55
56
57 public ReplicatedSession(Manager manager) {
58 super(manager);
59 mManager = manager;
60 }
61
62
63 public boolean isDirty()
64 {
65 return isDirty;
66 }
67
68 public void setIsDirty(boolean dirty)
69 {
70 isDirty = dirty;
71 }
72
73
74 public void setLastAccessWasDistributed(long time) {
75 lastAccessWasDistributed = time;
76 }
77
78 public long getLastAccessWasDistributed() {
79 return lastAccessWasDistributed;
80 }
81
82
83 public void removeAttribute(String name) {
84 setIsDirty(true);
85 super.removeAttribute(name);
86 }
87
88 /**
89 * see parent description,
90 * plus we also notify other nodes in the cluster
91 */
92 public void removeAttribute(String name, boolean notify) {
93 setIsDirty(true);
94 super.removeAttribute(name,notify);
95 }
96
97
98 /**
99 * Sets an attribute and notifies the other nodes in the cluster
100 */
101 public void setAttribute(String name, Object value)
102 {
103 if ( value == null ) {
104 removeAttribute(name);
105 return;
106 }
107 if (!(value instanceof java.io.Serializable))
108 throw new java.lang.IllegalArgumentException("Value for attribute "+name+" is not serializable.");
109 setIsDirty(true);
110 super.setAttribute(name,value);
111 }
112
113 public void setMaxInactiveInterval(int interval) {
114 setIsDirty(true);
115 super.setMaxInactiveInterval(interval);
116 }
117
118
119 /**
120 * Sets the manager for this session
121 * @param mgr - the servers InMemoryReplicationManager
122 */
123 public void setManager(SimpleTcpReplicationManager mgr)
124 {
125 mManager = mgr;
126 super.setManager(mgr);
127 }
128
129
130 /**
131 * Set the authenticated Principal that is associated with this Session.
132 * This provides an <code>Authenticator</code> with a means to cache a
133 * previously authenticated Principal, and avoid potentially expensive
134 * <code>Realm.authenticate()</code> calls on every request.
135 *
136 * @param principal The new Principal, or <code>null</code> if none
137 */
138 public void setPrincipal(Principal principal) {
139 super.setPrincipal(principal);
140 setIsDirty(true);
141 }
142
143 public void expire() {
144 SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
145 mgr.sessionInvalidated(getIdInternal());
146 setIsDirty(true);
147 super.expire();
148 }
149
150 public void invalidate() {
151 SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
152 mgr.sessionInvalidated(getIdInternal());
153 setIsDirty(true);
154 super.invalidate();
155 }
156
157
158 /**
159 * Read a serialized version of the contents of this session object from
160 * the specified object input stream, without requiring that the
161 * StandardSession itself have been serialized.
162 *
163 * @param stream The object input stream to read from
164 *
165 * @exception ClassNotFoundException if an unknown class is specified
166 * @exception IOException if an input/output error occurs
167 */
168 public void readObjectData(ObjectInputStream stream)
169 throws ClassNotFoundException, IOException {
170
171 super.readObjectData(stream);
172
173 }
174
175
176 /**
177 * Write a serialized version of the contents of this session object to
178 * the specified object output stream, without requiring that the
179 * StandardSession itself have been serialized.
180 *
181 * @param stream The object output stream to write to
182 *
183 * @exception IOException if an input/output error occurs
184 */
185 public void writeObjectData(ObjectOutputStream stream)
186 throws IOException {
187
188 super.writeObjectData(stream);
189
190 }
191
192 public void setId(String id, boolean tellNew) {
193
194 if ((this.id != null) && (manager != null))
195 manager.remove(this);
196
197 this.id = id;
198
199 if (manager != null)
200 manager.add(this);
201 if (tellNew) tellNew();
202 }
203
204
205
206
207
208
209
210
211 /**
212 * returns true if this session is the primary session, if that is the
213 * case, the manager can expire it upon timeout.
214 */
215 public boolean isPrimarySession() {
216 return isPrimarySession;
217 }
218
219 /**
220 * Sets whether this is the primary session or not.
221 * @param primarySession Flag value
222 */
223 public void setPrimarySession(boolean primarySession) {
224 this.isPrimarySession=primarySession;
225 }
226
227
228
229
230 /**
231 * Implements a log method to log through the manager
232 */
233 protected void log(String message) {
234
235 if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
236 ((SimpleTcpReplicationManager) mManager).log.debug("ReplicatedSession: " + message);
237 } else {
238 System.out.println("ReplicatedSession: " + message);
239 }
240
241 }
242
243 protected void log(String message, Throwable x) {
244
245 if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
246 ((SimpleTcpReplicationManager) mManager).log.error("ReplicatedSession: " + message,x);
247 } else {
248 System.out.println("ReplicatedSession: " + message);
249 x.printStackTrace();
250 }
251
252 }
253
254 public String toString() {
255 StringBuffer buf = new StringBuffer("ReplicatedSession id=");
256 buf.append(getIdInternal()).append(" ref=").append(super.toString()).append("\n");
257 java.util.Enumeration e = getAttributeNames();
258 while ( e.hasMoreElements() ) {
259 String name = (String)e.nextElement();
260 Object value = getAttribute(name);
261 buf.append("\tname=").append(name).append("; value=").append(value).append("\n");
262 }
263 buf.append("\tLastAccess=").append(getLastAccessedTime()).append("\n");
264 return buf.toString();
265 }
266 public int getAccessCount() {
267 return accessCount;
268 }
269 public void setAccessCount(int accessCount) {
270 this.accessCount = accessCount;
271 }
272 public long getLastAccessedTime() {
273 return lastAccessedTime;
274 }
275 public void setLastAccessedTime(long lastAccessedTime) {
276 this.lastAccessedTime = lastAccessedTime;
277 }
278 public long getThisAccessedTime() {
279 return thisAccessedTime;
280 }
281 public void setThisAccessedTime(long thisAccessedTime) {
282 this.thisAccessedTime = thisAccessedTime;
283 }
284
285 }