/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.service.session;
import java.util.HashMap;
import java.util.Map;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
import org.mobicents.servlet.sip.core.session.SipApplicationSessionKey;
import org.mobicents.servlet.sip.core.session.SipManager;
import org.mobicents.servlet.sip.core.session.SipSessionKey;
import org.mobicents.servlet.sip.message.SipServletRequestImpl;
import org.mobicents.servlet.sip.message.SipServletResponseImpl;
public final class ConvergedSessionReplicationContext
{
private static final ThreadLocal<ConvergedSessionReplicationContext> replicationContext = new ThreadLocal<ConvergedSessionReplicationContext>();
private static final ThreadLocal<ConvergedSessionReplicationContext> sipReplicationContext = new ThreadLocal<ConvergedSessionReplicationContext>();
private static final ConvergedSessionReplicationContext EMPTY = new ConvergedSessionReplicationContext();
private static final ConvergedSessionReplicationContext EMPTY_SIP = new ConvergedSessionReplicationContext();
private int webappCount;
private int sipappCount;
// private int activityCount;
// private int sipActivityCount;
private SnapshotManager soleManager;
private SnapshotSipManager soleSipManager;
private ClusteredSession<? extends OutgoingDistributableSessionData> soleSession;
private ClusteredSipSession<? extends OutgoingDistributableSessionData> soleSipSession;
private ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> soleSipApplicationSession;
private Map<ClusteredSession<? extends OutgoingDistributableSessionData>, SnapshotManager> crossCtxSessions;
// private Map crossCtxSipSessions;
// private Map crossCtxSipApplicationSessions;
// private Map expiredSessions;
// private Map expiredSipSessions;
// private Map expiredSipApplicationSessions;
private Request outerRequest;
private Response outerResponse;
private SipServletRequestImpl outerSipRequest;
private SipServletResponseImpl outerSipResponse;
/**
* Associate a SessionReplicationContext with the current thread, if
* there isn't one already. If there isn't one, associate the
* given request and response with the context.
* <p/>
* <strong>NOTE:</strong> Nested calls to this method and {@link #exitWebapp()}
* are supported; once a context is established the number of calls to this
* method and <code>exitWebapp()</code> are tracked.
*
* @param request
* @param response
*/
public static void enterWebapp(Request request, Response response, boolean startCacheActivity)
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
if (ctx == null)
{
ctx = new ConvergedSessionReplicationContext(request, response);
replicationContext.set(ctx);
}
ctx.webappCount++;
}
/**
* Signals that the webapp is finished handling the request (and
* therefore replication can begin.)
*
* @return a SessionReplicationContext, from which information
* about any sessions needing replication can be obtained.
* Will not return <code>null</code>.
*/
public static ConvergedSessionReplicationContext exitWebapp()
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
if (ctx != null)
{
ctx.webappCount--;
if (ctx.webappCount < 1)
{
// We've unwound any nested webapp calls, so we'll clean up and
// return the context to allow replication. If all cache activity
// is done as well, clear the ThreadLocal
ctx.outerRequest = null;
ctx.outerResponse = null;
replicationContext.set(null);
return ctx;
}
}
// A nested valve called us. Just return an empty context
return EMPTY;
}
/**
* Associate a SessionReplicationContext with the current thread, if
* there isn't one already. If there isn't one, associate the
* given request and response with the context.
* <p/>
* <strong>NOTE:</strong> Nested calls to this method and {@link #exitWebapp()}
* are supported; once a context is established the number of calls to this
* method and <code>exitWebapp()</code> are tracked.
*
* @param request
* @param response
*/
public static void enterSipapp(SipServletRequestImpl request, SipServletResponseImpl response, boolean startCacheActivity)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx == null)
{
ctx = new ConvergedSessionReplicationContext(request, response);
sipReplicationContext.set(ctx);
}
ctx.sipappCount++;
}
/**
* Associate a SessionReplicationContext with the current thread, if
* there isn't one already. If there isn't one, associate the
* given request and response with the context.
* <p/>
* <strong>NOTE:</strong> Nested calls to this method and {@link #exitWebapp()}
* are supported; once a context is established the number of calls to this
* method and <code>exitWebapp()</code> are tracked.
*
* @param request
* @param response
*/
public static void enterSipappAndBindSessions(SipServletRequestImpl request, SipServletResponseImpl response, SipManager manager, boolean startCacheActivity)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx == null)
{
ctx = new ConvergedSessionReplicationContext(request, response);
sipReplicationContext.set(ctx);
}
ctx.sipappCount++;
ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> clusteredSipApplicationSession = null;
ClusteredSipSession<? extends OutgoingDistributableSessionData> clusteredSipSession = null;
if(request != null) {
clusteredSipSession = (ClusteredSipSession<? extends OutgoingDistributableSessionData>)request.getSipSession();
} else {
clusteredSipSession = (ClusteredSipSession<? extends OutgoingDistributableSessionData>)response.getSipSession();
}
if(clusteredSipSession.getSipApplicationSession() instanceof org.mobicents.servlet.sip.message.MobicentsSipApplicationSessionFacade) {
clusteredSipApplicationSession = (ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData>)
((org.mobicents.servlet.sip.message.MobicentsSipApplicationSessionFacade)
clusteredSipSession.getSipApplicationSession()).getMobicentstSipApplicationSession();
} else {
clusteredSipApplicationSession = (ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData>)clusteredSipSession.getSipApplicationSession();
}
bindSipApplicationSession(clusteredSipApplicationSession, ((ClusteredSipManager<OutgoingDistributableSessionData>)manager).getSnapshotSipManager());
bindSipSession(clusteredSipSession, ((ClusteredSipManager<OutgoingDistributableSessionData>)manager).getSnapshotSipManager());
}
/**
* Signals that the webapp is finished handling the request (and
* therefore replication can begin.)
*
* @return a SessionReplicationContext, from which information
* about any sessions needing replication can be obtained.
* Will not return <code>null</code>.
*/
public static ConvergedSessionReplicationContext exitSipapp()
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx != null)
{
ctx.sipappCount--;
if (ctx.sipappCount < 1)
{
// We've unwound any nested webapp calls, so we'll clean up and
// return the context to allow replication. If all cache activity
// is done as well, clear the ThreadLocal
ctx.outerSipRequest = null;
ctx.outerSipResponse = null;
sipReplicationContext.set(null);
return ctx;
}
}
// A nested valve called us. Just return an empty context
return EMPTY_SIP;
}
public static void bindSession(ClusteredSession<? extends OutgoingDistributableSessionData> session, SnapshotManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
if (ctx != null && ctx.webappCount > 0)
{
ctx.addReplicatableSession(session, manager);
}
/*else {
We are past the part of the request cycle where we
track sessions for replication
}*/
}
public static void bindSipSession(ClusteredSipSession<? extends OutgoingDistributableSessionData> session, SnapshotSipManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx != null && ctx.sipappCount > 0)
{
ctx.addReplicatableSipSession(session, manager);
}
/*else {
We are past the part of the request cycle where we
track sessions for replication
}*/
}
public static void bindSipApplicationSession(ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> session, SnapshotSipManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx != null && ctx.sipappCount > 0)
{
ctx.addReplicatableSipApplicationSession(session, manager);
}
/*else {
We are past the part of the request cycle where we
track sessions for replication
}*/
}
public static void sessionExpired(ClusteredSession<? extends OutgoingDistributableSessionData> session, String realId, SnapshotManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
if (ctx != null && ctx.webappCount > 0)
{
ctx.sessionExpired(session, manager);
}
}
public static void sipSessionExpired(ClusteredSipSession<? extends OutgoingDistributableSessionData> session, SipSessionKey key, SnapshotSipManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx != null && ctx.sipappCount > 0)
{
ctx.sipSessionExpired(session, manager);
}
}
public static void sipApplicationSessionExpired(ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> session, SipApplicationSessionKey key, SnapshotSipManager manager)
{
ConvergedSessionReplicationContext ctx = getCurrentSipContext();
if (ctx != null && ctx.sipappCount > 0)
{
ctx.sipApplicationSessionExpired(session, manager);
}
}
/**
* Does nothing
*
* @return <code>false</code>
*
* @deprecated Always returns false; will be removed in AS 6
*/
@Deprecated
public static boolean isSessionBoundAndExpired(String realId, SnapshotManager manager)
{
return false;
}
/**
* Does nothing
*
* @return <code>false</code>
*
* @deprecated Always returns false; will be removed in AS 6
*/
@Deprecated
public static boolean isSipSessionBoundAndExpired(String key, SnapshotSipManager manager)
{
return false;
}
/**
* Does nothing
*
* @return <code>false</code>
*
* @deprecated Always returns false; will be removed in AS 6
*/
@Deprecated
public static boolean isSipApplicationSessionBoundAndExpired(String key, SnapshotSipManager manager)
{
return false;
}
/**
* Does nothing
*
* @deprecated Does nothing; will be removed in AS 6
*/
@Deprecated
public static void startCacheActivity()
{
// no-op
}
/**
* Does nothing
*
* @deprecated Does nothing; will be removed in AS 6
*/
@Deprecated
public static void finishCacheActivity()
{
// no-op
}
/**
* Does nothing
*
* @deprecated Does nothing; will be removed in AS 6
*/
@Deprecated
public static void startSipCacheActivity()
{
// no-op
}
/**
* Does nothing
*
* @deprecated Does nothing; will be removed in AS 6
*/
@Deprecated
public static void finishSipCacheActivity()
{
// no-op
}
/**
* Returns whether there is a ConvergedSessionReplicationContext associated with
* the current thread.
*
* @return <code>true</code> if there is a context associated with the thread
*
* @deprecated Will be removed in AS 6
*/
@Deprecated
public static boolean isLocallyActive()
{
return getCurrentContext() != null;
}
/**
* Returns whether there is a ConvergedSessionReplicationContext associated with
* the current thread.
*
* @return <code>true</code> if there is a context associated with the thread
*
* @deprecated Will be removed in AS 6
*/
@Deprecated
public static boolean isSipLocallyActive()
{
return getCurrentSipContext() != null;
}
public static Request getOriginalRequest()
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
return (ctx == null ? null : ctx.outerRequest);
}
public static Response getOriginalResponse()
{
ConvergedSessionReplicationContext ctx = getCurrentContext();
return (ctx == null ? null : ctx.outerResponse);
}
private static ConvergedSessionReplicationContext getCurrentContext()
{
return replicationContext.get();
}
private static ConvergedSessionReplicationContext getCurrentSipContext()
{
return sipReplicationContext.get();
}
private ConvergedSessionReplicationContext(Request request, Response response)
{
this.outerRequest = request;
this.outerResponse = response;
}
private ConvergedSessionReplicationContext(SipServletRequestImpl request, SipServletResponseImpl response)
{
this.outerSipRequest = request;
this.outerSipResponse = response;
}
private ConvergedSessionReplicationContext() {}
/**
* Gets a Map<SnapshotManager, ClusteredSession> of sessions that were accessed
* during the course of a request. Will only be non-null if
* {@link #bindSession(ClusteredSession, SnapshotManager)} was called
* with more than one SnapshotManager (i.e the request crossed session
* contexts.)
*/
public Map<ClusteredSession<? extends OutgoingDistributableSessionData>, SnapshotManager> getCrossContextSessions()
{
return crossCtxSessions;
}
/**
* Gets the SnapshotManager that was passed to
* {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
* if only one such SnapshotManager was passed. Returns <code>null</code>
* otherwise, in which case a cross-context request is a possibility,
* and {@link #getCrossContextSessions()} should be checked.
*/
public SnapshotManager getSoleSnapshotManager()
{
return soleManager;
}
/**
* Gets the SnapshotManager that was passed to
* {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
* if only one such SnapshotManager was passed. Returns <code>null</code>
* otherwise, in which case a cross-context request is a possibility,
* and {@link #getCrossContextSessions()} should be checked.
*/
public SnapshotSipManager getSoleSnapshotSipManager()
{
return soleSipManager;
}
/**
* Gets the ClusteredSession that was passed to
* {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
* if only one SnapshotManager was passed. Returns <code>null</code>
* otherwise, in which case a cross-context request is a possibility,
* and {@link #getCrossContextSessions()} should be checked.
*/
public ClusteredSession<? extends OutgoingDistributableSessionData> getSoleSession()
{
return soleSession;
}
/**
* Gets the ClusteredSession that was passed to
* {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
* if only one SnapshotManager was passed. Returns <code>null</code>
* otherwise, in which case a cross-context request is a possibility,
* and {@link #getCrossContextSessions()} should be checked.
*/
public ClusteredSipSession<? extends OutgoingDistributableSessionData> getSoleSipSession()
{
return soleSipSession;
}
/**
* Gets the ClusteredSession that was passed to
* {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
* if only one SnapshotManager was passed. Returns <code>null</code>
* otherwise, in which case a cross-context request is a possibility,
* and {@link #getCrossContextSessions()} should be checked.
*/
public ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> getSoleSipApplicationSession()
{
return soleSipApplicationSession;
}
private void addReplicatableSession(ClusteredSession<? extends OutgoingDistributableSessionData> session, SnapshotManager mgr)
{
if (crossCtxSessions != null)
{
crossCtxSessions.put(session, mgr);
}
else if (soleManager == null)
{
// First one bound
soleManager = mgr;
soleSession = session;
}
else if (!mgr.equals(soleManager))
{
// We have a cross-context call; need a Map for the sessions
crossCtxSessions = new HashMap<ClusteredSession<? extends OutgoingDistributableSessionData>, SnapshotManager>();
crossCtxSessions.put(soleSession, soleManager);
crossCtxSessions.put(session, mgr);
soleManager = null;
soleSession = null;
}
else
{
soleSession = session;
}
}
private void addReplicatableSipSession(
ClusteredSipSession<? extends OutgoingDistributableSessionData> session,
SnapshotSipManager mgr) {
// if (crossCtxSipSessions != null)
// {
// crossCtxSipSessions.put(session, mgr);
// }
// else
if (soleSipManager == null) {
// First one bound
soleSipManager = mgr;
soleSipSession = session;
}
// else if (!mgr.equals(soleManager))
// {
// // We have a cross-context call; need a Map for the sessions
// crossCtxSipSessions = new HashMap();
// crossCtxSipSessions.put(soleSipSession, soleManager);
// crossCtxSipSessions.put(session, mgr);
// soleManager = null;
// soleSipSession = null;
// }
else {
soleSipSession = session;
}
}
private void addReplicatableSipApplicationSession(
ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> session,
SnapshotSipManager mgr) {
// if (crossCtxSipApplicationSessions != null)
// {
// crossCtxSipApplicationSessions.put(session, mgr);
// }
// else
if (soleSipManager == null) {
// First one bound
soleSipManager = mgr;
soleSipApplicationSession = session;
}
// else if (!mgr.equals(soleManager))
// {
// // We have a cross-context call; need a Map for the sessions
// crossCtxSipApplicationSessions = new HashMap();
// crossCtxSipApplicationSessions.put(soleSipApplicationSession,
// soleManager);
// crossCtxSipApplicationSessions.put(session, mgr);
// soleManager = null;
// soleSipApplicationSession = null;
// }
else {
soleSipApplicationSession = session;
}
}
private void sessionExpired(ClusteredSession<? extends OutgoingDistributableSessionData> session, SnapshotManager manager)
{
if (manager.equals(soleManager))
{
soleManager = null;
soleSession = null;
}
else if (crossCtxSessions != null)
{
crossCtxSessions.remove(session);
}
}
private void sipSessionExpired(ClusteredSipSession<? extends OutgoingDistributableSessionData> session, SnapshotSipManager manager)
{
boolean store = manager.equals(soleSipManager);
if (store)
{
soleSipManager = null;
soleSipSession = null;
}
}
private void sipApplicationSessionExpired(ClusteredSipApplicationSession<? extends OutgoingDistributableSessionData> session, SnapshotSipManager manager)
{
boolean store = manager.equals(soleSipManager);
if (store)
{
soleSipManager = null;
soleSipApplicationSession = null;
}
}
}