All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.javakaffee.web.msm.MemcachedBackupSessionManager Maven / Gradle / Ivy

/*
 * Copyright 2009 Martin Grotzke
 *
 * Licensed 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 de.javakaffee.web.msm;


import static de.javakaffee.web.msm.Statistics.StatsType.*;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.spy.memcached.MemcachedClient;

import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.ha.session.SerializablePrincipal;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.StandardSession;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

import de.javakaffee.web.msm.LockingStrategy.LockingMode;

/**
 * This {@link Manager} stores session in configured memcached nodes after the
 * response is finished (committed).
 * 

* Use this session manager in a Context element, like this

 * <Context path="/foo">
 *     <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
 *         memcachedNodes="n1.localhost:11211 n2.localhost:11212" failoverNodes="n2"
 *         connectionType="SASL" non-required
 *         username="username" non-required
 *         password="password" non-required
 *         requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$" />
 * </Context>
 * 
*

* * @author Martin Grotzke * @version $Id$ */ public class MemcachedBackupSessionManager extends ManagerBase implements Lifecycle, PropertyChangeListener, MemcachedSessionService.SessionManager { protected static final String NAME = MemcachedBackupSessionManager.class.getSimpleName(); private static final String INFO = NAME + "/1.0"; protected final Log _log = LogFactory.getLog( getClass() ); private final LifecycleSupport _lifecycle = new LifecycleSupport( this ); private int _maxActiveSessions = -1; private int _rejectedSessions; /** * Has this component been _started yet? */ protected boolean _started = false; protected MemcachedSessionService _msm; public MemcachedBackupSessionManager() { _msm = new MemcachedSessionService( this ); } /** * Return descriptive information about this Manager implementation and the * corresponding version number, in the format * <description>/<version>. * * @return the info string */ @Override public String getInfo() { return INFO; } /** * Return the descriptive short name of this Manager implementation. * * @return the short name */ @Override public String getName() { return NAME; } /** * Initialize this manager. The memcachedClient parameter is there for testing * purposes. If the memcachedClient is provided it's used, otherwise a "real"/new * memcached client is created based on the configuration (like {@link #setMemcachedNodes(String)} etc.). * * @param memcachedClient the memcached client to use, for normal operations this should be null. */ protected void startInternal( final MemcachedClient memcachedClient ) throws LifecycleException { _msm.setMemcachedClient(memcachedClient); _msm.startInternal(); } /** * {@inheritDoc} */ @Override public void setContainer( final Container container ) { // De-register from the old Container (if any) if ( this.container != null && this.container instanceof Context ) { ( (Context) this.container ).removePropertyChangeListener( this ); } // Default processing provided by our superclass super.setContainer( container ); // Register with the new Container (if any) if ( this.container != null && this.container instanceof Context ) { setMaxInactiveInterval( ( (Context) this.container ).getSessionTimeout() * 60 ); ( (Context) this.container ).addPropertyChangeListener( this ); } } /** * {@inheritDoc} */ @Override public synchronized String generateSessionId() { return _msm.newSessionId( super.generateSessionId() ); } /** * {@inheritDoc} */ @Override public void expireSession( final String sessionId ) { if ( _log.isDebugEnabled() ) { _log.debug( "expireSession invoked: " + sessionId ); } super.expireSession( sessionId ); _msm.deleteFromMemcached( sessionId ); } /** * {@inheritDoc} */ @Override public void remove( final Session session ) { remove( session, session.getNote( MemcachedSessionService.NODE_FAILURE ) != Boolean.TRUE ); } @Override public void removeInternal( final Session session, final boolean update ) { // update is there for tomcat7, not available in tomcat6 super.remove( session ); } private void remove( final Session session, final boolean removeFromMemcached ) { if ( _log.isDebugEnabled() ) { _log.debug( "remove invoked, removeFromMemcached: " + removeFromMemcached + ", id: " + session.getId() ); } if ( removeFromMemcached ) { _msm.deleteFromMemcached( session.getId() ); } super.remove( session ); _msm.sessionRemoved((MemcachedBackupSession) session); } /** * Return the active Session, associated with this Manager, with the * specified session id (if any); otherwise return null. * * @param id * The session id for the session to be returned * @return the session or null if no session was found locally * or in memcached. * * @exception IllegalStateException * if a new session cannot be instantiated for any reason * @exception IOException * if an input/output error occurs while processing this * request */ @Override public Session findSession( final String id ) throws IOException { return _msm.findSession( id ); } /** * {@inheritDoc} */ @Override public MemcachedBackupSession createSession( final String sessionId ) { return _msm.createSession( sessionId ); } /** * {@inheritDoc} */ @Override public MemcachedBackupSession createEmptySession() { return _msm.createEmptySession(); } @Override public MemcachedBackupSession newMemcachedBackupSession() { return new MemcachedBackupSession( this ); } @Override public void changeSessionId( final Session session ) { // e.g. invoked by the AuthenticatorBase (for BASIC auth) on login to prevent session fixation // so that session backup won't be omitted we must store this event super.changeSessionId( session ); ((MemcachedBackupSession)session).setSessionIdChanged( true ); } /** * Set the maximum number of active Sessions allowed, or -1 for no limit. * * @param max * The new maximum number of sessions */ public void setMaxActiveSessions( final int max ) { final int oldMaxActiveSessions = _maxActiveSessions; _maxActiveSessions = max; support.firePropertyChange( "maxActiveSessions", Integer.valueOf( oldMaxActiveSessions ), Integer.valueOf( _maxActiveSessions ) ); } @Override public int getMaxActiveSessions() { return _maxActiveSessions; } @Override public void setRejectedSessions( final int rejectedSessions ) { _rejectedSessions = rejectedSessions; } @Override public int getRejectedSessions() { return _rejectedSessions; } /** * {@inheritDoc} */ @Override public void load() throws ClassNotFoundException, IOException { } /** * {@inheritDoc} */ @Override public void unload() throws IOException { } /** * Set the memcached nodes space or comma separated. *

* E.g. n1.localhost:11211 n2.localhost:11212 *

*

* When the memcached nodes are set when this manager is already initialized, * the new configuration will be loaded. *

* * @param memcachedNodes * the memcached node definitions, whitespace or comma separated */ @Override public void setMemcachedNodes( final String memcachedNodes ) { _msm.setMemcachedNodes( memcachedNodes ); } /** * The memcached nodes configuration as provided in the server.xml/context.xml. *

* This getter is there to make this configuration accessible via jmx. *

* @return the configuration string for the memcached nodes. */ public String getMemcachedNodes() { return _msm.getMemcachedNodes(); } /** * The node ids of memcached nodes, that shall only be used for session * backup by this tomcat/manager, if there are no other memcached nodes * left. Node ids are separated by whitespace or comma. *

* E.g. n1 n2 *

*

* When the failover nodes are set when this manager is already initialized, * the new configuration will be loaded. *

* * @param failoverNodes * the failoverNodes to set, whitespace or comma separated */ @Override public void setFailoverNodes( final String failoverNodes ) { _msm.setFailoverNodes( failoverNodes ); } /** * The memcached failover nodes configuration as provided in the server.xml/context.xml. *

* This getter is there to make this configuration accessible via jmx. *

* @return the configuration string for the failover nodes. */ public String getFailoverNodes() { return _msm.getFailoverNodes(); } /** * Set the regular expression for request uris to ignore for session backup. * This should include static resources like images, in the case they are * served by tomcat. *

* E.g. .*\.(png|gif|jpg|css|js)$ *

* * @param requestUriIgnorePattern * the requestUriIgnorePattern to set * @author Martin Grotzke */ public void setRequestUriIgnorePattern( final String requestUriIgnorePattern ) { _msm.setRequestUriIgnorePattern( requestUriIgnorePattern ); } /** * Return the compiled pattern used for including session attributes to a session-backup. * * @return the sessionAttributePattern */ @CheckForNull Pattern getSessionAttributePattern() { return _msm.getSessionAttributePattern(); } /** * Return the string pattern used for including session attributes to a session-backup. * * @return the sessionAttributeFilter */ @CheckForNull public String getSessionAttributeFilter() { return _msm.getSessionAttributeFilter(); } /** * Set the pattern used for including session attributes to a session-backup. * If not set, all session attributes will be part of the session-backup. *

* E.g. ^(userName|sessionHistory)$ *

* * @param sessionAttributeFilter * the sessionAttributeNames to set */ public void setSessionAttributeFilter( @Nullable final String sessionAttributeFilter ) { _msm.setSessionAttributeFilter( sessionAttributeFilter ); } /** * The class of the factory that creates the * {@link net.spy.memcached.transcoders.Transcoder} to use for serializing/deserializing * sessions to/from memcached (requires a default/no-args constructor). * The default value is the {@link JavaSerializationTranscoderFactory} class * (used if this configuration attribute is not specified). *

* After the {@link TranscoderFactory} instance was created from the specified class, * {@link TranscoderFactory#setCopyCollectionsForSerialization(boolean)} * will be invoked with the currently set copyCollectionsForSerialization propery, which * has either still the default value (false) or the value provided via * {@link #setCopyCollectionsForSerialization(boolean)}. *

* * @param transcoderFactoryClassName the {@link TranscoderFactory} class name. */ public void setTranscoderFactoryClass( final String transcoderFactoryClassName ) { _msm.setTranscoderFactoryClass( transcoderFactoryClassName ); } /** * Specifies, if iterating over collection elements shall be done on a copy * of the collection or on the collection itself. The default value is false * (used if this configuration attribute is not specified). *

* This option can be useful if you have multiple requests running in * parallel for the same session (e.g. AJAX) and you are using * non-thread-safe collections (e.g. {@link java.util.ArrayList} or * {@link java.util.HashMap}). In this case, your application might modify a * collection while it's being serialized for backup in memcached. *

*

* Note: This must be supported by the {@link TranscoderFactory} * specified via {@link #setTranscoderFactoryClass(String)}: after the {@link TranscoderFactory} instance * was created from the specified class, {@link TranscoderFactory#setCopyCollectionsForSerialization(boolean)} * will be invoked with the provided copyCollectionsForSerialization value. *

* * @param copyCollectionsForSerialization * true, if iterating over collection elements shall be done * on a copy of the collection, false if the collections own iterator * shall be used. */ public void setCopyCollectionsForSerialization( final boolean copyCollectionsForSerialization ) { _msm.setCopyCollectionsForSerialization( copyCollectionsForSerialization ); } /** * Custom converter allow you to provide custom serialization of application specific * types. Multiple converter classes are separated by comma (with optional space following the comma). *

* This option is useful if reflection based serialization is very verbose and you want * to provide a more efficient serialization for a specific type. *

*

* Note: This must be supported by the {@link TranscoderFactory} * specified via {@link #setTranscoderFactoryClass(String)}: after the {@link TranscoderFactory} instance * was created from the specified class, {@link TranscoderFactory#setCustomConverterClassNames(String[])} * is invoked with the provided custom converter class names. *

*

Requirements regarding the specific custom converter classes depend on the * actual serialization strategy, but a common requirement would be that they must * provide a default/no-args constructor.
* For more details have a look at * SerializationStrategies. *

* * @param customConverterClassNames a list of class names separated by comma */ public void setCustomConverter( final String customConverterClassNames ) { _msm.setCustomConverter( customConverterClassNames ); } /** * Specifies if statistics (like number of requests with/without session) shall be * gathered. Default value of this property is true. *

* Statistics will be available via jmx and the Manager mbean ( * e.g. in the jconsole mbean tab open the attributes node of the * Catalina/Manager/<context-path>/<host name> * mbean and check for msmStat* values. *

* * @param enableStatistics true if statistics shall be gathered. */ public void setEnableStatistics( final boolean enableStatistics ) { _msm.setEnableStatistics( enableStatistics ); } /** * Specifies the number of threads that are used if {@link #setSessionBackupAsync(boolean)} * is set to true. * * @param backupThreadCount the number of threads to use for session backup. */ public void setBackupThreadCount( final int backupThreadCount ) { _msm.setBackupThreadCount( backupThreadCount ); } /** * The number of threads to use for session backup if session backup shall be * done asynchronously. * @return the number of threads for session backup. */ public int getBackupThreadCount() { return _msm.getBackupThreadCount(); } /** * Specifies the memcached protocol to use, either "text" (default) or "binary". * * @param memcachedProtocol one of "text" or "binary". */ public void setMemcachedProtocol( final String memcachedProtocol ) { _msm.setMemcachedProtocol( memcachedProtocol ); } /** * Enable/disable memcached-session-manager (default true / enabled). * If disabled, sessions are neither looked up in memcached nor stored in memcached. * * @param enabled specifies if msm shall be disabled or not. * @throws IllegalStateException it's not allowed to disable this session manager when running in non-sticky mode. */ @Override public void setEnabled( final boolean enabled ) throws IllegalStateException { _msm.setEnabled( enabled ); } /** * Specifies, if msm is enabled or not. * * @return true if enabled, otherwise false. */ public boolean isEnabled() { return _msm.isEnabled(); } @Override public void setSticky( final boolean sticky ) { _msm.setSticky( sticky ); } public boolean isSticky() { return _msm.isSticky(); } @Override public void setOperationTimeout(final long operationTimeout ) { _msm.setOperationTimeout(operationTimeout); } public long getOperationTimeout() { return _msm.getOperationTimeout(); } /** * Sets the session locking mode. Possible values: *
    *
  • none - does not lock the session at all (default for non-sticky sessions).
  • *
  • all - the session is locked for each request accessing the session.
  • *
  • auto - locks the session for each request except for those the were detected to access the session only readonly.
  • *
  • uriPattern:<regexp> - locks the session for each request with a request uri (with appended querystring) matching * the provided regular expression.
  • *
*/ @Override public void setLockingMode( @Nullable final String lockingMode ) { _msm.setLockingMode( lockingMode ); } @Override public void setLockingMode( @Nullable final LockingMode lockingMode, @Nullable final Pattern uriPattern, final boolean storeSecondaryBackup ) { _msm.setLockingMode( lockingMode, uriPattern, storeSecondaryBackup ); } @Override public void setUsername(final String username) { _msm.setUsername(username); } @Override public void setPassword(final String password) { _msm.setPassword(password); } /** * {@inheritDoc} */ @Override public void addLifecycleListener( final LifecycleListener arg0 ) { _lifecycle.addLifecycleListener( arg0 ); } /** * {@inheritDoc} */ @Override public LifecycleListener[] findLifecycleListeners() { return _lifecycle.findLifecycleListeners(); } /** * {@inheritDoc} */ @Override public void removeLifecycleListener( final LifecycleListener arg0 ) { _lifecycle.removeLifecycleListener( arg0 ); } /** * {@inheritDoc} */ @Override public void start() throws LifecycleException { if( ! initialized ) { init(); } // Validate and update our current component state if (_started) { return; } _lifecycle.fireLifecycleEvent(START_EVENT, null); _started = true; // Force initialization of the random number generator if (log.isDebugEnabled()) { log.debug("Force random number initialization starting"); } super.generateSessionId(); if (log.isDebugEnabled()) { log.debug("Force random number initialization completed"); } startInternal( null ); } /** * {@inheritDoc} */ @Override public void stop() throws LifecycleException { if (log.isDebugEnabled()) { log.debug("Stopping"); } // Validate and update our current component state if (!_started) { throw new LifecycleException (sm.getString("standardManager.notStarted")); } _lifecycle.fireLifecycleEvent(STOP_EVENT, null); _started = false; // Require a new random number generator if we are restarted random = null; if ( initialized ) { if ( _msm.isSticky() ) { _log.info( "Removing sessions from local session map." ); for( final Session session : sessions.values() ) { swapOut( (StandardSession) session ); } } _msm.shutdown(); destroy(); } } private void swapOut( @Nonnull final StandardSession session ) { // implementation like the one in PersistentManagerBase.swapOut if (!session.isValid()) { return; } session.passivate(); remove( session, false ); session.recycle(); } /** * {@inheritDoc} */ @Override public void backgroundProcess() { _msm.updateExpirationInMemcached(); super.backgroundProcess(); } /** * {@inheritDoc} */ @Override public void propertyChange( final PropertyChangeEvent event ) { // Validate the source of this event if ( !( event.getSource() instanceof Context ) ) { return; } // Process a relevant property change if ( event.getPropertyName().equals( "sessionTimeout" ) ) { try { setMaxInactiveInterval( ( (Integer) event.getNewValue() ).intValue() * 60 ); } catch ( final NumberFormatException e ) { _log.warn( "standardManager.sessionTimeout: " + event.getNewValue().toString() ); } } } /** * Specifies if the session shall be stored asynchronously in memcached as * {@link MemcachedClient#set(String, int, Object)} supports it. If this is * false, the timeout set via {@link #setSessionBackupTimeout(int)} is * evaluated. If this is true, the {@link #setBackupThreadCount(int)} * is evaluated. *

* By default this property is set to true - the session * backup is performed asynchronously. *

* * @param sessionBackupAsync * the sessionBackupAsync to set */ public void setSessionBackupAsync( final boolean sessionBackupAsync ) { _msm.setSessionBackupAsync( sessionBackupAsync ); } /** * Specifies if the session shall be stored asynchronously in memcached as * {@link MemcachedClient#set(String, int, Object)} supports it. If this is * false, the timeout from {@link #getSessionBackupTimeout()} is * evaluated. */ public boolean isSessionBackupAsync() { return _msm.isSessionBackupAsync(); } /** * The timeout in milliseconds after that a session backup is considered as * beeing failed. *

* This property is only evaluated if sessions are stored synchronously (set * via {@link #setSessionBackupAsync(boolean)}). *

*

* The default value is 100 millis. * * @param sessionBackupTimeout * the sessionBackupTimeout to set (milliseconds) */ public void setSessionBackupTimeout( final int sessionBackupTimeout ) { _msm.setSessionBackupTimeout( sessionBackupTimeout ); } /** * The timeout in milliseconds after that a session backup is considered as * beeing failed when {@link #getSessionBackupAsync()}) is false. */ public long getSessionBackupTimeout() { return _msm.getSessionBackupTimeout(); } // ------------------------- statistics via jmx ---------------- /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithBackupFailure() */ public long getMsmStatNumBackupFailures() { return _msm.getStatistics().getRequestsWithBackupFailure(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithMemcachedFailover() */ public long getMsmStatNumTomcatFailover() { return _msm.getStatistics().getRequestsWithTomcatFailover(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithMemcachedFailover() */ public long getMsmStatNumMemcachedFailover() { return _msm.getStatistics().getRequestsWithMemcachedFailover(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithoutSession() */ public long getMsmStatNumRequestsWithoutSession() { return _msm.getStatistics().getRequestsWithoutSession(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithoutSessionAccess() */ public long getMsmStatNumNoSessionAccess() { return _msm.getStatistics().getRequestsWithoutSessionAccess(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithoutAttributesAccess() */ public long getMsmStatNumNoAttributesAccess() { return _msm.getStatistics().getRequestsWithoutAttributesAccess(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithoutSessionModification() */ public long getMsmStatNumNoSessionModification() { return _msm.getStatistics().getRequestsWithoutSessionModification(); } /** * @return * @see de.javakaffee.web.msm.Statistics#getRequestsWithSession() */ public long getMsmStatNumRequestsWithSession() { return _msm.getStatistics().getRequestsWithSession(); } public long getMsmStatNumNonStickySessionsPingFailed() { return _msm.getStatistics().getNonStickySessionsPingFailed(); } public long getMsmStatNumNonStickySessionsReadOnlyRequest() { return _msm.getStatistics().getNonStickySessionsReadOnlyRequest(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that took the attributes serialization. * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatAttributesSerializationInfo() { return _msm.getStatistics().getProbe( ATTRIBUTES_SERIALIZATION ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that session backups took in the request thread (including omitted * session backups e.g. because the session attributes were not accessed). * This time was spent in the request thread. * * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatEffectiveBackupInfo() { return _msm.getStatistics().getProbe( EFFECTIVE_BACKUP ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that session backups took (excluding backups where a session * was relocated). This time was spent in the request thread if session backup * is done synchronously, otherwise another thread used this time. * * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatBackupInfo() { return _msm.getStatistics().getProbe( BACKUP ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that loading sessions from memcached took (including deserialization). * @return a String array for statistics inspection via jmx. * @see #getMsmStatSessionDeserializationInfo() * @see #getMsmStatNonStickyAfterLoadFromMemcachedInfo() */ public String[] getMsmStatSessionsLoadedFromMemcachedInfo() { return _msm.getStatistics().getProbe( LOAD_FROM_MEMCACHED ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that deleting sessions from memcached took. * @return a String array for statistics inspection via jmx. * @see #getMsmStatNonStickyAfterDeleteFromMemcachedInfo() */ public String[] getMsmStatSessionsDeletedFromMemcachedInfo() { return _msm.getStatistics().getProbe( DELETE_FROM_MEMCACHED ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that deserialization of session data took. * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatSessionDeserializationInfo() { return _msm.getStatistics().getProbe( SESSION_DESERIALIZATION ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the size of the data that was sent to memcached. * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatCachedDataSizeInfo() { return _msm.getStatistics().getProbe( CACHED_DATA_SIZE ).getInfo(); } /** * Returns a string array with labels and values of count, min, avg and max * of the time that storing data in memcached took (excluding serialization, * including compression). * @return a String array for statistics inspection via jmx. */ public String[] getMsmStatMemcachedUpdateInfo() { return _msm.getStatistics().getProbe( MEMCACHED_UPDATE ).getInfo(); } /** * Info about locks acquired in non-sticky mode. */ public String[] getMsmStatNonStickyAcquireLockInfo() { return _msm.getStatistics().getProbe( ACQUIRE_LOCK ).getInfo(); } /** * Lock acquiration in non-sticky session mode. */ public String[] getMsmStatNonStickyAcquireLockFailureInfo() { return _msm.getStatistics().getProbe( ACQUIRE_LOCK_FAILURE ).getInfo(); } /** * Lock release in non-sticky session mode. */ public String[] getMsmStatNonStickyReleaseLockInfo() { return _msm.getStatistics().getProbe( RELEASE_LOCK ).getInfo(); } /** * Tasks executed (in the request thread) for non-sticky sessions at the end of requests that did not access * the session (validity load/update, ping session, ping 2nd session backup, update validity backup). */ public String[] getMsmStatNonStickyOnBackupWithoutLoadedSessionInfo() { return _msm.getStatistics().getProbe( NON_STICKY_ON_BACKUP_WITHOUT_LOADED_SESSION ).getInfo(); } /** * Tasks executed for non-sticky sessions after session backup (ping session, store validity info / meta data, * store additional backup in secondary memcached). */ public String[] getMsmStatNonStickyAfterBackupInfo() { return _msm.getStatistics().getProbe( NON_STICKY_AFTER_BACKUP ).getInfo(); } /** * Tasks executed for non-sticky sessions after a session was loaded from memcached (load validity info / meta data). */ public String[] getMsmStatNonStickyAfterLoadFromMemcachedInfo() { return _msm.getStatistics().getProbe( NON_STICKY_AFTER_LOAD_FROM_MEMCACHED ).getInfo(); } /** * Tasks executed for non-sticky sessions after a session was deleted from memcached (delete validity info and backup data). */ public String[] getMsmStatNonStickyAfterDeleteFromMemcachedInfo() { return _msm.getStatistics().getProbe( NON_STICKY_AFTER_DELETE_FROM_MEMCACHED ).getInfo(); } // --------------------------------------------------------------------------- @Override public String getSessionCookieName() { String result = getSessionCookieNameFromContext((Context) getContainer()); if ( result == null ) { result = Globals.SESSION_COOKIE_NAME; _log.debug( "Using session cookie name from context: " + result ); } return result; } @CheckForNull private String getSessionCookieNameFromContext( final Context context ) { // since 6.0.27 the session cookie name, domain and path is configurable per context, // see issue http://issues.apache.org/bugzilla/show_bug.cgi?id=48379 try { final Method getSessionCookieName = Context.class.getDeclaredMethod( "getSessionCookieName" ); final String result = (String) getSessionCookieName.invoke( context ); if ( result != null ) { _log.debug( "Using session cookie name from context: " + result ); } return result; } catch( final NoSuchMethodException e ) { // the context does not provide the method getSessionCookieName } catch ( final Exception e ) { throw new RuntimeException( "Could not read session cookie name from context.", e ); } return null; } @Override public MemcachedBackupSession getSessionInternal( final String sessionId ) { return (MemcachedBackupSession) sessions.get( sessionId ); } @Override public Map getSessionsInternal() { return sessions; } @Override public String getString( final String key ) { return sm.getString( key ); } @Override public void incrementSessionCounter() { sessionCounter++; } @Override public void incrementRejectedSessions() { _rejectedSessions++; } @Override public boolean isInitialized() { return initialized; } @Override public String getString( final String key, final Object ... args ) { return sm.getString( key, args ); } @Override public Principal readPrincipal( final ObjectInputStream ois ) throws ClassNotFoundException, IOException { return SerializablePrincipal.readPrincipal( ois, getContainer().getRealm() ); } @Override public MemcachedSessionService getMemcachedSessionService() { return _msm; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy