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

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

The newest version!
/*
 * 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.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Principal;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Response;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.StandardSession;
import org.apache.catalina.util.SessionConfig;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;

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, MemcachedSessionService.SessionManager { protected static final String NAME = MemcachedBackupSessionManager.class.getSimpleName(); protected final Log _log = LogFactory.getLog( getClass() ); protected MemcachedSessionService _msm; /** Can be used to override Context.sessionTimeout (to allow tests to set more fine grained session timeouts) */ private Integer _maxInactiveInterval; private Boolean _contextHasFormBasedSecurityConstraint; public MemcachedBackupSessionManager() { _msm = new MemcachedSessionService( this ) { @Override protected RequestTrackingContextValve createRequestTrackingContextValve(final String sessionCookieName) { final RequestTrackingContextValve result = super.createRequestTrackingContextValve(sessionCookieName); result.setAsyncSupported(true); return result; } @Override protected RequestTrackingHostValve createRequestTrackingHostValve(final String sessionCookieName, final CurrentRequest currentRequest) { final RequestTrackingHostValve result = super.createRequestTrackingHostValve(sessionCookieName, currentRequest); result.setAsyncSupported(true); return result; } }; } /** * Return the descriptive short name of this Manager implementation. * * @return the short name */ @Override public String getName() { return NAME; } /** * {@inheritDoc} */ @Override public void load() throws ClassNotFoundException, IOException { } /** * {@inheritDoc} */ @Override public void unload() throws IOException { } @Override public MemcachedBackupSession createSession( final String sessionId ) { return _msm.createSession(sessionId); } @Override public MemcachedBackupSession createEmptySession() { return _msm.createEmptySession(); } @Override public MemcachedBackupSession newMemcachedBackupSession() { return new MemcachedBackupSession( this ); } /** * {@inheritDoc} */ @Override public 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, final boolean update ) { removeInternal(session, update, session.getNote(MemcachedSessionService.NODE_FAILURE) != Boolean.TRUE); } @Override public void removeInternal( final Session session, final boolean update ) { super.remove(session, update); } private void removeInternal( final Session session, final boolean update, final boolean removeFromMemcached ) { if ( _log.isDebugEnabled() ) { _log.debug( "remove invoked, removeFromMemcached: " + removeFromMemcached + ", id: " + session.getId() ); } if ( removeFromMemcached ) { _msm.deleteFromMemcached( session.getId() ); } super.remove( session, update ); _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 ); } @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); } @Override public boolean isMaxInactiveIntervalSet() { return _maxInactiveInterval != null; } public int getMaxInactiveInterval() { return _maxInactiveInterval; } public void setMaxInactiveInterval(int interval) { Integer oldMaxInactiveInterval = _maxInactiveInterval; _maxInactiveInterval = interval; support.firePropertyChange("maxInactiveInterval", oldMaxInactiveInterval, _maxInactiveInterval); } /** * 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(); } @Override public void setLockExpiration(int lockExpiration) { _msm.setLockExpiration(lockExpiration); } /** * 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); } public void setStorageKeyPrefix(final String storageKeyPrefix) { _msm.setStorageKeyPrefix(storageKeyPrefix); } /** * {@inheritDoc} */ @Override public void startInternal() throws LifecycleException { super.startInternal(); _msm.startInternal(); setState(LifecycleState.STARTING); } /** * {@inheritDoc} */ @Override public void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); if ( _msm.isSticky() ) { _log.info( "Removing sessions from local session map." ); for( final Session session : sessions.values() ) { swapOut( (StandardSession) session ); } } _msm.shutdown(); super.stopInternal(); } private void swapOut( @Nonnull final StandardSession session ) { // implementation like the one in PersistentManagerBase.swapOut if (!session.isValid()) { return; } session.passivate(); removeInternal(session, true); session.recycle(); } /** * {@inheritDoc} */ @Override public void backgroundProcess() { _msm.updateExpirationInMemcached(); super.backgroundProcess(); } /** * Specifies if the session shall be stored asynchronously in memcached as * {@link StorageClient#set(String, int, byte[])} 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 StorageClient#set(String, int, byte[])} 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 #isSessionBackupAsync()}) 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() { return SessionConfig.getSessionCookieName(getContext()); } @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 getState() == LifecycleState.INITIALIZED || getState() == LifecycleState.STARTED; } @Override public String getString( final String key, final Object ... args ) { return sm.getString( key, args ); } @Override public ClassLoader getContainerClassLoader() { return getContext().getLoader().getClassLoader(); } @Override public void writePrincipal( @Nonnull Principal principal, @Nonnull ObjectOutputStream oos) throws IOException { oos.writeObject(principal); } @Override public Principal readPrincipal( final ObjectInputStream ois ) throws ClassNotFoundException, IOException { return (Principal) ois.readObject(); } public boolean contextHasFormBasedSecurityConstraint(){ if(_contextHasFormBasedSecurityConstraint != null) { return _contextHasFormBasedSecurityConstraint.booleanValue(); } final SecurityConstraint[] constraints = getContext().findConstraints(); final LoginConfig loginConfig = getContext().getLoginConfig(); _contextHasFormBasedSecurityConstraint = constraints != null && constraints.length > 0 && loginConfig != null && HttpServletRequest.FORM_AUTH.equals( loginConfig.getAuthMethod() ); return _contextHasFormBasedSecurityConstraint; } @Override public MemcachedSessionService getMemcachedSessionService() { return _msm; } @Override public String[] getSetCookieHeaders(final Response response) { final Collection result = response.getHeaders("Set-Cookie"); return result.toArray(new String[result.size()]); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy