View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.config;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.config.*;
21  import org.kuali.rice.core.lifecycle.Lifecycle;
22  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
23  import org.kuali.rice.core.resourceloader.ResourceLoader;
24  import org.kuali.rice.core.resourceloader.RiceResourceLoaderFactory;
25  import org.kuali.rice.core.resourceloader.SpringLoader;
26  import org.kuali.rice.core.util.OrmUtils;
27  import org.kuali.rice.kew.lifecycle.EmbeddedLifeCycle;
28  import org.kuali.rice.kew.plugin.PluginRegistry;
29  import org.kuali.rice.kew.plugin.PluginRegistryFactory;
30  import org.kuali.rice.kew.resourceloader.CoreResourceLoader;
31  import org.kuali.rice.kew.util.KEWConstants;
32  
33  import javax.sql.DataSource;
34  import java.util.ArrayList;
35  import java.util.LinkedList;
36  import java.util.List;
37  
38  
39  /**
40   * Configures the KEW Rice module.  KEW module initiation proceeds as follows:
41   *
42   * <ol>
43   *   <li>Parse and load configuration for:</li>
44   *     <ul>
45   *       <li>Client Protocol</li>
46   *       <li>Database</li>
47   *	   </ul>
48   *   </li>
49   *   <li>Configure and startup KEW for "Thin Client" mode OR</li>
50   *   <li>Configure and startup KEW for "Embedded Mode"</li>
51   * </ol>
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
54   */
55  public class KEWConfigurer extends ModuleConfigurer {
56  
57  	public static final String KEW_DATASOURCE_OBJ = "org.kuali.workflow.datasource";
58  	public static final String KEW_DATASOURCE_JNDI = "org.kuali.workflow.datasource.jndi.location";
59      private static final String ADDITIONAL_SPRING_FILES_PARAM = "kew.additionalSpringFiles";
60      
61  	private String clientProtocol;
62  
63  	private DataSource dataSource;
64  	private String dataSourceJndiName;
65  	/**
66  	 * 
67  	 */
68  	public KEWConfigurer() {
69  		super();
70  		setModuleName( "KEW" );
71  		setHasWebInterface( true );
72  	}
73  	
74  	@Override
75  	public String getSpringFileLocations(){
76  		String springFileLocations;
77  		if (KEWConfigurer.REMOTE_RUN_MODE.equals(getRunMode()) || KEWConfigurer.THIN_RUN_MODE.equals(getRunMode()) ||
78  				KEWConstants.WEBSERVICE_CLIENT_PROTOCOL.equals(ConfigContext.getCurrentContextConfig().getClientProtocol())) {
79  			springFileLocations = "";
80  		} else {
81  			springFileLocations = getEmbeddedSpringFileLocation();
82  		}
83  
84  		return springFileLocations;
85  	}
86  	
87      public String getEmbeddedSpringFileLocation(){
88      	String springLocation = ConfigContext.getCurrentContextConfig().getAlternateSpringFile();
89      	if (springLocation == null) {
90      	    springLocation = "classpath:org/kuali/rice/kew/config/KEWSpringBeans.xml";
91      	}
92  
93          if ( exposeServicesOnBus ) {
94          	if (setSOAPServicesAsDefault) {
95          		springLocation += "," + "classpath:org/kuali/rice/kew/config/KEWServiceBusSOAPDefaultSpringBeans.xml";
96          	} else {
97          		springLocation += "," + "classpath:org/kuali/rice/kew/config/KEWServiceBusSpringBeans.xml";
98          	}
99          }
100 
101     	springLocation += SpringLoader.SPRING_SEPARATOR_CHARACTER;
102         
103         if (OrmUtils.isJpaEnabled("rice.kew")) {
104             springLocation += "classpath:org/kuali/rice/kew/config/KEWJPASpringBeans.xml";
105         }
106         else {
107             springLocation += "classpath:org/kuali/rice/kew/config/KEWOJBSpringBeans.xml";
108         }
109     	
110     	String additionalSpringFiles = ConfigContext.getCurrentContextConfig().getProperty(ADDITIONAL_SPRING_FILES_PARAM);
111     	if(StringUtils.isNotEmpty(additionalSpringFiles) && 	additionalSpringFiles.contains(","))
112     		StringUtils.split(additionalSpringFiles, ",");
113     	String[] springLocations;
114     	if (!StringUtils.isEmpty(additionalSpringFiles)) {
115     		springLocations = new String[2];
116     		springLocations[0] = "," + additionalSpringFiles;
117     	}
118     	return springLocation;
119     }
120 
121 	@Override
122 	protected List<Lifecycle> loadLifecycles() throws Exception {
123 		List<Lifecycle> lifecycles = new LinkedList<Lifecycle>();
124 		if ( getRunMode().equals( THIN_RUN_MODE ) ) {
125 			lifecycles.add(createThinClientLifecycle());
126 		} else if ( !getRunMode().equals( REMOTE_RUN_MODE ) ) { // local or embedded
127 			lifecycles.add(createEmbeddedLifeCycle());
128 		}
129 		return lifecycles;
130 	}
131 
132 	protected boolean isStandaloneServer() {
133 	    return getRunMode().equals( LOCAL_RUN_MODE );
134 	}
135 
136 	/**
137 	 * TODO Because a lot of our lifecycles live behind the embedded plugin and the KEWConfigurer does not, this is a simple
138 	 * measure to load these without having to deal with the removal of the embedded plugin right away.
139      * @return Life Cycle
140      * @throws Exception if life cycle not created
141      */
142 	protected Lifecycle createEmbeddedLifeCycle() throws Exception {
143 		return new EmbeddedLifeCycle();
144 	}
145 
146 	protected Lifecycle createThinClientLifecycle() throws Exception {
147 		return new ThinClientLifecycle();
148 	}
149 
150 	@Override
151 	public Config loadConfig(Config parentConfig) throws Exception {
152 		parentConfig = super.loadConfig(parentConfig);
153 		Config currentConfig = parseConfig(parentConfig);
154 		configureClientProtocol(currentConfig);
155 		configureDataSource(currentConfig);
156 		return currentConfig;
157 	}
158 
159 	protected Config parseConfig(Config parentConfig) throws Exception {
160 		List<String> defaultConfigLocations = new ArrayList<String>();
161 		defaultConfigLocations.add(KEWConstants.DEFAULT_GLOBAL_CONFIG_LOCATION);
162 		defaultConfigLocations.add(KEWConstants.DEFAULT_APPLICATION_CONFIG_LOCATION);
163 		
164 		Config kewConfig = new JAXBConfigImpl(defaultConfigLocations, parentConfig.getProperties());
165 		
166 		kewConfig.parseConfig();
167 		mergeDefaultsIntoParentConfig(parentConfig, kewConfig);
168 		return parentConfig;
169 	}
170 
171 	/**
172 	 * Merges any default configuration into the parent config.  If a property appears in both
173 	 * places, precedence is given to the parentConfig.  This allows for our defaults to not
174 	 * override any property which has already been defined.
175      * @param parentConfig parent configuration
176      * @param defaultConfig original configuration
177      *
178      */
179 	protected void mergeDefaultsIntoParentConfig(Config parentConfig, Config defaultConfig) {
180 		for (Object keyObj : defaultConfig.getProperties().keySet()) {
181 			String key = (String)keyObj;
182 			if (!parentConfig.getProperties().containsKey(key)) {
183 				parentConfig.putProperty(key, defaultConfig.getProperty(key));
184 			}
185 		}
186 	}
187 
188 	protected String getServiceNamespace(Config config) {
189 		if (StringUtils.isBlank(config.getServiceNamespace())) {
190 			throw new ConfigurationException("The 'service.namespace' property was not properly configured.");
191 		}
192 		return config.getServiceNamespace();
193 	}
194 
195 	protected void configureClientProtocol(Config config) {
196 		if (StringUtils.isBlank(clientProtocol)) {
197 			clientProtocol = config.getClientProtocol();
198 			if (StringUtils.isBlank(clientProtocol)) {
199 			    // if not explcitly set, set the protocol based on the run mode
200 			    if ( getRunMode().equals( REMOTE_RUN_MODE ) || getRunMode().equals( THIN_RUN_MODE ) ) {
201 			        clientProtocol = KEWConstants.WEBSERVICE_CLIENT_PROTOCOL;
202 			    } else {
203 			        clientProtocol = KEWConstants.LOCAL_CLIENT_PROTOCOL;
204 			    }
205 			}
206 		}
207 		// from a client, LOCAL protocol is equivalent to EMBEDDED
208 		// TODO this was messing up the tests were LOCAL was actually being used
209 		/*if (KEWConstants.LOCAL_CLIENT_PROTOCOL.equals(clientProtocol)) {
210 			clientProtocol = KEWConstants.EMBEDDED_CLIENT_PROTOCOL;
211 		}*/
212 		if (!KEWConstants.CLIENT_PROTOCOLS.contains(clientProtocol)) {
213 			throw new ConfigurationException("Invalid client protocol specified '" + clientProtocol + "'.");
214 		}
215 		config.putProperty(Config.CLIENT_PROTOCOL, clientProtocol);
216 	}
217 
218 	protected void configureDataSource(Config config) {
219 		if (getDataSource() != null) {
220 			config.putObject(KEW_DATASOURCE_OBJ, getDataSource());
221 		} else if (!StringUtils.isBlank(getDataSourceJndiName())) {
222 			config.putProperty(KEW_DATASOURCE_JNDI, getDataSourceJndiName());
223 		}
224 	}
225 
226 	public ResourceLoader getResourceLoaderToRegister() throws Exception{
227 		// create the plugin registry
228 		PluginRegistry registry = null;
229 		String pluginRegistryEnabled = ConfigContext.getCurrentContextConfig().getProperty("plugin.registry.enabled");
230 		if (!StringUtils.isBlank(pluginRegistryEnabled) && Boolean.valueOf(pluginRegistryEnabled)) {
231 			registry = new PluginRegistryFactory().createPluginRegistry();
232 		}
233 
234 		CoreResourceLoader coreResourceLoader = 
235 			new CoreResourceLoader(RiceResourceLoaderFactory.getSpringResourceLoader(), registry);
236 		coreResourceLoader.start();
237 
238 		//wait until core resource loader is started to attach to GRL;  this is so startup
239 		//code can depend on other things hooked into GRL without incomplete KEW resources
240 		//messing things up.
241 
242 		GlobalResourceLoader.addResourceLoader(coreResourceLoader);
243 
244 		// now start the plugin registry if there is one
245 		if (registry != null) {
246 			registry.start();
247 			// the registry resourceloader is now being handled by the CoreResourceLoader
248 			//GlobalResourceLoader.addResourceLoader(registry);
249 		}
250 		return coreResourceLoader;
251 	}
252 
253 	public String getClientProtocol() {
254 		return clientProtocol;
255 	}
256 
257 	public void setClientProtocol(String clientProtocol) {
258 		this.clientProtocol = clientProtocol;
259 	}
260 
261 	public DataSource getDataSource() {
262 		return dataSource;
263 	}
264 
265 	public void setDataSource(DataSource dataSource) {
266 		this.dataSource = dataSource;
267 	}
268 
269 	public String getDataSourceJndiName() {
270 		return dataSourceJndiName;
271 	}
272 
273 	public void setDataSourceJndiName(String jndiDatasourceLocation) {
274 		this.dataSourceJndiName = jndiDatasourceLocation;
275 	}
276 
277 }