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