001    // Copyright 2006, 2007, 2008 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.test;
016    
017    import org.mortbay.http.NCSARequestLog;
018    import org.mortbay.http.SocketListener;
019    import org.mortbay.http.SunJsseListener;
020    import org.mortbay.jetty.Server;
021    import org.mortbay.jetty.servlet.WebApplicationContext;
022    
023    import java.io.File;
024    import static java.lang.String.format;
025    
026    /**
027     * Used to start up an instance of the Jetty servlet container in-process, as part of an integration test suite. The
028     * started Jetty is reliant on the file <code>src/test/conf/webdefault.xml</code>.
029     *
030     * @see AbstractIntegrationTestSuite
031     */
032    public class JettyRunner
033    {
034        public static final String DEFAULT_CONTEXT_PATH = "/";
035    
036        public static final int DEFAULT_PORT = 8080;
037    
038        public static final int DEFAULT_SECURE_PORT = 8443;
039    
040        private final File workingDir;
041    
042        private final String contextPath;
043    
044        private final int port;
045    
046        private final String warPath;
047    
048        private final Server jetty;
049        
050        private final String[] virtualHosts;
051    
052        /**
053         * Creates and starts a new instance of Jetty. This should be done from a test case setup method.
054         *
055         * @param workingDir  current directory (used for any relative files)
056         * @param contextPath the context path for the deployed application
057         * @param port        the port number used to access the application
058         * @param warPath     the path to the exploded web application (typically, "src/main/webapp")
059         * @param virtualHosts an array with virtual hosts
060         */
061        public JettyRunner(File workingDir, String contextPath, int port, String warPath,
062                    String ... virtualHosts)
063        {
064            this.workingDir = workingDir;
065            this.contextPath = contextPath;
066            this.port = port;
067            this.warPath = warPath;
068            this.virtualHosts = virtualHosts;
069    
070            jetty = createAndStart();
071        }
072    
073        /**
074         * Stops the Jetty instance. This should be called from a test case tear down method.
075         */
076        public void stop()
077        {
078            System.out.printf("Stopping Jetty instance on port %d\n", port);
079    
080            try
081            {
082                // Stop immediately and not gracefully.
083                jetty.stop(false);
084    
085                while (jetty.isStarted())
086                {
087                    Thread.sleep(100);
088                }
089            }
090            catch (Exception ex)
091            {
092                throw new RuntimeException("Error stopping Jetty instance: " + ex.toString(), ex);
093            }
094    
095            System.out.println("Jetty instance has stopped.");
096        }
097    
098        @Override
099        public String toString()
100        {
101            return format("<JettyRunner %s:%d (%s)>", contextPath, port, warPath);
102        }
103    
104    
105        private Server createAndStart()
106        {
107            try
108            {
109    
110                    File warPathFile = new File(warPath);
111                    
112                String webappPath = warPathFile.isAbsolute()
113                                    ? warPath
114                                    : new File(workingDir, this.warPath).getPath();
115                String webDefaults = new File(workingDir, "src/test/conf/webdefault.xml").getPath();
116    
117                File keystoreFile = new File(workingDir, "src/test/conf/keystore");
118                String keystore = keystoreFile.getPath();
119    
120                System.out.printf("Starting Jetty instance on port %d (%s mapped to %s)\n", port, contextPath, webappPath);
121    
122                Server server = new Server();
123    
124    
125                SocketListener socketListener = new SocketListener();
126                socketListener.setPort(port);
127                server.addListener(socketListener);
128    
129                if (keystoreFile.exists())
130                {
131                    SunJsseListener secureListener = new SunJsseListener();
132                    secureListener.setPort(DEFAULT_SECURE_PORT);
133                    secureListener.setKeystore(keystore);
134                    secureListener.setPassword("tapestry");
135                    secureListener.setKeyPassword("tapestry");
136    
137                    server.addListener(secureListener);
138                }
139    
140                NCSARequestLog log = new NCSARequestLog();
141                server.setRequestLog(log);
142    
143                WebApplicationContext context = server.addWebApplication(contextPath, webappPath);
144                
145                for (String virtualHost : virtualHosts) {
146                                    context.addVirtualHost(virtualHost);
147                            }
148    
149                context.setDefaultsDescriptor(webDefaults);
150    
151                server.start();
152    
153                return server;
154            }
155            catch (Exception ex)
156            {
157                throw new RuntimeException("Failure starting Jetty instance: " + ex.toString(), ex);
158            }
159        }
160    }