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