001 /** 002 * Copyright 2004-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.test.launch; 017 018 import java.io.File; 019 import java.util.ArrayList; 020 import java.util.List; 021 import java.util.StringTokenizer; 022 023 import javax.servlet.Servlet; 024 025 import org.apache.commons.collections.CollectionUtils; 026 import org.apache.commons.lang.builder.ToStringBuilder; 027 import org.eclipse.jetty.server.Server; 028 import org.eclipse.jetty.servlet.ServletContextHandler; 029 import org.eclipse.jetty.servlet.ServletHolder; 030 import org.eclipse.jetty.util.resource.ResourceCollection; 031 import org.eclipse.jetty.webapp.WebAppContext; 032 033 public class JettyLauncher { 034 035 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(JettyLauncher.class); 036 037 /** 038 * The name of an attribute we set in the ServletContext to indicate to the webapp 039 * that it is running within unit tests, in case it needs to alter its configuration 040 * or behavior. 041 */ 042 public static final String JETTYSERVER_TESTMODE_ATTRIB = "JETTYSERVER_TESTMODE"; 043 044 private int port; 045 private String contextName; 046 private List<String> relativeWebappRoots = new ArrayList<String>(); 047 private Class<? extends Servlet> servletClass; 048 private Server server; 049 private ServletContextHandler context; 050 private boolean failOnContextFailure; 051 052 /** 053 * Whether we are in test mode 054 */ 055 private boolean testMode = false; 056 057 public JettyLauncher() { 058 this(8080); 059 } 060 061 public JettyLauncher(int port) { 062 this(port, null, null, null); 063 } 064 065 public JettyLauncher(int port, String contextName) { 066 this(port, contextName, null, null); 067 } 068 069 public JettyLauncher(int port, String contextName, String relativeWebappRoot) { 070 this(port, contextName, relativeWebappRoot, null); 071 } 072 073 public JettyLauncher(int port, String contextName, Class<? extends Servlet> servletClass) { 074 this(port, contextName, null, servletClass); 075 } 076 077 public JettyLauncher(int port, String contextName, String relativeWebappRoots, Class<? extends Servlet> servletClass) { 078 this.port = port; 079 this.contextName = contextName; 080 StringTokenizer tokenizer = new StringTokenizer(relativeWebappRoots, ","); 081 while (tokenizer.hasMoreTokens()) { 082 String relativeWebappRoot = tokenizer.nextToken(); 083 this.relativeWebappRoots.add(relativeWebappRoot); 084 } 085 this.servletClass = servletClass; 086 } 087 088 public void setTestMode(boolean t) { 089 this.testMode = t; 090 } 091 092 public boolean isTestMode() { 093 return testMode; 094 } 095 096 public Server getServer() { 097 return server; 098 } 099 100 public ServletContextHandler getContext() { 101 return context; 102 } 103 104 public void start() throws Exception { 105 server = createServer(); 106 server.start(); 107 if (isFailOnContextFailure() && contextStartupFailed()) { 108 try { 109 server.stop(); 110 } catch (Exception e) { 111 LOG.warn("Failed to stop server after web application startup failure."); 112 } 113 throw new Exception("Failed to startup web application context! Check logs for specific error."); 114 } 115 } 116 117 public void stop() throws Exception { 118 server.stop(); 119 } 120 121 public boolean isStarted() { 122 return server.isStarted(); 123 } 124 125 protected Server createServer() { 126 Server server = new Server(getPort()); 127 setBaseDirSystemProperty(); 128 if (useWebAppContext()) { 129 File tmpDir = new File(System.getProperty("basedir") + "/target/jetty-tmp"); 130 tmpDir.mkdirs(); 131 WebAppContext webAppContext = new WebAppContext(); 132 webAppContext.setContextPath(getContextName()); 133 String[] fullRelativeWebappRoots = new String[this.relativeWebappRoots.size()]; 134 for (int i = 0; i < this.relativeWebappRoots.size(); i++) { 135 String fullRelativeWebappRoot = this.relativeWebappRoots.get(i); 136 fullRelativeWebappRoots[i] = System.getProperty("basedir") + fullRelativeWebappRoot; 137 if (LOG.isInfoEnabled()) { 138 LOG.info("WebAppRoot = " + fullRelativeWebappRoots[i]); 139 } 140 } 141 webAppContext.setBaseResource(new ResourceCollection(fullRelativeWebappRoots)); 142 webAppContext.setTempDirectory(tmpDir); 143 webAppContext.setAttribute(JETTYSERVER_TESTMODE_ATTRIB, String.valueOf(isTestMode())); 144 context = webAppContext; 145 server.setHandler(context); 146 } else { 147 ServletContextHandler root = new ServletContextHandler(server,"/",ServletContextHandler.SESSIONS); 148 root.addServlet(new ServletHolder(servletClass), getContextName()); 149 root.setAttribute(JETTYSERVER_TESTMODE_ATTRIB, String.valueOf(isTestMode())); 150 context = root; 151 } 152 return server; 153 } 154 155 protected void setBaseDirSystemProperty() { 156 if (System.getProperty("basedir") == null) { 157 System.setProperty("basedir", System.getProperty("user.dir")); 158 } 159 } 160 161 private boolean useWebAppContext() { 162 return CollectionUtils.isNotEmpty(this.relativeWebappRoots); 163 } 164 165 protected boolean contextStartupFailed() throws Exception { 166 return !context.isAvailable(); 167 } 168 169 public String getContextName() { 170 if (contextName == null) { 171 return "/SampleRiceClient"; 172 } 173 return contextName; 174 } 175 176 public void setContextName(String contextName) { 177 this.contextName = contextName; 178 } 179 180 public int getPort() { 181 return port; 182 } 183 184 public void setPort(int port) { 185 this.port = port; 186 } 187 188 189 public boolean isFailOnContextFailure() { 190 return this.failOnContextFailure; 191 } 192 193 public void setFailOnContextFailure(boolean failOnContextFailure) { 194 this.failOnContextFailure = failOnContextFailure; 195 } 196 197 public String toString() { 198 return new ToStringBuilder(this).append("port", port) 199 .append("contextName", contextName) 200 .append("relativeWebappRoots", relativeWebappRoots) 201 .append("servletClass", servletClass) 202 .toString(); 203 } 204 205 public static void main(String[] args) { 206 int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080; 207 String contextName = args.length > 1 ? args[1] : null; 208 String relativeWebappRoot = args.length > 2 ? args[2] : null; 209 try { 210 new JettyLauncher(port, contextName, relativeWebappRoot).start(); 211 } catch (Exception e) { 212 e.printStackTrace(); 213 } 214 } 215 }