org.atomserver.testutils.client.JettyWebAppTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.atomserver.testutils.client.JettyWebAppTestCase.java

Source

/* Copyright (c) 2007 HomeAway, Inc.
 *  All rights reserved.  http://www.atomserver.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.atomserver.testutils.client;

import junit.framework.TestCase;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.webapp.WebAppContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.atomserver.utils.conf.ConfigurationAwareClassLoader;

import javax.servlet.ServletContext;
import java.util.Random;

/**
 * This base JUnit TestCase starts up Jetty based on "spring/jettyBeans.xml"
 * It does this by using a <b>separate</b> Spring ApplicationContext from that
 * used by the webapp itself. I.e. separate from the WebApplicationContext
 * used for our Spring-based Abdera Servlet.
 * <p/>
 * You specify whether you want either a non-secure or a secure system
 * in Class constructor. This turns off/on the Acegi Servlet Filters
 */
public class JettyWebAppTestCase extends TestCase {

    protected Log log = LogFactory.getLog(JettyWebAppTestCase.class);

    // Create a psuedo-random number generator  
    static private Random random = new Random();

    static private final int NOT_SET = -1;
    static private final String JETTY_CONNECTOR_ID = "httpConnector";

    static protected String[] DEFAULT_CONFIGS = { "/org/atomserver/spring/propertyConfigurerBeans.xml",
            "/jettyBeans.xml" };

    static protected String jettyServerBeanId = "jettyWebAppServer";

    protected Server jettyServer = null;

    private ServletHandler servletHandler = null;

    protected String servletContextName;

    protected ClassPathXmlApplicationContext jettySpringFactory = null;
    protected ApplicationContext appSpringFactory = null;

    private int jettyPort = NOT_SET;

    private boolean useNonSecure = true;
    private String[] configs = null;

    protected JettyWebAppTestCase() {
        this(true);
    }

    protected JettyWebAppTestCase(boolean useNonSecure) {
        this(useNonSecure, DEFAULT_CONFIGS);
    }

    protected JettyWebAppTestCase(boolean useNonSecure, String[] configs) {
        this.useNonSecure = useNonSecure;
        this.configs = configs;
    }

    protected String getServletContextName() {
        return servletContextName;
    }

    protected void setUp() throws Exception {
        try {
            super.setUp();

            // just in case, stop Jetty if it is running
            stopJetty();

            // Set the variable in the Spring acegiBeans.xml
            log.debug("useNonSecure= " + useNonSecure);
            if (useNonSecure) {
                System.setProperty("security.use.filters", "false");
            } else {
                System.setProperty("security.use.filters", "true");
            }

            if (jettySpringFactory == null) {
                log.debug("Loading jettySpringFactory........");
                jettySpringFactory = new ClassPathXmlApplicationContext(configs, false);
                jettySpringFactory
                        .setClassLoader(new ConfigurationAwareClassLoader(jettySpringFactory.getClassLoader()));
                jettySpringFactory.refresh();
            }

            startJetty();

        } catch (Exception ee) {
            // just in case, stop Jetty if it is running
            stopJetty();
            throw ee;
        }
    }

    protected void tearDown() throws Exception {
        super.tearDown();
        // set it back to the default
        System.setProperty("security.use.filters", "true");

        stopJetty();
    }

    /**
     * NOTE: if you're getting BindExceptions (Address is in use)
     * This can happen if an Exception is thrown during the setUp()
     * And, in general, this will be due to some errant file in /var
     * So try a ./bin/clear-test-files.sh.
     */
    private void startJetty() throws Exception {
        Server jserver = getJettyServer();
        if (!jserver.isStarted()) {
            try {
                doStart(jserver);
            } catch (org.mortbay.util.MultiException ee) {
                startJettyOnAlternatePorts(jserver);
            } catch (java.net.BindException ee) {
                startJettyOnAlternatePorts(jserver);
            }
        }
    }

    private void doStart(Server jserver) throws Exception {
        log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        log.debug(getPortsString());
        log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        jserver.start();
    }

    private int getPortAdd() {
        int portAdd = 0;
        while (portAdd == 0) {
            portAdd = random.nextInt(1000);
        }
        return portAdd;
    }

    private void startJettyOnAlternatePorts(Server jserver) throws Exception {
        log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        log.debug("              TRYING ALTERNATE PORTS ");
        log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        int portNS = getPort();
        int tries = 0;
        while (tries < 3) {
            try {
                tries++;
                int portAdd = getPortAdd();
                setPort(portNS + portAdd, JETTY_CONNECTOR_ID);
                doStart(jserver);
                break;
            } catch (org.mortbay.util.MultiException ee) {
                // continue...
            } catch (java.net.BindException ee) {
                // continue...
            }
        }
    }

    private void stopJetty() throws Exception {
        if (jettySpringFactory != null) {
            Server jserver = getJettyServer();
            if (jserver != null && jserver.isStarted()) {
                log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
                log.debug(getPortsString());
                log.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
                jserver.stop();
            }
        }
    }

    private String getPortsString() {
        return "       START JETTY ( port: " + getPort() + ")";
    }

    /**
     * return the Application Spring WebApplicationContext.
     * Its a bit convoluted to get at it from here, but ultimately its doable.
     * We have to traverse from the Jetty Server, until we get to the ServletContext.
     * NOTE: this code is entirely dependent on the structure of jettyBeans.xml
     * Thus, if that Bean changes, so must this code !!!
     */
    protected ApplicationContext getSpringFactory() throws Exception {
        if (appSpringFactory == null) {
            Server jserver = getJettyServer();

            WebAppContext webappContext = (WebAppContext) jserver.getHandler();
            log.debug("webappContext= " + webappContext);

            servletHandler = webappContext.getServletHandler();
            log.debug("ServletHandler = " + servletHandler);

            ServletContext servletContext = servletHandler.getServletContext();
            log.debug("servletContext= " + servletContext);

            servletContextName = servletContext.getServletContextName();
            if (servletContextName == null) {
                throw new RuntimeException("No servletContextName defined for atomserver");
            }
            // will come back as e.g. /atomserver/
            servletContextName = StringUtils.strip(servletContextName, "/");
            log.debug("****************** servletContextName= " + servletContextName);

            appSpringFactory = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        }
        return appSpringFactory;
    }

    protected Server getJettyServer() {
        if (jettyServer == null) {
            jettyServer = (Server) jettySpringFactory.getBean(jettyServerBeanId);
            assertNotNull(jettyServer);
        }
        return jettyServer;
    }

    protected ServletHandler getJettyServletHandler() throws Exception {
        if (appSpringFactory == null) {
            getSpringFactory();
        }
        return servletHandler;
    }

    private void setPort(int port, String connectorName) {
        log.debug("Setting port for " + connectorName + " to " + port);
        Connector conn = getConnector(connectorName);
        conn.setPort(port);
        if (connectorName.equals(JETTY_CONNECTOR_ID)) {
            jettyPort = port;
        }
    }

    protected int getPort() {
        if (jettyPort == NOT_SET) {
            jettyPort = getPortFromConnector(JETTY_CONNECTOR_ID);
        }
        return jettyPort;
    }

    private int getPortFromConnector(String connectorName) {
        Connector conn = getConnector(connectorName);
        int port = conn.getPort();
        assertTrue(port != NOT_SET);
        return port;
    }

    private Connector getConnector(String connectorName) {
        Server jserver = getJettyServer();
        Connector[] connectors = jserver.getConnectors();
        for (int ii = 0; ii < connectors.length; ii++) {
            log.debug("Connector Name = " + connectors[ii].getName());
            if (connectors[ii].getName().equals(connectorName)) {
                return connectors[ii];
            }
        }
        fail("The Connector named (" + connectorName + ") was not found in the Jetty Spring Bean");
        return null;
    }
}