View Javadoc
1   /**
2    * Copyright 2005-2015 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.krad.bo;
17  
18  import org.apache.commons.beanutils.MethodUtils;
19  import org.apache.commons.lang.builder.ToStringBuilder;
20  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
21  import org.kuali.rice.krad.data.KradDataServiceLocator;
22  import org.kuali.rice.krad.data.provider.MetadataProvider;
23  import org.kuali.rice.krad.data.provider.Provider;
24  import org.kuali.rice.krad.data.provider.ProviderRegistry;
25  import org.kuali.rice.krad.service.DataDictionaryService;
26  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
27  import org.springframework.beans.factory.InitializingBean;
28  import org.springframework.context.ApplicationContext;
29  import org.springframework.context.ApplicationContextAware;
30  
31  
32  import java.lang.reflect.Modifier;
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.List;
36  import java.util.Map;
37  
38  /**
39   * This class contains various configuration properties for a Rice module.
40   *
41   * <p>
42   * The Rice framework is  composed of several separate modules, each of which is
43   * responsible for providing a set of functionality. These include:
44   * <ul>
45   *      <li>KEW - the Rice enterprise workflow module
46   *      <li>KIM - the Rice identity management module
47   *      <li>KSB - the Rice service bus
48   *      <li>KRAD - the Rice rapid application development module
49   *      <li>KRMS - the Rice business rules management syste
50   *      <li>eDocLite - a Rice framework for creating simple documents quickly
51   *      <li>...as well as several others. Refer to the Rice documentation for a complete list.
52   * </ul>
53   * <br>
54   * Client Applications will also have their own module configurations. A client application could create a single
55   * module or multiple modules, depending on how it is organized.
56   * <br>
57   * This ModuleConfiguration object is created during Spring initialization. The properties of this ModuleConfiguration
58   * are specified in the module's SpringBean definition XML configuration file.
59   *</p>
60   *
61   * @author Kuali Rice Team (rice.collab@kuali.org)
62   *
63   */
64  public class ModuleConfiguration implements InitializingBean, ApplicationContextAware {
65      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ModuleConfiguration.class);
66      /**
67       * the module's namespace.
68       */
69  	protected String namespaceCode;
70  	protected ApplicationContext applicationContext;
71  
72      /**
73       * the package name prefixes for classes used in this module
74       */
75  	protected List<String> packagePrefixes;
76  
77      /**
78       * a list of entity description files to be loaded during initialization of the persistence service.
79       * <p>
80       * Currently only used by OJB repository service implementation.
81       * </p>
82       */
83  	protected List<String> databaseRepositoryFilePaths;
84  
85      /**
86       * the list of data dictionary packages to be loaded for this module by the data dictionary service during system
87       * startup.
88       */
89  	protected List<String> dataDictionaryPackages;
90  
91  	protected List<String> scriptConfigurationFilePaths;
92  
93      protected List<String> resourceBundleNames;
94  
95  	//optional
96  	protected String dataSourceName;
97  
98  	protected Map<Class, Class> externalizableBusinessObjectImplementations;
99  
100 	protected boolean initializeDataDictionary;
101 
102 	protected Object persistenceService;
103 
104 	protected ProviderRegistry providerRegistry;
105 	
106     /**
107      * the implementation of the data dictionary service to use for this module.
108      */
109 	protected DataDictionaryService dataDictionaryService;
110 
111     protected List<Provider> providers = Collections.unmodifiableList(Collections.<Provider>emptyList());
112 
113     /**
114      *  Constructor for a ModuleConfiguration.
115      *
116      *  <p>
117      *  Initializes the arrays of this ModuleConfiguration to empty ArrayLists.
118      *  </p>
119      */
120 	public ModuleConfiguration() {
121 		databaseRepositoryFilePaths = new ArrayList<String>();
122 		dataDictionaryPackages = new ArrayList<String>();
123 		scriptConfigurationFilePaths = new ArrayList<String>();
124         resourceBundleNames = new ArrayList<String>();
125 	}
126 
127     /**
128      * Performs additional custom initialization after the bean is created and it's properties are set by the
129      * Spring framework.
130      *
131      * <p>
132      * Loads the data dictionary packages configured for this module.
133      * Also loads any OJB database repository files configured.
134      * </p>
135      *
136      * @throws Exception
137      */
138 	@Override
139     public void afterPropertiesSet() throws Exception {
140         if (isInitializeDataDictionary() && getDataDictionaryPackages() != null &&
141                 !getDataDictionaryPackages().isEmpty()) {
142             if (getDataDictionaryService() == null) {
143                 setDataDictionaryService(KRADServiceLocatorWeb.getDataDictionaryService());
144             }
145 
146             if (getDataDictionaryService() == null) {
147                 setDataDictionaryService((DataDictionaryService) applicationContext.getBean(
148                         KRADServiceLocatorWeb.DATA_DICTIONARY_SERVICE));
149             }
150 
151             if (dataDictionaryService != null) {
152                 dataDictionaryService.addDataDictionaryLocations(getNamespaceCode(), getDataDictionaryPackages());
153             }
154         }
155 
156         loadOjbRepositoryFiles();
157 
158         if ( getProviders() != null ) {
159             ProviderRegistry providerRegistry = getProviderRegistry();
160             if ( providerRegistry != null ) {
161                 for ( Provider provider : getProviders() ) {
162                     LOG.info( "Registering data module provider for module with " + getNamespaceCode() + ": " + provider);
163                     providerRegistry.registerProvider(provider);
164                 }
165             } else {
166                 LOG.error( "Provider registry not initialized.  Data module provider configuration will be incomplete. (" + getNamespaceCode() + ")" );
167             }
168         }
169     }
170 
171     /**
172      * This method is deprecated and won't do anything if the database repository file paths are null or empty.
173      *
174      * We use reflection here to avoid having to reference PersistenceService directly since it may or may not be on
175      * our classpath depending on whether or not KSB is in use.
176      */
177     @Deprecated
178     protected void loadOjbRepositoryFiles() {
179         String persistenceServiceOjbName = "persistenceServiceOjb";
180         if (getDatabaseRepositoryFilePaths() != null) {
181             for (String repositoryLocation : getDatabaseRepositoryFilePaths()) {
182                 // Need the OJB persistence service because it is the only one ever using the database repository files
183                 if (getPersistenceService() == null) {
184                     setPersistenceService(GlobalResourceLoader.getService(persistenceServiceOjbName));
185                 }
186                 if (persistenceService == null) {
187                     setPersistenceService(applicationContext.getBean(persistenceServiceOjbName));
188                 }
189                 LOG.warn("Loading OJB Configuration in "
190                         + getNamespaceCode()
191                         + " module.  OJB is deprecated as of Rice 2.4: "
192                         + repositoryLocation);
193                 try {
194                     MethodUtils.invokeExactMethod(persistenceService, "loadRepositoryDescriptor", repositoryLocation);
195                 } catch (Exception e) {
196                     throw new RuntimeException(e);
197                 }
198             }
199         }
200 
201     }
202 
203 	/**
204      * Retrieves the database repository file paths to be used by the persistence service configured for this module.
205      *
206      * <p>
207      * Used by the OBJ persistence service to load entity descriptors.
208      * The file paths are returned as a List of Strings. If no file paths are configured,
209      * an empty list is returned.  This method should never return null.
210      * </p>
211      *
212 	 * @return a List containing the databaseRepositoryFilePaths
213      *
214      * @deprecated OJB is deprecated
215 	 */
216     @Deprecated
217 	public List<String> getDatabaseRepositoryFilePaths() {
218 		return this.databaseRepositoryFilePaths;
219 	}
220 
221 	/**
222      * Initializes the list of database repository files to load during persistence service initialization.
223      *
224      * <p>
225      * The repository file names are listed in the module's Spring bean configuration file.
226      * This property is set during Spring initialization.
227      * </p>
228      *
229 	 * @param databaseRepositoryFilePaths the List of entity descriptor files to load.
230      *
231      * @deprecated OJB is deprecated
232      */
233     @Deprecated
234 	public void setDatabaseRepositoryFilePaths(
235 			List<String> databaseRepositoryFilePaths) {
236 		this.trimList(databaseRepositoryFilePaths);
237 		this.databaseRepositoryFilePaths = databaseRepositoryFilePaths;
238 	}
239 
240 	/**
241      * Returns a list of data dictionary packages configured for this ModuleConfiguration.
242      *
243      * <p>
244      * If no data dictionary packages are defined, will return an empty list.
245      * Should never return null.
246      * </p>
247      *
248 	 * @return a List of Strings containing the names of the dataDictionaryPackages
249 	 */
250 	public List<String> getDataDictionaryPackages() {
251 		return this.dataDictionaryPackages;
252 	}
253 
254 	/**
255      * Initializes the list of data dictionary packages associated with this ModuleConfiguration.
256      *
257      * <p>
258      * The data dictionary packages are listed in the module's Spring bean configuration file.
259      * This property is set during Spring initialization.
260      * </p>
261      *
262 	 * @param dataDictionaryPackages a List of Strings containing the dataDictionaryPackages.
263 	 */
264 	public void setDataDictionaryPackages(List<String> dataDictionaryPackages) {
265 		this.trimList(dataDictionaryPackages);
266 		this.dataDictionaryPackages = dataDictionaryPackages;
267 	}
268 
269 	/**
270 	 * @return the externalizableBusinessObjectImplementations
271 	 */
272 	public Map<Class, Class> getExternalizableBusinessObjectImplementations() {
273 		if (this.externalizableBusinessObjectImplementations == null) {
274             return null;
275         }
276 		return Collections.unmodifiableMap(this.externalizableBusinessObjectImplementations);
277 	}
278 
279 	/**
280 	 * @param externalizableBusinessObjectImplementations the externalizableBusinessObjectImplementations to set
281 	 */
282 	public void setExternalizableBusinessObjectImplementations(
283 			Map<Class, Class> externalizableBusinessObjectImplementations) {
284 		if (externalizableBusinessObjectImplementations != null) {
285 			for (Class implClass : externalizableBusinessObjectImplementations.values()) {
286 				int implModifiers = implClass.getModifiers();
287 				if (Modifier.isInterface(implModifiers) || Modifier.isAbstract(implModifiers)) {
288 					throw new RuntimeException("Externalizable business object implementation class " +
289 							implClass.getName() + " must be a non-interface, non-abstract class");
290 				}
291 			}
292 		}
293 		this.externalizableBusinessObjectImplementations = externalizableBusinessObjectImplementations;
294 	}
295 
296 	public List<String> getPackagePrefixes(){
297 		return this.packagePrefixes;
298 	}
299 
300 	public void setPackagePrefixes(List<String> packagePrefixes){
301 		this.trimList(packagePrefixes);
302 		this.packagePrefixes = packagePrefixes;
303 	}
304 
305 	public void setInitializeDataDictionary(boolean initializeDataDictionary){
306 		this.initializeDataDictionary = initializeDataDictionary;
307 	}
308 
309 	public List<String> getScriptConfigurationFilePaths(){
310 		return this.scriptConfigurationFilePaths;
311 	}
312 
313     /**
314      * List of resource bundle names that will provides messages for this module
315      *
316      * <p>
317      * Each bundle will point to a resource property file that contain key/value message pairs. The properties
318      * file should be on the classpath and the name is given by specifying the fully qualified class name
319      * (dot notation).
320      * </p>
321      *
322      * @return List<String> resource bundle names
323      * @see java.util.ResourceBundle
324      */
325     public List<String> getResourceBundleNames() {
326         return resourceBundleNames;
327     }
328 
329     /**
330      * Setter for the list of resource bundle names that provides messages for the module
331      *
332      * @param resourceBundleNames
333      */
334     public void setResourceBundleNames(List<String> resourceBundleNames) {
335         this.resourceBundleNames = resourceBundleNames;
336     }
337 
338     /**
339 	 * @return the initializeDataDictionary
340 	 */
341 	public boolean isInitializeDataDictionary() {
342 		return this.initializeDataDictionary;
343 	}
344 
345 	/**
346 	 * @param scriptConfigurationFilePaths the scriptConfigurationFilePaths to set
347 	 */
348 	public void setScriptConfigurationFilePaths(
349 			List<String> scriptConfigurationFilePaths) {
350 		this.scriptConfigurationFilePaths = scriptConfigurationFilePaths;
351 	}
352 
353 	/**
354 	 * @return the namespaceCode
355 	 */
356 	public String getNamespaceCode() {
357 		return this.namespaceCode;
358 	}
359 
360 	/**
361 	 * @param namespaceCode the namespaceCode to set
362 	 */
363 	public void setNamespaceCode(String namespaceCode) {
364 		this.namespaceCode = namespaceCode;
365 	}
366 
367 	@Override
368 	public void setApplicationContext(ApplicationContext applicationContext) {
369 		this.applicationContext = applicationContext;
370 	}
371 
372     /**
373      * Sets the list of providers for this module
374      * @param providers list of providers
375      */
376     public void setProviders(List<Provider> providers) {
377         this.providers = Collections.unmodifiableList(new ArrayList<Provider>(providers));
378     }
379 
380     public List<Provider> getProviders() {
381         return providers;
382     }
383 
384 	/**
385 	 * @return the dataDictionaryService
386 	 */
387 	public DataDictionaryService getDataDictionaryService() {
388 		return this.dataDictionaryService;
389 	}
390 
391 	/**
392 	 * @param dataDictionaryService the dataDictionaryService to set
393 	 */
394 	public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
395 		this.dataDictionaryService = dataDictionaryService;
396 	}
397 
398 	/**
399      * @return the providerRegistry
400      */
401     public ProviderRegistry getProviderRegistry() {
402         if (this.providerRegistry == null) {
403             this.providerRegistry = KradDataServiceLocator.getProviderRegistry();
404         }
405         
406         return this.providerRegistry;
407     }
408 
409     /**
410      * @param providerRegistry the providerRegistry to set
411      */
412     public void setProviderRegistry(ProviderRegistry providerRegistry) {
413         this.providerRegistry = providerRegistry;
414     }
415 
416     /**
417 	 * @return the persistenceService
418 	 */
419     @Deprecated
420 	public Object getPersistenceService() {
421 		return this.persistenceService;
422 	}
423 
424 	/**
425 	 * @param persistenceService the persistenceService to set
426 	 */
427     @Deprecated
428 	public void setPersistenceService(Object persistenceService) {
429 		this.persistenceService = persistenceService;
430 	}
431 
432     public String getDataSourceName() {
433         return this.dataSourceName;
434     }
435 
436     public void setDataSourceName(String dataSourceName) {
437         this.dataSourceName = dataSourceName;
438     }
439 
440     /**
441 	 *
442 	 * This method passes by reference. It will alter the list passed in.
443 	 *
444 	 * @param stringList
445 	 */
446 	protected void trimList(List<String> stringList){
447 		if(stringList != null){
448 			// we need to trim whitespace from the stringList. Because trim() creates a new string
449 			// we have to explicitly put the new string back into the list
450 			for(int i=0; i<stringList.size(); i++){
451 				String elmt = stringList.get(i);
452 				elmt = elmt.trim();
453 				stringList.set(i, elmt);
454 			}
455 		}
456 	}
457 
458     @Override
459     public String toString() {
460         return new ToStringBuilder(this)
461                     .append("namespaceCode", namespaceCode)
462                     .append("applicationContext", applicationContext.getDisplayName())
463                     .append("dataSourceName", dataSourceName)
464                     .toString();
465     }
466 
467 }