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.krad.service.impl; 017 018import java.io.Serializable; 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.List; 023import java.util.Map; 024 025import org.apache.commons.lang.StringUtils; 026import org.apache.log4j.Logger; 027import org.kuali.rice.core.api.criteria.Predicate; 028import org.kuali.rice.core.api.criteria.PredicateFactory; 029import org.kuali.rice.core.api.criteria.QueryByCriteria; 030import org.kuali.rice.core.api.util.RiceKeyConstants; 031import org.kuali.rice.core.api.util.io.SerializationUtils; 032import org.kuali.rice.core.framework.persistence.jta.TransactionalNoValidationExceptionRollback; 033import org.kuali.rice.kew.api.exception.WorkflowException; 034import org.kuali.rice.krad.bo.DataObjectBase; 035import org.kuali.rice.krad.bo.PersistableBusinessObject; 036import org.kuali.rice.krad.data.CopyOption; 037import org.kuali.rice.krad.data.DataObjectService; 038import org.kuali.rice.krad.data.KradDataServiceLocator; 039import org.kuali.rice.krad.exception.DocumentTypeAuthorizationException; 040import org.kuali.rice.krad.maintenance.Maintainable; 041import org.kuali.rice.krad.maintenance.MaintenanceDocument; 042import org.kuali.rice.krad.maintenance.MaintenanceLock; 043import org.kuali.rice.krad.service.DataObjectAuthorizationService; 044import org.kuali.rice.krad.service.DocumentDictionaryService; 045import org.kuali.rice.krad.service.DocumentService; 046import org.kuali.rice.krad.service.LegacyDataAdapter; 047import org.kuali.rice.krad.service.MaintenanceDocumentService; 048import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 049import org.kuali.rice.krad.util.GlobalVariables; 050import org.kuali.rice.krad.util.KRADConstants; 051import org.kuali.rice.krad.util.KRADPropertyConstants; 052import org.kuali.rice.krad.util.KRADUtils; 053import org.springframework.beans.factory.annotation.Required; 054 055/** 056 * Service implementation for the MaintenanceDocument structure. This is the 057 * default implementation, that is delivered with Kuali 058 * 059 * @author Kuali Rice Team (rice.collab@kuali.org) 060 */ 061@TransactionalNoValidationExceptionRollback 062public class MaintenanceDocumentServiceImpl implements MaintenanceDocumentService { 063 private static final Logger LOG = Logger.getLogger(MaintenanceDocumentServiceImpl.class); 064 065 protected LegacyDataAdapter legacyDataAdapter; 066 protected DataObjectService dataObjectService; 067 protected DataObjectAuthorizationService dataObjectAuthorizationService; 068 protected DocumentService documentService; 069 protected DocumentDictionaryService documentDictionaryService; 070 071 /** 072 * @see org.kuali.rice.krad.service.MaintenanceDocumentService#setupNewMaintenanceDocument(java.lang.String, 073 * java.lang.String, java.lang.String) 074 */ 075 @Override 076 @SuppressWarnings("unchecked") 077 public MaintenanceDocument setupNewMaintenanceDocument(String objectClassName, String documentTypeName, 078 String maintenanceAction) { 079 if (StringUtils.isEmpty(objectClassName) && StringUtils.isEmpty(documentTypeName)) { 080 throw new IllegalArgumentException("Document type name or bo class not given!"); 081 } 082 083 // get document type if not passed 084 if (StringUtils.isEmpty(documentTypeName)) { 085 try { 086 documentTypeName = 087 getDocumentDictionaryService().getMaintenanceDocumentTypeName(Class.forName(objectClassName)); 088 } catch (ClassNotFoundException e) { 089 throw new RuntimeException(e); 090 } 091 092 if (StringUtils.isEmpty(documentTypeName)) { 093 throw new RuntimeException( 094 "documentTypeName is empty; does this Business Object have a maintenance document definition? " + 095 objectClassName); 096 } 097 } 098 099 // check doc type allows new or copy if that action was requested 100 if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction) || 101 KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { 102 Class<?> boClass = 103 getDocumentDictionaryService().getMaintenanceDataObjectClass(documentTypeName); 104 boolean allowsNewOrCopy = getDataObjectAuthorizationService() 105 .canCreate(boClass, GlobalVariables.getUserSession().getPerson(), documentTypeName); 106 if (!allowsNewOrCopy) { 107 LOG.error("Document type " + documentTypeName + " does not allow new or copy actions."); 108 throw new DocumentTypeAuthorizationException( 109 GlobalVariables.getUserSession().getPerson().getPrincipalId(), "newOrCopy", documentTypeName); 110 } 111 } 112 113 // get new document from service 114 try { 115 return (MaintenanceDocument) getDocumentService().getNewDocument(documentTypeName); 116 } catch (WorkflowException e) { 117 LOG.error("Cannot get new maintenance document instance for doc type: " + documentTypeName, e); 118 throw new RuntimeException("Cannot get new maintenance document instance for doc type: " + documentTypeName, 119 e); 120 } 121 } 122 123 /** 124 * @see org.kuali.rice.krad.service.impl.MaintenanceDocumentServiceImpl#setupMaintenanceObject 125 */ 126 @Override 127 public void setupMaintenanceObject(MaintenanceDocument document, String maintenanceAction, 128 Map<String, String[]> requestParameters) { 129 document.getNewMaintainableObject().setMaintenanceAction(maintenanceAction); 130 document.getOldMaintainableObject().setMaintenanceAction(maintenanceAction); 131 132 // if action is delete, check that object can be deleted 133 if (KRADConstants.MAINTENANCE_DELETE_ACTION.equals(maintenanceAction)) 134 { 135 checkMaintenanceActionAuthorization(document, document.getOldMaintainableObject(), 136 maintenanceAction, requestParameters); 137 } 138 139 // if action is edit or copy first need to retrieve the old record 140 if (!KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction) && 141 !KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) { 142 Object oldDataObject = retrieveObjectForMaintenance(document, requestParameters); 143 144 Object newDataObject = null; 145 146 /* 147 Copy with clearing objectId and version number in the parent and all nested objects if dataObject is an 148 instance of DataObjectBase or PersistableBusinessObject 149 */ 150 if (dataObjectService.supports(oldDataObject.getClass())) { 151 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { 152 newDataObject = dataObjectService.copyInstance(oldDataObject, CopyOption.RESET_VERSION_NUMBER, 153 CopyOption.RESET_OBJECT_ID); 154 } else { 155 newDataObject = dataObjectService.copyInstance(oldDataObject); 156 } 157 } else { 158 newDataObject = SerializationUtils.deepCopy((Serializable) oldDataObject); 159 } 160 161 // set object instance for editing 162 document.getOldMaintainableObject().setDataObject(oldDataObject); 163 document.getNewMaintainableObject().setDataObject(newDataObject); 164 165 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction) && !document.isFieldsClearedOnCopy()) { 166 Maintainable maintainable = document.getNewMaintainableObject(); 167 168 // Since this will be a new object, we also need to blank out the object ID and version number fields 169 // (if they exist). If the object uses a different locking key or unique ID field, the blanking of 170 // these will need to be done in the Maintainable.processAfterCopy() method. 171 if(!dataObjectService.supports(oldDataObject.getClass())) { 172 // If neither then use reflection to see if the object has setVersionNumber and setObjectId methods 173 if(ObjectPropertyUtils.getWriteMethod(maintainable.getDataObject().getClass(), "versionNumber") != null) { 174 ObjectPropertyUtils.setPropertyValue(maintainable.getDataObject(), "versionNumber", null); 175 } 176 177 if(ObjectPropertyUtils.getWriteMethod(maintainable.getDataObject().getClass(), "objectId") != null) { 178 ObjectPropertyUtils.setPropertyValue(maintainable.getDataObject(), "objectId", null); 179 } 180 } 181 182 clearValuesForPropertyNames(newDataObject, maintainable.getDataObjectClass()); 183 184 if (!getDocumentDictionaryService().getPreserveLockingKeysOnCopy(maintainable.getDataObjectClass())) { 185 clearPrimaryKeyFields(newDataObject, maintainable.getDataObjectClass()); 186 } 187 } 188 189 checkMaintenanceActionAuthorization(document, oldDataObject, maintenanceAction, requestParameters); 190 } 191 192 // if new with existing we need to populate with passed in parameters 193 if (KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) { 194 Object newBO = document.getNewMaintainableObject().getDataObject(); 195 Map<String, String> parameters = 196 buildKeyMapFromRequest(requestParameters, document.getNewMaintainableObject().getDataObjectClass()); 197 ObjectPropertyUtils.copyPropertiesToObject(parameters, newBO); 198 if (newBO instanceof PersistableBusinessObject) { 199 ((PersistableBusinessObject) newBO).refresh(); 200 } 201 202 document.getNewMaintainableObject().setupNewFromExisting(document, requestParameters); 203 } else if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)) { 204 document.getNewMaintainableObject().processAfterNew(document, requestParameters); 205 } 206 } 207 208 /** 209 * For the edit and delete maintenance actions checks with the 210 * <code>BusinessObjectAuthorizationService</code> to check whether the 211 * action is allowed for the record data. In action is allowed invokes the 212 * custom processing hook on the <code>Maintainble</code>. 213 * 214 * @param document - document instance for the maintenance object 215 * @param oldBusinessObject - the old maintenance record 216 * @param maintenanceAction - type of maintenance action requested 217 * @param requestParameters - map of parameters from the request 218 */ 219 protected void checkMaintenanceActionAuthorization(MaintenanceDocument document, Object oldBusinessObject, 220 String maintenanceAction, Map<String, String[]> requestParameters) { 221 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction)) { 222 boolean allowsEdit = getDataObjectAuthorizationService() 223 .canMaintain(oldBusinessObject, GlobalVariables.getUserSession().getPerson(), 224 document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 225 if (!allowsEdit) { 226 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName() + 227 " does not allow edit actions."); 228 throw new DocumentTypeAuthorizationException( 229 GlobalVariables.getUserSession().getPerson().getPrincipalId(), "edit", 230 document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 231 } 232 233 // invoke custom processing method 234 document.getNewMaintainableObject().processAfterEdit(document, requestParameters); 235 } else if (KRADConstants.MAINTENANCE_DELETE_ACTION.equals(maintenanceAction)) { 236 boolean allowsDelete = getDataObjectAuthorizationService() 237 .canMaintain(oldBusinessObject, GlobalVariables.getUserSession().getPerson(), 238 document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 239 240 if (!allowsDelete) { 241 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName() + 242 " does not allow delete actions."); 243 throw new DocumentTypeAuthorizationException( 244 GlobalVariables.getUserSession().getPerson().getPrincipalId(), "delete", 245 document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 246 } 247 248 boolean dataObjectAllowsDelete = getDocumentDictionaryService().getAllowsRecordDeletion( 249 document.getOldMaintainableObject().getDataObject().getClass()); 250 251 if (!dataObjectAllowsDelete) { 252 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName() + 253 " does not allow delete actions."); 254 GlobalVariables.getMessageMap().removeAllWarningMessagesForProperty(KRADConstants.GLOBAL_MESSAGES); 255 GlobalVariables.getMessageMap().putError(KRADConstants.DOCUMENT_ERRORS, 256 RiceKeyConstants.MESSAGE_DELETE_ACTION_NOT_SUPPORTED); 257 258 } 259 260 } 261 } 262 263 /** 264 * For the edit or copy actions retrieves the record that is to be 265 * maintained 266 * 267 * <p> 268 * Based on the persistence metadata for the maintenance object class 269 * retrieves the primary key values from the given request parameters map 270 * (if the class is persistable). With those key values attempts to find the 271 * record using the <code>LookupService</code>. 272 * </p> 273 * 274 * @param document - document instance for the maintenance object 275 * @param requestParameters - Map of parameters from the request 276 * @return Object the retrieved old object 277 */ 278 protected Object retrieveObjectForMaintenance(MaintenanceDocument document, 279 Map<String, String[]> requestParameters) { 280 Map<String, String> keyMap = 281 buildKeyMapFromRequest(requestParameters, document.getNewMaintainableObject().getDataObjectClass()); 282 283 Object oldDataObject = document.getNewMaintainableObject().retrieveObjectForEditOrCopy(document, keyMap); 284 285 if (oldDataObject == null && !document.getOldMaintainableObject().isExternalBusinessObject()) { 286 throw new RuntimeException( 287 "Cannot retrieve old record for maintenance document, incorrect parameters passed on maint url: " + 288 requestParameters); 289 } 290 291 if (document.getOldMaintainableObject().isExternalBusinessObject()) { 292 if (oldDataObject == null) { 293 try { 294 oldDataObject = document.getOldMaintainableObject().getDataObjectClass().newInstance(); 295 } catch (Exception ex) { 296 throw new RuntimeException( 297 "External BO maintainable was null and unable to instantiate for old maintainable object.", 298 ex); 299 } 300 } 301 302 populateMaintenanceObjectWithCopyKeyValues(KRADUtils.translateRequestParameterMap(requestParameters), 303 oldDataObject, document.getOldMaintainableObject()); 304 document.getOldMaintainableObject().prepareExternalBusinessObject((PersistableBusinessObject) oldDataObject); 305 oldDataObject = document.getOldMaintainableObject().getDataObject(); 306 } 307 308 return oldDataObject; 309 } 310 311 /** 312 * Clears the value of the primary key fields on the maintenance object 313 * 314 * @param maintenanceObject - document to clear the pk fields on 315 * @param dataObjectClass - class to use for retrieving primary key metadata 316 */ 317 protected void clearPrimaryKeyFields(Object maintenanceObject, Class<?> dataObjectClass) { 318 List<String> keyFieldNames = legacyDataAdapter.listPrimaryKeyFieldNames(dataObjectClass); 319 for (String keyFieldName : keyFieldNames) { 320 ObjectPropertyUtils.setPropertyValue(maintenanceObject, keyFieldName, null); 321 } 322 } 323 324 /** 325 * Clears the value of the particular fields on the maintenance object 326 * 327 * @param maintenanceObject - document to clear the fields on 328 * @param dataObjectClass - class to use for retrieving list of fields to clear 329 */ 330 protected void clearValuesForPropertyNames(Object maintenanceObject, Class<?> dataObjectClass) { 331 List<String> clearValueOnCopyPropertyNames = getDocumentDictionaryService().getClearValueOnCopyPropertyNames( 332 dataObjectClass); 333 334 for (String clearValueOnCopyPropertyName : clearValueOnCopyPropertyNames) { 335 if (!StringUtils.contains(clearValueOnCopyPropertyName, ".")) { 336 if (ObjectPropertyUtils.isWritableProperty(maintenanceObject, clearValueOnCopyPropertyName)) { 337 ObjectPropertyUtils.setPropertyValue(maintenanceObject, clearValueOnCopyPropertyName, null); 338 } 339 } else { 340 String objectName = StringUtils.substringBeforeLast(clearValueOnCopyPropertyName, "."); 341 String objectToClear = StringUtils.substringAfterLast(clearValueOnCopyPropertyName, "."); 342 343 clearValuesInNestedObjects(objectName, maintenanceObject, objectToClear); 344 } 345 } 346 } 347 348 /** 349 * Clears the value of objects in nested objects on the maintenance object 350 * 351 * @param objectName - name of the object which contains the field to be cleared 352 * @param maintenanceObject - Object to clear the fields on 353 * @param objectToClear - the object to be cleared on the nested object 354 */ 355 private void clearValuesInNestedObjects(String objectName, Object maintenanceObject, String objectToClear) { 356 if (objectName.contains(".")) { 357 String newObjectName = StringUtils.substringAfter(objectName, "."); 358 objectName = StringUtils.substringBefore(objectName, "."); 359 360 if (ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName) instanceof Collection<?>) { 361 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName); 362 363 for (Object object : collection) { 364 clearValuesInNestedObjects(newObjectName, object, objectToClear); 365 } 366 } else { 367 Object object = ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName); 368 clearValuesInNestedObjects(newObjectName, object, objectToClear); 369 } 370 } else { 371 if (ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName) instanceof Collection<?>) { 372 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName); 373 374 for (Object object : collection) { 375 if (ObjectPropertyUtils.isWritableProperty(object, objectToClear)) { 376 ObjectPropertyUtils.setPropertyValue(object, objectToClear, null); 377 } 378 } 379 } else { 380 Object object = ObjectPropertyUtils.getPropertyValue(maintenanceObject, objectName); 381 382 if (ObjectPropertyUtils.isWritableProperty(object, objectToClear)) { 383 ObjectPropertyUtils.setPropertyValue(object, objectToClear, null); 384 } 385 } 386 } 387 } 388 389 /** 390 * Based on the maintenance object class retrieves the key field names from 391 * the <code>BusinessObjectMetaDataService</code> (or alternatively from the 392 * request parameters), then retrieves any matching key value pairs from the 393 * request parameters 394 * 395 * @param requestParameters - map of parameters from the request 396 * @param dataObjectClass - class to use for checking security parameter restrictions 397 * @return Map<String, String> key value pairs 398 */ 399 protected Map<String, String> buildKeyMapFromRequest(Map<String, String[]> requestParameters, 400 Class<?> dataObjectClass) { 401 List<String> keyFieldNames = null; 402 403 // translate request parameters 404 Map<String, String> parameters = KRADUtils.translateRequestParameterMap(requestParameters); 405 406 // are override keys listed in the request? If so, then those need to be 407 // our keys, not the primary key fields for the BO 408 if (!StringUtils.isBlank(parameters.get(KRADConstants.OVERRIDE_KEYS))) { 409 String[] overrideKeys = 410 parameters.get(KRADConstants.OVERRIDE_KEYS).split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR); 411 keyFieldNames = Arrays.asList(overrideKeys); 412 } else { 413 keyFieldNames = legacyDataAdapter.listPrimaryKeyFieldNames(dataObjectClass); 414 } 415 416 return KRADUtils.getParametersFromRequest(keyFieldNames, dataObjectClass, parameters); 417 } 418 419 /** 420 * Looks for a special request parameters giving the names of the keys that 421 * should be retrieved from the request parameters and copied to the 422 * maintenance object 423 * 424 * @param parameters - map of parameters from the request 425 * @param oldBusinessObject - the old maintenance object 426 * @param oldMaintainableObject - the old maintainble object (used to get object class for 427 * security checks) 428 */ 429 protected void populateMaintenanceObjectWithCopyKeyValues(Map<String, String> parameters, Object oldBusinessObject, 430 Maintainable oldMaintainableObject) { 431 List<String> keyFieldNamesToCopy = null; 432 Map<String, String> parametersToCopy = null; 433 434 if (!StringUtils.isBlank(parameters.get(KRADConstants.COPY_KEYS))) { 435 String[] copyKeys = 436 parameters.get(KRADConstants.COPY_KEYS).split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR); 437 keyFieldNamesToCopy = Arrays.asList(copyKeys); 438 parametersToCopy = KRADUtils 439 .getParametersFromRequest(keyFieldNamesToCopy, oldMaintainableObject.getDataObjectClass(), 440 parameters); 441 } 442 443 if (parametersToCopy != null) { 444 // TODO: make sure we are doing formatting here eventually 445 ObjectPropertyUtils.copyPropertiesToObject(parametersToCopy, oldBusinessObject); 446 } 447 } 448 449 /** 450 * @see org.kuali.rice.krad.service.MaintenanceDocumentService#getLockingDocumentId(org.kuali.rice.krad.maintenance.MaintenanceDocument) 451 */ 452 @Override 453 public String getLockingDocumentId(MaintenanceDocument document) { 454 return getLockingDocumentId(document.getNewMaintainableObject(), document.getDocumentNumber()); 455 } 456 457 /** 458 * @see org.kuali.rice.krad.service.MaintenanceDocumentService#getLockingDocumentId(org.kuali.rice.krad.maintenance.Maintainable, 459 * java.lang.String) 460 */ 461 @Override 462 public String getLockingDocumentId(Maintainable maintainable, final String documentNumber) { 463 final List<MaintenanceLock> maintenanceLocks = maintainable.generateMaintenanceLocks(); 464 String lockingDocId = null; 465 for (MaintenanceLock maintenanceLock : maintenanceLocks) { 466 lockingDocId = getLockingDocumentNumber(maintenanceLock.getLockingRepresentation(), 467 documentNumber); 468 if (StringUtils.isNotBlank(lockingDocId)) { 469 break; 470 } 471 } 472 473 return lockingDocId; 474 } 475 476 protected String getLockingDocumentNumber(String lockingRepresentation, String documentNumber) { 477 String lockingDocNumber = ""; 478 479 // build the query criteria 480 List<Predicate> predicates = new ArrayList<Predicate>(); 481 predicates.add(PredicateFactory.equal("lockingRepresentation", lockingRepresentation)); 482 483 // if a docHeaderId is specified, then it will be excluded from the 484 // locking representation test. 485 if (StringUtils.isNotBlank(documentNumber)) { 486 predicates.add(PredicateFactory.notEqual(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber)); 487 } 488 489 QueryByCriteria.Builder qbc = QueryByCriteria.Builder.create(); 490 qbc.setPredicates(PredicateFactory.and(predicates.toArray(new Predicate[predicates.size()]))); 491 492 // attempt to retrieve a document based off this criteria 493 List<MaintenanceLock> results = KradDataServiceLocator.getDataObjectService().findMatching(MaintenanceLock.class, qbc.build()) 494 .getResults(); 495 if (results.size() > 1) { 496 throw new IllegalStateException( 497 "Expected single result querying for MaintenanceLock. LockRep: " + lockingRepresentation); 498 } 499 500 // if a document was found, then there's already one out there pending, 501 // and we consider it 'locked' and we return the docnumber. 502 if (!results.isEmpty()) { 503 lockingDocNumber = results.get(0).getDocumentNumber(); 504 } 505 return lockingDocNumber; 506 } 507 508 /** 509 * @see org.kuali.rice.krad.service.MaintenanceDocumentService#deleteLocks(String) 510 */ 511 @Override 512 public void deleteLocks(String documentNumber) { 513 dataObjectService.deleteMatching(MaintenanceLock.class, QueryByCriteria.Builder.forAttribute( 514 "documentNumber", documentNumber).build()); 515 } 516 517 /** 518 * @see org.kuali.rice.krad.service.MaintenanceDocumentService#storeLocks(java.util.List) 519 */ 520 @Override 521 public void storeLocks(List<MaintenanceLock> maintenanceLocks) { 522 if (maintenanceLocks == null) { 523 return; 524 } 525 for (MaintenanceLock maintenanceLock : maintenanceLocks) { 526 dataObjectService.save(maintenanceLock); 527 } 528 } 529 530 protected DataObjectAuthorizationService getDataObjectAuthorizationService() { 531 return dataObjectAuthorizationService; 532 } 533 534 @Required 535 public void setDataObjectAuthorizationService(DataObjectAuthorizationService dataObjectAuthorizationService) { 536 this.dataObjectAuthorizationService = dataObjectAuthorizationService; 537 } 538 539 protected DocumentService getDocumentService() { 540 return this.documentService; 541 } 542 543 @Required 544 public void setDocumentService(DocumentService documentService) { 545 this.documentService = documentService; 546 } 547 548 public DocumentDictionaryService getDocumentDictionaryService() { 549 return documentDictionaryService; 550 } 551 552 @Required 553 public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) { 554 this.documentDictionaryService = documentDictionaryService; 555 } 556 557 @Required 558 public void setDataObjectService(DataObjectService dataObjectService) { 559 this.dataObjectService = dataObjectService; 560 } 561 562 @Required 563 public void setLegacyDataAdapter(LegacyDataAdapter legacyDataAdapter) { 564 this.legacyDataAdapter = legacyDataAdapter; 565 } 566 567}