View Javadoc

1   /*
2    * Copyright 2007-2008 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 org.apache.commons.beanutils.PropertyUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.kuali.rice.krad.bo.BusinessObject;
22  import org.kuali.rice.krad.bo.DataObjectRelationship;
23  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
24  import org.kuali.rice.krad.bo.ModuleConfiguration;
25  import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
26  import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition;
27  import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
28  import org.kuali.rice.krad.service.BusinessObjectDictionaryService;
29  import org.kuali.rice.krad.service.BusinessObjectNotLookupableException;
30  import org.kuali.rice.krad.service.BusinessObjectService;
31  import org.kuali.rice.krad.service.KRADServiceLocator;
32  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33  import org.kuali.rice.krad.service.KualiModuleService;
34  import org.kuali.rice.krad.service.LookupService;
35  import org.kuali.rice.krad.service.ModuleService;
36  import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
37  import org.kuali.rice.krad.util.KRADConstants;
38  import org.kuali.rice.krad.util.ObjectUtils;
39  import org.kuali.rice.krad.util.UrlFactory;
40  import org.springframework.beans.BeansException;
41  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
42  import org.springframework.context.ApplicationContext;
43  
44  import java.lang.reflect.Modifier;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Map.Entry;
49  import java.util.Properties;
50  
51  /**
52   * This class implements ModuleService interface.
53   *
54   * @author Kuali Rice Team (rice.collab@kuali.org)
55   */
56  public class ModuleServiceBase implements ModuleService {
57  
58  	protected static final Logger LOG = Logger.getLogger(ModuleServiceBase.class);
59  
60  	protected ModuleConfiguration moduleConfiguration;
61  	protected BusinessObjectService businessObjectService;
62  	protected LookupService lookupService;
63  	protected BusinessObjectDictionaryService businessObjectDictionaryService;
64  	protected KualiModuleService kualiModuleService;
65  	protected ApplicationContext applicationContext;
66  
67  	/***
68  	 * @see org.kuali.rice.krad.service.ModuleService#isResponsibleFor(java.lang.Class)
69  	 */
70  	public boolean isResponsibleFor(Class businessObjectClass) {
71  		if(getModuleConfiguration() == null)
72  			throw new IllegalStateException("Module configuration has not been initialized for the module service.");
73  
74  		if (getModuleConfiguration().getPackagePrefixes() == null || businessObjectClass == null) {
75  			return false;
76  		}
77  		for (String prefix : getModuleConfiguration().getPackagePrefixes()) {
78  			if (businessObjectClass.getPackage().getName().startsWith(prefix)) {
79  				return true;
80  			}
81  		}
82  		if (ExternalizableBusinessObject.class.isAssignableFrom(businessObjectClass)) {
83  			Class externalizableBusinessObjectInterface = ExternalizableBusinessObjectUtils.determineExternalizableBusinessObjectSubInterface(businessObjectClass);
84  			if (externalizableBusinessObjectInterface != null) {
85  				for (String prefix : getModuleConfiguration().getPackagePrefixes()) {
86  					if (externalizableBusinessObjectInterface.getPackage().getName().startsWith(prefix)) {
87  						return true;
88  					}
89  				}
90  			}
91  		}
92  		return false;
93  	}
94  
95  
96  
97  	/***
98  	 * @see org.kuali.rice.krad.service.ModuleService#isResponsibleFor(java.lang.Class)
99  	 */
100 	public boolean isResponsibleForJob(String jobName) {
101 		if(getModuleConfiguration() == null)
102 			throw new IllegalStateException("Module configuration has not been initialized for the module service.");
103 
104 		if (getModuleConfiguration().getJobNames() == null || StringUtils.isEmpty(jobName))
105 			return false;
106 
107 		return getModuleConfiguration().getJobNames().contains(jobName);
108 	}
109 
110     /***
111      * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObject(java.lang.Class, java.util.Map)
112      */
113     public <T extends ExternalizableBusinessObject> T getExternalizableBusinessObject(Class<T> businessObjectClass, Map<String, Object> fieldValues) {
114     	Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(businessObjectClass);
115 		ExternalizableBusinessObject businessObject = (ExternalizableBusinessObject)
116 			getBusinessObjectService().findByPrimaryKey(implementationClass, fieldValues);
117         return (T) businessObject;
118 	}
119 
120     /***
121      * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObject(java.lang.Class, java.util.Map)
122      */
123 	public <T extends ExternalizableBusinessObject> List<T> getExternalizableBusinessObjectsList(
124 			Class<T> externalizableBusinessObjectClass, Map<String, Object> fieldValues) {
125 		Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(externalizableBusinessObjectClass);
126 		return (List<T>) getBusinessObjectService().findMatching(implementationClass, fieldValues);
127 	}
128 
129 	/***
130 	 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectsListForLookup(java.lang.Class, java.util.Map, boolean)
131 	 */
132 	public <T extends ExternalizableBusinessObject> List<T> getExternalizableBusinessObjectsListForLookup(
133 			Class<T> externalizableBusinessObjectClass, Map<String, Object> fieldValues, boolean unbounded) {
134 		Class<? extends ExternalizableBusinessObject> implementationClass = getExternalizableBusinessObjectImplementation(externalizableBusinessObjectClass);
135 		if (isExternalizableBusinessObjectLookupable(implementationClass)) {
136 			Map<String, String> searchCriteria = new HashMap<String, String>();
137 			for (Entry<String, Object> fieldValue : fieldValues.entrySet()) {
138 				if (fieldValue.getValue() != null) {
139 					searchCriteria.put(fieldValue.getKey(), fieldValue.getValue().toString());
140 				}
141 				else {
142 					searchCriteria.put(fieldValue.getKey(), null);
143 				}
144 			}
145 		    return (List<T>) getLookupService().findCollectionBySearchHelper(implementationClass, searchCriteria, unbounded);
146 		} else {
147 		   throw new BusinessObjectNotLookupableException("External business object is not a Lookupable:  " + implementationClass);
148 		}
149 	}
150 
151 	public List listPrimaryKeyFieldNames(Class businessObjectInterfaceClass){
152 		Class clazz = getExternalizableBusinessObjectImplementation(businessObjectInterfaceClass);
153 		return KRADServiceLocator.getPersistenceStructureService().listPrimaryKeyFieldNames(clazz);
154 	}
155 
156 	/***
157 	 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectDictionaryEntry(java.lang.Class)
158 	 */
159 	public BusinessObjectEntry getExternalizableBusinessObjectDictionaryEntry(
160 			Class businessObjectInterfaceClass) {
161 		Class boClass = businessObjectInterfaceClass;
162 		if(businessObjectInterfaceClass.isInterface())
163 			boClass = getExternalizableBusinessObjectImplementation(businessObjectInterfaceClass);
164 		return boClass==null?null:
165 			KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntryForConcreteClass(boClass.getName());
166 	}
167 
168 	public String getExternalizableBusinessObjectInquiryUrl(Class inquiryBusinessObjectClass, Map<String, String[]> parameters) {
169 		if(!ExternalizableBusinessObject.class.isAssignableFrom(inquiryBusinessObjectClass)) {
170 	        return KRADConstants.EMPTY_STRING;
171 		}
172 		String businessObjectClassAttribute;
173 		if(inquiryBusinessObjectClass.isInterface()){
174 			Class implementationClass = getExternalizableBusinessObjectImplementation(inquiryBusinessObjectClass);
175 			if (implementationClass == null) {
176 				LOG.error("Can't find ExternalizableBusinessObject implementation class for interface " + inquiryBusinessObjectClass.getName());
177 				throw new RuntimeException("Can't find ExternalizableBusinessObject implementation class for interface " + inquiryBusinessObjectClass.getName());
178 			}
179 			businessObjectClassAttribute = implementationClass.getName();
180 		}else{
181 			LOG.warn("Inquiry was invoked with a non-interface class object " + inquiryBusinessObjectClass.getName());
182 			businessObjectClassAttribute = inquiryBusinessObjectClass.getName();
183 		}
184         return UrlFactory.parameterizeUrl(
185         		getInquiryUrl(inquiryBusinessObjectClass),
186         		getUrlParameters(businessObjectClassAttribute, parameters));
187 	}
188 
189 	protected Properties getUrlParameters(String businessObjectClassAttribute, Map<String, String[]> parameters){
190 		Properties urlParameters = new Properties();
191 		for (String paramName : parameters.keySet()) {
192 			String[] parameterValues = parameters.get(paramName);
193 			if (parameterValues.length > 0) {
194 				urlParameters.put(paramName, parameterValues[0]);
195 			}
196 		}
197 		urlParameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObjectClassAttribute);
198 		urlParameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.CONTINUE_WITH_INQUIRY_METHOD_TO_CALL);
199 		return urlParameters;
200 	}
201 
202 	protected String getInquiryUrl(Class inquiryBusinessObjectClass){
203 		String riceBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
204                 KRADConstants.APPLICATION_URL_KEY);
205 		String inquiryUrl = riceBaseUrl;
206 		if (!inquiryUrl.endsWith("/")) {
207 			inquiryUrl = inquiryUrl + "/";
208 		}
209 		return inquiryUrl + "kr/" + KRADConstants.INQUIRY_ACTION;
210 	}
211 
212 	/**
213 	 * This overridden method ...
214 	 *
215 	 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectLookupUrl(java.lang.Class, java.util.Map)
216 	 */
217 	public String getExternalizableBusinessObjectLookupUrl(Class inquiryBusinessObjectClass, Map<String, String> parameters) {
218 		Properties urlParameters = new Properties();
219 
220 		String riceBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
221                 KRADConstants.APPLICATION_URL_KEY);
222 		String lookupUrl = riceBaseUrl;
223 		if (!lookupUrl.endsWith("/")) {
224 			lookupUrl = lookupUrl + "/";
225 		}
226 		if (parameters.containsKey(KRADConstants.MULTIPLE_VALUE)) {
227 			lookupUrl = lookupUrl + "kr/" + KRADConstants.MULTIPLE_VALUE_LOOKUP_ACTION;
228 		}
229 		else {
230 			lookupUrl = lookupUrl + "kr/" + KRADConstants.LOOKUP_ACTION;
231 		}
232 		for (String paramName : parameters.keySet()) {
233 			urlParameters.put(paramName, parameters.get(paramName));
234 		}
235 
236 		Class clazz = getExternalizableBusinessObjectImplementation(inquiryBusinessObjectClass);
237 		urlParameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, clazz==null?"":clazz.getName());
238 
239 		return UrlFactory.parameterizeUrl(lookupUrl, urlParameters);
240 	}
241 
242 	/***
243 	 *
244 	 * This method assumes that the property type for externalizable relationship in the business object is an interface
245 	 * and gets the concrete implementation for it
246 	 *
247 	 * @see org.kuali.rice.krad.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.krad.bo.BusinessObject, org.kuali.rice.krad.bo.BusinessObject, java.lang.String)
248 	 */
249 	public <T extends ExternalizableBusinessObject> T retrieveExternalizableBusinessObjectIfNecessary(
250 			BusinessObject businessObject, T currentInstanceExternalizableBO, String externalizableRelationshipName) {
251 
252 		if(businessObject==null) return null;
253 		Class clazz;
254 		try{
255 			clazz = getExternalizableBusinessObjectImplementation(
256 					PropertyUtils.getPropertyType(businessObject, externalizableRelationshipName));
257 		} catch(Exception iex){
258 			LOG.warn("Exception:"+iex+" thrown while trying to get property type for property:"+externalizableRelationshipName+
259 					" from business object:"+businessObject);
260 			return null;
261 		}
262 
263 		//Get the business object entry for this business object from data dictionary
264 		//using the class name (without the package) as key
265 		BusinessObjectEntry entry =
266 			KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get(
267 					businessObject.getClass().getSimpleName());
268 		RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName);
269 		List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes();
270 
271 		Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>();
272 		Object sourcePropertyValue;
273 		Object targetPropertyValue = null;
274 		boolean sourceTargetPropertyValuesSame = true;
275 		for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){
276 	    	sourcePropertyValue = ObjectUtils.getPropertyValue(
277 	    			businessObject, primitiveAttributeDefinition.getSourceName());
278 	    	if(currentInstanceExternalizableBO!=null)
279 	    		targetPropertyValue = ObjectUtils.getPropertyValue(currentInstanceExternalizableBO, primitiveAttributeDefinition.getTargetName());
280 		    if(sourcePropertyValue==null){
281 		        return null;
282 		    } else if(targetPropertyValue==null || (targetPropertyValue!=null && !targetPropertyValue.equals(sourcePropertyValue))){
283 		    	sourceTargetPropertyValuesSame = false;
284 		    }
285 		    fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue);
286 		}
287 
288 		if(!sourceTargetPropertyValuesSame)
289 			return (T) getExternalizableBusinessObject(clazz, fieldValuesInEBO);
290 		return currentInstanceExternalizableBO;
291 	}
292 
293 	/***
294 	 *
295 	 * This method assumes that the externalizableClazz is an interface
296 	 * and gets the concrete implementation for it
297 	 *
298 	 * @see org.kuali.rice.krad.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.krad.bo.BusinessObject, org.kuali.rice.krad.bo.BusinessObject, java.lang.String)
299 	 */
300 	public List<? extends ExternalizableBusinessObject> retrieveExternalizableBusinessObjectsList(
301 			BusinessObject businessObject, String externalizableRelationshipName, Class externalizableClazz) {
302 
303 		if(businessObject==null) return null;
304 		//Get the business object entry for this business object from data dictionary
305 		//using the class name (without the package) as key
306 		String className = businessObject.getClass().getName();
307 		String key = className.substring(className.lastIndexOf(".")+1);
308 		BusinessObjectEntry entry =
309 			KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get(key);
310 		RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName);
311 		List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes();
312 		Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>();
313 		Object sourcePropertyValue;
314 		for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){
315 	    	sourcePropertyValue = ObjectUtils.getPropertyValue(
316 	    			businessObject, primitiveAttributeDefinition.getSourceName());
317 		    if(sourcePropertyValue==null){
318 		        return null;
319 		    }
320 		    fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue);
321 		}
322 		return getExternalizableBusinessObjectsList(
323 				getExternalizableBusinessObjectImplementation(externalizableClazz), fieldValuesInEBO);
324 	}
325 
326 	/**
327 	 * @see org.kuali.rice.krad.service.ModuleService#getExternalizableBusinessObjectImplementation(java.lang.Class)
328 	 */
329 	public <E extends ExternalizableBusinessObject> Class<E> getExternalizableBusinessObjectImplementation(Class<E> externalizableBusinessObjectInterface) {
330 		if (getModuleConfiguration() == null) {
331 			throw new IllegalStateException("Module configuration has not been initialized for the module service.");
332 		}
333 		int classModifiers = externalizableBusinessObjectInterface.getModifiers();
334 		if (!Modifier.isInterface(classModifiers) && !Modifier.isAbstract(classModifiers)) {
335 			// the interface is really a non-abstract class
336 			return externalizableBusinessObjectInterface;
337 		}
338 		if (getModuleConfiguration().getExternalizableBusinessObjectImplementations() == null) {
339 			return null;
340 		}
341 		else {
342 			Class<E> implementationClass = getModuleConfiguration().getExternalizableBusinessObjectImplementations().get(externalizableBusinessObjectInterface);
343 			int implClassModifiers = implementationClass.getModifiers();
344 			if (Modifier.isInterface(implClassModifiers) || Modifier.isAbstract(implClassModifiers)) {
345 				throw new RuntimeException("Implementation class must be non-abstract class: ebo interface: " + externalizableBusinessObjectInterface.getName() + " impl class: "
346 						+ implementationClass.getName() + " module: " + getModuleConfiguration().getNamespaceCode());
347 			}
348 			return implementationClass;
349 		}
350 
351 	}
352 
353 	/***
354 	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
355 	 */
356 	public void afterPropertiesSet() throws Exception {
357 		KualiModuleService kualiModuleService = null;
358 		try {
359 			kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
360 			if ( kualiModuleService == null ) {
361 				kualiModuleService = ((KualiModuleService)applicationContext.getBean( KRADServiceLocatorWeb.KUALI_MODULE_SERVICE ));
362 			}
363 		} catch ( NoSuchBeanDefinitionException ex ) {
364 			kualiModuleService = ((KualiModuleService)applicationContext.getBean( KRADServiceLocatorWeb.KUALI_MODULE_SERVICE ));
365 		}
366 		kualiModuleService.getInstalledModuleServices().add( this );
367 	}
368 
369 	/**
370 	 * @return the moduleConfiguration
371 	 */
372 	public ModuleConfiguration getModuleConfiguration() {
373 		return this.moduleConfiguration;
374 	}
375 
376 	/**
377 	 * @param moduleConfiguration the moduleConfiguration to set
378 	 */
379 	public void setModuleConfiguration(ModuleConfiguration moduleConfiguration) {
380 		this.moduleConfiguration = moduleConfiguration;
381 	}
382 
383     /***
384      * @see org.kuali.rice.krad.service.ModuleService#isExternalizable(java.lang.Class)
385      */
386     public boolean isExternalizable(Class boClazz){
387     	if(boClazz==null) return false;
388     	return ExternalizableBusinessObject.class.isAssignableFrom(boClazz);
389     }
390 
391 	public boolean isExternalizableBusinessObjectLookupable(Class boClass) {
392 		return getBusinessObjectDictionaryService().isLookupable(boClass);
393 	}
394 
395 	public boolean isExternalizableBusinessObjectInquirable(Class boClass) {
396 		return getBusinessObjectDictionaryService().isInquirable(boClass);
397 	}
398 
399 	public <T extends ExternalizableBusinessObject> T createNewObjectFromExternalizableClass(Class<T> boClass) {
400 		try {
401 			return (T) getExternalizableBusinessObjectImplementation(boClass).newInstance();
402 		} catch (Exception e) {
403 			throw new RuntimeException("Unable to create externalizable business object class", e);
404 		}
405 	}
406 
407 	public DataObjectRelationship getBusinessObjectRelationship(Class boClass, String attributeName, String attributePrefix){
408 		return null;
409 	}
410 
411 
412 
413 	public BusinessObjectDictionaryService getBusinessObjectDictionaryService () {
414 		if ( businessObjectDictionaryService == null ) {
415 			businessObjectDictionaryService = KRADServiceLocatorWeb.getBusinessObjectDictionaryService();
416 		}
417 		return businessObjectDictionaryService;
418 	}
419 
420 	/**
421 	 * @return the businessObjectService
422 	 */
423 	public BusinessObjectService getBusinessObjectService() {
424 		if ( businessObjectService == null ) {
425 			businessObjectService = KRADServiceLocator.getBusinessObjectService();
426 		}
427 		return businessObjectService;
428 	}
429 
430     /**
431      * Gets the lookupService attribute.
432      * @return Returns the lookupService.
433      */
434     protected LookupService getLookupService() {
435         return lookupService != null ? lookupService : KRADServiceLocatorWeb.getLookupService();
436     }
437 
438 	/**
439 	 * @return the kualiModuleService
440 	 */
441 	public KualiModuleService getKualiModuleService() {
442 		return this.kualiModuleService;
443 	}
444 
445 	/**
446 	 * @param kualiModuleService the kualiModuleService to set
447 	 */
448 	public void setKualiModuleService(KualiModuleService kualiModuleService) {
449 		this.kualiModuleService = kualiModuleService;
450 	}
451 
452 	/**
453 	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
454 	 */
455 	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
456 		this.applicationContext = applicationContext;
457 	}
458 
459 
460 
461 	/**
462 	 * This overridden method ...
463 	 *
464 	 * @see org.kuali.rice.krad.service.ModuleService#listAlternatePrimaryKeyFieldNames(java.lang.Class)
465 	 */
466 	public List<List<String>> listAlternatePrimaryKeyFieldNames(
467 			Class businessObjectInterfaceClass) {
468 		return null;
469 	}
470 
471 }
472