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.kns.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.kns.bo.BusinessObject;
29  import org.kuali.rice.kns.bo.BusinessObjectRelationship;
30  import org.kuali.rice.kns.bo.ExternalizableBusinessObject;
31  import org.kuali.rice.kns.bo.ModuleConfiguration;
32  import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
33  import org.kuali.rice.kns.datadictionary.PrimitiveAttributeDefinition;
34  import org.kuali.rice.kns.datadictionary.RelationshipDefinition;
35  import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
36  import org.kuali.rice.kns.service.BusinessObjectNotLookupableException;
37  import org.kuali.rice.kns.service.BusinessObjectService;
38  import org.kuali.rice.kns.service.KNSServiceLocator;
39  import org.kuali.rice.kns.service.KNSServiceLocatorWeb;
40  import org.kuali.rice.kns.service.KualiModuleService;
41  import org.kuali.rice.kns.service.LookupService;
42  import org.kuali.rice.kns.service.ModuleService;
43  import org.kuali.rice.kns.util.ExternalizableBusinessObjectUtils;
44  import org.kuali.rice.kns.util.KNSConstants;
45  import org.kuali.rice.kns.util.ObjectUtils;
46  import org.kuali.rice.kns.util.UrlFactory;
47  import org.springframework.beans.BeansException;
48  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
49  import org.springframework.context.ApplicationContext;
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.kns.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.kns.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.kns.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.kns.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.kns.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 KNSServiceLocator.getPersistenceStructureService().listPrimaryKeyFieldNames(clazz);
154 	}
155 
156 	/***
157 	 * @see org.kuali.rice.kns.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 			KNSServiceLocatorWeb.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 KNSConstants.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(KNSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObjectClassAttribute);
198 		urlParameters.put(KNSConstants.DISPATCH_REQUEST_PARAMETER, KNSConstants.CONTINUE_WITH_INQUIRY_METHOD_TO_CALL);
199 		return urlParameters;
200 	}
201 
202 	protected String getInquiryUrl(Class inquiryBusinessObjectClass){
203 		String riceBaseUrl = KNSServiceLocator.getKualiConfigurationService().getPropertyString(KNSConstants.APPLICATION_URL_KEY);
204 		String inquiryUrl = riceBaseUrl;
205 		if (!inquiryUrl.endsWith("/")) {
206 			inquiryUrl = inquiryUrl + "/";
207 		}
208 		return inquiryUrl + "kr/" + KNSConstants.INQUIRY_ACTION;
209 	}
210 
211 	/**
212 	 * This overridden method ...
213 	 *
214 	 * @see org.kuali.rice.kns.service.ModuleService#getExternalizableBusinessObjectLookupUrl(java.lang.Class, java.util.Map)
215 	 */
216 	public String getExternalizableBusinessObjectLookupUrl(Class inquiryBusinessObjectClass, Map<String, String> parameters) {
217 		Properties urlParameters = new Properties();
218 
219 		String riceBaseUrl = KNSServiceLocator.getKualiConfigurationService().getPropertyString(KNSConstants.APPLICATION_URL_KEY);
220 		String lookupUrl = riceBaseUrl;
221 		if (!lookupUrl.endsWith("/")) {
222 			lookupUrl = lookupUrl + "/";
223 		}
224 		if (parameters.containsKey(KNSConstants.MULTIPLE_VALUE)) {
225 			lookupUrl = lookupUrl + "kr/" + KNSConstants.MULTIPLE_VALUE_LOOKUP_ACTION;
226 		}
227 		else {
228 			lookupUrl = lookupUrl + "kr/" + KNSConstants.LOOKUP_ACTION;
229 		}
230 		for (String paramName : parameters.keySet()) {
231 			urlParameters.put(paramName, parameters.get(paramName));
232 		}
233 
234 		Class clazz = getExternalizableBusinessObjectImplementation(inquiryBusinessObjectClass);
235 		urlParameters.put(KNSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, clazz==null?"":clazz.getName());
236 
237 		return UrlFactory.parameterizeUrl(lookupUrl, urlParameters);
238 	}
239 
240 	/***
241 	 *
242 	 * This method assumes that the property type for externalizable relationship in the business object is an interface
243 	 * and gets the concrete implementation for it
244 	 *
245 	 * @see org.kuali.rice.kns.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.kns.bo.BusinessObject, org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
246 	 */
247 	public <T extends ExternalizableBusinessObject> T retrieveExternalizableBusinessObjectIfNecessary(
248 			BusinessObject businessObject, T currentInstanceExternalizableBO, String externalizableRelationshipName) {
249 
250 		if(businessObject==null) return null;
251 		Class clazz;
252 		try{
253 			clazz = getExternalizableBusinessObjectImplementation(
254 					PropertyUtils.getPropertyType(businessObject, externalizableRelationshipName));
255 		} catch(Exception iex){
256 			LOG.warn("Exception:"+iex+" thrown while trying to get property type for property:"+externalizableRelationshipName+
257 					" from business object:"+businessObject);
258 			return null;
259 		}
260 
261 		//Get the business object entry for this business object from data dictionary
262 		//using the class name (without the package) as key
263 		BusinessObjectEntry entry =
264 			KNSServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get(
265 					businessObject.getClass().getSimpleName());
266 		RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName);
267 		List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes();
268 
269 		Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>();
270 		Object sourcePropertyValue;
271 		Object targetPropertyValue = null;
272 		boolean sourceTargetPropertyValuesSame = true;
273 		for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){
274 	    	sourcePropertyValue = ObjectUtils.getPropertyValue(
275 	    			businessObject, primitiveAttributeDefinition.getSourceName());
276 	    	if(currentInstanceExternalizableBO!=null)
277 	    		targetPropertyValue = ObjectUtils.getPropertyValue(currentInstanceExternalizableBO, primitiveAttributeDefinition.getTargetName());
278 		    if(sourcePropertyValue==null){
279 		        return null;
280 		    } else if(targetPropertyValue==null || (targetPropertyValue!=null && !targetPropertyValue.equals(sourcePropertyValue))){
281 		    	sourceTargetPropertyValuesSame = false;
282 		    }
283 		    fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue);
284 		}
285 
286 		if(!sourceTargetPropertyValuesSame)
287 			return (T) getExternalizableBusinessObject(clazz, fieldValuesInEBO);
288 		return currentInstanceExternalizableBO;
289 	}
290 
291 	/***
292 	 *
293 	 * This method assumes that the externalizableClazz is an interface
294 	 * and gets the concrete implementation for it
295 	 *
296 	 * @see org.kuali.rice.kns.service.ModuleService#retrieveExternalizableBusinessObjectIfNecessary(org.kuali.rice.kns.bo.BusinessObject, org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
297 	 */
298 	public List<? extends ExternalizableBusinessObject> retrieveExternalizableBusinessObjectsList(
299 			BusinessObject businessObject, String externalizableRelationshipName, Class externalizableClazz) {
300 
301 		if(businessObject==null) return null;
302 		//Get the business object entry for this business object from data dictionary
303 		//using the class name (without the package) as key
304 		String className = businessObject.getClass().getName();
305 		String key = className.substring(className.lastIndexOf(".")+1);
306 		BusinessObjectEntry entry =
307 			KNSServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().get(key);
308 		RelationshipDefinition relationshipDefinition = entry.getRelationshipDefinition(externalizableRelationshipName);
309 		List<PrimitiveAttributeDefinition> primitiveAttributeDefinitions = relationshipDefinition.getPrimitiveAttributes();
310 		Map<String, Object> fieldValuesInEBO = new HashMap<String, Object>();
311 		Object sourcePropertyValue;
312 		for(PrimitiveAttributeDefinition primitiveAttributeDefinition: primitiveAttributeDefinitions){
313 	    	sourcePropertyValue = ObjectUtils.getPropertyValue(
314 	    			businessObject, primitiveAttributeDefinition.getSourceName());
315 		    if(sourcePropertyValue==null){
316 		        return null;
317 		    }
318 		    fieldValuesInEBO.put(primitiveAttributeDefinition.getTargetName(), sourcePropertyValue);
319 		}
320 		return getExternalizableBusinessObjectsList(
321 				getExternalizableBusinessObjectImplementation(externalizableClazz), fieldValuesInEBO);
322 	}
323 
324 	/**
325 	 * @see org.kuali.rice.kns.service.ModuleService#getExternalizableBusinessObjectImplementation(java.lang.Class)
326 	 */
327 	public <E extends ExternalizableBusinessObject> Class<E> getExternalizableBusinessObjectImplementation(Class<E> externalizableBusinessObjectInterface) {
328 		if (getModuleConfiguration() == null) {
329 			throw new IllegalStateException("Module configuration has not been initialized for the module service.");
330 		}
331 		int classModifiers = externalizableBusinessObjectInterface.getModifiers();
332 		if (!Modifier.isInterface(classModifiers) && !Modifier.isAbstract(classModifiers)) {
333 			// the interface is really a non-abstract class
334 			return externalizableBusinessObjectInterface;
335 		}
336 		if (getModuleConfiguration().getExternalizableBusinessObjectImplementations() == null) {
337 			return null;
338 		}
339 		else {
340 			Class<E> implementationClass = getModuleConfiguration().getExternalizableBusinessObjectImplementations().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 = KNSServiceLocatorWeb.getKualiModuleService();
358 			if ( kualiModuleService == null ) {
359 				kualiModuleService = ((KualiModuleService)applicationContext.getBean( KNSServiceLocatorWeb.KUALI_MODULE_SERVICE ));
360 			}
361 		} catch ( NoSuchBeanDefinitionException ex ) {
362 			kualiModuleService = ((KualiModuleService)applicationContext.getBean( KNSServiceLocatorWeb.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.kns.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 BusinessObjectRelationship getBusinessObjectRelationship(Class boClass, String attributeName, String attributePrefix){
406 		return null;
407 	}
408 
409 
410 
411 	public BusinessObjectDictionaryService getBusinessObjectDictionaryService () {
412 		if ( businessObjectDictionaryService == null ) {
413 			businessObjectDictionaryService = KNSServiceLocatorWeb.getBusinessObjectDictionaryService();
414 		}
415 		return businessObjectDictionaryService;
416 	}
417 
418 	/**
419 	 * @return the businessObjectService
420 	 */
421 	public BusinessObjectService getBusinessObjectService() {
422 		if ( businessObjectService == null ) {
423 			businessObjectService = KNSServiceLocator.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 : KNSServiceLocatorWeb.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.kns.service.ModuleService#listAlternatePrimaryKeyFieldNames(java.lang.Class)
463 	 */
464 	public List<List<String>> listAlternatePrimaryKeyFieldNames(
465 			Class businessObjectInterfaceClass) {
466 		return null;
467 	}
468 
469 }
470