001/** 002 * Copyright 2005-2015 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 */ 016package org.kuali.rice.krad.bo; 017 018import org.apache.commons.beanutils.MethodUtils; 019import org.apache.commons.lang.builder.ToStringBuilder; 020import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 021import org.kuali.rice.krad.data.KradDataServiceLocator; 022import org.kuali.rice.krad.data.provider.MetadataProvider; 023import org.kuali.rice.krad.data.provider.Provider; 024import org.kuali.rice.krad.data.provider.ProviderRegistry; 025import org.kuali.rice.krad.service.DataDictionaryService; 026import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 027import org.springframework.beans.factory.InitializingBean; 028import org.springframework.context.ApplicationContext; 029import org.springframework.context.ApplicationContextAware; 030 031 032import java.lang.reflect.Modifier; 033import java.util.ArrayList; 034import java.util.Collections; 035import java.util.List; 036import java.util.Map; 037 038/** 039 * This class contains various configuration properties for a Rice module. 040 * 041 * <p> 042 * The Rice framework is composed of several separate modules, each of which is 043 * responsible for providing a set of functionality. These include: 044 * <ul> 045 * <li>KEW - the Rice enterprise workflow module 046 * <li>KIM - the Rice identity management module 047 * <li>KSB - the Rice service bus 048 * <li>KRAD - the Rice rapid application development module 049 * <li>KRMS - the Rice business rules management syste 050 * <li>eDocLite - a Rice framework for creating simple documents quickly 051 * <li>...as well as several others. Refer to the Rice documentation for a complete list. 052 * </ul> 053 * <br> 054 * Client Applications will also have their own module configurations. A client application could create a single 055 * module or multiple modules, depending on how it is organized. 056 * <br> 057 * This ModuleConfiguration object is created during Spring initialization. The properties of this ModuleConfiguration 058 * are specified in the module's SpringBean definition XML configuration file. 059 *</p> 060 * 061 * @author Kuali Rice Team (rice.collab@kuali.org) 062 * 063 */ 064public class ModuleConfiguration implements InitializingBean, ApplicationContextAware { 065 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ModuleConfiguration.class); 066 /** 067 * the module's namespace. 068 */ 069 protected String namespaceCode; 070 protected ApplicationContext applicationContext; 071 072 /** 073 * the package name prefixes for classes used in this module 074 */ 075 protected List<String> packagePrefixes; 076 077 /** 078 * a list of entity description files to be loaded during initialization of the persistence service. 079 * <p> 080 * Currently only used by OJB repository service implementation. 081 * </p> 082 */ 083 protected List<String> databaseRepositoryFilePaths; 084 085 /** 086 * the list of data dictionary packages to be loaded for this module by the data dictionary service during system 087 * startup. 088 */ 089 protected List<String> dataDictionaryPackages; 090 091 protected List<String> scriptConfigurationFilePaths; 092 093 protected List<String> resourceBundleNames; 094 095 //optional 096 protected String dataSourceName; 097 098 protected Map<Class, Class> externalizableBusinessObjectImplementations; 099 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}