001    // Copyright 2006 Howard M. Lewis Ship
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 com.javaforge.tapestry.testng;
016    
017    import org.mortbay.jetty.Connector;
018    import org.mortbay.jetty.Server;
019    import org.mortbay.jetty.nio.BlockingChannelConnector;
020    import org.mortbay.jetty.webapp.WebAppContext;
021    
022    import static java.lang.String.format;
023    
024    /**
025     * A utitilty class for running an instance of the <a
026     * href="http://jetty.mortbay.com/jetty/index.html">Jetty servlet container</a> from within a unit
027     * test. This code is based on the Jetty 6 code base (which is in beta at the time of writing). When
028     * combined with <a href="http://jwebunit.sourceforge.net/">jWebUnit</a>, this allows for basic
029     * <em>integration</em> testing of an application from within a unit test case.
030     * 
031     * @author Howard M. Lewis Ship
032     */
033    public class JettyRunner
034    {
035        public static final String DEFAULT_CONTEXT_PATH = "/";
036    
037        public static final int DEFAULT_PORT = 80;
038    
039        public static final String DEFAULT_WAR_PATH = "src/main/webapp";
040    
041        private final String _contextPath;
042    
043        private final int _port;
044    
045        private final String _warPath;
046    
047        private final Server _jetty;
048    
049        /**
050         * Creates and starts a new instance of Jetty, using default configuration values. The
051         * contextPath will be /, the port will be 80, the warPath will be src/main/webapp.
052         */
053        public JettyRunner()
054        {
055            this(DEFAULT_CONTEXT_PATH, DEFAULT_PORT, DEFAULT_WAR_PATH);
056        }
057    
058        /**
059         * Creates and starts a new instance of Jetty. This should be done from a test case setup
060         * method.
061         * 
062         * @param contextPath
063         *            the context path for the deployed application
064         * @param port
065         *            the port number used to access the application
066         * @param warPath
067         *            the path to the exploded web application (typically, "src/main/webapp")
068         */
069        public JettyRunner(String contextPath, int port, String warPath)
070        {
071            _contextPath = contextPath;
072            _port = port;
073            _warPath = warPath;
074    
075            _jetty = new Server();
076    
077            startJetty();
078        }
079    
080        /** Stops the Jetty instance. This should be called from a test case tear down method. */
081        public void stop()
082        {
083            try
084            {
085                _jetty.stop();
086            }
087            catch (Exception ex)
088            {
089                throw new RuntimeException("Error stopping Jetty instance: " + ex.toString(), ex);
090            }
091        }
092    
093        @Override
094        public String toString()
095        {
096            return format("<JettyRunner %s:%d (%s)>", _contextPath, _port, _warPath);
097        }
098    
099        private void startJetty()
100        {
101            try
102            {
103                BlockingChannelConnector connector = new BlockingChannelConnector();
104                connector.setPort(_port);
105    
106                _jetty.setConnectors(new Connector[]
107                { connector });
108    
109                WebAppContext context = new WebAppContext();
110    
111                context.setContextPath(_contextPath);
112                context.setWar(_warPath);
113    
114                _jetty.addHandler(context);
115    
116                _jetty.start();
117            }
118            catch (Exception ex)
119            {
120                throw new RuntimeException("Failure starting Jetty instance: " + ex.toString(), ex);
121            }
122        }
123    
124    }