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  
21  import org.apache.log4j.Logger;
22  import org.kuali.rice.core.config.Config;
23  import org.kuali.rice.core.config.ConfigContext;
24  import org.kuali.rice.core.lifecycle.Lifecycle;
25  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
26  import org.kuali.rice.core.resourceloader.ResourceLoader;
27  import org.kuali.rice.core.util.RiceUtilities;
28  import org.kuali.rice.core.web.jetty.JettyServer;
29  
30  /**
31   * A lifecycle for running a jetty web server.
32   * @author Kuali Rice Team (rice.collab@kuali.org)
33   */
34  public class JettyServerLifecycle implements Lifecycle {
35      private static final Logger LOG = Logger.getLogger(JettyServerLifecycle.class);
36  
37      private static final HashMap<Integer, Config> WEBAPP_CONFIGS = new HashMap<Integer, Config>();
38  
39      public static Config getWebappConfig(int port) {
40          return WEBAPP_CONFIGS.get(port);
41      }
42  
43      /**
44       * Enum for dealing with the webapp's Config
45       */
46      public static enum ConfigMode {
47          /**
48           * Do nothing
49           */
50          NONE,
51          /**
52           * Override the Config for the context class loader
53           */
54          OVERRIDE,
55          /**
56           * Merge the webapp's Config into the existing context class loader config
57           */
58          MERGE
59      }
60  
61      /**
62       * By default we set the JettyServer to test mode
63       */
64      private boolean testMode = true;
65      private boolean started;
66      private ConfigMode configMode = ConfigMode.OVERRIDE;
67      private boolean addWebappResourceLoaders = true;
68  
69  	
70  	protected JettyServer jettyServer;
71  		
72  	public JettyServerLifecycle() {
73  		this(8080, null);
74  	}
75  
76  	public JettyServerLifecycle(int port) {
77  		this(port, null, null);
78  	}
79  
80  	public JettyServerLifecycle(int port, String contextName) {
81  		this(port, contextName, null);
82  	}
83  	
84  	public JettyServerLifecycle(int port, String contextName, String relativeWebappRoot) {
85  		jettyServer = new JettyServer(port, contextName, relativeWebappRoot);
86  		jettyServer.setFailOnContextFailure(true);
87  		jettyServer.setTestMode(testMode);
88  	}	
89  	
90      public void setTestMode(boolean t) {
91          this.testMode = t;
92      }
93  
94      public boolean isTestMode() {
95          return testMode;
96      }
97  
98      public ConfigMode getConfigMode() {
99          return this.configMode;
100     }
101 
102     public void setConfigMode(ConfigMode configMode) {
103         this.configMode = configMode;
104     }
105 
106     public boolean isAddWebappResourceLoaders() {
107         return this.addWebappResourceLoaders;
108     }
109 
110     public void setAddWebappResourceLoaders(boolean addWebappResourceLoaders) {
111         this.addWebappResourceLoaders = addWebappResourceLoaders;
112     }
113 
114 	public boolean isStarted() {
115 		return started;
116 	}
117 
118 	public void start() throws Exception {
119 	    try {
120 	        jettyServer.start();
121 	        
122 	    } catch (RuntimeException re) {
123 	        // add some handling to make port conflicts more easily identified
124 	        if (RiceUtilities.findExceptionInStack(re, BindException.class) != null) {
125 	            LOG.error("JettyServerLifecycle encountered BindException on port: " + jettyServer.getPort() + "; check logs for test failures or and the config for duplicate port specifications.");
126 	        }
127 	        throw re;
128 	    }
129 
130 	    ClassLoader webappClassLoader = jettyServer.getContext().getClassLoader();
131 	    if (addWebappResourceLoaders) {
132 	        ResourceLoader rl = GlobalResourceLoader.getResourceLoader(webappClassLoader);
133             if (rl == null) {
134                 throw new RuntimeException("Could not find resource loader for workflow test harness web app for: " + webappClassLoader);
135             }
136             GlobalResourceLoader.addResourceLoader(rl);
137 	    }
138 	    Config webappConfig = ConfigContext.getConfig(webappClassLoader);
139 	    WEBAPP_CONFIGS.put(jettyServer.getPort(), webappConfig);
140 	    if (ConfigMode.OVERRIDE == configMode) {
141             // this overrides the test harness classloader config with the webapp's config...
142             ConfigContext.overrideConfig(Thread.currentThread().getContextClassLoader(), webappConfig);
143         } else if (ConfigMode.MERGE == configMode) {
144             Config curCtxConfig = ConfigContext.getCurrentContextConfig();
145             if (webappConfig != null) {
146                 curCtxConfig.putProperties(webappConfig.getProperties());
147                 curCtxConfig.putObjects(webappConfig.getObjects());
148             }
149         }
150 
151 		started = true;
152 	}
153 
154 	public void stop() throws Exception {
155 	    LOG.info("Shutting down jetty: " + jettyServer);
156 	    try {
157 	    	if (jettyServer != null && jettyServer.isStarted()) {
158 	    		jettyServer.stop();
159 	    		WEBAPP_CONFIGS.remove(jettyServer.getPort());
160 	    	}
161 	    } catch (Exception e) {
162 	        LOG.error("Error shutting down Jetty " + jettyServer.getContextName() + " " + jettyServer.getRelativeWebappRoot(), e);
163 	    }
164 		started = false;
165 	}
166 }