001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kns.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.util.RiceKeyConstants; 020import org.kuali.rice.kew.api.KewApiServiceLocator; 021import org.kuali.rice.kew.api.doctype.DocumentType; 022import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition; 023import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition; 024import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition; 025import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition; 026import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry; 027import org.kuali.rice.kns.document.MaintenanceDocument; 028import org.kuali.rice.kns.maintenance.Maintainable; 029import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 030import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 031import org.kuali.rice.krad.bo.PersistableBusinessObject; 032import org.kuali.rice.krad.datadictionary.DataDictionary; 033import org.kuali.rice.krad.rules.rule.BusinessRule; 034import org.kuali.rice.krad.service.DataDictionaryService; 035import org.kuali.rice.krad.util.GlobalVariables; 036import org.kuali.rice.krad.util.ObjectUtils; 037import org.kuali.rice.krad.valuefinder.ValueFinder; 038 039import java.util.ArrayList; 040import java.util.Collection; 041import java.util.Iterator; 042import java.util.List; 043 044/** 045 * This class is the service implementation for the MaintenanceDocumentDictionary structure. Defines the API for the interacting 046 * with Document-related entries in the data dictionary. This is the default implementation, that is delivered with Kuali. 047 */ 048@Deprecated 049public class MaintenanceDocumentDictionaryServiceImpl implements MaintenanceDocumentDictionaryService { 050 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentDictionaryServiceImpl.class); 051 052 private DataDictionaryService dataDictionaryService; 053 054 /** 055 * Gets the workflow document type for the given documentTypeName 056 * 057 * @param documentTypeName 058 * @return 059 */ 060 protected DocumentType getDocumentType(String documentTypeName) { 061 return KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(documentTypeName); 062 } 063 064 /** 065 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getMaintenanceLabel(java.lang.String) 066 */ 067 public String getMaintenanceLabel(String docTypeName) { 068 String label = null; 069 070 DocumentType docType = getDocumentType(docTypeName); 071 if (docType != null) { 072 label = docType.getLabel(); 073 } 074 075 return label; 076 } 077 078 /** 079 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getMaintenanceDescription(java.lang.String) 080 */ 081 public String getMaintenanceDescription(String docTypeName) { 082 String description = null; 083 084 DocumentType docType = getDocumentType(docTypeName); 085 if (docType != null) { 086 description = docType.getDescription(); 087 } 088 089 return description; 090 } 091 092 /** 093 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getMaintainableClass(java.lang.String) 094 */ 095 @Deprecated 096 public Class getMaintainableClass(String docTypeName) { 097 Class maintainableClass = null; 098 099 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 100 if (entry != null) { 101 LOG.debug("suppling a generic Rule to insure basic validation"); 102 maintainableClass = entry.getMaintainableClass(); 103 } 104 105 return maintainableClass; 106 } 107 108 /** 109 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getDataObjectClass(java.lang.String) 110 */ 111 public Class getDataObjectClass(String docTypeName) { 112 Class dataObjectClass = null; 113 114 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 115 if (entry != null) { 116 dataObjectClass = entry.getDataObjectClass(); 117 } 118 119 return dataObjectClass; 120 } 121 122 /** 123 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getDocumentTypeName(java.lang.Class) 124 */ 125 public String getDocumentTypeName(Class businessObjectClass) { 126 String documentTypeName = null; 127 128 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(businessObjectClass); 129 if (entry != null) { 130 documentTypeName = entry.getDocumentTypeName(); 131 } 132 133 return documentTypeName; 134 } 135 136 /** 137 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getMaintainableSections(java.lang.String) 138 */ 139 @Deprecated 140 public List getMaintainableSections(String docTypeName) { 141 List sections = null; 142 143 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 144 if (entry != null) { 145 sections = entry.getMaintainableSections(); 146 } 147 148 return sections; 149 } 150 151 152 /** 153 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getDefaultExistenceChecks(java.lang.Class) 154 */ 155 public Collection getDefaultExistenceChecks(Class businessObjectClass) { 156 return getDefaultExistenceChecks(getDocumentTypeName(businessObjectClass)); 157 } 158 159 /** 160 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getDefaultExistenceChecks(java.lang.String) 161 */ 162 public Collection getDefaultExistenceChecks(String docTypeName) { 163 164 Collection defaultExistenceChecks = null; 165 166 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 167 if (entry != null) { 168 defaultExistenceChecks = entry.getDefaultExistenceChecks(); 169 } 170 171 return defaultExistenceChecks; 172 } 173 174 /** 175 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getLockingKeys(java.lang.String) 176 */ 177 public List getLockingKeys(String docTypeName) { 178 List lockingKeys = null; 179 180 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 181 if (entry != null) { 182 lockingKeys = entry.getLockingKeyFieldNames(); 183 } 184 185 return lockingKeys; 186 } 187 188 /** 189 * @param dataDictionaryService 190 */ 191 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 192 this.dataDictionaryService = dataDictionaryService; 193 } 194 195 /** 196 * @return 197 */ 198 public DataDictionary getDataDictionary() { 199 return this.dataDictionaryService.getDataDictionary(); 200 } 201 202 /** 203 * @param docTypeName 204 * @return 205 */ 206 public MaintenanceDocumentEntry getMaintenanceDocumentEntry(String docTypeName) { 207 if (StringUtils.isBlank(docTypeName)) { 208 throw new IllegalArgumentException("invalid (blank) docTypeName"); 209 } 210 211 MaintenanceDocumentEntry entry = (MaintenanceDocumentEntry)getDataDictionary().getDocumentEntry(docTypeName); 212 return entry; 213 } 214 215 private MaintenanceDocumentEntry getMaintenanceDocumentEntry(Class businessObjectClass) { 216 if (businessObjectClass == null) { 217 throw new IllegalArgumentException("invalid (blank) dataObjectClass"); 218 } 219 220 // Treat KRAD documents as non existing (KULRICE-9909) 221 org.kuali.rice.krad.datadictionary.MaintenanceDocumentEntry 222 entry = getDataDictionary().getMaintenanceDocumentEntryForBusinessObjectClass(businessObjectClass); 223 return (entry instanceof MaintenanceDocumentEntry) ? (MaintenanceDocumentEntry) entry : null; 224 } 225 226 /** 227 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getFieldDefaultValue(java.lang.Class, java.lang.String) 228 */ 229 public String getFieldDefaultValue(Class boClass, String fieldName) { 230 231 // input parameter validation 232 if (boClass == null) { 233 throw new IllegalArgumentException("The boClass parameter value specified was " + "null. A valid class representing the boClass must " + "be specified."); 234 } 235 236 // call the twin 237 return getFieldDefaultValue(getDocumentTypeName(boClass), fieldName); 238 } 239 240 /** 241 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getFieldDefaultValue(java.lang.String, java.lang.String) 242 */ 243 public String getFieldDefaultValue(String docTypeName, String fieldName) { 244 245 // input parameter validation 246 if (StringUtils.isBlank(docTypeName)) { 247 throw new IllegalArgumentException("The docTypeName parameter value specified was " + "blank, whitespace, or null. A valid string representing the docTypeName must " + "be specified."); 248 } 249 if (StringUtils.isBlank(fieldName)) { 250 throw new IllegalArgumentException("The fieldName parameter value specified was " + "blank, whitespace, or null. A valid string representing the fieldName must " + "be specified."); 251 } 252 253 // walk through the sections 254 List sections = getMaintainableSections(docTypeName); 255 for (Iterator sectionIterator = sections.iterator(); sectionIterator.hasNext();) { 256 MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator.next(); 257 258 // walk through the fields 259 Collection fields = section.getMaintainableItems(); 260 String defaultValue = getFieldDefaultValue(fields, fieldName); 261 // need to keep trying sections until a match is found 262 if (defaultValue != null) { 263 return defaultValue; 264 } 265 } 266 return null; 267 } 268 269 private String getFieldDefaultValue(Collection maintainableFields, String fieldName) { 270 for (Iterator iterator = maintainableFields.iterator(); iterator.hasNext();) { 271 MaintainableItemDefinition item = (MaintainableItemDefinition) iterator.next(); 272 // only check fields...skip subcollections 273 if (item instanceof MaintainableFieldDefinition) { 274 275 MaintainableFieldDefinition field = (MaintainableFieldDefinition) item; 276 277 // if the field name matches 278 if (field.getName().endsWith(fieldName)) { 279 280 // preferentially take the raw default value 281 if (StringUtils.isNotBlank(field.getDefaultValue())) { 282 return field.getDefaultValue(); 283 } 284 285 // take the valuefinder 286 else if (field.getDefaultValueFinderClass() != null) { 287 288 // attempt to get an instance of the defaultValueFinderClass 289 ValueFinder valueFinder = null; 290 try { 291 valueFinder = (ValueFinder) field.getDefaultValueFinderClass().newInstance(); 292 } 293 catch (Exception e) { 294 LOG.info("Exception obtaining valueFinder for collection field default value", e); 295 valueFinder = null; 296 } 297 298 // get the value 299 if (valueFinder != null) { 300 return valueFinder.getValue(); 301 } 302 } 303 // if we found the field, but no default anything, then we're done 304 else { 305 return null; 306 } 307 } 308 } 309 } 310 return null; 311 } 312 313 /** 314 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getCollectionFieldDefaultValue(java.lang.String, 315 * java.lang.String, java.lang.String) 316 */ 317 public String getCollectionFieldDefaultValue(String docTypeName, String collectionName, String fieldName) { 318 // input parameter validation 319 if (StringUtils.isBlank(docTypeName)) { 320 throw new IllegalArgumentException("The docTypeName parameter value specified was blank, whitespace, or null. A valid string representing the docTypeName must be specified."); 321 } 322 if (StringUtils.isBlank(fieldName)) { 323 throw new IllegalArgumentException("The fieldName parameter value specified was blank, whitespace, or null. A valid string representing the fieldName must be specified."); 324 } 325 if (StringUtils.isBlank(collectionName)) { 326 throw new IllegalArgumentException("The collectionName parameter value specified was null. A valid string representing the collectionName must be specified."); 327 } 328 329 MaintainableCollectionDefinition coll = getMaintainableCollection(docTypeName, collectionName); 330 if (coll != null) { 331 Collection collectionFields = coll.getMaintainableFields(); 332 return getFieldDefaultValue(collectionFields, fieldName); 333 } 334 return null; 335 } 336 337 /** 338 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getAllowsCopy(MaintenanceDocument) 339 */ 340 public Boolean getAllowsCopy(MaintenanceDocument document) { 341 Boolean allowsCopy = Boolean.FALSE; 342 if (document != null && document.getNewMaintainableObject() != null) { 343 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(document.getNewMaintainableObject().getBoClass()); 344 if (entry != null) { 345 allowsCopy = Boolean.valueOf(entry.getAllowsCopy()); 346 } 347 } 348 349 return allowsCopy; 350 } 351 352 /** 353 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getAllowsNewOrCopy(java.lang.String) 354 */ 355 public Boolean getAllowsNewOrCopy(String docTypeName) { 356 Boolean allowsNewOrCopy = Boolean.FALSE; 357 358 if (docTypeName != null) { 359 MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName); 360 if (entry != null) { 361 allowsNewOrCopy = Boolean.valueOf(entry.getAllowsNewOrCopy()); 362 } 363 } 364 365 return allowsNewOrCopy; 366 } 367 368 public MaintainableItemDefinition getMaintainableItem(String docTypeName, String itemName) { 369 // input parameter validation 370 if (StringUtils.isBlank(docTypeName)) { 371 throw new IllegalArgumentException("The docTypeName parameter value specified was " + "blank, whitespace, or null. A valid string representing the docTypeName must " + "be specified."); 372 } 373 if (StringUtils.isBlank(itemName)) { 374 throw new IllegalArgumentException("The itemName parameter value specified was " + "blank, whitespace, or null. A valid string representing the itemName must " + "be specified."); 375 } 376 377 // split name for subcollections 378 String[] subItems = {}; 379 subItems = StringUtils.split(itemName, "."); 380 381 382 // walk through the sections 383 List sections = getMaintainableSections(docTypeName); 384 for (Iterator sectionIterator = sections.iterator(); sectionIterator.hasNext();) { 385 MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator.next(); 386 387 // walk through the fields 388 Collection fields = section.getMaintainableItems(); 389 for (Iterator fieldIterator = fields.iterator(); fieldIterator.hasNext();) { 390 MaintainableItemDefinition item = (MaintainableItemDefinition) fieldIterator.next(); 391 392 if (item.getName().equals(itemName)) { 393 return item; 394 } 395 // if collection check to see if it has sub collections 396 // for now this only allows 1 level (i.e. a.b) it should be expanded at some point 397 if (item instanceof MaintainableCollectionDefinition) { 398 MaintainableCollectionDefinition col = (MaintainableCollectionDefinition) item; 399 if ((subItems.length > 1) && (StringUtils.equals(col.getName(), subItems[0]))) { 400 for (Iterator<MaintainableCollectionDefinition> colIterator = col.getMaintainableCollections().iterator(); colIterator.hasNext();) { 401 MaintainableCollectionDefinition subCol = (MaintainableCollectionDefinition) colIterator.next(); 402 if (subCol.getName().equals(subItems[1])) { 403 return subCol; 404 } 405 } 406 } 407 } 408 } 409 } 410 return null; 411 } 412 413 public MaintainableFieldDefinition getMaintainableField(String docTypeName, String fieldName) { 414 MaintainableItemDefinition item = getMaintainableItem(docTypeName, fieldName); 415 if (item != null && item instanceof MaintainableFieldDefinition) { 416 return (MaintainableFieldDefinition) item; 417 } 418 return null; 419 } 420 421 public MaintainableCollectionDefinition getMaintainableCollection(String docTypeName, String collectionName) { 422 // strip brackets as they are not needed to get to collection class 423 // Like the other subcollections changes this currently only supports one sub level 424 if (StringUtils.contains(collectionName, "[")) { 425 collectionName = StringUtils.substringBefore(collectionName, "[") + StringUtils.substringAfter(collectionName, "]"); 426 } 427 MaintainableItemDefinition item = getMaintainableItem(docTypeName, collectionName); 428 if (item != null && item instanceof MaintainableCollectionDefinition) { 429 return (MaintainableCollectionDefinition) item; 430 } 431 return null; 432 } 433 434 public Class getCollectionBusinessObjectClass(String docTypeName, String collectionName) { 435 MaintainableCollectionDefinition coll = getMaintainableCollection(docTypeName, collectionName); 436 if (coll != null) { 437 return coll.getBusinessObjectClass(); 438 } 439 return null; 440 } 441 442 public List<MaintainableCollectionDefinition> getMaintainableCollections(String docTypeName) { 443 ArrayList<MaintainableCollectionDefinition> collections = new ArrayList<MaintainableCollectionDefinition>(); 444 445 // walk through the sections 446 List sections = getMaintainableSections(docTypeName); 447 for (Iterator sectionIterator = sections.iterator(); sectionIterator.hasNext();) { 448 MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator.next(); 449 450 // walk through the fields 451 Collection fields = section.getMaintainableItems(); 452 for (Iterator fieldIterator = fields.iterator(); fieldIterator.hasNext();) { 453 MaintainableItemDefinition item = (MaintainableItemDefinition) fieldIterator.next(); 454 455 if (item instanceof MaintainableCollectionDefinition) { 456 collections.add((MaintainableCollectionDefinition) item); 457 // collections.addAll( getMaintainableCollections( (MaintainableCollectionDefinition)item ) ); 458 } 459 } 460 } 461 462 return collections; 463 } 464 465 public List<MaintainableCollectionDefinition> getMaintainableCollections(MaintainableCollectionDefinition parentCollection) { 466 ArrayList<MaintainableCollectionDefinition> collections = new ArrayList<MaintainableCollectionDefinition>(); 467 468 // walk through the sections 469 Collection<MaintainableCollectionDefinition> colls = parentCollection.getMaintainableCollections(); 470 for (MaintainableCollectionDefinition coll : colls) { 471 collections.add(coll); 472 collections.addAll(getMaintainableCollections(coll)); 473 } 474 475 return collections; 476 } 477 478 /** 479 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#validateMaintenanceRequiredFields(org.kuali.rice.krad.maintenance.MaintenanceDocument) 480 */ 481 public void validateMaintenanceRequiredFields(MaintenanceDocument document) { 482 Maintainable newMaintainableObject = document.getNewMaintainableObject(); 483 if (newMaintainableObject == null) { 484 LOG.error("New maintainable is null"); 485 throw new RuntimeException("New maintainable is null"); 486 } 487 488 List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections(getDocumentTypeName(newMaintainableObject.getBoClass())); 489 for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) { 490 for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition.getMaintainableItems()) { 491 // validate fields 492 if (maintainableItemDefinition instanceof MaintainableFieldDefinition) { 493 validateMaintainableFieldRequiredFields((MaintainableFieldDefinition) maintainableItemDefinition, newMaintainableObject.getBusinessObject(), maintainableItemDefinition.getName()); 494 } 495 // validate collections 496 else if (maintainableItemDefinition instanceof MaintainableCollectionDefinition) { 497 validateMaintainableCollectionsRequiredFields(newMaintainableObject.getBusinessObject(), (MaintainableCollectionDefinition) maintainableItemDefinition); 498 } 499 } 500 } 501 } 502 503 /** 504 * generates error message if a field is marked as required but is not filled in 505 * 506 * @param maintainableFieldDefinition 507 * @param businessObject 508 * @param fieldName 509 */ 510 private void validateMaintainableFieldRequiredFields(MaintainableFieldDefinition maintainableFieldDefinition, PersistableBusinessObject businessObject, String fieldName) { 511 512 if (StringUtils.isBlank(fieldName)) { 513 throw new IllegalArgumentException("invalid fieldName parameter."); 514 } 515 // if required check we have a value for this field 516 if (maintainableFieldDefinition.isRequired() && !maintainableFieldDefinition.isUnconditionallyReadOnly() ) { 517 try { 518 Object obj = ObjectUtils.getNestedValue(businessObject, fieldName); 519 520 if (obj == null || StringUtils.isBlank(obj.toString())) { 521 String attributeLabel = dataDictionaryService.getAttributeLabel(businessObject.getClass(), fieldName); 522 String shortLabel = dataDictionaryService.getAttributeShortLabel(businessObject.getClass(), fieldName); 523 GlobalVariables.getMessageMap().putError(fieldName, RiceKeyConstants.ERROR_REQUIRED, attributeLabel + " (" + shortLabel + ")" ); 524 } else if ( fieldName.endsWith(".principalName") ) { 525 // special handling to catch when the principalName is not really a valid user 526 // pull the Person object and test the entity ID. If that's null, then this 527 // is just a shell user instance and does not represent a true user 528 // the main principalId property on the main object would be null at this point 529 // but it is also unconditionally read only and not tested - checking that would 530 // require checking the relationships and be more complex than we want to get here 531 String personProperty = ObjectUtils.getNestedAttributePrefix(fieldName); 532 if ( StringUtils.isNotBlank(personProperty) ) { 533 if ( StringUtils.isBlank( (String)ObjectUtils.getNestedValue(businessObject, personProperty+".entityId") ) ) { 534 String attributeLabel = dataDictionaryService.getAttributeLabel(businessObject.getClass(), fieldName); 535 GlobalVariables.getMessageMap().putError(fieldName, RiceKeyConstants.ERROR_EXISTENCE, attributeLabel ); 536 } 537 } 538 } 539 } catch( Exception ex ) { 540 LOG.error( "unable to read property during doc required field checks", ex ); 541 } 542 } 543 } 544 545 546 private MaintainableCollectionDefinition getCollectionDefinition( String docTypeName, String collectionName ) { 547 String currentCollection = collectionName; 548 String nestedCollections = ""; 549 if (StringUtils.contains(collectionName, "[")) { 550 // strip off any array indexes 551 currentCollection = StringUtils.substringBefore( collectionName, "[" ); 552 nestedCollections = StringUtils.substringAfter( collectionName, "." ); 553 } 554 555 // loop over all sections to find this collection 556 List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections( docTypeName ); 557 for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) { 558 for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition.getMaintainableItems()) { 559 if (maintainableItemDefinition instanceof MaintainableCollectionDefinition && maintainableItemDefinition.getName().equals( currentCollection ) ) { 560 if ( StringUtils.isBlank( nestedCollections ) ) { 561 return (MaintainableCollectionDefinition) maintainableItemDefinition; 562 } 563 564 return getCollectionDefinition( (MaintainableCollectionDefinition)maintainableItemDefinition, nestedCollections ); 565 } 566 } 567 } 568 569 return null; 570 } 571 572 private MaintainableCollectionDefinition getCollectionDefinition( MaintainableCollectionDefinition collectionDef, String collectionName ) { 573 String currentCollection = collectionName; 574 String nestedCollections = ""; 575 if (StringUtils.contains(collectionName, "[")) { 576 // strip off any array indexes 577 currentCollection = StringUtils.substringBefore( collectionName, "[" ); 578 nestedCollections = StringUtils.substringAfter( collectionName, "." ); 579 } 580 581 // loop over all nested collections 582 for (MaintainableCollectionDefinition maintainableCollectionDefinition : collectionDef.getMaintainableCollections()) { 583 if ( maintainableCollectionDefinition.getName().equals( currentCollection ) ) { 584 if ( StringUtils.isBlank( nestedCollections ) ) { 585 return maintainableCollectionDefinition; 586 } 587 return getCollectionDefinition( maintainableCollectionDefinition, nestedCollections ); 588 } 589 } 590 591 return null; 592 } 593 594 public void validateMaintainableCollectionsAddLineRequiredFields(MaintenanceDocument document, PersistableBusinessObject businessObject, String collectionName ) { 595 MaintainableCollectionDefinition def = getCollectionDefinition( getDocumentTypeName(businessObject.getClass()), collectionName ); 596 if ( def != null ) { 597 validateMaintainableCollectionsAddLineRequiredFields( document, businessObject, collectionName, def, 0); 598 } 599 } 600 /** 601 * calls code to generate error messages if maintainableFields within any collections or sub-collections are marked as required 602 * 603 * @param document 604 * @param businessObject 605 * @param collectionName 606 * @param maintainableCollectionDefinition 607 * @param depth 608 */ 609 private void validateMaintainableCollectionsAddLineRequiredFields(MaintenanceDocument document, PersistableBusinessObject businessObject, String collectionName, MaintainableCollectionDefinition maintainableCollectionDefinition, int depth) { 610 if ( depth == 0 ) { 611 GlobalVariables.getMessageMap().addToErrorPath("add"); 612 } 613 // validate required fields on fields withing collection definition 614 PersistableBusinessObject element = document.getNewMaintainableObject().getNewCollectionLine( collectionName ); 615 GlobalVariables.getMessageMap().addToErrorPath(collectionName); 616 for (MaintainableFieldDefinition maintainableFieldDefinition : maintainableCollectionDefinition.getMaintainableFields()) { 617 final String fieldName = maintainableFieldDefinition.getName(); 618 validateMaintainableFieldRequiredFields(maintainableFieldDefinition, element, fieldName); 619 620 } 621 622 GlobalVariables.getMessageMap().removeFromErrorPath(collectionName); 623 if ( depth == 0 ) { 624 GlobalVariables.getMessageMap().removeFromErrorPath("add"); 625 } 626 } 627 628 /** 629 * calls code to generate error messages if maintainableFields within any collections or sub-collections are marked as required 630 * 631 * @param businessObject 632 * @param maintainableCollectionDefinition 633 */ 634 private void validateMaintainableCollectionsRequiredFields(PersistableBusinessObject businessObject, MaintainableCollectionDefinition maintainableCollectionDefinition) { 635 final String collectionName = maintainableCollectionDefinition.getName(); 636 637 // validate required fields on fields withing collection definition 638 Collection<PersistableBusinessObject> collection = (Collection) ObjectUtils.getPropertyValue(businessObject, collectionName); 639 if (collection != null && !collection.isEmpty()) { 640 for (MaintainableFieldDefinition maintainableFieldDefinition : maintainableCollectionDefinition.getMaintainableFields()) { 641 int pos = 0; 642 final String fieldName = maintainableFieldDefinition.getName(); 643 for (PersistableBusinessObject element : collection) { 644 String parentName = collectionName + "[" + (pos++) + "]"; 645 GlobalVariables.getMessageMap().addToErrorPath(parentName); 646 validateMaintainableFieldRequiredFields(maintainableFieldDefinition, element, fieldName); 647 GlobalVariables.getMessageMap().removeFromErrorPath(parentName); 648 } 649 } 650 651 // recursivley validate required fields on subcollections 652 GlobalVariables.getMessageMap().addToErrorPath(collectionName); 653 for (MaintainableCollectionDefinition nestedMaintainableCollectionDefinition : maintainableCollectionDefinition.getMaintainableCollections()) { 654 for (PersistableBusinessObject element : collection) { 655 validateMaintainableCollectionsRequiredFields(element, nestedMaintainableCollectionDefinition); 656 } 657 } 658 GlobalVariables.getMessageMap().removeFromErrorPath(collectionName); 659 } 660 } 661 662 /** 663 * default implementation checks for duplicats based on keys of objects only 664 * 665 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#validateMaintainableCollectionsForDuplicateEntries(org.kuali.rice.krad.maintenance.MaintenanceDocument) 666 */ 667 public void validateMaintainableCollectionsForDuplicateEntries(MaintenanceDocument document) { 668 Maintainable newMaintainableObject = document.getNewMaintainableObject(); 669 if (newMaintainableObject == null) { 670 LOG.error("New maintainable is null"); 671 throw new RuntimeException("New maintainable is null"); 672 } 673 674 List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections(getDocumentTypeName(newMaintainableObject.getBoClass())); 675 for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) { 676 for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition.getMaintainableItems()) { 677 // validate collections 678 if (maintainableItemDefinition instanceof MaintainableCollectionDefinition) { 679 validateMaintainableCollectionsForDuplicateEntries(newMaintainableObject.getBusinessObject(), (MaintainableCollectionDefinition) maintainableItemDefinition); 680 } 681 } 682 } 683 } 684 685 /** 686 * recursivly checks collections for duplicate entries based on key valuse 687 * 688 * @param businessObject 689 * @param maintainableCollectionDefinition 690 */ 691 private void validateMaintainableCollectionsForDuplicateEntries(PersistableBusinessObject businessObject, MaintainableCollectionDefinition maintainableCollectionDefinition) { 692 final String collectionName = maintainableCollectionDefinition.getName(); 693 694 if (maintainableCollectionDefinition.dissallowDuplicateKey()) { 695 final Class maintainableBusinessObjectClass = businessObject.getClass(); 696 // validate that no duplicates based on keys exist 697 Collection<PersistableBusinessObject> collection = (Collection) ObjectUtils.getPropertyValue(businessObject, collectionName); 698 if (collection != null && !collection.isEmpty()) { 699 final String propertyName = maintainableCollectionDefinition.getAttributeToHighlightOnDuplicateKey(); 700 // get collection label for dd 701 final String label = dataDictionaryService.getCollectionLabel(maintainableBusinessObjectClass, collectionName); 702 final String shortLabel = dataDictionaryService.getCollectionShortLabel(maintainableBusinessObjectClass, collectionName); 703 int pos = 0; 704 for (PersistableBusinessObject element : collection) { 705 String pathToElement = collectionName + "[" + (pos++) + "]"; 706 if (ObjectUtils.countObjectsWithIdentitcalKey(collection, element) > 1) { 707 GlobalVariables.getMessageMap().addToErrorPath(pathToElement); 708 GlobalVariables.getMessageMap().putError(propertyName, RiceKeyConstants.ERROR_DUPLICATE_ELEMENT, new String[] { label, shortLabel }); 709 GlobalVariables.getMessageMap().removeFromErrorPath(pathToElement); 710 } 711 } 712 713 // recursivley check for duplicate entries on subcollections 714 GlobalVariables.getMessageMap().addToErrorPath(collectionName); 715 for (MaintainableCollectionDefinition nestedMaintainableCollectionDefinition : maintainableCollectionDefinition.getMaintainableCollections()) { 716 for (PersistableBusinessObject element : collection) { 717 validateMaintainableCollectionsForDuplicateEntries(element, nestedMaintainableCollectionDefinition); 718 } 719 } 720 GlobalVariables.getMessageMap().removeFromErrorPath(collectionName); 721 722 } 723 } 724 } 725 726 /** 727 * for issue KULRice 3072 728 * 729 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getgetPreserveLockingKeysOnCopy(java.lang.Class) 730 */ 731 public boolean getPreserveLockingKeysOnCopy(Class businessObjectClass) { 732 733 boolean preserveLockingKeysOnCopy = false; 734 735 MaintenanceDocumentEntry docEntry = getMaintenanceDocumentEntry(businessObjectClass); 736 737 if (docEntry != null) { 738 preserveLockingKeysOnCopy = docEntry.getPreserveLockingKeysOnCopy(); 739 } 740 741 return preserveLockingKeysOnCopy; 742 } 743 744 /** 745 * for isue KULRice 3070 746 * 747 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getAllowsRecordDeletion(java.lang.Class) 748 */ 749 public Boolean getAllowsRecordDeletion(Class businessObjectClass) { 750 751 Boolean allowsRecordDeletion = Boolean.FALSE; 752 753 MaintenanceDocumentEntry docEntry = getMaintenanceDocumentEntry(businessObjectClass); 754 755 if (docEntry != null) { 756 allowsRecordDeletion = Boolean.valueOf(docEntry.getAllowsRecordDeletion()); 757 } 758 759 return allowsRecordDeletion; 760 } 761 762 /** 763 * for issue KULRice3070, see if need delete button 764 * 765 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#getAllowsRecordDeletion(org.kuali.rice.krad.maintenance.MaintenanceDocument) 766 */ 767 public Boolean getAllowsRecordDeletion(MaintenanceDocument document) { 768 return document != null ? this.getAllowsRecordDeletion(document.getNewMaintainableObject().getBoClass()) : Boolean.FALSE; 769 } 770 771 /** 772 * @see org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService#translateCodes(java.lang.Class) 773 */ 774 public Boolean translateCodes(Class businessObjectClass) { 775 boolean translateCodes = false; 776 777 MaintenanceDocumentEntry docEntry = getMaintenanceDocumentEntry(businessObjectClass); 778 779 if (docEntry != null) { 780 translateCodes = docEntry.isTranslateCodes(); 781 } 782 783 return translateCodes; 784 } 785 786}