001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.context;
021:
022: import org.apache.axis2.AxisFault;
023: import org.apache.axis2.description.AxisService;
024: import org.apache.axis2.engine.AxisConfiguration;
025: import org.apache.axis2.engine.DependencyManager;
026: import org.apache.axis2.util.ObjectStateUtils;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029:
030: import java.io.Externalizable;
031: import java.io.IOException;
032: import java.io.ObjectInput;
033: import java.io.ObjectOutput;
034: import java.util.Date;
035: import java.util.HashMap;
036: import java.util.Iterator;
037: import java.util.Map;
038:
039: /**
040: * All the engine components are stateless across the executions and all the states should be kept in the
041: * Contexts, there are three context Global, Session and Message.
042: */
043: public class SessionContext extends AbstractContext implements
044: Externalizable {
045:
046: /**
047: * @serial The serialization version ID tracks the version of the class.
048: * If a class definition changes, then the serialization/externalization
049: * of the class is affected. If a change to the class is made which is
050: * not compatible with the serialization/externalization of the class,
051: * then the serialization version ID should be updated.
052: * Refer to the "serialVer" utility to compute a serialization
053: * version ID.
054: */
055: private static final long serialVersionUID = -1100610673067568556L;
056:
057: /**
058: * @serial Tracks the revision level of a class to identify changes to the
059: * class definition that are compatible to serialization/externalization.
060: * If a class definition changes, then the serialization/externalization
061: * of the class is affected.
062: * Refer to the writeExternal() and readExternal() methods.
063: */
064: // supported revision levels, add a new level to manage compatible changes
065: private static final int REVISION_1 = 1;
066: // current revision level of this object
067: private static final int revisionID = REVISION_1;
068:
069: // TODO: investigate whether these collections need to be saved
070: private transient HashMap serviceContextMap = new HashMap();
071: private transient HashMap serviceGroupContextMap = new HashMap();
072:
073: private String cookieID;
074:
075: private static final Log log = LogFactory
076: .getLog(SessionContext.class);
077: private static final String myClassName = "SessionContext";
078:
079: // current time out interval is 30 secs. Need to make this configurable
080: public long sessionContextTimeoutInterval = 30 * 1000;
081:
082: /**
083: * @param parent
084: */
085: public SessionContext(AbstractContext parent) {
086: super (parent);
087: }
088:
089: public SessionContext() {
090: }
091:
092: public void init(AxisConfiguration axisConfiguration)
093: throws AxisFault {
094: }
095:
096: public ServiceContext getServiceContext(AxisService axisService) {
097: return (ServiceContext) serviceContextMap.get(axisService
098: .getName());
099: }
100:
101: public void addServiceContext(ServiceContext serviceContext) {
102: serviceContextMap.put(
103: serviceContext.getAxisService().getName(),
104: serviceContext);
105: }
106:
107: public void addServiceGroupContext(
108: ServiceGroupContext serviceGroupContext) {
109: String serviceGroupID = serviceGroupContext.getDescription()
110: .getServiceGroupName();
111: serviceGroupContextMap.put(serviceGroupID, serviceGroupContext);
112: }
113:
114: public ServiceGroupContext getServiceGroupContext(
115: String serviceGroupID) {
116: return (ServiceGroupContext) serviceGroupContextMap
117: .get(serviceGroupID);
118: }
119:
120: public String getCookieID() {
121: return cookieID;
122: }
123:
124: public void setCookieID(String cookieID) {
125: this .cookieID = cookieID;
126: }
127:
128: /**
129: * ServiceContext and ServiceGroupContext are not getting automatically garbage collectible. And there
130: * is no specific way for some one to go and make it garbage collectable.
131: * So the current solution is to make them time out. So the logic is that, there is a timer task
132: * in each and every service group which will check for the last touched time. And if it has not
133: * been touched for some time, the timer task will remove it from the memory.
134: * The touching logic happens like this. Whenever there is a call to addMessageContext in the operationContext
135: * it will go and update operationCOntext -> serviceContext -> serviceGroupContext.
136: */
137: public void touch() {
138: lastTouchedTime = new Date().getTime();
139: if (parent != null) {
140: parent.touch();
141: }
142: }
143:
144: public long getLastTouchedTime() {
145: return lastTouchedTime;
146: }
147:
148: public Iterator getServiceGroupContext() {
149: if (serviceGroupContextMap != null) {
150: if (serviceGroupContextMap.isEmpty()) {
151: return null;
152: }
153: return serviceGroupContextMap.values().iterator();
154: } else {
155: return null;
156: }
157: }
158:
159: protected void finalize() throws Throwable {
160: super .finalize();
161: if (serviceGroupContextMap != null
162: && !serviceGroupContextMap.isEmpty()) {
163: Iterator valuse = serviceGroupContextMap.values()
164: .iterator();
165: while (valuse.hasNext()) {
166: ServiceGroupContext serviceGroupContext = (ServiceGroupContext) valuse
167: .next();
168: cleanupServiceContextes(serviceGroupContext);
169: }
170: }
171: }
172:
173: private void cleanupServiceContextes(
174: ServiceGroupContext serviceGroupContext) {
175: Iterator serviceContecxtes = serviceGroupContext
176: .getServiceContexts();
177: while (serviceContecxtes.hasNext()) {
178: ServiceContext serviceContext = (ServiceContext) serviceContecxtes
179: .next();
180: DependencyManager.destroyServiceObject(serviceContext);
181: }
182: }
183:
184: /* ===============================================================
185: * Externalizable support
186: * ===============================================================
187: */
188:
189: /**
190: * Save the contents of this object.
191: * <p/>
192: * NOTE: Transient fields and static fields are not saved.
193: *
194: * @param out The stream to write the object contents to
195: * @throws IOException
196: */
197: public void writeExternal(ObjectOutput out) throws IOException {
198: // write out contents of this object
199:
200: // NOTES: For each item, where appropriate,
201: // write out the following information, IN ORDER:
202: // the class name
203: // the active or empty flag
204: // the data length, if appropriate
205: // the data
206:
207: //---------------------------------------------------------
208: // in order to handle future changes to the message
209: // context definition, be sure to maintain the
210: // object level identifiers
211: //---------------------------------------------------------
212: // serialization version ID
213: out.writeLong(serialVersionUID);
214:
215: // revision ID
216: out.writeInt(revisionID);
217:
218: //---------------------------------------------------------
219: // various simple fields
220: //---------------------------------------------------------
221: out.writeLong(getLastTouchedTime());
222:
223: out.writeLong(sessionContextTimeoutInterval);
224:
225: ObjectStateUtils.writeString(out, cookieID,
226: "SessionContext.cookieID");
227:
228: //---------------------------------------------------------
229: // properties
230: //---------------------------------------------------------
231: Map tmpMap = getProperties();
232:
233: HashMap tmpHashMap = null;
234:
235: if ((tmpMap != null) && (!tmpMap.isEmpty())) {
236: tmpHashMap = new HashMap(tmpMap);
237: }
238:
239: ObjectStateUtils.writeHashMap(out, tmpHashMap,
240: "SessionContext.properties");
241:
242: //---------------------------------------------------------
243: // "nested"
244: //---------------------------------------------------------
245:
246: // Options parent
247: ObjectStateUtils.writeObject(out, parent,
248: "SessionContext.parent");
249:
250: }
251:
252: /**
253: * Restore the contents of the MessageContext that was
254: * previously saved.
255: * <p/>
256: * NOTE: The field data must read back in the same order and type
257: * as it was written. Some data will need to be validated when
258: * resurrected.
259: *
260: * @param in The stream to read the object contents from
261: * @throws IOException
262: * @throws ClassNotFoundException
263: */
264: public void readExternal(ObjectInput in) throws IOException,
265: ClassNotFoundException {
266: // trace point
267: if (log.isTraceEnabled()) {
268: log
269: .trace(myClassName
270: + ":readExternal(): BEGIN bytes available in stream ["
271: + in.available() + "] ");
272: }
273:
274: // serialization version ID
275: long suid = in.readLong();
276:
277: // revision ID
278: int revID = in.readInt();
279:
280: // make sure the object data is in a version we can handle
281: if (suid != serialVersionUID) {
282: throw new ClassNotFoundException(
283: ObjectStateUtils.UNSUPPORTED_SUID);
284: }
285:
286: // make sure the object data is in a revision level we can handle
287: if (revID != REVISION_1) {
288: throw new ClassNotFoundException(
289: ObjectStateUtils.UNSUPPORTED_REVID);
290: }
291:
292: //---------------------------------------------------------
293: // various simple fields
294: //---------------------------------------------------------
295: long time = in.readLong();
296: setLastTouchedTime(time);
297:
298: sessionContextTimeoutInterval = in.readLong();
299:
300: cookieID = ObjectStateUtils.readString(in,
301: "SessionContext.cookieID");
302:
303: //---------------------------------------------------------
304: // properties
305: //---------------------------------------------------------
306:
307: HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,
308: "SessionContext.properties");
309:
310: properties = new HashMap();
311: if (tmpHashMap != null) {
312: setProperties(tmpHashMap);
313: }
314:
315: //---------------------------------------------------------
316: // "nested"
317: //---------------------------------------------------------
318:
319: // parent
320: Object tmpParent = ObjectStateUtils.readObject(in,
321: "SessionContext.parent");
322:
323: if (tmpParent != null) {
324: parent = (AbstractContext) tmpParent;
325: } else {
326: parent = null;
327: }
328:
329: //---------------------------------------------------------
330: // done
331: //---------------------------------------------------------
332:
333: }
334:
335: public ConfigurationContext getRootContext() {
336: // Session Context does not live within the hierarchy
337: return null;
338: }
339:
340: }
|