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