001/**
002 * Copyright 2004-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.test.lifecycles;
017
018import java.net.BindException;
019import java.util.HashMap;
020
021import org.apache.log4j.Logger;
022import org.kuali.rice.core.api.config.property.Config;
023import org.kuali.rice.core.api.config.property.ConfigContext;
024import org.kuali.rice.core.api.lifecycle.Lifecycle;
025import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
026import org.kuali.rice.core.api.resourceloader.ResourceLoader;
027import org.kuali.rice.core.api.util.RiceUtilities;
028import org.kuali.rice.test.launch.JettyLauncher;
029
030
031/**
032 * A lifecycle for running a jetty web server.
033 * @author Kuali Rice Team (rice.collab@kuali.org)
034 */
035public class JettyServerLifecycle implements Lifecycle {
036    private static final Logger LOG = Logger.getLogger(JettyServerLifecycle.class);
037
038    private static final HashMap<Integer, Config> WEBAPP_CONFIGS = new HashMap<Integer, Config>();
039
040    public static Config getWebappConfig(int port) {
041        return WEBAPP_CONFIGS.get(port);
042    }
043
044    /**
045     * Enum for dealing with the webapp's Config
046     */
047    public static enum ConfigMode {
048        /**
049         * Do nothing
050         */
051        NONE,
052        /**
053         * Override the Config for the context class loader
054         */
055        OVERRIDE,
056        /**
057         * Merge the webapp's Config into the existing context class loader config
058         */
059        MERGE
060    }
061
062    /**
063     * By default we set the JettyServer to test mode
064     */
065    private boolean testMode = true;
066    private boolean started;
067    private ConfigMode configMode = ConfigMode.OVERRIDE;
068    private boolean addWebappResourceLoaders = true;
069
070
071        protected JettyLauncher jettyServer;
072
073        public JettyServerLifecycle() {
074                this(8080, null);
075        }
076
077        public JettyServerLifecycle(int port) {
078                this(port, null, null);
079        }
080
081        public JettyServerLifecycle(int port, String contextName) {
082                this(port, contextName, null);
083        }
084
085        public JettyServerLifecycle(int port, String contextName, String relativeWebappRoot) {
086                jettyServer = new JettyLauncher(port, contextName, relativeWebappRoot);
087        jettyServer.setFailOnContextFailure(true);
088                jettyServer.setTestMode(testMode);
089        }
090
091    public void setTestMode(boolean t) {
092        this.testMode = t;
093    }
094
095    public boolean isTestMode() {
096        return testMode;
097    }
098
099    public ConfigMode getConfigMode() {
100        return this.configMode;
101    }
102
103    public void setConfigMode(ConfigMode configMode) {
104        this.configMode = configMode;
105    }
106
107    public boolean isAddWebappResourceLoaders() {
108        return this.addWebappResourceLoaders;
109    }
110
111    public void setAddWebappResourceLoaders(boolean addWebappResourceLoaders) {
112        this.addWebappResourceLoaders = addWebappResourceLoaders;
113    }
114
115        public boolean isStarted() {
116                return started;
117        }
118
119        public void start() throws Exception {
120            try {
121                jettyServer.start();
122
123            } catch (RuntimeException re) {
124                // add some handling to make port conflicts more easily identified
125                if (RiceUtilities.findExceptionInStack(re, BindException.class) != null) {
126                    LOG.error("JettyServerLifecycle encountered BindException on port: " + jettyServer.getPort() + "; check logs for test junit.framework.Assert.failures or and the config for duplicate port specifications.");
127                }
128                throw re;
129            }
130
131            ClassLoader webappClassLoader = jettyServer.getContext().getClassLoader();
132            if (addWebappResourceLoaders) {
133                ResourceLoader rl = GlobalResourceLoader.getResourceLoader(webappClassLoader);
134            if (rl == null) {
135                throw new RuntimeException("Could not find resource loader for workflow test harness web app for: " + webappClassLoader);
136            }
137            //GlobalResourceLoader.addResourceLoaderFirst();
138            GlobalResourceLoader.addResourceLoader(rl);
139            }
140            //org.kuali.rice.core.api.config.property.Config webappConfig = ConfigContext.getCurrentContextConfig();
141        org.kuali.rice.core.api.config.property.Config webappConfig = ConfigContext.getConfig(webappClassLoader);
142            WEBAPP_CONFIGS.put(new Integer(jettyServer.getPort()), webappConfig);
143            if (ConfigMode.OVERRIDE == configMode) {
144            // this overrides the test harness classloader config with the webapp's config...
145
146
147            ConfigContext.overrideConfig(Thread.currentThread().getContextClassLoader(), webappConfig);
148        } else if (ConfigMode.MERGE == configMode) {
149            Config curCtxConfig = ConfigContext.getCurrentContextConfig();
150            if (webappConfig != null) {
151                curCtxConfig.putProperties(webappConfig.getProperties());
152                curCtxConfig.putObjects(webappConfig.getObjects());
153            }
154        }
155
156                started = true;
157        }
158
159        public void stop() throws Exception {
160            LOG.info("Shutting down jetty: " + jettyServer);
161            try {
162                if (jettyServer != null && jettyServer.isStarted()) {
163                        jettyServer.stop();
164                        WEBAPP_CONFIGS.remove(jettyServer.getPort());
165                }
166            } catch (Exception e) {
167                LOG.error("Error shutting down Jetty " + jettyServer.getContextName(), e);
168            }
169                started = false;
170        }
171}