001 /** 002 * Copyright 2005-2011 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 */ 016 package org.kuali.rice.krad.service.impl; 017 018 import java.lang.reflect.Modifier; 019 import java.util.HashMap; 020 import java.util.List; 021 import java.util.Map; 022 import java.util.Map.Entry; 023 import java.util.Properties; 024 025 import org.apache.commons.beanutils.PropertyUtils; 026 import org.apache.commons.lang.StringUtils; 027 import org.apache.log4j.Logger; 028 import org.kuali.rice.core.framework.parameter.ParameterService; 029 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator; 030 import org.kuali.rice.krad.bo.BusinessObject; 031 import org.kuali.rice.krad.bo.DataObjectRelationship; 032 import org.kuali.rice.krad.bo.ExternalizableBusinessObject; 033 import org.kuali.rice.krad.bo.ModuleConfiguration; 034 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry; 035 import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition; 036 import org.kuali.rice.krad.datadictionary.RelationshipDefinition; 037 import org.kuali.rice.krad.service.BusinessObjectDictionaryService; 038 import org.kuali.rice.krad.service.BusinessObjectNotLookupableException; 039 import org.kuali.rice.krad.service.BusinessObjectService; 040 import org.kuali.rice.krad.service.KRADServiceLocator; 041 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 042 import org.kuali.rice.krad.service.KualiModuleService; 043 import org.kuali.rice.krad.service.LookupService; 044 import org.kuali.rice.krad.service.ModuleService; 045 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils; 046 import org.kuali.rice.krad.util.KRADConstants; 047 import org.kuali.rice.krad.util.ObjectUtils; 048 import org.kuali.rice.krad.util.UrlFactory; 049 import org.springframework.beans.BeansException; 050 import org.springframework.beans.factory.NoSuchBeanDefinitionException; 051 import org.springframework.context.ApplicationContext; 052 053 /** 054 * This class implements ModuleService interface. 055 * 056 * @author Kuali Rice Team (rice.collab@kuali.org) 057 */ 058 public class ModuleServiceBase implements ModuleService { 059 060 protected static final Logger LOG = Logger.getLogger(ModuleServiceBase.class); 061 062 protected ModuleConfiguration moduleConfiguration; 063 protected BusinessObjectService businessObjectService; 064 protected LookupService lookupService; 065 protected BusinessObjectDictionaryService businessObjectDictionaryService; 066 protected KualiModuleService kualiModuleService; 067 protected ApplicationContext applicationContext; 068 069 /*** 070 * @see org.kuali.rice.krad.service.ModuleService#isResponsibleFor(java.lang.Class) 071 */ 072 public boolean isResponsibleFor(Class businessObjectClass) { 073 if(getModuleConfiguration() == null) 074 throw new IllegalStateException("Module configuration has not been initialized for the module service."); 075 076 if (getModuleConfiguration().getPackagePrefixes() == null || businessObjectClass == null) { 077 return false; 078 } 079 for (String prefix : getModuleConfiguration().getPackagePrefixes()) { 080 if (businessObjectClass.getPackage().getName().startsWith(prefix)) { 081 return true; 082 } 083 } 084 if (ExternalizableBusinessObject.class.isAssignableFrom(businessObjectClass)) { 085 Class externalizableBusinessObjectInterface = ExternalizableBusinessObjectUtils.determineExternalizableBusinessObjectSubInterface(businessObjectClass); 086 if (externalizableBusinessObjectInterface != null) { 087 for (String prefix : getModuleConfiguration().getPackagePrefixes()) { 088 if (externalizableBusinessObjectInterface.getPackage().getName().startsWith(prefix)) { 089 return true; 090 } 091 } 092 } 093 } 094 return false; 095 } 096 097 098 099 /*** 100 * @see org.kuali.rice.krad.service.ModuleService#isResponsibleFor(java.lang.Class) 101 */ 102 public boolean isResponsibleForJob(String jobName) { 103 if(getModuleConfiguration() == null) 104 throw new IllegalStateException("Module configuration has not been initialized for the module service."); 105 106 if (getModuleConfiguration().getJobNames() == null || StringUtils.isEmpty(jobName)) 107 return false; 108 109 return getModuleConfiguration().getJobNames().contains(jobName); 110 } 111 112 /*** 113 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObject(java.lang.Class, java.util.Map) 114 */ 115 public <T extends ExternalizableBusinessObject> T getExternalizableBusinessObject(Class<T> businessObjectClass, Map<String, Object> fieldValues) { 116 Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(businessObjectClass); 117 ExternalizableBusinessObject businessObject = (ExternalizableBusinessObject) 118 getBusinessObjectService().findByPrimaryKey(implementationClass, fieldValues); 119 return (T) businessObject; 120 } 121 122 /*** 123 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObject(java.lang.Class, java.util.Map) 124 */ 125 public <T extends ExternalizableBusinessObject> List<T> getExternalizableBusinessObjectsList( 126 Class<T> externalizableBusinessObjectClass, Map<String, Object> fieldValues) { 127 Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(externalizableBusinessObjectClass); 128 return (List<T>) getBusinessObjectService().findMatching(implementationClass, fieldValues); 129 } 130 131 /*** 132 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectsListForLookup(java.lang.Class, java.util.Map, boolean) 133 */ 134 public <T extends ExternalizableBusinessObject> List<T> getExternalizableBusinessObjectsListForLookup( 135 Class<T> externalizableBusinessObjectClass, Map<String, Object> fieldValues, boolean unbounded) { 136 Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(externalizableBusinessObjectClass); 137 if (isExternalizableBusinessObjectLookupable(implementationClass)) { 138 Map<String, String> searchCriteria = new HashMap<String, String>(); 139 for (Entry<String, Object> fieldValue : fieldValues.entrySet()) { 140 if (fieldValue.getValue() != null) { 141 searchCriteria.put(fieldValue.getKey(), fieldValue.getValue().toString()); 142 } 143 else { 144 searchCriteria.put(fieldValue.getKey(), null); 145 } 146 } 147 return (List<T>) getLookupService().findCollectionBySearchHelper(implementationClass, searchCriteria, unbounded); 148 } else { 149 throw new BusinessObjectNotLookupableException("External business object is not a Lookupable: " + implementationClass); 150 } 151 } 152 153 public List listPrimaryKeyFieldNames(Class businessObjectInterfaceClass){ 154 Class clazz = getExternalizableBusinessObjectImplementation(businessObjectInterfaceClass); 155 return KRADServiceLocator.getPersistenceStructureService().listPrimaryKeyFieldNames(clazz); 156 } 157 158 /*** 159 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectDictionaryEntry(java.lang.Class) 160 */ 161 public BusinessObjectEntry getExternalizableBusinessObjectDictionaryEntry( 162 Class businessObjectInterfaceClass) { 163 Class boClass = getExternalizableBusinessObjectImplementation(businessObjectInterfaceClass); 164 165 return boClass==null?null: 166 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntryForConcreteClass(boClass.getName()); 167 } 168 169 public String getExternalizableBusinessObjectInquiryUrl(Class inquiryBusinessObjectClass, Map<String, String[]> parameters) { 170 if(!ExternalizableBusinessObject.class.isAssignableFrom(inquiryBusinessObjectClass)) { 171 return KRADConstants.EMPTY_STRING; 172 } 173 String businessObjectClassAttribute; 174 175 Class implementationClass = getExternalizableBusinessObjectImplementation(inquiryBusinessObjectClass); 176 if (implementationClass == null) { 177 LOG.error("Can't find ExternalizableBusinessObject implementation class for " + inquiryBusinessObjectClass.getName()); 178 throw new RuntimeException("Can't find ExternalizableBusinessObject implementation class for interface " + inquiryBusinessObjectClass.getName()); 179 } 180 businessObjectClassAttribute = implementationClass.getName(); 181 return UrlFactory.parameterizeUrl( 182 getInquiryUrl(inquiryBusinessObjectClass), 183 getUrlParameters(businessObjectClassAttribute, parameters)); 184 } 185 186 protected Properties getUrlParameters(String businessObjectClassAttribute, Map<String, String[]> parameters){ 187 Properties urlParameters = new Properties(); 188 for (String paramName : parameters.keySet()) { 189 String[] parameterValues = parameters.get(paramName); 190 if (parameterValues.length > 0) { 191 urlParameters.put(paramName, parameterValues[0]); 192 } 193 } 194 urlParameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObjectClassAttribute); 195 urlParameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.CONTINUE_WITH_INQUIRY_METHOD_TO_CALL); 196 return urlParameters; 197 } 198 199 protected String getInquiryUrl(Class inquiryBusinessObjectClass){ 200 String riceBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString( 201 KRADConstants.APPLICATION_URL_KEY); 202 String inquiryUrl = riceBaseUrl; 203 if (!inquiryUrl.endsWith("/")) { 204 inquiryUrl = inquiryUrl + "/"; 205 } 206 return inquiryUrl + "kr/" + KRADConstants.INQUIRY_ACTION; 207 } 208 209 /** 210 * This overridden method ... 211 * 212 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectLookupUrl(java.lang.Class, java.util.Map) 213 */ 214 public String getExternalizableBusinessObjectLookupUrl(Class inquiryBusinessObjectClass, Map<String, String> parameters) { 215 Properties urlParameters = new Properties(); 216 217 String riceBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString( 218 KRADConstants.APPLICATION_URL_KEY); 219 String lookupUrl = riceBaseUrl; 220 if (!lookupUrl.endsWith("/")) { 221 lookupUrl = lookupUrl + "/"; 222 } 223 if (parameters.containsKey(KRADConstants.MULTIPLE_VALUE)) { 224 lookupUrl = lookupUrl + "kr/" + KRADConstants.MULTIPLE_VALUE_LOOKUP_ACTION; 225 } 226 else { 227 lookupUrl = lookupUrl + "kr/" + KRADConstants.LOOKUP_ACTION; 228 } 229 for (String paramName : parameters.keySet()) { 230 urlParameters.put(paramName, parameters.get(paramName)); 231 } 232 233 Class clazz = getExternalizableBusinessObjectImplementation(inquiryBusinessObjectClass); 234 urlParameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, clazz==null?"":clazz.getName()); 235 236 return UrlFactory.parameterizeUrl(lookupUrl, urlParameters); 237 } 238 239 /*** 240 * 241 * This method assumes that the property type for externalizable relationship in the business object is an interface 242 * and gets the concrete implementation for it 243 * 244 * @see org.kuali.rice.krad.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.krad.bo.BusinessObject, org.kuali.rice.krad.bo.BusinessObject, java.lang.String) 245 */ 246 public <T extends ExternalizableBusinessObject> T retrieveExternalizableBusinessObjectIfNecessary( 247 BusinessObject businessObject, T currentInstanceExternalizableBO, String externalizableRelationshipName) { 248 249 if(businessObject==null) return null; 250 Class clazz; 251 try{ 252 clazz = getExternalizableBusinessObjectImplementation( 253 PropertyUtils.getPropertyType(businessObject, externalizableRelationshipName)); 254 } catch(Exception iex){ 255 LOG.warn("Exception:"+iex+" thrown while trying to get property type for property:"+externalizableRelationshipName+ 256 " from business object:"+businessObject); 257 return null; 258 } 259 260 //Get the business object entry for this business object from data dictionary 261 //using the class name (without the package) as key 262 BusinessObjectEntry entry = 263 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get( 264 businessObject.getClass().getSimpleName()); 265 RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName); 266 List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes(); 267 268 Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>(); 269 Object sourcePropertyValue; 270 Object targetPropertyValue = null; 271 boolean sourceTargetPropertyValuesSame = true; 272 for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){ 273 sourcePropertyValue = ObjectUtils.getPropertyValue( 274 businessObject, primitiveAttributeDefinition.getSourceName()); 275 if(currentInstanceExternalizableBO!=null) 276 targetPropertyValue = ObjectUtils.getPropertyValue(currentInstanceExternalizableBO, primitiveAttributeDefinition.getTargetName()); 277 if(sourcePropertyValue==null){ 278 return null; 279 } else if(targetPropertyValue==null || (targetPropertyValue!=null && !targetPropertyValue.equals(sourcePropertyValue))){ 280 sourceTargetPropertyValuesSame = false; 281 } 282 fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue); 283 } 284 285 if(!sourceTargetPropertyValuesSame) 286 return (T) getExternalizableBusinessObject(clazz, fieldValuesInEBO); 287 return currentInstanceExternalizableBO; 288 } 289 290 /*** 291 * 292 * This method assumes that the externalizableClazz is an interface 293 * and gets the concrete implementation for it 294 * 295 * @see org.kuali.rice.krad.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.krad.bo.BusinessObject, org.kuali.rice.krad.bo.BusinessObject, java.lang.String) 296 */ 297 public List<? extends ExternalizableBusinessObject> retrieveExternalizableBusinessObjectsList( 298 BusinessObject businessObject, String externalizableRelationshipName, Class externalizableClazz) { 299 300 if(businessObject==null) return null; 301 //Get the business object entry for this business object from data dictionary 302 //using the class name (without the package) as key 303 String className = businessObject.getClass().getName(); 304 String key = className.substring(className.lastIndexOf(".")+1); 305 BusinessObjectEntry entry = 306 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get(key); 307 RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName); 308 List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes(); 309 Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>(); 310 Object sourcePropertyValue; 311 for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){ 312 sourcePropertyValue = ObjectUtils.getPropertyValue( 313 businessObject, primitiveAttributeDefinition.getSourceName()); 314 if(sourcePropertyValue==null){ 315 return null; 316 } 317 fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue); 318 } 319 return getExternalizableBusinessObjectsList( 320 getExternalizableBusinessObjectImplementation(externalizableClazz), fieldValuesInEBO); 321 } 322 323 /** 324 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectImplementation(java.lang.Class) 325 */ 326 public <E extends ExternalizableBusinessObject> Class<E> getExternalizableBusinessObjectImplementation(Class<E> externalizableBusinessObjectInterface) { 327 if (getModuleConfiguration() == null) { 328 throw new IllegalStateException("Module configuration has not been initialized for the module service."); 329 } 330 int classModifiers = externalizableBusinessObjectInterface.getModifiers(); 331 Map<Class, Class> ebos = getModuleConfiguration().getExternalizableBusinessObjectImplementations(); 332 333 if (ebos.containsValue(externalizableBusinessObjectInterface)) { 334 return externalizableBusinessObjectInterface; 335 } 336 if (getModuleConfiguration().getExternalizableBusinessObjectImplementations() == null) { 337 return null; 338 } 339 else { 340 Class<E> implementationClass = ebos.get(externalizableBusinessObjectInterface); 341 int implClassModifiers = implementationClass.getModifiers(); 342 if (Modifier.isInterface(implClassModifiers) || Modifier.isAbstract(implClassModifiers)) { 343 throw new RuntimeException("Implementation class must be non-abstract class: ebo interface: " + externalizableBusinessObjectInterface.getName() + " impl class: " 344 + implementationClass.getName() + " module: " + getModuleConfiguration().getNamespaceCode()); 345 } 346 return implementationClass; 347 } 348 349 } 350 351 /*** 352 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 353 */ 354 public void afterPropertiesSet() throws Exception { 355 KualiModuleService kualiModuleService = null; 356 try { 357 kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService(); 358 if ( kualiModuleService == null ) { 359 kualiModuleService = ((KualiModuleService)applicationContext.getBean( KRADServiceLocatorWeb.KUALI_MODULE_SERVICE )); 360 } 361 } catch ( NoSuchBeanDefinitionException ex ) { 362 kualiModuleService = ((KualiModuleService)applicationContext.getBean( KRADServiceLocatorWeb.KUALI_MODULE_SERVICE )); 363 } 364 kualiModuleService.getInstalledModuleServices().add( this ); 365 } 366 367 /** 368 * @return the moduleConfiguration 369 */ 370 public ModuleConfiguration getModuleConfiguration() { 371 return this.moduleConfiguration; 372 } 373 374 /** 375 * @param moduleConfiguration the moduleConfiguration to set 376 */ 377 public void setModuleConfiguration(ModuleConfiguration moduleConfiguration) { 378 this.moduleConfiguration = moduleConfiguration; 379 } 380 381 /*** 382 * @see org.kuali.rice.krad.service.ModuleService#isExternalizable(java.lang.Class) 383 */ 384 public boolean isExternalizable(Class boClazz){ 385 if(boClazz==null) return false; 386 return ExternalizableBusinessObject.class.isAssignableFrom(boClazz); 387 } 388 389 public boolean isExternalizableBusinessObjectLookupable(Class boClass) { 390 return getBusinessObjectDictionaryService().isLookupable(boClass); 391 } 392 393 public boolean isExternalizableBusinessObjectInquirable(Class boClass) { 394 return getBusinessObjectDictionaryService().isInquirable(boClass); 395 } 396 397 public <T extends ExternalizableBusinessObject> T createNewObjectFromExternalizableClass(Class<T> boClass) { 398 try { 399 return (T) getExternalizableBusinessObjectImplementation(boClass).newInstance(); 400 } catch (Exception e) { 401 throw new RuntimeException("Unable to create externalizable business object class", e); 402 } 403 } 404 405 public DataObjectRelationship getBusinessObjectRelationship(Class boClass, String attributeName, String attributePrefix){ 406 return null; 407 } 408 409 410 411 public BusinessObjectDictionaryService getBusinessObjectDictionaryService () { 412 if ( businessObjectDictionaryService == null ) { 413 businessObjectDictionaryService = KRADServiceLocatorWeb.getBusinessObjectDictionaryService(); 414 } 415 return businessObjectDictionaryService; 416 } 417 418 /** 419 * @return the businessObjectService 420 */ 421 public BusinessObjectService getBusinessObjectService() { 422 if ( businessObjectService == null ) { 423 businessObjectService = KRADServiceLocator.getBusinessObjectService(); 424 } 425 return businessObjectService; 426 } 427 428 /** 429 * Gets the lookupService attribute. 430 * @return Returns the lookupService. 431 */ 432 protected LookupService getLookupService() { 433 return lookupService != null ? lookupService : KRADServiceLocatorWeb.getLookupService(); 434 } 435 436 /** 437 * @return the kualiModuleService 438 */ 439 public KualiModuleService getKualiModuleService() { 440 return this.kualiModuleService; 441 } 442 443 /** 444 * @param kualiModuleService the kualiModuleService to set 445 */ 446 public void setKualiModuleService(KualiModuleService kualiModuleService) { 447 this.kualiModuleService = kualiModuleService; 448 } 449 450 /** 451 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 452 */ 453 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 454 this.applicationContext = applicationContext; 455 } 456 457 458 459 /** 460 * This overridden method ... 461 * 462 * @see org.kuali.rice.krad.service.ModuleService#listAlternatePrimaryKeyFieldNames(java.lang.Class) 463 */ 464 public List<List<String>> listAlternatePrimaryKeyFieldNames( 465 Class businessObjectInterfaceClass) { 466 return null; 467 } 468 469 470 471 /** 472 * This method determines whether or not this module is currently locked 473 * 474 * @see org.kuali.rice.krad.service.ModuleService#isLocked() 475 */ 476 @Override 477 public boolean isLocked() { 478 ModuleConfiguration configuration = this.getModuleConfiguration(); 479 if(configuration != null) { 480 String namespaceCode = configuration.getNamespaceCode(); 481 String componentCode = KRADConstants.DetailTypes.OLTP_LOCKOUT_DETAIL_TYPE; 482 String parameterName = KRADConstants.SystemGroupParameterNames.OLTP_LOCKOUT_ACTIVE_IND; 483 ParameterService parameterService = CoreFrameworkServiceLocator.getParameterService(); 484 String shouldLockout = parameterService.getParameterValueAsString(namespaceCode, componentCode, parameterName); 485 if(StringUtils.isNotBlank(shouldLockout)) { 486 return parameterService.getParameterValueAsBoolean(namespaceCode, componentCode, parameterName); 487 } 488 } 489 return false; 490 } 491 } 492