/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Externalizable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;
import javax.servlet.sip.ServletTimer;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipApplicationSessionAttributeListener;
import javax.servlet.sip.SipApplicationSessionBindingEvent;
import javax.servlet.sip.SipApplicationSessionBindingListener;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.session.PersistentManagerBase;
import org.jvnet.glassfish.comms.util.LogUtil;
import com.ericsson.ssa.config.ConvergedContext;
import org.jvnet.glassfish.comms.deployment.backend.SipApplicationListeners;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.ericsson.ssa.sip.timer.ServletTimerImplBase;
public class SipApplicationSessionImpl extends SipApplicationSessionBase
implements Externalizable, LifeCycle {
private static final Logger logger = LogUtil.SIP_LOGGER.getLogger();
private static final long serialVersionUID = 1972145565288132288L;
private static final String SAS_DESCRIPTION = "SipApplicationSession with id ";
/** The serialized format versioning. 1 = first version. */
private static final short serializedFormVersion = 1;
private transient SipSessionManager sipSessionManager;
// ---- Persistable fields ----
private String applicationName;
private long creationDate = new Date().getTime();
private Map<String, Object> applicationAttributes;
private Set<String> persistentSipSessionIds;
private Set<String> transientSipSessionIds;
private Set<String> httpProtocolSessionIds;
private Set<String> nonPersistentApplicationTimerIds;
private Set<String> persistentApplicationTimerIds;
protected String id;
private transient boolean shouldBePersisted;
// ----- Extra param field -------
// these are persisted as well, but maybe overridden later
private long expirationTime;
/**
* Constructor.
*/
public SipApplicationSessionImpl(SipSessionManagerBase manager, String id) {
this.id = id;
this.sipSessionManager = manager;
initInvalidateWhenReady();
}
public SipApplicationSessionImpl() { // default constructor for externalization.
}
/**
* sipSessionManager will be null after deserializing the SAS object
* back from the ObjectInputStream. So, the deserializer must explicitly
* set the sipSessionManager after deserialization, which means that the
* serialization/deserialization of the SAS object should only be done in a
* context using the appropriate SipStore interfaces.
*
* @return the sip session manager.
*/
@Override
public SipSessionManager getSipSessionManager() {
synchronized (getSasObjectLock()) {
return sipSessionManager;
}
}
/**
* The sipSessionManager must be explicitly set by the deserializer after
* deserializing the SAS object back from the ObjectInputStream.
*
* @see org.jvnet.glassfish.comms.replication.sessmgmt.SipApplicationSessionStoreImpl
*
* @param manager sip session mananger.
*/
public void setSipSessionManager(SipSessionManager manager) {
synchronized (getSasObjectLock()) {
this.sipSessionManager = manager;
}
}
public void doCleanup() {
sipSessionManager.removeSipApplicationSession(this);
}
public Set<String> getPersistentSessionIds() {
return new HashSet<String>(getPersistentSipSessionIds(false));
}
public Set<String> getPersistentTimerIds() {
return new HashSet<String>(getPersistentApplicationTimerIds(false));
}
protected Manager getHttpSessionManager() {
SipSessionManager manager = getSipSessionManager();
if (manager != null) {
ConvergedContext ctxt = manager.getContext();
if (ctxt != null) {
return ctxt.getManager();
}
}
return null;
}
@Override
protected String getPFieldApplicationName() {
return applicationName;
}
@Override
protected void setPFieldApplicationName(String applicationName) {
this.applicationName = applicationName;
}
@Override
protected Object getPFieldApplicationAttribute(String key) {
if (applicationAttributes == null) {
return null;
}
return applicationAttributes.get(key);
}
@Override
protected void setPFieldApplicationAttribute(String key, Object value) {
if (applicationAttributes == null) {
applicationAttributes = new HashMap<String, Object>();
}
Object oldValue = applicationAttributes.put(key, value);
if(oldValue==null){
// No old value => the attribute was added
attributeAdded(key,value);
}
else {
// An old value
if(oldValue!=value){
// Call replaced only if it is a different value.
attributeReplaced(key,oldValue,value);
}
}
}
@Override
protected Iterator<String> getPFieldApplicationAttributeNames() {
if (applicationAttributes == null) {
return null;
}
return applicationAttributes.keySet().iterator();
}
@Override
protected void removePFieldApplicationAttribute(String key) {
if (applicationAttributes != null) {
Object removedObject = applicationAttributes.remove(key);
if(removedObject!=null){
attributeRemoved(key,removedObject);
}
}
}
/**
* Helper interface for invocation of a callback on a listener.
*
* This interface is used to be able to write the <code>callAttributeListeners</code>
* method without duplicating that code and hence have a maintenance problem.
*
* An alternative to this approach is to use a switch case on an enum or
* to use reflection. I like this approach best since it is the most object oriented
* and type safe approach.
*
* @author Magnus Hessel, HiQ Stockholm AB
*
*/
private static interface AttributeCallback {
void call(SipApplicationSessionBindingEvent event,
SipApplicationSessionAttributeListener listener);
static final AttributeCallback ADDED = new AttributeCallback() {
public void call(SipApplicationSessionBindingEvent event,
SipApplicationSessionAttributeListener listener) {
listener.attributeAdded(event);
}
};
static final AttributeCallback REPLACED = new AttributeCallback() {
public void call(SipApplicationSessionBindingEvent event,
SipApplicationSessionAttributeListener listener) {
listener.attributeReplaced(event);
}
};
static final AttributeCallback REMOVED = new AttributeCallback() {
public void call(SipApplicationSessionBindingEvent event,
SipApplicationSessionAttributeListener listener) {
listener.attributeRemoved(event);
}
};
}
/**
* Called when an attribute is added
*
* @param name
*/
private void attributeAdded(String name,Object addedObject) {
callAttributeListeners(AttributeCallback.ADDED, name);
if(addedObject instanceof SipApplicationSessionBindingListener){
((SipApplicationSessionBindingListener)addedObject).valueBound(new SipApplicationSessionBindingEvent(this,name));
}
}
/**
* Called when an attribute is replaced
*
* @param name
*/
private void attributeReplaced(String name,Object oldValue,Object newValue) {
callAttributeListeners(AttributeCallback.REPLACED, name);
if(oldValue instanceof SipApplicationSessionBindingListener){
((SipApplicationSessionBindingListener)oldValue).valueUnbound(new SipApplicationSessionBindingEvent(this,name));
}
if(newValue instanceof SipApplicationSessionBindingListener){
((SipApplicationSessionBindingListener)newValue).valueBound(new SipApplicationSessionBindingEvent(this,name));
}
}
/**
* Called when an attribute is removed
*
* @param name
*/
private void attributeRemoved(String name, Object removedValue) {
callAttributeListeners(AttributeCallback.REMOVED, name);
if(removedValue instanceof SipApplicationSessionBindingListener){
((SipApplicationSessionBindingListener)removedValue).valueUnbound(new SipApplicationSessionBindingEvent(this,name));
}
}
/**
* Helper to call a callback on all SipSessionAttributeListeners.
*
* @param callback Which callback to invoke
* @param attributeName Name of attribute the callback involves
*/
private void callAttributeListeners(AttributeCallback callback, String attributeName) {
// List all listeners
List<SipApplicationSessionAttributeListener> sipApplicationSessionAttributeListeners =
getSipApplicationListeners().getSipApplicationSessionAttributeListeners();
// If there are at least one, create event and call all of them.
if (sipApplicationSessionAttributeListeners != null
&& !sipApplicationSessionAttributeListeners.isEmpty()) {
SipApplicationSessionBindingEvent event = new SipApplicationSessionBindingEvent(this,
attributeName);
for (SipApplicationSessionAttributeListener listener : sipApplicationSessionAttributeListeners) {
callback.call(event, listener);
}
}
}
/**
* Notify all SipApplicationSessionBindingListeners that are values that this
* the binding to this SipApplicationSession is due.
*/
@Override
protected void notifyAttributesUnbound() {
if(applicationAttributes!=null){
Iterator<Entry<String, Object>> entries = applicationAttributes.entrySet().iterator();
while(entries.hasNext()){
Entry<String, Object> entry = entries.next();
entries.remove();
Object value = entry.getValue();
if(value instanceof SipApplicationSessionBindingListener){
((SipApplicationSessionBindingListener)value).valueUnbound(new SipApplicationSessionBindingEvent(this,entry.getKey()));
}
}
}
}
@Override
protected long getPFieldCreationDate() {
return creationDate;
}
@Override
public long getPFieldExpirationTime() {
return expirationTime;
}
@Override
protected void setPFieldExpirationTime(long anExpirationTime) {
expirationTime = anExpirationTime;
}
@Override
protected Iterable<SipSessionBase> getPFieldSipSessions() {
return getPFieldSipSessions(true);
}
protected Iterable<SipSessionBase> getPFieldSipSessions(
final boolean loadDependencies) {
final Set<String> allSsIds =
new HashSet<String>(getTransientSipSessionIds(false));
allSsIds.addAll(getPersistentSipSessionIds(false));
return new Iterable<SipSessionBase>() {
// The iterator skips SS:es that can not be found in the
// SipSessionManager
public Iterator<SipSessionBase> iterator() {
return new Iterator<SipSessionBase>() {
Iterator<String> idIterator = allSsIds.iterator();
private SipSessionDialogImpl nextSs;
public boolean hasNext() {
while (idIterator.hasNext()) {
nextSs = null;
try {
nextSs = getSipSessionManager()
.findSipSession(idIterator.next(),
loadDependencies);
} catch (RemoteLockException ex) {
throw new RemoteLockRuntimeException(ex);
}
if (nextSs != null) {
return true;
}
}
return false;
}
public SipSessionBase next() {
SipSessionDialogImpl ssTmp = nextSs;
nextSs = null;
if (ssTmp != null) {
return ssTmp;
}
if (hasNext()) {
return nextSs;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException(
"Removal via iterator is not supported");
}
};
}
};
}
/**
* Gets all SIP protocol sessions that are currently active.
*
* @return the currently active SIP protocol sessions
*/
@Override
protected Iterable<SipSessionBase> getPFieldSipSessionsActiveOnly() {
final Set<String> allSsIds =
new HashSet<String>(getTransientSipSessionIds(false));
allSsIds.addAll(getPersistentSipSessionIds(false));
return new Iterable<SipSessionBase>() {
public Iterator<SipSessionBase> iterator() {
return new Iterator<SipSessionBase>() {
Iterator<String> idIterator = allSsIds.iterator();
private SipSessionDialogImpl nextSs;
SipSessionManager manager = getSipSessionManager();
public boolean hasNext() {
while (idIterator.hasNext()) {
String id = idIterator.next();
nextSs = null;
try {
if (manager instanceof
PersistentSipSessionManagerBase) {
nextSs =
((PersistentSipSessionManagerBase)manager).
findSipSessionFromCacheOnly(id);
} else {
nextSs = manager.findSipSession(id);
}
} catch (Exception ioe) {
// Ignore, skip to the next session
// TODO add warning logging
}
if (nextSs != null) {
return true;
}
}
return false;
}
public SipSessionBase next() {
SipSessionDialogImpl ssTmp = nextSs;
nextSs = null;
if (ssTmp != null) {
return ssTmp;
}
if (hasNext()) {
return nextSs;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException(
"Removal via iterator is not supported");
}
};
}
};
}
@Override
protected SipSessionBase getPFieldSipSession(String id) {
try {
return getSipSessionManager().findSipSession(id);
} catch(RemoteLockException rle) {
logger.log(Level.SEVERE, rle.getMessage(), rle);
return null;
}
}
@Override
protected void removePFieldSipProtocolSession(SipSessionBase session) {
if (checkSessionReadyToInvalidate()) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Transitioning " + this + " to" +
" ready-to-invalidate state upon invalidation of last " + session);
}
sessionReadyToInvalidate();
}
getPersistentSipSessionIds(false).remove(session.getId());
getTransientSipSessionIds(false).remove(session.getId());
}
@Override
protected void addSipProtocolSession(SipSessionBase session) {
getTransientSipSessionIds(true).add(session.getId());
setReadyToInvalidate(false);
}
private Set<String> getTransientSipSessionIds(boolean create) {
if (transientSipSessionIds == null) {
if (!create) {
return Collections.emptySet();
} else {
transientSipSessionIds = new HashSet<String>(8);
}
}
return transientSipSessionIds;
}
private Set<String> getPersistentSipSessionIds(boolean create) {
if (persistentSipSessionIds == null) {
if (!create) {
return Collections.emptySet();
} else {
persistentSipSessionIds = new HashSet<String>(8);
}
}
return persistentSipSessionIds;
}
private boolean hasValidSipSession() {
if (getTransientSipSessionIds(false).isEmpty() &&
getPersistentSipSessionIds(false).isEmpty()) {
return false;
}
boolean hasValidSession = false;
for (SipSessionBase sess : getPFieldSipSessions()) {
if (sess.isValid()) {
hasValidSession = true; // this session is valid.
break;
}
}
return hasValidSession;
}
private boolean hasValidHttpSession() {
if (getHttpProtocolSessionIds(false).isEmpty()) { // no http sessions.
return false;
}
boolean hasValidSession = false;
for (HttpSession sess : getPFieldHttpSessions()) {
ConvergedHttpSessionFacade s = (ConvergedHttpSessionFacade) sess;
if(s.isValid()) {
hasValidSession = true; // this session is valid.
break;
}
}
return hasValidSession;
}
private boolean hasServletTimer() {
if(getPersistentApplicationTimerIds(false).isEmpty() &&
getNonPersistentApplicationTimerIds(false).isEmpty()) {
return false;
}
return true;
}
@Override
protected boolean isEmpty() {
if(hasValidSipSession() || hasServletTimer() || hasValidHttpSession()) {
return false;
}
return true;
}
@Override
protected Iterable<HttpSession> getPFieldHttpSessions() {
final Set<String> sessionIds =
new HashSet<String>(getHttpProtocolSessionIds(false));
return new Iterable<HttpSession>() {
public Iterator<HttpSession> iterator() {
return new Iterator<HttpSession>() {
Iterator<String> idIterator = sessionIds.iterator();
private HttpSession nextSess;
public boolean hasNext() {
while (idIterator.hasNext()) {
try {
Session sess = getHttpSessionManager()
.findSession(idIterator.next());
if (sess != null) {
nextSess = sess.getSession();
}
} catch (IOException e) {
// Ignore, skip to the next session
// TODO add warning logging
}
if (nextSess != null) {
return true;
}
}
return false;
}
public HttpSession next() {
HttpSession sessTmp = nextSess;
nextSess = null;
if (sessTmp != null) {
return sessTmp;
}
if (hasNext()) {
return nextSess;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException(
"Removal via iterator is not supported");
}
};
}
};
}
/**
* Gets all HTTP protocol sessions that are currently active.
*
* @return the currently active HTTP protocol sessions
*/
@Override
protected Iterable<HttpSession> getPFieldHttpSessionsActiveOnly() {
return new Iterable<HttpSession>() {
public Iterator<HttpSession> iterator() {
return new Iterator<HttpSession>() {
Iterator<String> idIterator =
getHttpProtocolSessionIds(false).iterator();
private HttpSession nextSess = null;
Manager manager = getHttpSessionManager();
public boolean hasNext() {
while (idIterator.hasNext()) {
String id = idIterator.next();
try {
Session sess = null;
if (manager instanceof PersistentManagerBase) {
sess = ((PersistentManagerBase)manager).
findSessionFromCacheOnly(id);
} else {
sess = manager.findSession(id);
}
if (sess != null) {
nextSess = sess.getSession();
}
} catch (Exception ioe) {
// Ignore, skip to the next session
// TODO add warning logging
}
if (nextSess != null) {
return true;
}
}
return false;
}
public HttpSession next() {
HttpSession sessTmp = nextSess;
nextSess = null;
if (sessTmp != null) {
return sessTmp;
}
if (hasNext()) {
return nextSess;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException(
"Removal via iterator is not supported");
}
};
}
};
}
@Override
protected HttpSession getPFieldHttpSession(String id) {
Session sess = null;
try {
sess = getHttpSessionManager().findSession(id);
} catch(IOException ioe) {
logger.log(Level.SEVERE, ioe.getMessage(), ioe);
}
return sess == null ? null : sess.getSession();
}
@Override
protected void removePFieldHttpProtocolSession(HttpSession session) {
this.removePFieldHttpProtocolSession(session, true);
}
@Override
protected void removePFieldHttpProtocolSession(
HttpSession session, boolean removeFromManager) {
if (removeFromManager) {
try {
Manager m = getHttpSessionManager();
if (m != null) {
Session s = m.findSession(session.getId());
if (s != null) {
m.remove(s);
}
}
} catch (IOException e) {
// Ignore, the session apparently does not exist anyway
}
}
getHttpProtocolSessionIds(false).remove(session.getId());
if (checkSessionReadyToInvalidate()) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Transitioning " + this + " to" +
" ready-to-invalidate state upon invalidation of last" +
" HttpSession " + session);
}
sessionReadyToInvalidate();
}
}
@Override
protected void addPFieldHttpProtocolSession(HttpSession session) {
getHttpProtocolSessionIds(true).add(session.getId());
setReadyToInvalidate(false);
setShouldBePersisted();
}
private Set<String> getHttpProtocolSessionIds(boolean create) {
if (httpProtocolSessionIds == null) {
if (!create) {
return Collections.emptySet();
} else {
httpProtocolSessionIds = new HashSet<String>(8);
}
}
return httpProtocolSessionIds;
}
@Override
protected Collection<ServletTimer> getPFieldApplicationTimers() {
return getPFieldApplicationTimers(true);
}
protected Collection<ServletTimer> getPFieldApplicationTimers(boolean loadDependencies) {
Set<String> persistentTimerIds = getPersistentApplicationTimerIds(false);
Set<String> nonPersistentTimerIds = getNonPersistentApplicationTimerIds(false);
List<ServletTimer> timers = new ArrayList<ServletTimer>(persistentTimerIds.size() +
nonPersistentTimerIds.size());
for (String id : persistentTimerIds) {
ServletTimerImpl st = null;
try {
st = getSipSessionManager().findServletTimer(id, loadDependencies);
} catch (RemoteLockException e) {
throw new RemoteLockRuntimeException(e);
}
if (st != null) {
timers.add(st);
}
}
for (String id : nonPersistentTimerIds) {
ServletTimerImpl st = null;
st = findServletTimerLocally(id, loadDependencies);
if (st != null) {
timers.add(st);
}
}
return timers;
}
@Override
protected ServletTimer getPFieldApplicationTimer(String id) {
Set<String> persistentTimerIds =
getPersistentApplicationTimerIds(false);
if (persistentTimerIds.contains(id)) {
try {
return getSipSessionManager().findServletTimer(id, true);
} catch (RemoteLockException rle) {
logger.log(Level.SEVERE, rle.getMessage(), rle);
return null;
}
}
Set<String> nonPersistentTimerIds =
getNonPersistentApplicationTimerIds(false);
if (nonPersistentTimerIds.contains(id)) {
return findServletTimerLocally(id, true);
}
return null;
}
public boolean hasServletTimer(String timerId) {
return (getNonPersistentApplicationTimerIds(false).contains(timerId) ||
getPersistentApplicationTimerIds(false).contains(timerId));
}
protected ServletTimerImpl findServletTimerLocally(String id, boolean loadDependencies) {
try {
return getSipSessionManager().findServletTimer(id, loadDependencies);
} catch (RemoteLockException e) {
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, "ignoring RemoteLockException for non persistent timers", e);
return null;
}
}
/**
* @see com.ericsson.ssa.sip.SipApplicationSessionImpl#addPFieldApplicationTimer(com.ericsson.ssa.sip.timer.ServletTimerImpl)
*/
@Override
protected void addPFieldApplicationTimer(ServletTimerImpl timer) {
if (timer.isPersistent()) {
getPersistentApplicationTimerIds(true).add(timer.getId());
} else {
getNonPersistentApplicationTimerIds(true).add(timer.getId());
}
setReadyToInvalidate(false);
}
/**
* @see com.ericsson.ssa.sip.SipApplicationSessionImpl#removePFieldApplicationTimer(com.ericsson.ssa.sip.timer.ServletTimerImpl)
*/
@Override
protected void removePFieldApplicationTimer(ServletTimerImpl timer) {
getNonPersistentApplicationTimerIds(false).remove(timer.getId());
getPersistentApplicationTimerIds(false).remove(timer.getId());
}
private Set<String> getPersistentApplicationTimerIds(boolean create) {
if (persistentApplicationTimerIds == null) {
if (!create) {
return Collections.emptySet();
} else {
persistentApplicationTimerIds = new HashSet<String>(8);
}
}
return persistentApplicationTimerIds;
}
private Set<String> getNonPersistentApplicationTimerIds(boolean create) {
if (nonPersistentApplicationTimerIds == null) {
if (!create) {
return Collections.emptySet();
} else {
nonPersistentApplicationTimerIds = new HashSet<String>(8);
}
}
return nonPersistentApplicationTimerIds;
}
/**
* @see com.ericsson.ssa.sip.SipApplicationSessionImpl#getId()
*/
@Override
public String getId() {
return id;
}
/**
* Gets the id to be included in the serialized representation of this
* SipApplicationSession. Normally, this will be the same as the id of
* this SipApplicationSession, but subclasses may override this method to
* return null or an empty string (for optimization purposes), if they
* are able to obtain the id from another source after deserialization.
*/
protected String getIdForSerial() {
return getId();
}
/**
* @see com.ericsson.ssa.sip.SipApplicationSessionImpl#getAppId()
*/
public String getAppId() {
return sipSessionManager != null
? sipSessionManager.getApplicationId() : null;
}
/**
* Check if this SipApplicationSession should be persisted.
* @return true if this SAS shall be persisted
*/
public boolean shouldBePersisted() {
SipSessionManager manager = getSipSessionManager();
if (manager != null && manager.isBeingReleased()) {
return false;
}
return shouldBePersisted;
}
/**
* Indicate that this SipApplicationSession should from now on be persisted.
*/
public void setShouldBePersisted() {
shouldBePersisted = true;
}
protected void setSipSessionShouldBePersisted(
SipSessionDialogImpl sipSession) {
synchronized (getSasObjectLock()) {
getTransientSipSessionIds(false).remove(sipSession.getId());
getPersistentSipSessionIds(true).add(sipSession.getId());
setShouldBePersisted();
}
}
public void setServletTimerShouldBePersisted(ServletTimerImplBase timer) {
synchronized (getSasObjectLock()) {
getNonPersistentApplicationTimerIds(false).remove(timer.getId());
getPersistentApplicationTimerIds(true).add(timer.getId());
}
}
/**
* @serialData See serialized form version 1 in #readExternal(ObjectInput in)
*
* @param out the stream to write the object members
*
* @throws IOException
* @throws ClassNotFoundException
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeShort(serializedFormVersion);
super.writeExternal(out);
out.writeUTF(getIdForSerial());
out.writeUTF(applicationName);
out.writeLong(creationDate);
out.writeLong(expirationTime); // possibly overridden by extraparams
Set<String> sipSessionIds = getPersistentSipSessionIds(false);
out.writeInt(sipSessionIds.size());
for (String ssId : sipSessionIds) {
out.writeUTF(ssId);
}
Set<String> httpSessionIds = getHttpProtocolSessionIds(false);
out.writeInt(httpSessionIds.size());
for (String hsId : httpSessionIds) {
out.writeUTF(hsId);
}
Set<String> appTimerIds = getPersistentApplicationTimerIds(false);
out.writeInt(appTimerIds.size());
for (String atId : appTimerIds) {
out.writeUTF(atId);
}
// Serialize session attributes
IOUtil.writeSessionAttributes(applicationAttributes, out);
}
/**
* Identifies this SAS as non SSR enabled.
*
* This is used by the non-persistent ServletTimers of this SAS to decide
* whether they need to establish and save a UOW during their firing.
*/
public boolean isReplicationEnabled() {
return false;
}
public SipApplicationListeners getSipApplicationListeners()
{
SipSessionManager manager = getSipSessionManager();
if (manager != null) {
ConvergedContext ctxt = manager.getContext();
if (ctxt != null) {
return ctxt.getSipApplicationListeners();
}
}
return null;
}
/**
* @serialData first field is an short and represents the serializedFormVersion.<br><br>
* <h3>Data layout for serializedFormVersion = 1 follows</h3>
*
* <li>field is a <b>String</b> and represents sipApplicationId field</li>
* <li>field is a <b>String</b> and represents applicationName field</li>
* <li>field is a <b>Long</b> and represents creationDate field as absolute time</li>
* <li>field is a <b>Long</b> and represents expirationTime field as absolute time</li>
* <li>field is a <b>String</b> and represents beKey field</li>
* <li>field is a <b>Integer</b> and represents number of persistent sip session ids</li>
* <li>0..n fields as <b>String</b> and represents sessionId of persistent sip session</li>
* <li>field is a <b>Integer</b> and represents number of persistent http session ids</li>
* <li>0..n fields as <b>String</b> and represents sessionId of persistent http session</li>
* <li>field is a <b>Integer</b> and represents number of timer ids</li>
* <li>0..n fields as <b>String</b> and represents timerId of timer</li>
* <li>field is a <b>Integer</b> and represents number of key-value attributes serialized</li>
* <li>0..n key-value fields as <b>Object</b> and represents key-value attributes</li>
*
* @param in the stream to read the object members
*
* @throws IOException is thrown when unsupported version is detected
* @throws ClassNotFoundException
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
short readSerializedFormVersion = in.readShort();
switch(readSerializedFormVersion) {
case 1:
super.readExternal(in);
id = in.readUTF();
applicationName = in.readUTF();
creationDate = in.readLong();
expirationTime = in.readLong();
int size = in.readInt();
if (size > 0) {
persistentSipSessionIds = new HashSet<String>(size);
for (int i = 0; i < size; i++) {
persistentSipSessionIds.add(in.readUTF());
}
}
size = in.readInt();
if (size > 0) {
httpProtocolSessionIds = new HashSet<String>(size);
for (int i = 0; i < size; i++) {
httpProtocolSessionIds.add(in.readUTF());
}
}
size = in.readInt();
if (size > 0) {
persistentApplicationTimerIds = new HashSet<String>(size);
for (int i = 0; i < size; i++) {
persistentApplicationTimerIds.add(in.readUTF());
}
}
// Deserialize session attributes
applicationAttributes = IOUtil.readSessionAttributes(in);
shouldBePersisted = true;
break;
default:
throw new IOException("Unable to deserialize into "
+ this.getClass().getName()
+ " with serialVersionUID = " + serialVersionUID
+ " due to unknown serializedFormVersion of "
+ readSerializedFormVersion);
}
}
/**
* Activates this SipApplicationSession.
*/
public boolean activate() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("IN " + this.getClass().getName() +
">>activate: " + this);
}
// Add to active cache
SipSessionManager mgr = getSipSessionManager();
if (mgr != null) {
SipApplicationSession sas = mgr.addSipApplicationSession(this);
if (sas != null) {
// While this thread has been in the process of loading the
// requested sas, and is now trying to activate it, another
// thread has also loaded the same sas, and has already
// added it to the active cache. Abort activation.
return true;
}
}
// Make sure to notify any listeners before restarting the activation
// timer, see SailFin Issue 615
long oldExpirationTime = getPFieldExpirationTime();
notifySessionDidActivate();
restartAppSessionTimer();
long newExpirationTime = getPFieldExpirationTime();
//this does touch and save - updating the wiggled expiration
//times for SAS, SS and DF
if (isUpdateExpiration(isValid, oldExpirationTime,
newExpirationTime)) {
this.setPFieldExpirationTime(this.getPFieldExpirationTime());
}
//returning isValid because restartAppSessionTimer
//may have invalidated the SAS
return isValid;
}
protected boolean isUpdateExpiration(boolean isValid,
long oldExpirationTime,
long newExpirationTime) {
return isValid && (oldExpirationTime != newExpirationTime);
}
/**
* Passivates this SipApplicationSession.
*/
public void passivate() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("IN " + this.getClass().getName() +
">>passivate: " + this);
}
notifySessionWillPassivate();
// cancel the NonPersistetTimers.
// the persistent timers will be migrated at expiration
cancelNonPersistentTimers();
// Remove from active cache
SipSessionManager mgr = getSipSessionManager();
if (mgr != null) {
mgr.removeSipApplicationSession(this);
}
if (sasTimer != null) {
sasTimer.cancel();
}
}
protected void cancelNonPersistentTimers() {
Set<String> nonPersistentTimerIds = getNonPersistentApplicationTimerIds(false);
for (String id : nonPersistentTimerIds) {
ServletTimerImpl st = findServletTimerLocally(id, false);
if (st != null) {
st.cancel(true);
}
}
}
public String toString() {
return SAS_DESCRIPTION + getAppId() + ":" + id;
}
public String getObjectRefString() {
return this.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this));
}
}