001    /**
002     * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
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. See accompanying LICENSE file.
014     */
015    package org.apache.oozie.test;
016    
017    import org.mortbay.jetty.Server;
018    import org.mortbay.jetty.servlet.FilterHolder;
019    import org.mortbay.jetty.servlet.ServletHolder;
020    import org.mortbay.jetty.servlet.Context;
021    
022    import java.net.InetAddress;
023    import java.net.ServerSocket;
024    
025    /**
026     * An embedded servlet container for testing purposes. <p/> It provides reduced functionality, it supports only
027     * Servlets. <p/> The servlet container is started in a free port.
028     */
029    public class EmbeddedServletContainer {
030        private Server server;
031        private String host = null;
032        private int port = -1;
033        private String contextPath;
034        Context context;
035    
036        /**
037         * Create a servlet container.
038         *
039         * @param contextPath context path for the servlet, it must not be prefixed or append with "/", for the default
040         * context use ""
041         */
042        public EmbeddedServletContainer(String contextPath) {
043            this.contextPath = contextPath;
044            server = new Server(0);
045            context = new Context();
046            context.setContextPath("/" + contextPath);
047            server.setHandler(context);
048        }
049    
050        /**
051         * Add a servlet to the container.
052         *
053         * @param servletPath servlet path for the servlet, it should be prefixed with '/", it may contain a wild card at
054         * the end.
055         * @param servletClass servlet class
056         */
057        public void addServletEndpoint(String servletPath, Class servletClass) {
058            context.addServlet(new ServletHolder(servletClass), servletPath);
059        }
060    
061        /**
062         * Add a filter to the container.
063         *
064         * @param filterPath path for the filter, it should be prefixed with '/", it may contain a wild card at
065         * the end.
066         * @param filterClass servlet class
067         */
068        public void addFilter(String filterPath, Class filterClass) {
069            context.addFilter(new FilterHolder(filterClass), filterPath, 0);
070        }
071    
072        /**
073         * Start the servlet container. <p/> The container starts on a free port.
074         *
075         * @throws Exception thrown if the container could not start.
076         */
077        public void start() throws Exception {
078            host = InetAddress.getLocalHost().getHostName();
079            ServerSocket ss = new ServerSocket(0);
080            port = ss.getLocalPort();
081            ss.close();
082            server.getConnectors()[0].setHost(host);
083            server.getConnectors()[0].setPort(port);
084            server.start();
085            System.out.println("Running embedded servlet container at: http://" + host + ":" + port);
086        }
087    
088        /**
089         * Return the hostname the servlet container is bound to.
090         *
091         * @return the hostname.
092         */
093        public String getHost() {
094            return host;
095        }
096    
097        /**
098         * Return the port number the servlet container is bound to.
099         *
100         * @return the port number.
101         */
102        public int getPort() {
103            return port;
104        }
105    
106        /**
107         * Return the full URL (including protocol, host, port, context path, servlet path) for the context path.
108         *
109         * @return URL to the context path.
110         */
111        public String getContextURL() {
112            return "http://" + host + ":" + port + "/" + contextPath;
113        }
114    
115        /**
116         * Return the full URL (including protocol, host, port, context path, servlet path) for a servlet path.
117         *
118         * @param servletPath the path which will be expanded to a full URL.
119         * @return URL to the servlet.
120         */
121        public String getServletURL(String servletPath) {
122            String path = servletPath;
123            if (path.endsWith("*")) {
124                path = path.substring(0, path.length() - 1);
125            }
126            return getContextURL() + path;
127        }
128    
129        /**
130         * Stop the servlet container.
131         */
132        public void stop() {
133            try {
134                server.stop();
135            }
136            catch (Exception e) {
137                // ignore exception
138            }
139    
140            try {
141                server.destroy();
142            }
143            catch (Exception e) {
144                // ignore exception
145            }
146    
147            host = null;
148            port = -1;
149        }
150    
151    }