/*
* Copyright (c) 2010-2012 Engine Yard, Inc.
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
* This source code is available under the MIT license.
* See the file LICENSE.txt for details.
*/
package org.jruby.rack;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.jruby.rack.servlet.DefaultServletRackContext;
import org.jruby.rack.servlet.ServletRackConfig;
import org.jruby.rack.servlet.ServletRackContext;
import static org.jruby.rack.DefaultRackConfig.isThrowInitException;
/**
* Web application lifecycle listener.
* @author nicksieger
*/
public class RackServletContextListener implements ServletContextListener {
private final RackApplicationFactory factory;
/**
* Used by web container.
*/
public RackServletContextListener() {
this.factory = null;
}
/**
* Only for injecting a mock factory for testing.
*/
RackServletContextListener(RackApplicationFactory factory) {
this.factory = factory;
}
public void contextInitialized(final ServletContextEvent event) {
final ServletContext context = event.getServletContext();
final ServletRackConfig config = new ServletRackConfig(context);
final RackApplicationFactory factory = newApplicationFactory(config);
context.setAttribute(RackApplicationFactory.FACTORY, factory);
final ServletRackContext rackContext = new DefaultServletRackContext(config);
context.setAttribute(RackApplicationFactory.RACK_CONTEXT, rackContext);
try {
factory.init(rackContext);
}
catch (RuntimeException e) {
handleInitializationException(e, factory, rackContext);
}
}
public void contextDestroyed(final ServletContextEvent event) {
final ServletContext context = event.getServletContext();
final RackApplicationFactory factory =
(RackApplicationFactory) context.getAttribute(RackApplicationFactory.FACTORY);
if ( factory != null ) {
context.removeAttribute(RackApplicationFactory.FACTORY);
context.removeAttribute(RackApplicationFactory.RACK_CONTEXT);
factory.destroy();
}
}
protected RackApplicationFactory newApplicationFactory(RackConfig config) {
if (factory != null) return factory; // only != null while testing
final RackApplicationFactory factory = new DefaultRackApplicationFactory();
final Integer maxRuntimes = config.getMaximumRuntimes();
// for backwards compatibility when runtime mix/max values not specified
// we assume a single shared (threadsafe) runtime to be used :
if ( maxRuntimes == null || maxRuntimes.intValue() == 1 ) {
return new SharedRackApplicationFactory(factory);
}
else {
return config.isSerialInitialization() ?
new SerialPoolingRackApplicationFactory(factory) :
new PoolingRackApplicationFactory(factory) ;
}
}
protected void handleInitializationException(
final Exception e,
final RackApplicationFactory factory,
final ServletRackContext rackContext) {
// TODO for backwards compat we do not throw (by default) but should :
if ( isThrowInitException(rackContext.getConfig()) ) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw RackInitializationException.wrap(e);
}
// NOTE: factory should have already logged the error ...
rackContext.log(RackLogger.ERROR, "initialization failed", e);
}
}