/*
* 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 java.io.IOException;
import javax.annotation.Nonnull;
import javax.servlet.ServletException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* This valve is used for tracking that a request was actually processed
* (after e.g. authentication was passed) and detects if sessionId must
* be changed (due to tomcat/memcached failover).
*
* @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a>
* @version $Id$
*/
public class RequestTrackingContextValve extends ValveBase {
static final String INVOKED = "de.javakaffee.msm.contextValve.invoked";
static final String RELOCATE = "session.relocate";
protected static final Log _log = LogFactory.getLog( RequestTrackingHostValve.class );
private final MemcachedSessionService _sessionBackupService;
protected final String _sessionCookieName;
/**
* Creates a new instance with the given ignore pattern and
* {@link MemcachedSessionService}.
* @param sessionBackupService
* the service that actually backups sessions
* @param ignorePattern
* the regular expression for request uris to ignore
* @param context
* the catalina context of this valve
* @param statistics
* used to store statistics
*/
public RequestTrackingContextValve( @Nonnull final String sessionCookieName,
@Nonnull final MemcachedSessionService sessionBackupService ) {
_sessionBackupService = sessionBackupService;
_sessionCookieName = sessionCookieName;
}
/**
* Returns the actually used name for the session cookie.
* @return the cookie name, never null.
*/
protected String getSessionCookieName() {
return _sessionCookieName;
}
public boolean wasInvokedWith(final Request currentRequest) {
return currentRequest != null && currentRequest.getNote(INVOKED) == Boolean.TRUE;
}
/**
* {@inheritDoc}
*/
@Override
public void invoke( final Request request, final Response response ) throws IOException, ServletException {
final Object processRequest = request.getNote(RequestTrackingHostValve.REQUEST_PROCESS);
if(processRequest != Boolean.TRUE) {
request.setNote(INVOKED, Boolean.TRUE);
try {
getNext().invoke( request, response );
} finally {
request.setNote(RequestTrackingHostValve.REQUEST_PROCESSED, Boolean.TRUE);
}
}
else {
boolean sessionIdChanged = false;
try {
request.setNote(INVOKED, Boolean.TRUE);
sessionIdChanged = changeRequestedSessionId( request, response );
getNext().invoke( request, response );
} finally {
request.setNote(RequestTrackingHostValve.REQUEST_PROCESSED, Boolean.TRUE);
request.setNote(RequestTrackingHostValve.SESSION_ID_CHANGED, Boolean.valueOf(sessionIdChanged));
}
}
}
/**
* If there's a session for a requested session id that is taken over (tomcat failover) or
* that will be relocated (memcached failover), the new session id will be set (via {@link Request#changeSessionId(String)}).
*
* @param request the request
* @param response the response
*
* @return <code>true</code> if the id of a valid session was changed.
*
* @see Request#changeSessionId(String)
*/
private boolean changeRequestedSessionId( final Request request, final Response response ) {
/*
* Check for session relocation only if a session id was requested
*/
if ( request.getRequestedSessionId() != null ) {
String newSessionId = _sessionBackupService.changeSessionIdOnTomcatFailover( request.getRequestedSessionId() );
if ( newSessionId == null ) {
newSessionId = _sessionBackupService.changeSessionIdOnMemcachedFailover( request.getRequestedSessionId() );
}
if ( newSessionId != null ) {
request.changeSessionId( newSessionId );
return true;
}
}
return false;
}
}