View Javadoc

1   /**
2    * Copyright 2005-2011 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.service.impl;
17  
18  import java.lang.reflect.Modifier;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Map.Entry;
23  import java.util.Properties;
24  
25  import org.apache.commons.beanutils.PropertyUtils;
26  import org.apache.commons.lang.StringUtils;
27  import org.apache.log4j.Logger;
28  import org.kuali.rice.core.framework.parameter.ParameterService;
29  import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
30  import org.kuali.rice.krad.bo.BusinessObject;
31  import org.kuali.rice.krad.bo.DataObjectRelationship;
32  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
33  import org.kuali.rice.krad.bo.ModuleConfiguration;
34  import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
35  import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition;
36  import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
37  import org.kuali.rice.krad.service.BusinessObjectDictionaryService;
38  import org.kuali.rice.krad.service.BusinessObjectNotLookupableException;
39  import org.kuali.rice.krad.service.BusinessObjectService;
40  import org.kuali.rice.krad.service.KRADServiceLocator;
41  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
42  import org.kuali.rice.krad.service.KualiModuleService;
43  import org.kuali.rice.krad.service.LookupService;
44  import org.kuali.rice.krad.service.ModuleService;
45  import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
46  import org.kuali.rice.krad.util.KRADConstants;
47  import org.kuali.rice.krad.util.ObjectUtils;
48  import org.kuali.rice.krad.util.UrlFactory;
49  import org.springframework.beans.BeansException;
50  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
51  import org.springframework.context.ApplicationContext;
52  
53  /**
54   * This class implements ModuleService interface.
55   *
56   * @author Kuali Rice Team (rice.collab@kuali.org)
57   */
58  public class ModuleServiceBase implements ModuleService {
59  
60  	protected static final Logger LOG = Logger.getLogger(ModuleServiceBase.class);
61  
62  	protected ModuleConfiguration moduleConfiguration;
63  	protected BusinessObjectService businessObjectService;
64  	protected LookupService lookupService;
65  	protected BusinessObjectDictionaryService businessObjectDictionaryService;
66  	protected KualiModuleService kualiModuleService;
67  	protected ApplicationContext applicationContext;
68  
69  	/***
70  	 * @see org.kuali.rice.krad.service.ModuleService#isResponsibleFor(java.lang.Class)
71  	 */
72  	public boolean isResponsibleFor(Class businessObjectClass) {
73  		if(getModuleConfiguration() == null)
74  			throw new IllegalStateException("Module configuration has not been initialized for the module service.");
75  
76  		if (getModuleConfiguration().getPackagePrefixes() == null || businessObjectClass == null) {
77  			return false;
78  		}
79  		for (String prefix : getModuleConfiguration().getPackagePrefixes()) {
80  			if (businessObjectClass.getPackage().getName().startsWith(prefix)) {
81  				return true;
82  			}
83  		}
84  		if (ExternalizableBusinessObject.class.isAssignableFrom(businessObjectClass)) {
85  			Class externalizableBusinessObjectInterface = ExternalizableBusinessObjectUtils.determineExternalizableBusinessObjectSubInterface(businessObjectClass);
86  			if (externalizableBusinessObjectInterface != null) {
87  				for (String prefix : getModuleConfiguration().getPackagePrefixes()) {
88  					if (externalizableBusinessObjectInterface.getPackage().getName().startsWith(prefix)) {
89  						return true;
90  					}
91  				}
92  			}
93  		}
94  		return false;
95  	}
96  
97  
98  
99  	/***
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