001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.test;
020
021import org.mortbay.jetty.Server;
022import org.mortbay.jetty.servlet.FilterHolder;
023import org.mortbay.jetty.servlet.ServletHolder;
024import org.mortbay.jetty.servlet.Context;
025
026import java.net.InetAddress;
027import java.net.ServerSocket;
028import java.util.Map;
029
030/**
031 * An embedded servlet container for testing purposes. <p> It provides reduced functionality, it supports only
032 * Servlets. <p> The servlet container is started in a free port.
033 */
034public class EmbeddedServletContainer {
035    private Server server;
036    private String host = null;
037    private int port = -1;
038    private String contextPath;
039    Context context;
040
041    /**
042     * Create a servlet container.
043     *
044     * @param contextPath context path for the servlet, it must not be prefixed or append with "/", for the default
045     * context use ""
046     */
047    public EmbeddedServletContainer(String contextPath) {
048        this.contextPath = contextPath;
049        server = new Server(0);
050        context = new Context();
051        context.setContextPath("/" + contextPath);
052        server.setHandler(context);
053    }
054
055    /**
056     * Add a servlet to the container.
057     *
058     * @param servletPath servlet path for the servlet, it should be prefixed with '/", it may contain a wild card at
059     * the end.
060     * @param servletClass servlet class
061     * @param initParams a mapping of init parameters for the servlet, or null
062     */
063    public void addServletEndpoint(String servletPath, Class servletClass, Map<String, String> initParams) {
064        ServletHolder s = new ServletHolder(servletClass);
065        context.addServlet(s, servletPath);
066        if (initParams != null) {
067            s.setInitParameters(initParams);
068        }
069    }
070
071    /**
072     * Add a servlet to the container.
073     *
074     * @param servletPath servlet path for the servlet, it should be prefixed with '/", it may contain a wild card at
075     * the end.
076     * @param servletClass servlet class
077     */
078    public void addServletEndpoint(String servletPath, Class servletClass) {
079        addServletEndpoint(servletPath, servletClass, null);
080    }
081
082    /**
083     * Add a filter to the container.
084     *
085     * @param filterPath path for the filter, it should be prefixed with '/", it may contain a wild card at
086     * the end.
087     * @param filterClass servlet class
088     */
089    public void addFilter(String filterPath, Class filterClass) {
090        context.addFilter(new FilterHolder(filterClass), filterPath, 0);
091    }
092
093    /**
094     * Start the servlet container. <p> The container starts on a free port.
095     *
096     * @throws Exception thrown if the container could not start.
097     */
098    public void start() throws Exception {
099        host = InetAddress.getLocalHost().getHostName();
100        ServerSocket ss = new ServerSocket(0);
101        port = ss.getLocalPort();
102        ss.close();
103        server.getConnectors()[0].setHost(host);
104        server.getConnectors()[0].setPort(port);
105        server.start();
106        System.out.println("Running embedded servlet container at: http://" + host + ":" + port);
107    }
108
109    /**
110     * Return the hostname the servlet container is bound to.
111     *
112     * @return the hostname.
113     */
114    public String getHost() {
115        return host;
116    }
117
118    /**
119     * Return the port number the servlet container is bound to.
120     *
121     * @return the port number.
122     */
123    public int getPort() {
124        return port;
125    }
126
127    /**
128     * Return the full URL (including protocol, host, port, context path, servlet path) for the context path.
129     *
130     * @return URL to the context path.
131     */
132    public String getContextURL() {
133        return "http://" + host + ":" + port + "/" + contextPath;
134    }
135
136    /**
137     * Return the full URL (including protocol, host, port, context path, servlet path) for a servlet path.
138     *
139     * @param servletPath the path which will be expanded to a full URL.
140     * @return URL to the servlet.
141     */
142    public String getServletURL(String servletPath) {
143        String path = servletPath;
144        if (path.endsWith("*")) {
145            path = path.substring(0, path.length() - 1);
146        }
147        return getContextURL() + path;
148    }
149
150    /**
151     * Stop the servlet container.
152     */
153    public void stop() {
154        try {
155            server.stop();
156        }
157        catch (Exception e) {
158            // ignore exception
159        }
160
161        try {
162            server.destroy();
163        }
164        catch (Exception e) {
165            // ignore exception
166        }
167
168        host = null;
169        port = -1;
170    }
171
172}