001    /**
002     * Copyright 2004-2013 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     */
016    package org.kuali.rice.test.lifecycles;
017    
018    import java.net.BindException;
019    import java.util.HashMap;
020    
021    import org.apache.log4j.Logger;
022    import org.kuali.rice.core.api.config.property.Config;
023    import org.kuali.rice.core.api.config.property.ConfigContext;
024    import org.kuali.rice.core.api.lifecycle.Lifecycle;
025    import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
026    import org.kuali.rice.core.api.resourceloader.ResourceLoader;
027    import org.kuali.rice.core.api.util.RiceUtilities;
028    import 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     */
035    public 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    }