package de.javakaffee.web.msm.integration;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Hashtable;
import javax.annotation.Nonnull;
import javax.naming.NamingException;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Valve;
import org.apache.catalina.authenticator.AuthenticatorBase;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.deploy.SecurityCollection;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.realm.UserDatabaseRealm;
import org.apache.catalina.startup.Embedded;
import org.apache.naming.NamingContext;
import de.javakaffee.web.msm.MemcachedBackupSessionManager;
import de.javakaffee.web.msm.MemcachedSessionService;
import de.javakaffee.web.msm.MemcachedSessionService.SessionManager;
/**
* @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
*/
public class Tomcat6Builder extends TomcatBuilder<Embedded> {
private Embedded tomcat;
@Override
public Tomcat6Builder buildAndStart() throws Exception {
tomcat = build();
tomcat.start();
return this;
}
@Override
public void stop() throws Exception {
tomcat.stop();
}
@Override
public Context getContext() {
return (Context) tomcat.getContainer().findChild( DEFAULT_HOST ).findChild( CONTEXT_PATH );
}
@Override
public MemcachedSessionService.SessionManager getManager() {
return (MemcachedSessionService.SessionManager) getContext().getManager();
}
@Override
public MemcachedSessionService getService() {
return ((MemcachedSessionService.SessionManager) getContext().getManager()).getMemcachedSessionService();
}
@Override
public Engine getEngine() {
return (Engine) tomcat.getContainer();
}
@Override
public void setChangeSessionIdOnAuth(final boolean changeSessionIdOnAuth) {
final Engine engine = (StandardEngine)tomcat.getContainer();
final Host host = (Host)engine.findChild( DEFAULT_HOST );
final Container context = host.findChild( CONTEXT_PATH );
final Valve first = context.getPipeline().getFirst();
if ( first instanceof AuthenticatorBase) {
((AuthenticatorBase)first).setChangeSessionIdOnAuthentication( changeSessionIdOnAuth );
}
}
@edu.umd.cs.findbugs.annotations.SuppressWarnings( "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" )
public Embedded build() throws MalformedURLException,
UnknownHostException, LifecycleException {
final Embedded catalina = new Embedded();
final StandardServer server = new StandardServer();
server.addService( catalina );
try {
final NamingContext globalNamingContext = new NamingContext( new Hashtable<String, Object>(), "ctxt" );
server.setGlobalNamingContext( globalNamingContext );
globalNamingContext.bind( USER_DATABASE, createUserDatabase() );
} catch ( final NamingException e ) {
throw new RuntimeException( e );
}
final URL root = new URL( TestUtils.class.getResource( "/" ), "../test-classes" );
// use file to get correct separator char, replace %20 introduced by URL for spaces
final String cleanedRoot = new File( root.getFile().replaceAll("%20", " ") ).toString();
final String fileSeparator = File.separator.equals( "\\" ) ? "\\\\" : File.separator;
final String docBase = cleanedRoot + File.separator + TestUtils.class.getPackage().getName().replaceAll( "\\.", fileSeparator );
final Engine engine = catalina.createEngine();
/* we must have a unique name for mbeans
*/
engine.setName( "engine-" + port );
engine.setDefaultHost( DEFAULT_HOST );
engine.setJvmRoute( jvmRoute );
catalina.addEngine( engine );
engine.setService( catalina );
final UserDatabaseRealm realm = new UserDatabaseRealm();
realm.setResourceName( USER_DATABASE );
engine.setRealm( realm );
final Host host = catalina.createHost( DEFAULT_HOST, docBase );
engine.addChild( host );
new File( docBase ).mkdirs();
final Context context = createContext( catalina, CONTEXT_PATH, "webapp" );
host.addChild( context );
final MemcachedSessionService.SessionManager sessionManager = createSessionManager();
context.setManager( sessionManager );
context.setBackgroundProcessorDelay( 1 );
context.setCookies(cookies);
new File( "webapp" + File.separator + "webapp" ).mkdirs();
if ( loginType != null ) {
context.addConstraint( createSecurityConstraint( "/*", ROLE_NAME ) );
// context.addConstraint( createSecurityConstraint( "/j_security_check", null ) );
context.addSecurityRole( ROLE_NAME );
final LoginConfig loginConfig = loginType == TestUtils.LoginType.FORM
? new LoginConfig( "FORM", null, "/login", "/error" )
: new LoginConfig( "BASIC", null, null, null );
context.setLoginConfig( loginConfig );
}
/* we must set the maxInactiveInterval after the context,
* as setContainer(context) uses the session timeout set on the context
*/
sessionManager.getMemcachedSessionService().setMemcachedNodes( memcachedNodes );
sessionManager.getMemcachedSessionService().setFailoverNodes( failoverNodes );
sessionManager.getMemcachedSessionService().setEnabled(enabled);
sessionManager.getMemcachedSessionService().setSticky(sticky);
if(lockingMode != null) {
sessionManager.getMemcachedSessionService().setLockingMode(lockingMode.name());
}
sessionManager.getMemcachedSessionService().setMemcachedProtocol(memcachedProtocol);
sessionManager.getMemcachedSessionService().setUsername(username);
sessionManager.setMaxInactiveInterval( sessionTimeout ); // 1 second
sessionManager.getMemcachedSessionService().setSessionBackupAsync( false );
sessionManager.getMemcachedSessionService().setSessionBackupTimeout( 100 );
sessionManager.setProcessExpiresFrequency( 1 ); // 1 second (factor for context.setBackgroundProcessorDelay)
sessionManager.getMemcachedSessionService().setTranscoderFactoryClass( transcoderFactoryClassName != null ? transcoderFactoryClassName : DEFAULT_TRANSCODER_FACTORY );
sessionManager.getMemcachedSessionService().setRequestUriIgnorePattern(".*\\.(png|gif|jpg|css|js|ico)$");
sessionManager.getMemcachedSessionService().setStorageKeyPrefix(storageKeyPrefix);
final Connector connector = catalina.createConnector( "localhost", port, false );
connector.setProperty("bindOnInit", "false");
catalina.addConnector( connector );
return catalina;
}
@Nonnull
protected Context createContext( @Nonnull final Embedded catalina, @Nonnull final String contextPath, @Nonnull final String docBase ) {
return catalina.createContext( contextPath, docBase );
}
/**
* Must create a {@link SessionManager} for the current tomcat version.
*/
@Override
@Nonnull
protected SessionManager createSessionManager() {
return new MemcachedBackupSessionManager();
}
private static SecurityConstraint createSecurityConstraint( final String pattern, final String role ) {
final SecurityConstraint constraint = new SecurityConstraint();
final SecurityCollection securityCollection = new SecurityCollection();
securityCollection.addPattern( pattern );
constraint.addCollection( securityCollection );
if ( role != null ) {
constraint.addAuthRole( role );
}
return constraint;
}
}