001    /**
002     * Copyright 2004-2013 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    }