package net.unit8.waitt.server.tomcat8; import net.unit8.waitt.api.ClassLoaderFactory; import net.unit8.waitt.api.EmbeddedServer; import net.unit8.waitt.api.ServerStatus; import net.unit8.waitt.api.WebappDecorator; import net.unit8.waitt.api.configuration.FilterConfiguration; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.Wrapper; import org.apache.catalina.core.AprLifecycleListener; import org.apache.catalina.core.StandardHost; import org.apache.catalina.core.StandardServer; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.startup.Constants; import org.apache.catalina.startup.ContextConfig; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.JarScanner; import org.apache.tomcat.util.descriptor.web.FilterDef; import org.apache.tomcat.util.descriptor.web.FilterMap; import org.codehaus.plexus.classworlds.realm.ClassRealm; import java.io.File; import java.net.URL; import java.util.List; /** * Tomcat8 server. * * @author kawasima */ public class Tomcat8EmbeddedServer implements EmbeddedServer { final Tomcat tomcat; Context context; List<WebappDecorator> decorators; public Tomcat8EmbeddedServer() { tomcat = new Tomcat(); if (tomcat.getHost() instanceof StandardHost) { StandardHost host = (StandardHost) tomcat.getHost(); host.setUnpackWARs(true); File appBase = new File("target/tomcat8/webapps"); if (!appBase.exists()) appBase.mkdirs(); host.setAppBase(appBase.getAbsolutePath()); File workDir = new File("target/tomcat8/work"); if (!workDir.exists()) workDir.mkdirs(); host.setWorkDir(workDir.getAbsolutePath()); } } public String getName() { return "tomcat8"; } public void setPort(int port) { tomcat.setPort(port); } public void setBaseDir(String baseDir) { } public void setClassLoaderFactory(ClassLoaderFactory factory) { ClassLoaderFactoryHolder.setClassLoaderFactory(factory); } public void setMainContext(String contextPath, String docBase, ClassLoader classLoader) { File appBaseDir = new File(docBase); if (!appBaseDir.exists()) { if (!appBaseDir.mkdirs()) { throw new IllegalStateException("Can't create appBase:" + docBase); } } context = addWebapp(contextPath, docBase, classLoader, true); context.setSessionCookieDomain(null); Wrapper defaultServlet = context.createWrapper(); defaultServlet.setName("default1"); defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet"); defaultServlet.addInitParameter("debug", "0"); defaultServlet.addInitParameter("listings", "false"); defaultServlet.setLoadOnStartup(1); context.addChild(defaultServlet); context.addServletMapping("/", "default1"); context.addWelcomeFile("index.html"); } public void addContext(String contextPath, String docBase, ClassLoader classLoader) { Context context = addWebapp(contextPath, docBase, classLoader, false); context.setSessionCookieDomain(null); Wrapper defaultServlet = context.createWrapper(); defaultServlet.setName("default1"); defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet"); defaultServlet.addInitParameter("debug", "0"); defaultServlet.addInitParameter("listings", "false"); defaultServlet.setLoadOnStartup(1); context.addChild(defaultServlet); context.addServletMapping("/", "default1"); context.addWelcomeFile("index.html"); } @Override public void start() { StandardServer server = (StandardServer) tomcat.getServer(); AprLifecycleListener listener = new AprLifecycleListener(); server.addLifecycleListener(listener); server.setParentClassLoader(getClass().getClassLoader()); tomcat.getConnector().setURIEncoding("UTF-8"); tomcat.getConnector().setUseBodyEncodingForURI(true); try { server.start(); } catch (LifecycleException e) { throw new IllegalStateException(e); } } @Override public void reload() { context.reload(); } @Override public ServerStatus getStatus() { switch(tomcat.getServer().getState()) { case STARTED: return ServerStatus.RUNNING; case STOPPED: return ServerStatus.STOPPED; default: return ServerStatus.UNKNOWN; } } @Override public void await() { tomcat.getServer().await(); } @Override public void stop() { try { tomcat.stop(); } catch (LifecycleException e) { throw new IllegalStateException(e); } } @Override public void setWebappDecorators(List<WebappDecorator> decorators) { this.decorators = decorators; } private Context addWebapp(String contextPath, String appBase, ClassLoader classLoader, boolean mainContext) { Context context; String contextClass = ((StandardHost) tomcat.getHost()).getContextClass(); try { context = (Context) Class.forName(contextClass).getConstructor().newInstance(); } catch (Exception ex) { throw new IllegalStateException(ex); } if (mainContext) { for (WebappDecorator decorator : decorators) { for (FilterConfiguration filterConfig : decorator.getFilterConfigs()) { FilterDef filterDef = new FilterDef(); filterDef.setFilterClass(filterConfig.getClassName()); filterDef.setFilterName(filterConfig.getName()); context.addFilterDef(filterDef); FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterConfig.getName()); for (String urlPattern : filterConfig.getUrlPattern()) { filterMap.addURLPattern(urlPattern); } context.addFilterMap(filterMap); for (URL url : ((ClassRealm) decorator.getClass().getClassLoader()).getURLs()) { ((ClassRealm) classLoader).addURL(url); } } } } final WebappLoader webappLoader = new WebappLoader(classLoader); if (mainContext && ClassLoaderFactoryHolder.getClassLoaderFactory() != null) { webappLoader.setLoaderClass("net.unit8.waitt.server.tomcat8.Tomcat8WebappClassLoaderWrapper"); JarScanner jarScanner = new ClassRealmJarScanner(); context.setJarScanner(jarScanner); } webappLoader.setDelegate(true); context.setLoader(webappLoader); ContextConfig config = new ContextConfig(); context.setPath(contextPath); context.setDocBase(appBase); context.addLifecycleListener(new Tomcat.DefaultWebXmlListener()); context.setConfigFile(null); context.addLifecycleListener(config); config.setDefaultWebXml(Constants.NoDefaultWebXml); tomcat.getHost().addChild(context); return context; } }