001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.terracotta.session;
006:
007: import com.tc.session.SessionSupport;
008: import com.tc.util.Assert;
009: import com.terracotta.session.util.ContextMgr;
010: import com.terracotta.session.util.LifecycleEventMgr;
011: import com.terracotta.session.util.StringArrayEnumeration;
012: import com.terracotta.session.util.Timestamp;
013:
014: import java.util.ArrayList;
015: import java.util.Collection;
016: import java.util.Enumeration;
017: import java.util.HashMap;
018: import java.util.Map;
019: import java.util.Set;
020:
021: import javax.servlet.ServletContext;
022: import javax.servlet.http.HttpSessionContext;
023:
024: public class SessionData implements Session, SessionSupport {
025: private final Map attributes = new HashMap();
026: private final Map internalAttributes = new HashMap();
027: private transient Map transientAttributes;
028: private final long createTime;
029: private final Timestamp timestamp;
030:
031: private long lastAccessedTime;
032: private long maxIdleMillis;
033: private transient long requestStartMillis;
034:
035: private transient SessionId sessionId;
036: private transient LifecycleEventMgr eventMgr;
037: private transient ContextMgr contextMgr;
038: private transient SessionManager sessionManager;
039: private transient boolean invalidated = false;
040: private transient boolean invalidating = false;
041:
042: private static final ThreadLocal request = new ThreadLocal();
043: private static final long NEVER_EXPIRE = -1;
044:
045: protected SessionData(int maxIdleSeconds) {
046: this .createTime = System.currentTimeMillis();
047: this .lastAccessedTime = 0;
048: this .timestamp = new Timestamp(System.currentTimeMillis());
049: setMaxInactiveSeconds(maxIdleSeconds);
050: }
051:
052: void associate(SessionId sid, LifecycleEventMgr lifecycleEventMgr,
053: ContextMgr ctxMgr, SessionManager sessionMgr) {
054: this .sessionId = sid;
055: this .eventMgr = lifecycleEventMgr;
056: this .contextMgr = ctxMgr;
057: this .sessionManager = sessionMgr;
058: }
059:
060: public void associateRequest(SessionRequest req) {
061: Assert.pre(request.get() == null);
062: request.set(req);
063: }
064:
065: public void clearRequest() {
066: request.set(null);
067: }
068:
069: public SessionId getSessionId() {
070: return this .sessionId;
071: }
072:
073: public SessionData getSessionData() {
074: return this ;
075: }
076:
077: public ServletContext getServletContext() {
078: return contextMgr.getServletContext();
079: }
080:
081: public HttpSessionContext getSessionContext() {
082: return contextMgr.getSessionContext();
083: }
084:
085: public synchronized boolean isValid() {
086: if (invalidating) {
087: return true;
088: }
089: if (invalidated) {
090: return false;
091: }
092:
093: if (getMaxInactiveMillis() == NEVER_EXPIRE) {
094: return true;
095: }
096:
097: final boolean isValid = getIdleMillis() < getMaxInactiveMillis();
098: return isValid;
099: }
100:
101: public boolean isNew() {
102: checkIfValid();
103: return sessionId.isNew();
104: }
105:
106: synchronized void invalidateIfNecessary() {
107: if (invalidated)
108: return;
109: invalidate(false);
110: }
111:
112: public void invalidate() {
113: invalidate(true);
114: }
115:
116: public synchronized void invalidate(boolean unlock) {
117: if (invalidated) {
118: throw new IllegalStateException(
119: "session already invalidated");
120: }
121: if (invalidating) {
122: return;
123: }
124:
125: invalidating = true;
126:
127: try {
128: eventMgr.fireSessionDestroyedEvent(this );
129:
130: String[] attrs = (String[]) attributes.keySet().toArray(
131: new String[attributes.size()]);
132:
133: for (int i = 0; i < attrs.length; i++) {
134: unbindAttribute(attrs[i]);
135: }
136: } finally {
137: try {
138: SessionRequest r = (SessionRequest) request.get();
139: if (r != null) {
140: r.clearSession();
141: clearRequest();
142: }
143: sessionManager.remove(this , unlock);
144: } finally {
145: invalidated = true;
146: invalidating = false;
147: }
148: }
149: }
150:
151: private void checkIfValid() {
152: if (!isValid())
153: throw new IllegalStateException("This session is invalid");
154: }
155:
156: synchronized void startRequest() {
157: requestStartMillis = System.currentTimeMillis();
158: }
159:
160: public void setMaxInactiveInterval(int v) {
161: setMaxInactiveSeconds(v);
162: if (isValid() && v == 0) {
163: invalidate();
164: }
165: }
166:
167: /**
168: * returns idle millis.
169: */
170: synchronized long getIdleMillis() {
171: if (lastAccessedTime == 0)
172: return 0;
173: if (requestStartMillis > lastAccessedTime)
174: return requestStartMillis - lastAccessedTime;
175: return Math.max(System.currentTimeMillis() - lastAccessedTime,
176: 0);
177: }
178:
179: synchronized void finishRequest() {
180: requestStartMillis = 0;
181: lastAccessedTime = System.currentTimeMillis();
182: }
183:
184: public synchronized long getCreationTime() {
185: checkIfValid();
186: return createTime;
187: }
188:
189: public synchronized long getLastAccessedTime() {
190: checkIfValid();
191: return lastAccessedTime;
192: }
193:
194: public void setAttribute(String name, Object value) {
195: setAttributeReturnOld(name, value);
196: }
197:
198: public synchronized Object setAttributeReturnOld(String name,
199: Object value) {
200: checkIfValid();
201: if (value == null) {
202: return unbindAttribute(name);
203: } else {
204: return bindAttribute(name, value);
205: }
206: }
207:
208: public void putValue(String name, Object val) {
209: setAttribute(name, val);
210: }
211:
212: public synchronized Object getAttribute(String name) {
213: checkIfValid();
214: return attributes.get(name);
215: }
216:
217: public Object getValue(String name) {
218: return getAttribute(name);
219: }
220:
221: public synchronized String[] getValueNames() {
222: checkIfValid();
223: Set keys = attributes.keySet();
224: return (String[]) keys.toArray(new String[keys.size()]);
225: }
226:
227: public Enumeration getAttributeNames() {
228: return new StringArrayEnumeration(getValueNames());
229: }
230:
231: public void removeAttribute(String name) {
232: removeAttributeReturnOld(name);
233: }
234:
235: public synchronized Object removeAttributeReturnOld(String name) {
236: checkIfValid();
237: return unbindAttribute(name);
238: }
239:
240: public void removeValue(String name) {
241: removeAttribute(name);
242: }
243:
244: synchronized long getMaxInactiveMillis() {
245: return maxIdleMillis;
246: }
247:
248: boolean neverExpires() {
249: return getMaxInactiveMillis() == NEVER_EXPIRE;
250: }
251:
252: public int getMaxInactiveInterval() {
253: if (getMaxInactiveMillis() == NEVER_EXPIRE) {
254: return (int) NEVER_EXPIRE;
255: }
256:
257: return (int) (getMaxInactiveMillis() / 1000L);
258: }
259:
260: private synchronized void setMaxInactiveSeconds(int secs) {
261: if (secs < 0) {
262: maxIdleMillis = NEVER_EXPIRE;
263: this .timestamp.setMillis(Long.MAX_VALUE);
264: return;
265: }
266:
267: maxIdleMillis = secs * 1000L;
268: this .timestamp.setMillis(System.currentTimeMillis()
269: + maxIdleMillis);
270: }
271:
272: public synchronized Object getInternalAttribute(String name) {
273: checkIfValid();
274: return internalAttributes.get(name);
275: }
276:
277: public synchronized Object setInternalAttribute(String name,
278: Object value) {
279: checkIfValid();
280: return internalAttributes.put(name, value);
281: }
282:
283: public synchronized Object removeInternalAttribute(String name) {
284: checkIfValid();
285: return internalAttributes.remove(name);
286: }
287:
288: public synchronized Object getTransientAttribute(String name) {
289: checkIfValid();
290: return getTransientAttributes().get(name);
291: }
292:
293: public synchronized Object setTransientAttribute(String name,
294: Object value) {
295: checkIfValid();
296: return getTransientAttributes().put(name, value);
297: }
298:
299: public synchronized Object removeTransientAttribute(String name) {
300: checkIfValid();
301: return getTransientAttributes().remove(name);
302: }
303:
304: public synchronized Collection getTransientAttributeKeys() {
305: checkIfValid();
306: return new ArrayList(getTransientAttributes().keySet());
307: }
308:
309: private Object bindAttribute(String name, Object newVal) {
310: Object oldVal = getAttribute(name);
311: if (newVal != oldVal)
312: eventMgr.bindAttribute(this , name, newVal);
313:
314: oldVal = attributes.put(name, newVal);
315:
316: if (oldVal != newVal)
317: eventMgr.unbindAttribute(this , name, oldVal);
318:
319: // now deal with attribute listener events
320: if (oldVal != null)
321: eventMgr.replaceAttribute(this , name, oldVal, newVal);
322: else
323: eventMgr.setAttribute(this , name, newVal);
324:
325: return oldVal;
326: }
327:
328: private Object unbindAttribute(String name) {
329: Object oldVal = attributes.remove(name);
330: if (oldVal != null) {
331: eventMgr.unbindAttribute(this , name, oldVal);
332: eventMgr.removeAttribute(this , name, oldVal);
333: }
334: return oldVal;
335: }
336:
337: public void resumeRequest() {
338: TerracottaSessionManager.resumeRequest(this );
339: }
340:
341: public void pauseRequest() {
342: TerracottaSessionManager.pauseRequest(this );
343: }
344:
345: private Map getTransientAttributes() {
346: if (transientAttributes == null) {
347: transientAttributes = new HashMap();
348: }
349: return transientAttributes;
350: }
351:
352: public String getId() {
353: return sessionId.getExternalId();
354: }
355:
356: Timestamp getTimestamp() {
357: return timestamp;
358: }
359:
360: }
|