View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collection;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.apache.log4j.Logger;
27  import org.kuali.rice.core.api.criteria.Predicate;
28  import org.kuali.rice.core.api.criteria.PredicateFactory;
29  import org.kuali.rice.core.api.criteria.QueryByCriteria;
30  import org.kuali.rice.core.api.util.RiceKeyConstants;
31  import org.kuali.rice.core.api.util.io.SerializationUtils;
32  import org.kuali.rice.core.framework.persistence.jta.TransactionalNoValidationExceptionRollback;
33  import org.kuali.rice.kew.api.exception.WorkflowException;
34  import org.kuali.rice.krad.bo.DataObjectBase;
35  import org.kuali.rice.krad.bo.PersistableBusinessObject;
36  import org.kuali.rice.krad.data.CopyOption;
37  import org.kuali.rice.krad.data.DataObjectService;
38  import org.kuali.rice.krad.data.KradDataServiceLocator;
39  import org.kuali.rice.krad.exception.DocumentTypeAuthorizationException;
40  import org.kuali.rice.krad.maintenance.Maintainable;
41  import org.kuali.rice.krad.maintenance.MaintenanceDocument;
42  import org.kuali.rice.krad.maintenance.MaintenanceLock;
43  import org.kuali.rice.krad.service.DataObjectAuthorizationService;
44  import org.kuali.rice.krad.service.DocumentDictionaryService;
45  import org.kuali.rice.krad.service.DocumentService;
46  import org.kuali.rice.krad.service.LegacyDataAdapter;
47  import org.kuali.rice.krad.service.MaintenanceDocumentService;
48  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
49  import org.kuali.rice.krad.util.GlobalVariables;
50  import org.kuali.rice.krad.util.KRADConstants;
51  import org.kuali.rice.krad.util.KRADPropertyConstants;
52  import org.kuali.rice.krad.util.KRADUtils;
53  import org.springframework.beans.factory.annotation.Required;
54  
55  /**
56   * Service implementation for the MaintenanceDocument structure. This is the
57   * default implementation, that is delivered with Kuali
58   *
59   * @author Kuali Rice Team (rice.collab@kuali.org)
60   */
61  @TransactionalNoValidationExceptionRollback
62  public class MaintenanceDocumentServiceImpl implements MaintenanceDocumentService {
63      private static final Logger LOG = Logger.getLogger(MaintenanceDocumentServiceImpl.class);
64  
65      protected LegacyDataAdapter legacyDataAdapter;
66      protected DataObjectService dataObjectService;
67      protected DataObjectAuthorizationService dataObjectAuthorizationService;
68      protected DocumentService documentService;
69      protected DocumentDictionaryService documentDictionaryService;
70  
71      /**
72       * @see org.kuali.rice.krad.service.MaintenanceDocumentService#setupNewMaintenanceDocument(java.lang.String,
73       *      java.lang.String, java.lang.String)
74       */
75      @Override
76  	@SuppressWarnings("unchecked")
77      public MaintenanceDocument setupNewMaintenanceDocument(String objectClassName, String documentTypeName,
78              String maintenanceAction) {
79          if (StringUtils.isEmpty(objectClassName) && StringUtils.isEmpty(documentTypeName)) {
80              throw new IllegalArgumentException("Document type name or bo class not given!");
81          }
82  
83          // get document type if not passed
84          if (StringUtils.isEmpty(documentTypeName)) {
85              try {
86                  documentTypeName =
87                          getDocumentDictionaryService().getMaintenanceDocumentTypeName(Class.forName(objectClassName));
88              } catch (ClassNotFoundException e) {
89                  throw new RuntimeException(e);
90              }
91  
92              if (StringUtils.isEmpty(documentTypeName)) {
93                  throw new RuntimeException(
94                          "documentTypeName is empty; does this Business Object have a maintenance document definition? " +
95                                  objectClassName);
96              }
97          }
98  
99          // 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 }