View Javadoc

1   /*
2    * Copyright 2007-2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.test.lifecycles;
17  
18  import java.net.BindException;
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import org.apache.log4j.Logger;
24  import org.kuali.rice.core.api.config.property.Config;
25  import org.kuali.rice.core.api.config.property.ConfigContext;
26  import org.kuali.rice.core.api.lifecycle.Lifecycle;
27  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
28  import org.kuali.rice.core.api.resourceloader.ResourceLoader;
29  import org.kuali.rice.core.api.util.RiceUtilities;
30  import org.kuali.rice.core.web.jetty.JettyServer;
31  import org.mortbay.jetty.webapp.WebAppClassLoader;
32  
33  
34  /**
35   * A lifecycle for running a jetty web server.
36   * @author Kuali Rice Team (rice.collab@kuali.org)
37   */
38  public class JettyServerLifecycle implements Lifecycle {
39      private static final Logger LOG = Logger.getLogger(JettyServerLifecycle.class);
40  
41      private static final HashMap<Integer, Config> WEBAPP_CONFIGS = new HashMap<Integer, Config>();
42  
43      public static Config getWebappConfig(int port) {
44          return WEBAPP_CONFIGS.get(port);
45      }
46  
47      /**
48       * Enum for dealing with the webapp's Config
49       */
50      public static enum ConfigMode {
51          /**
52           * Do nothing
53           */
54          NONE,
55          /**
56           * Override the Config for the context class loader
57           */
58          OVERRIDE,
59          /**
60           * Merge the webapp's Config into the existing context class loader config
61           */
62          MERGE
63      }
64  
65      /**
66       * By default we set the JettyServer to test mode
67       */
68      private boolean testMode = true;
69      private boolean started;
70      private ConfigMode configMode = ConfigMode.OVERRIDE;
71      private boolean addWebappResourceLoaders = true;
72  
73  	
74  	protected JettyServer jettyServer;
75  		
76  	public JettyServerLifecycle() {
77  		this(8080, null);
78  	}
79  
80  	public JettyServerLifecycle(int port) {
81  		this(port, null, null);
82  	}
83  
84  	public JettyServerLifecycle(int port, String contextName) {
85  		this(port, contextName, null);
86  	}
87  	
88  	public JettyServerLifecycle(int port, String contextName, String relativeWebappRoot) {
89  		jettyServer = new JettyServer(port, contextName, relativeWebappRoot);
90  		jettyServer.setFailOnContextFailure(true);
91  		jettyServer.setTestMode(testMode);
92  	}	
93  	
94      public void setTestMode(boolean t) {
95          this.testMode = t;
96      }
97  
98      public boolean isTestMode() {
99          return testMode;
100     }
101 
102     public ConfigMode getConfigMode() {
103         return this.configMode;
104     }
105 
106     public void setConfigMode(ConfigMode configMode) {
107         this.configMode = configMode;
108     }
109 
110     public boolean isAddWebappResourceLoaders() {
111         return this.addWebappResourceLoaders;
112     }
113 
114     public void setAddWebappResourceLoaders(boolean addWebappResourceLoaders) {
115         this.addWebappResourceLoaders = addWebappResourceLoaders;
116     }
117 
118 	public boolean isStarted() {
119 		return started;
120 	}
121 
122 	public void start() throws Exception {
123 	    try {
124 	        jettyServer.start();
125 	        
126 	    } catch (RuntimeException re) {
127 	        // add some handling to make port conflicts more easily identified
128 	        if (RiceUtilities.findExceptionInStack(re, BindException.class) != null) {
129 	            LOG.error("JettyServerLifecycle encountered BindException on port: " + jettyServer.getPort() + "; check logs for test failures or and the config for duplicate port specifications.");
130 	        }
131 	        throw re;
132 	    }
133 
134 	    ClassLoader webappClassLoader = jettyServer.getContext().getClassLoader();
135 	    if (addWebappResourceLoaders) {
136 	        ResourceLoader rl = GlobalResourceLoader.getResourceLoader(webappClassLoader);
137             if (rl == null) {
138                 throw new RuntimeException("Could not find resource loader for workflow test harness web app for: " + webappClassLoader);
139             }
140             GlobalResourceLoader.addResourceLoader(rl);
141 	    }
142 
143         // TODO: RICE-2.0 UPGRADE had to jump through hoops with M8 because getConfig was made private.  Uncomment the following and remove the next block
144 	    // Config webappConfig = ConfigContext.getConfig(webappClassLoader);
145 
146         Config webappConfig = null;
147         for (Map.Entry<ClassLoader, Config> configEntry : ConfigContext.getConfigs()) {
148             if (configEntry.getKey() instanceof WebAppClassLoader) {
149                 webappConfig = configEntry.getValue();
150             }
151         }
152 
153         WEBAPP_CONFIGS.put(jettyServer.getPort(), webappConfig);
154 	    if (ConfigMode.OVERRIDE == configMode) {
155             // this overrides the test harness classloader config with the webapp's config...
156             ConfigContext.overrideConfig(Thread.currentThread().getContextClassLoader(), webappConfig);
157         } else if (ConfigMode.MERGE == configMode) {
158             Config curCtxConfig = ConfigContext.getCurrentContextConfig();
159             if (webappConfig != null) {
160                 curCtxConfig.putProperties(webappConfig.getProperties());
161                 curCtxConfig.putObjects(webappConfig.getObjects());
162             }
163         }
164 
165 		started = true;
166 	}
167 
168 	public void stop() throws Exception {
169 	    LOG.info("Shutting down jetty: " + jettyServer);
170 	    try {
171 	    	if (jettyServer != null && jettyServer.isStarted()) {
172 	    		jettyServer.stop();
173 	    		WEBAPP_CONFIGS.remove(jettyServer.getPort());
174 	    	}
175 	    } catch (Exception e) {
176 	        LOG.error("Error shutting down Jetty " + jettyServer.getContextName() + " " + jettyServer.getRelativeWebappRoot(), e);
177 	    }
178 		started = false;
179 	}
180 }