001 /** 002 * Copyright 2005-2012 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.kns.service.impl; 017 018 import java.lang.reflect.InvocationTargetException; 019 import java.util.ArrayList; 020 import java.util.Collection; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 026 import org.apache.commons.lang.StringUtils; 027 import org.kuali.rice.kns.datadictionary.FieldDefinition; 028 import org.kuali.rice.kns.datadictionary.InquirySectionDefinition; 029 import org.kuali.rice.kns.service.BusinessObjectDictionaryService; 030 import org.kuali.rice.kns.service.BusinessObjectMetaDataService; 031 import org.kuali.rice.krad.bo.BusinessObject; 032 import org.kuali.rice.krad.bo.DataObjectRelationship; 033 import org.kuali.rice.krad.bo.PersistableBusinessObject; 034 import org.kuali.rice.krad.datadictionary.DataDictionaryEntry; 035 import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition; 036 import org.kuali.rice.krad.datadictionary.RelationshipDefinition; 037 import org.kuali.rice.krad.datadictionary.SupportAttributeDefinition; 038 import org.kuali.rice.krad.valuefinder.ValueFinder; 039 import org.kuali.rice.krad.service.DataDictionaryService; 040 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 041 import org.kuali.rice.krad.service.ModuleService; 042 import org.kuali.rice.krad.service.PersistenceStructureService; 043 import org.kuali.rice.krad.service.impl.DataObjectMetaDataServiceImpl; 044 import org.kuali.rice.krad.util.ObjectUtils; 045 046 /** 047 * 048 * Implementation of the <code>BusinessObjectMetaDataService</code> which uses 049 * the following services to gather its meta data: 050 * 051 * @see BusinessObjectDictionaryService 052 * @see DataDictionaryService 053 * @see PersistenceStructureService 054 */ 055 @Deprecated 056 public class BusinessObjectMetaDataServiceImpl extends DataObjectMetaDataServiceImpl implements BusinessObjectMetaDataService { 057 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger 058 .getLogger(BusinessObjectMetaDataServiceImpl.class); 059 060 private BusinessObjectDictionaryService businessObjectDictionaryService; 061 062 public Collection<String> getCollectionNames(BusinessObject bo) { 063 return getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(bo.getClass().getName()) 064 .getCollectionNames(); 065 } 066 067 public Collection<String> getInquirableFieldNames(Class boClass, String sectionTitle) { 068 return businessObjectDictionaryService.getInquiryFieldNames(boClass, sectionTitle); 069 } 070 071 public List<String> getLookupableFieldNames(Class boClass) { 072 return businessObjectDictionaryService.getLookupFieldNames(boClass); 073 } 074 075 public String getLookupFieldDefaultValue(Class businessObjectClass, String attributeName) { 076 return businessObjectDictionaryService.getLookupFieldDefaultValue(businessObjectClass, attributeName); 077 } 078 079 public Class getLookupFieldDefaultValueFinderClass(Class businessObjectClass, String attributeName) { 080 return businessObjectDictionaryService 081 .getLookupFieldDefaultValueFinderClass(businessObjectClass, attributeName); 082 } 083 084 /** {@inheritDoc} */ 085 public String getLookupFieldQuickfinderParameterString(Class businessObjectClass, String attributeName) { 086 return businessObjectDictionaryService.getLookupFieldQuickfinderParameterString(businessObjectClass, 087 attributeName); 088 } 089 090 /** {@inheritDoc} */ 091 public Class<? extends ValueFinder> getLookupFieldQuickfinderParameterStringBuilderClass(Class businessObjectClass, 092 String attributeName) { 093 return businessObjectDictionaryService.getLookupFieldQuickfinderParameterStringBuilderClass( 094 businessObjectClass, attributeName); 095 } 096 097 public boolean isAttributeInquirable(Class boClass, String attributeName, String sectionTitle) { 098 Collection sections = businessObjectDictionaryService.getInquirySections(boClass); 099 boolean isInquirable = true; 100 101 Iterator iter = sections.iterator(); 102 103 while (iter.hasNext()) { 104 InquirySectionDefinition def = (InquirySectionDefinition) iter.next(); 105 for (FieldDefinition field : def.getInquiryFields()) { 106 if (field.getAttributeName().equalsIgnoreCase(attributeName)) { 107 isInquirable = !field.isNoInquiry(); 108 } 109 } 110 } 111 if (isInquirable) { 112 Object obj = null; 113 if (boClass != null && BusinessObject.class.isAssignableFrom(boClass)) { 114 obj = ObjectUtils.createNewObjectFromClass(boClass); 115 } 116 117 if (obj != null) { 118 BusinessObject bo = (BusinessObject) obj; 119 Class clazz = getNestedBOClass(bo, attributeName); 120 if (clazz != null && BusinessObject.class.isAssignableFrom(clazz)) { 121 return businessObjectDictionaryService.isInquirable(clazz); 122 } 123 else { 124 return false; 125 } 126 } 127 else { 128 return false; 129 } 130 131 } 132 133 return isInquirable; 134 } 135 136 public boolean isInquirable(Class boClass) { 137 boolean inquirable = false; 138 ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(boClass); 139 if (moduleService != null && moduleService.isExternalizable(boClass)) { 140 inquirable = moduleService.isExternalizableBusinessObjectInquirable(boClass); 141 } 142 else { 143 Boolean isLookupable = businessObjectDictionaryService.isInquirable(boClass); 144 if (isLookupable != null) { 145 inquirable = isLookupable.booleanValue(); 146 } 147 } 148 return inquirable; 149 } 150 151 public boolean isAttributeLookupable(Class boClass, String attributeName) { 152 Object obj = null; 153 if (boClass != null && BusinessObject.class.isAssignableFrom(boClass)) { 154 obj = ObjectUtils.createNewObjectFromClass(boClass); 155 } 156 if (obj != null) { 157 BusinessObject bo = (BusinessObject) obj; 158 DataObjectRelationship relationship = getBusinessObjectRelationship(bo, attributeName); 159 160 if (relationship != null && relationship.getRelatedClass() != null 161 && BusinessObject.class.isAssignableFrom(relationship.getRelatedClass())) { 162 return isLookupable(relationship.getRelatedClass()); 163 } 164 else { 165 return false; 166 } 167 } 168 else { 169 return false; 170 } 171 } 172 173 public boolean isLookupable(Class boClass) { 174 boolean lookupable = false; 175 ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(boClass); 176 if (moduleService != null && moduleService.isExternalizable(boClass)) { 177 lookupable = moduleService.isExternalizableBusinessObjectLookupable(boClass); 178 } 179 else { 180 Boolean isLookupable = businessObjectDictionaryService.isLookupable(boClass); 181 if (isLookupable != null) { 182 lookupable = isLookupable.booleanValue(); 183 } 184 } 185 return lookupable; 186 } 187 188 public DataObjectRelationship getBusinessObjectRelationship(BusinessObject bo, String attributeName) { 189 return getBusinessObjectRelationship(bo, bo.getClass(), attributeName, "", true); 190 } 191 192 // TODO: four different exit points?! 193 public DataObjectRelationship getBusinessObjectRelationship(RelationshipDefinition ddReference, 194 BusinessObject bo, Class boClass, String attributeName, String attributePrefix, boolean keysOnly) { 195 196 DataObjectRelationship relationship = null; 197 198 // if it is nested then replace the bo and attributeName with the 199 // sub-refs 200 if (ObjectUtils.isNestedAttribute(attributeName)) { 201 if (ddReference != null) { 202 relationship = new DataObjectRelationship(boClass, ddReference.getObjectAttributeName(), 203 ddReference.getTargetClass()); 204 for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) { 205 if (StringUtils.isNotBlank(attributePrefix)) { 206 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(), 207 def.getTargetName()); 208 } 209 else { 210 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName()); 211 } 212 } 213 if (!keysOnly) { 214 for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) { 215 if (StringUtils.isNotBlank(attributePrefix)) { 216 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(), 217 def.getTargetName()); 218 if (def.isIdentifier()) { 219 relationship.setUserVisibleIdentifierKey(attributePrefix + "." + def.getSourceName()); 220 } 221 } 222 else { 223 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName()); 224 if (def.isIdentifier()) { 225 relationship.setUserVisibleIdentifierKey(def.getSourceName()); 226 } 227 } 228 } 229 } 230 return relationship; 231 } 232 // recurse down to the next object to find the relationship 233 234 String localPrefix = StringUtils.substringBefore(attributeName, "."); 235 String localAttributeName = StringUtils.substringAfter(attributeName, "."); 236 if (bo == null) { 237 bo = (BusinessObject) ObjectUtils.createNewObjectFromClass(boClass); 238 } 239 Class nestedClass = ObjectUtils.getPropertyType(bo, localPrefix, getPersistenceStructureService()); 240 String fullPrefix = localPrefix; 241 if (StringUtils.isNotBlank(attributePrefix)) { 242 fullPrefix = attributePrefix + "." + localPrefix; 243 } 244 if (BusinessObject.class.isAssignableFrom(nestedClass)) { 245 relationship = getBusinessObjectRelationship(null, nestedClass, localAttributeName, fullPrefix, 246 keysOnly); 247 } 248 return relationship; 249 } 250 int maxSize = Integer.MAX_VALUE; 251 // try persistable reference first 252 if (PersistableBusinessObject.class.isAssignableFrom(boClass) 253 && getPersistenceStructureService().isPersistable(boClass)) { 254 Map<String, DataObjectRelationship> rels = getPersistenceStructureService().getRelationshipMetadata(boClass, 255 attributeName, attributePrefix); 256 if (rels.size() > 0) { 257 for (DataObjectRelationship rel : rels.values()) { 258 if (rel.getParentToChildReferences().size() < maxSize && isLookupable(rel.getRelatedClass())) { 259 maxSize = rel.getParentToChildReferences().size(); 260 relationship = rel; 261 } 262 } 263 } 264 } 265 else { 266 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService() 267 .getResponsibleModuleService(boClass); 268 if (moduleService != null && moduleService.isExternalizable(boClass)) { 269 relationship = getRelationshipMetadata(boClass, attributeName, attributePrefix); 270 // relationship = 271 // moduleService.getBusinessObjectRelationship(boClass, 272 // attributeName, attributePrefix); 273 if (relationship != null) { 274 return relationship; 275 } 276 } 277 } 278 279 // then check the DD for relationships defined there 280 // TODO move out to a separate method 281 // so that the logic for finding the relationships is similar to 282 // primitiveReference 283 if (ddReference != null && isLookupable(ddReference.getTargetClass()) && bo != null 284 && ddReference.getPrimitiveAttributes().size() < maxSize) { 285 relationship = new DataObjectRelationship(boClass, ddReference.getObjectAttributeName(), 286 ddReference.getTargetClass()); 287 for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) { 288 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName()); 289 } 290 if (!keysOnly) { 291 for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) { 292 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName()); 293 } 294 } 295 } 296 297 return relationship; 298 299 } 300 301 302 303 public RelationshipDefinition getBusinessObjectRelationshipDefinition(Class c, String attributeName) { 304 return getDictionaryRelationship(c, attributeName); 305 } 306 307 public RelationshipDefinition getBusinessObjectRelationshipDefinition(BusinessObject bo, String attributeName) { 308 return getBusinessObjectRelationshipDefinition(bo.getClass(), attributeName); 309 } 310 311 public DataObjectRelationship getBusinessObjectRelationship(BusinessObject bo, Class boClass, 312 String attributeName, String attributePrefix, boolean keysOnly) { 313 RelationshipDefinition ddReference = getBusinessObjectRelationshipDefinition(boClass, attributeName); 314 return getBusinessObjectRelationship(ddReference, bo, boClass, attributeName, attributePrefix, keysOnly); 315 } 316 317 /** 318 * Gets the businessObjectDictionaryService attribute. 319 * 320 * @return Returns the businessObjectDictionaryService. 321 */ 322 public BusinessObjectDictionaryService getBusinessObjectDictionaryService() { 323 return businessObjectDictionaryService; 324 } 325 326 /** 327 * Sets the businessObjectDictionaryService attribute value. 328 * 329 * @param businessObjectDictionaryService 330 * The BusinessObjectDictionaryService to set. 331 */ 332 public void setBusinessObjectDictionaryService(BusinessObjectDictionaryService businessObjectDictionaryService) { 333 this.businessObjectDictionaryService = businessObjectDictionaryService; 334 } 335 336 /** 337 * 338 * This method retrieves the business object class for a specific attribute 339 * 340 * @param bo 341 * @param attributeName 342 * @return a business object class for a specific attribute 343 */ 344 private Class getNestedBOClass(BusinessObject bo, String attributeName) { 345 346 String[] nestedAttributes = StringUtils.split(attributeName, "."); 347 String attributeRefName = ""; 348 Class clazz = null; 349 if (nestedAttributes.length > 1) { 350 String attributeStringSoFar = ""; 351 for (int i = 0; i < nestedAttributes.length - 1; i++) { 352 try { 353 // we need to build a string of the attribute names 354 // depending on which iteration we're in. 355 // so if the original attributeName string we're using is 356 // "a.b.c.d.e", then first iteration would use 357 // "a", 2nd "a.b", 3rd "a.b.c", etc. 358 if (i != 0) { 359 attributeStringSoFar = attributeStringSoFar + "."; 360 } 361 attributeStringSoFar = attributeStringSoFar + nestedAttributes[i]; 362 clazz = ObjectUtils.easyGetPropertyType(bo, attributeStringSoFar); 363 } 364 catch (InvocationTargetException ite) { 365 LOG.info(ite); 366 return null; 367 } 368 catch (NoSuchMethodException nsme) { 369 LOG.info(nsme); 370 return null; 371 } 372 catch (IllegalAccessException iae) { 373 LOG.info(iae); 374 return null; 375 } 376 } 377 } 378 return clazz; 379 } 380 381 public List<DataObjectRelationship> getBusinessObjectRelationships(BusinessObject bo) { 382 if (bo == null) { 383 return null; 384 } 385 return getBusinessObjectRelationships(bo.getClass()); 386 } 387 388 @SuppressWarnings("unchecked") 389 public List<DataObjectRelationship> getBusinessObjectRelationships(Class<? extends BusinessObject> boClass) { 390 if (boClass == null) { 391 return null; 392 } 393 394 Map<String, Class> referenceClasses = null; 395 if (PersistableBusinessObject.class.isAssignableFrom(boClass) 396 && getPersistenceStructureService().isPersistable(boClass)) { 397 referenceClasses = getPersistenceStructureService().listReferenceObjectFields(boClass); 398 } 399 DataDictionaryEntry ddEntry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry( 400 boClass.getName()); 401 List<RelationshipDefinition> ddRelationships = (ddEntry == null ? new ArrayList<RelationshipDefinition>() 402 : ddEntry.getRelationships()); 403 List<DataObjectRelationship> relationships = new ArrayList<DataObjectRelationship>(); 404 405 // loop over all relationships 406 if (referenceClasses != null) { 407 for (Map.Entry<String, Class> entry : referenceClasses.entrySet()) { 408 if (isLookupable(entry.getValue())) { 409 Map<String, String> fkToPkRefs = getPersistenceStructureService().getForeignKeysForReference(boClass, 410 entry.getKey()); 411 DataObjectRelationship rel = new DataObjectRelationship(boClass, entry.getKey(), 412 entry.getValue()); 413 for (Map.Entry<String, String> ref : fkToPkRefs.entrySet()) { 414 rel.getParentToChildReferences().put(ref.getKey(), ref.getValue()); 415 } 416 relationships.add(rel); 417 } 418 } 419 } 420 421 for (RelationshipDefinition rd : ddRelationships) { 422 if (isLookupable(rd.getTargetClass())) { 423 DataObjectRelationship rel = new DataObjectRelationship(boClass, rd.getObjectAttributeName(), 424 rd.getTargetClass()); 425 for (PrimitiveAttributeDefinition def : rd.getPrimitiveAttributes()) { 426 rel.getParentToChildReferences().put(def.getSourceName(), def.getTargetName()); 427 } 428 relationships.add(rel); 429 } 430 } 431 432 return relationships; 433 } 434 435 /*************************************************************************** 436 * @see org.kuali.rice.kns.service.BusinessObjectMetaDataService#getReferencesForForeignKey(java.lang.Class, 437 * java.lang.String) 438 */ 439 public Map<String, Class> getReferencesForForeignKey(BusinessObject bo, String attributeName) { 440 List<DataObjectRelationship> dataObjectRelationships = getBusinessObjectRelationships(bo); 441 Map<String, Class> referencesForForeignKey = new HashMap<String, Class>(); 442 for (DataObjectRelationship dataObjectRelationship : dataObjectRelationships) { 443 if (dataObjectRelationship != null && dataObjectRelationship.getParentToChildReferences() != null 444 && dataObjectRelationship.getParentToChildReferences().containsKey(attributeName)) { 445 referencesForForeignKey.put(dataObjectRelationship.getParentAttributeName(), 446 dataObjectRelationship.getRelatedClass()); 447 } 448 } 449 return referencesForForeignKey; 450 } 451 452 public String getForeignKeyFieldName(Class businessObjectClass, String attributeName, String targetName) { 453 454 String fkName = ""; 455 456 // first try DD-based relationships 457 RelationshipDefinition relationshipDefinition = getDictionaryRelationship(businessObjectClass, attributeName); 458 459 if (relationshipDefinition != null) { 460 List<PrimitiveAttributeDefinition> primitives = relationshipDefinition.getPrimitiveAttributes(); 461 for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitives) { 462 if (primitiveAttributeDefinition.getTargetName().equals(targetName)) { 463 fkName = primitiveAttributeDefinition.getSourceName(); 464 break; 465 } 466 } 467 } 468 469 // if we can't find anything in the DD, then try the persistence service 470 if (StringUtils.isBlank(fkName) && PersistableBusinessObject.class.isAssignableFrom(businessObjectClass) 471 && getPersistenceStructureService().isPersistable(businessObjectClass)) { 472 fkName = getPersistenceStructureService().getForeignKeyFieldName(businessObjectClass, attributeName, 473 targetName); 474 } 475 return fkName; 476 } 477 }