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