package de.rwth.idsg.steve;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.apache.tomcat.InstanceManager;
import org.apache.tomcat.SimpleInstanceManager;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule;
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import static de.rwth.idsg.steve.SteveConfiguration.CONFIG;
/**
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
* @since 07.04.2015
*/
public class SteveAppContext {
private AnnotationConfigWebApplicationContext springContext;
public SteveAppContext() {
springContext = new AnnotationConfigWebApplicationContext();
springContext.scan("de.rwth.idsg.steve.config");
}
public HandlerCollection getHandlers() throws IOException {
HandlerList handlerList = new HandlerList();
handlerList.setHandlers(
new Handler[]{
getRedirectHandler(),
getWebApp()
});
return handlerList;
}
private Handler getWebApp() throws IOException {
if (CONFIG.getJetty().isGzipEnabled()) {
return enableGzip(initWebApp());
} else {
return initWebApp();
}
}
/**
* Wraps the whole web app in a gzip handler to make Jetty return compressed content
*
* http://www.eclipse.org/jetty/documentation/current/gzip-filter.html
*/
private Handler enableGzip(WebAppContext ctx) {
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setHandler(ctx);
return gzipHandler;
}
private WebAppContext initWebApp() throws IOException {
WebAppContext ctx = new WebAppContext();
ctx.setContextPath(CONFIG.getContextPath());
ctx.setResourceBase(new ClassPathResource("webapp").getURI().toString());
// Disable directory listings if no index.html is found.
ctx.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
ServletHolder web = new ServletHolder("spring-dispatcher", new DispatcherServlet(springContext));
ServletHolder cxf = new ServletHolder("cxf", new CXFServlet());
ctx.addEventListener(new ContextLoaderListener(springContext));
ctx.addServlet(web, CONFIG.getSpringMapping());
ctx.addServlet(cxf, CONFIG.getCxfMapping());
if (CONFIG.getProfile().isProd()) {
addSecurityFilter(ctx);
}
initJSP(ctx);
return ctx;
}
private void addSecurityFilter(WebAppContext ctx) {
// The bean name is not arbitrary, but is as expected by Spring
Filter f = new DelegatingFilterProxy(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
ctx.addFilter(
new FilterHolder(f),
CONFIG.getSpringManagerMapping(),
EnumSet.allOf(DispatcherType.class)
);
}
private Handler getRedirectHandler() {
RewriteHandler rewrite = new RewriteHandler();
rewrite.setRewriteRequestURI(true);
rewrite.setRewritePathInfo(true);
for (String redirect : getRedirectSet()) {
RedirectPatternRule rule = new RedirectPatternRule();
rule.setTerminating(true);
rule.setPattern(redirect);
rule.setLocation(CONFIG.getContextPath() + "/manager/home");
rewrite.addRule(rule);
}
return rewrite;
}
private HashSet<String> getRedirectSet() {
String path = CONFIG.getContextPath();
HashSet<String> redirectSet = new HashSet<>(3);
redirectSet.add("");
redirectSet.add(path + "");
// Otherwise (if path = ""), we would already be at root of the server ("/")
// and using the redirection below would cause an infinite loop.
if (!"".equals(path)) {
redirectSet.add(path + "/");
}
return redirectSet;
}
// -------------------------------------------------------------------------
// JSP stuff
//
// Help by:
//
// https://github.com/jetty-project/embedded-jetty-jsp
// https://github.com/jasonish/jetty-springmvc-jsp-template
// http://examples.javacodegeeks.com/enterprise-java/jetty/jetty-jsp-example
// -------------------------------------------------------------------------
private void initJSP(WebAppContext ctx) throws IOException {
ctx.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
ctx.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
ctx.addBean(new ServletContainerInitializersStarter(ctx), true);
}
/**
* Ensure the JSP engine is initialized correctly
*/
private List<ContainerInitializer> jspInitializers() {
List<ContainerInitializer> initializers = new ArrayList<>();
initializers.add(new ContainerInitializer(new JettyJasperInitializer(), null));
return initializers;
}
}