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 }