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 }