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 }