blob: f4f98f79d23774fe0317b76682794e11bc47473f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.context;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.externalize.ExternalizeConstants;
import org.apache.axis2.context.externalize.SafeObjectInputStream;
import org.apache.axis2.context.externalize.SafeObjectOutputStream;
import org.apache.axis2.context.externalize.SafeSerializable;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.DependencyManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* All the engine components are stateless across the executions and all the states should be kept in the
* Contexts, there are three context Global, Session and Message.
*/
public class SessionContext extends AbstractContext
implements Externalizable, SafeSerializable {
/**
* @serial The serialization version ID tracks the version of the class.
* If a class definition changes, then the serialization/externalization
* of the class is affected. If a change to the class is made which is
* not compatible with the serialization/externalization of the class,
* then the serialization version ID should be updated.
* Refer to the "serialVer" utility to compute a serialization
* version ID.
*/
private static final long serialVersionUID = -1100610673067568556L;
/**
* @serial Tracks the revision level of a class to identify changes to the
* class definition that are compatible to serialization/externalization.
* If a class definition changes, then the serialization/externalization
* of the class is affected.
* Refer to the writeExternal() and readExternal() methods.
*/
// supported revision levels, add a new level to manage compatible changes
private static final int REVISION_2 = 2;
// current revision level of this object
private static final int revisionID = REVISION_2;
// TODO: investigate whether these collections need to be saved
private transient Map<String, ServiceContext> serviceContextMap = new HashMap<String, ServiceContext>();
private transient Map<String, ServiceGroupContext> serviceGroupContextMap = new HashMap<String, ServiceGroupContext>();
private String cookieID;
private static final Log log = LogFactory.getLog(SessionContext.class);
private static final String myClassName = "SessionContext";
// current time out interval is 30 secs. Need to make this configurable
public long sessionContextTimeoutInterval = 30 * 1000;
/**
* @param parent
*/
public SessionContext(AbstractContext parent) {
super(parent);
}
public SessionContext() {
}
public void init(AxisConfiguration axisConfiguration) throws AxisFault {
}
public ServiceContext getServiceContext(AxisService axisService) {
return (ServiceContext) serviceContextMap.get(axisService.getName());
}
public void addServiceContext(ServiceContext serviceContext) {
serviceContextMap.put(serviceContext.getAxisService().getName(), serviceContext);
}
public void addServiceGroupContext(ServiceGroupContext serviceGroupContext) {
String serviceGroupID = serviceGroupContext.getDescription().getServiceGroupName();
serviceGroupContextMap.put(serviceGroupID, serviceGroupContext);
}
public ServiceGroupContext getServiceGroupContext(String serviceGroupID) {
return (ServiceGroupContext) serviceGroupContextMap.get(serviceGroupID);
}
public String getCookieID() {
return cookieID;
}
public void setCookieID(String cookieID) {
this.cookieID = cookieID;
}
/**
* ServiceContext and ServiceGroupContext are not getting automatically garbage collectible. And there
* is no specific way for some one to go and make it garbage collectable.
* So the current solution is to make them time out. So the logic is that, there is a timer task
* in each and every service group which will check for the last touched time. And if it has not
* been touched for some time, the timer task will remove it from the memory.
* The touching logic happens like this. Whenever there is a call to addMessageContext in the operationContext
* it will go and update operationCOntext -> serviceContext -> serviceGroupContext.
*/
public void touch() {
lastTouchedTime = new Date().getTime();
if (parent != null) {
parent.touch();
}
}
public long getLastTouchedTime() {
return lastTouchedTime;
}
public Iterator<ServiceGroupContext> getServiceGroupContext() {
if (serviceGroupContextMap != null) {
if (serviceGroupContextMap.isEmpty()) {
return null;
}
return serviceGroupContextMap.values().iterator();
} else {
return null;
}
}
protected void finalize() throws Throwable {
super.finalize();
if (serviceGroupContextMap != null && !serviceGroupContextMap.isEmpty()) {
Iterator<ServiceGroupContext> valuse = serviceGroupContextMap.values().iterator();
while (valuse.hasNext()) {
ServiceGroupContext serviceGroupContext = (ServiceGroupContext) valuse.next();
cleanupServiceContextes(serviceGroupContext);
}
}
}
private void cleanupServiceContextes(ServiceGroupContext serviceGroupContext) {
Iterator<ServiceContext> serviceContecxtes = serviceGroupContext.getServiceContexts();
while (serviceContecxtes.hasNext()) {
ServiceContext serviceContext = (ServiceContext) serviceContecxtes.next();
DependencyManager.destroyServiceObject(serviceContext);
}
}
/* ===============================================================
* Externalizable support
* ===============================================================
*/
/**
* Save the contents of this object.
* <p/>
* NOTE: Transient fields and static fields are not saved.
*
* @param o The stream to write the object contents to
* @throws IOException
*/
public void writeExternal(ObjectOutput o) throws IOException {
SafeObjectOutputStream out = SafeObjectOutputStream.install(o);
// write out contents of this object
// NOTES: For each item, where appropriate,
// write out the following information, IN ORDER:
// the class name
// the active or empty flag
// the data length, if appropriate
// the data
//---------------------------------------------------------
// in order to handle future changes to the message
// context definition, be sure to maintain the
// object level identifiers
//---------------------------------------------------------
// serialization version ID
out.writeLong(serialVersionUID);
// revision ID
out.writeInt(revisionID);
//---------------------------------------------------------
// various simple fields
//---------------------------------------------------------
out.writeLong(getLastTouchedTime());
out.writeLong(sessionContextTimeoutInterval);
out.writeObject(cookieID);
//---------------------------------------------------------
// properties
//---------------------------------------------------------
out.writeMap(getProperties());
//---------------------------------------------------------
// "nested"
//---------------------------------------------------------
out.writeObject(parent);
}
/**
* Restore the contents of the MessageContext that was
* previously saved.
* <p/>
* NOTE: The field data must read back in the same order and type
* as it was written. Some data will need to be validated when
* resurrected.
*
* @param in The stream to read the object contents from
* @throws IOException
* @throws ClassNotFoundException
*/
public void readExternal(ObjectInput inObject) throws IOException, ClassNotFoundException {
SafeObjectInputStream in = SafeObjectInputStream.install(inObject);
// trace point
if (log.isTraceEnabled()) {
log.trace(myClassName + ":readExternal(): BEGIN bytes available in stream [" +
in.available() + "] ");
}
// serialization version ID
long suid = in.readLong();
// revision ID
int revID = in.readInt();
// make sure the object data is in a version we can handle
if (suid != serialVersionUID) {
throw new ClassNotFoundException(ExternalizeConstants.UNSUPPORTED_SUID);
}
// make sure the object data is in a revision level we can handle
if (revID != REVISION_2) {
throw new ClassNotFoundException(ExternalizeConstants.UNSUPPORTED_REVID);
}
//---------------------------------------------------------
// various simple fields
//---------------------------------------------------------
long time = in.readLong();
setLastTouchedTime(time);
sessionContextTimeoutInterval = in.readLong();
cookieID = (String) in.readObject();
//---------------------------------------------------------
// properties
//---------------------------------------------------------
properties = in.readMap(new HashMapUpdateLockable());
//---------------------------------------------------------
// "nested"
//---------------------------------------------------------
// parent
parent = (AbstractContext) in.readObject();
//---------------------------------------------------------
// done
//---------------------------------------------------------
serviceContextMap = new HashMap<String, ServiceContext>();
serviceGroupContextMap = new HashMap<String, ServiceGroupContext>();
}
public ConfigurationContext getRootContext() {
// Session Context does not live within the hierarchy
return null;
}
}