View Javadoc
1   package org.kuali.rice.krad.maintenance;
2   
3   import java.io.Serializable;
4   import java.security.GeneralSecurityException;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.Iterator;
8   import java.util.List;
9   import java.util.Map;
10  
11  import org.apache.commons.collections.CollectionUtils;
12  import org.apache.commons.collections.MapUtils;
13  import org.apache.commons.lang.StringUtils;
14  import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
15  import org.kuali.ole.olekrad.util.OLEObjectPropertyReference;
16  import org.kuali.rice.core.api.CoreApiServiceLocator;
17  import org.kuali.rice.core.api.encryption.EncryptionService;
18  import org.kuali.rice.kim.api.identity.Person;
19  import org.kuali.rice.krad.bo.AdHocRoutePerson;
20  import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
21  import org.kuali.rice.krad.bo.BusinessObject;
22  import org.kuali.rice.krad.bo.DocumentHeader;
23  import org.kuali.rice.krad.bo.Note;
24  import org.kuali.rice.krad.data.CompoundKey;
25  import org.kuali.rice.krad.data.DataObjectService;
26  import org.kuali.rice.krad.data.DataObjectWrapper;
27  import org.kuali.rice.krad.exception.PessimisticLockingException;
28  import org.kuali.rice.krad.rules.rule.event.AddCollectionLineEvent;
29  import org.kuali.rice.krad.service.DataObjectAuthorizationService;
30  import org.kuali.rice.krad.service.DocumentDictionaryService;
31  import org.kuali.rice.krad.service.KRADServiceLocator;
32  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33  import org.kuali.rice.krad.service.KualiRuleService;
34  import org.kuali.rice.krad.service.LegacyDataAdapter;
35  import org.kuali.rice.krad.service.MaintenanceDocumentService;
36  import org.kuali.rice.krad.uif.UifConstants;
37  import org.kuali.rice.krad.uif.component.BindingInfo;
38  import org.kuali.rice.krad.uif.container.CollectionGroup;
39  import org.kuali.rice.krad.uif.field.DataField;
40  import org.kuali.rice.krad.uif.field.InputField;
41  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
42  import org.kuali.rice.krad.uif.service.ViewHelperService;
43  import org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl;
44  import org.kuali.rice.krad.uif.util.LifecycleElement;
45  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
46  import org.kuali.rice.krad.uif.util.ProcessLogger;
47  import org.kuali.rice.krad.uif.view.MaintenanceDocumentView;
48  import org.kuali.rice.krad.uif.view.View;
49  import org.kuali.rice.krad.uif.view.ViewModel;
50  import org.kuali.rice.krad.util.KRADConstants;
51  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
52  
53  /**
54   * Created by sheiksalahudeenm on 10/23/14.
55   *
56   * Overridden for fixing the active flag issue while copying document.
57   * Modified method name: clearUnauthorizedField.
58   * Newly added method name: setPropertyValue.
59   * Changes description : Passing the property value to OLEObjectPropertyReference.resolvePath(..) method to fix the active flag issue.
60   */
61  public class MaintainableImpl extends ViewHelperServiceImpl implements Maintainable {
62      private static final long serialVersionUID = 9125271369161634992L;
63      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintainableImpl.class);
64  
65      private String documentNumber;
66      private Object dataObject;
67      private Class<?> dataObjectClass;
68      private String maintenanceAction;
69  
70      private transient LegacyDataAdapter legacyDataAdapter;
71      private transient DataObjectAuthorizationService dataObjectAuthorizationService;
72      private transient DocumentDictionaryService documentDictionaryService;
73      private transient EncryptionService encryptionService;
74      private transient DataObjectService dataObjectService;
75      private transient MaintenanceDocumentService maintenanceDocumentService;
76      private transient KualiRuleService kualiRuleService;
77  
78      /**
79       * @see org.kuali.rice.krad.maintenance.Maintainable#retrieveObjectForEditOrCopy(MaintenanceDocument, java.util.Map)
80       */
81      @Override
82      public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
83          Object dataObject = null;
84          if ( getDataObjectService().supports(getDataObjectClass())) {
85              dataObject = getDataObjectService().find(getDataObjectClass(), new CompoundKey(dataObjectKeys));
86          } else {
87              try {
88                  dataObject = getLegacyDataAdapter().findObjectBySearch(getDataObjectClass(), dataObjectKeys);
89              } catch (Exception ex) {
90                  if ( ex.getClass().equals( LegacyDataAdapter.CLASS_NOT_PERSISTABLE_OJB_EXCEPTION_CLASS )
91                          && !document.getOldMaintainableObject().isExternalBusinessObject()) {
92                      throw new RuntimeException("Data Object Class: "
93                              + getDataObjectClass()
94                              + " is not persistable and is not externalizable - configuration error");
95                  }
96                  // otherwise, let fall through
97              }
98          }
99  
100         return dataObject;
101     }
102 
103 
104     /**
105      * @see Maintainable#setDocumentNumber
106      */
107     @Override
108     public void setDocumentNumber(String documentNumber) {
109         this.documentNumber = documentNumber;
110     }
111 
112     /**
113      * @see Maintainable#getDocumentTitle
114      */
115     @Override
116     public String getDocumentTitle(MaintenanceDocument document) {
117         // default implementation is to allow MaintenanceDocumentBase to
118         // generate the doc title
119         return "";
120     }
121 
122     /**
123      * @see Maintainable#getDataObject
124      */
125     @Override
126     public Object getDataObject() {
127         return dataObject;
128     }
129 
130     /**
131      * @see Maintainable#setDataObject
132      */
133     @Override
134     public void setDataObject(Object object) {
135         this.dataObject = object;
136     }
137 
138     /**
139      * @see Maintainable#getDataObjectClass
140      */
141     @Override
142     public Class<?> getDataObjectClass() {
143         return dataObjectClass;
144     }
145 
146     /**
147      * @see Maintainable#setDataObjectClass
148      */
149     @Override
150     public void setDataObjectClass(Class<?> dataObjectClass) {
151         this.dataObjectClass = dataObjectClass;
152     }
153 
154     /**
155      * Persistable business objects are lockable
156      *
157      * @deprecated note used by Rice framework
158      */
159     @Override
160     @Deprecated
161     public boolean isLockable() {
162         return KRADServiceLocatorWeb.getLegacyDataAdapter().isLockable(getDataObject());
163     }
164 
165 //    /**
166 //     * Returns the data object if its persistable, null otherwise.
167 //     *
168 //     * @deprecated this method has been left for compatibility reasons, use getDataObject instead.
169 //     */
170 //    @Override
171 //    @Deprecated // Uses KNS Classes
172 //    public PersistableBusinessObject getPersistableBusinessObject() {
173 //        return KRADServiceLocatorWeb.getLegacyDataAdapter().toPersistableBusinessObject(getDataObject());
174 //    }
175 
176     /**
177      * @see Maintainable#getMaintenanceAction
178      */
179     @Override
180     public String getMaintenanceAction() {
181         return maintenanceAction;
182     }
183 
184     /**
185      * @see Maintainable#setMaintenanceAction
186      */
187     @Override
188     public void setMaintenanceAction(String maintenanceAction) {
189         this.maintenanceAction = maintenanceAction;
190     }
191 
192     /**
193      * Note: as currently implemented, every key field for a given
194      * data object class must have a visible getter
195      *
196      * @see Maintainable#generateMaintenanceLocks
197      */
198     @Override
199     public List<MaintenanceLock> generateMaintenanceLocks() {
200         return generateMaintenanceLocks(getDocumentNumber(), getDocumentTypeName(), getDataObjectClass(), getDataObject());
201     }
202 
203     /**
204      * Allows locking of maintenance objects other than the one of the current maintenance object.
205      *
206      * @param documentNumber of the locking maintenance document
207      * @param documentTypeName of the maintenance document to be locked
208      * @param dataObjectClass of the maintenance document to be locked
209      * @param dataObject of the maintenance document to be locked
210      * @return
211      */
212     protected List<MaintenanceLock> generateMaintenanceLocks(String documentNumber, String documentTypeName, Class<?> dataObjectClass, Object dataObject) {
213         List<MaintenanceLock> maintenanceLocks = new ArrayList<MaintenanceLock>();
214         StringBuffer lockRepresentation = new StringBuffer(dataObjectClass.getName());
215         lockRepresentation.append(KRADConstants.Maintenance.LOCK_AFTER_CLASS_DELIM);
216 
217         DataObjectWrapper<Object> wrapper = getDataObjectService().wrap(dataObject);
218 
219         List<String> keyFieldNames = getDocumentDictionaryService().getLockingKeys(documentTypeName);
220 
221         for (Iterator<?> i = keyFieldNames.iterator(); i.hasNext(); ) {
222             String fieldName = (String) i.next();
223 
224             Object fieldValue = wrapper.getPropertyValueNullSafe(fieldName);
225             if (fieldValue == null) {
226                 fieldValue = "";
227             }
228 
229             // check if field is a secure
230             if (getDataObjectAuthorizationService()
231                     .attributeValueNeedsToBeEncryptedOnFormsAndLinks(dataObjectClass, fieldName)) {
232                 try {
233                     if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
234                         fieldValue = getEncryptionService().encrypt(fieldValue);
235                     }
236                 } catch (GeneralSecurityException e) {
237                     LOG.error("Unable to encrypt secure field for locking representation " + e.getMessage());
238                     throw new RuntimeException(
239                             "Unable to encrypt secure field for locking representation " + e.getMessage());
240                 }
241             }
242 
243             lockRepresentation.append(fieldName);
244             lockRepresentation.append(KRADConstants.Maintenance.LOCK_AFTER_FIELDNAME_DELIM);
245             lockRepresentation.append(String.valueOf(fieldValue));
246             if (i.hasNext()) {
247                 lockRepresentation.append(KRADConstants.Maintenance.LOCK_AFTER_VALUE_DELIM);
248             }
249         }
250 
251         MaintenanceLock maintenanceLock = new MaintenanceLock();
252         maintenanceLock.setDocumentNumber(documentNumber);
253         maintenanceLock.setLockingRepresentation(lockRepresentation.toString());
254         maintenanceLocks.add(maintenanceLock);
255 
256         return maintenanceLocks;
257     }
258 
259     /**
260      * Retrieves the document type name from the data dictionary based on
261      * business object class
262      */
263     protected String getDocumentTypeName() {
264         return getDocumentDictionaryService().getMaintenanceDocumentTypeName(dataObjectClass);
265     }
266 
267     /**
268      * @see Maintainable#saveDataObject
269      */
270     @Override
271     public void saveDataObject() {
272         if ( dataObject == null ) {
273             LOG.warn( "dataObject in maintainable was null - this should not be the case.  Skipping saveDataObject()");
274             return;
275         }
276         dataObject = getLegacyDataAdapter().linkAndSave((Serializable)dataObject);
277     }
278 
279     /**
280      * @see Maintainable#deleteDataObject
281      */
282     @Override
283     public void deleteDataObject() {
284         if (dataObject == null) {
285             return;
286         }
287         getLegacyDataAdapter().delete(dataObject);
288     }
289 
290     /**
291      * @see Maintainable#doRouteStatusChange
292      */
293     @Override
294     public void doRouteStatusChange(DocumentHeader documentHeader) {
295         // no default implementation
296     }
297 
298     /**
299      * @see Maintainable#getLockingDocumentId
300      */
301     @Override
302     public String getLockingDocumentId() {
303         return getMaintenanceDocumentService().getLockingDocumentId(this, documentNumber);
304     }
305 
306     /**
307      * @see Maintainable#getWorkflowEngineDocumentIdsToLock
308      */
309     @Override
310     public List<String> getWorkflowEngineDocumentIdsToLock() {
311         return null;
312     }
313 
314     /**
315      * Default implementation simply returns false to indicate that custom
316      * lock descriptors are not supported by MaintainableImpl. If custom
317      * lock descriptors are needed, the appropriate subclasses should override
318      * this method
319      *
320      * @see Maintainable#useCustomLockDescriptors
321      */
322     @Override
323     public boolean useCustomLockDescriptors() {
324         return false;
325     }
326 
327     /**
328      * Default implementation just throws a PessimisticLockingException.
329      * Subclasses of MaintainableImpl that need support for custom lock
330      * descriptors should override this method
331      *
332      * @see Maintainable#getCustomLockDescriptor
333      */
334     @Override
335     public String getCustomLockDescriptor(Person user) {
336         throw new PessimisticLockingException("The Maintainable for document " + documentNumber +
337                 " is using pessimistic locking with custom lock descriptors, but the Maintainable has not overridden the getCustomLockDescriptor method");
338     }
339 
340     /**
341      * @see Maintainable#isNotesEnabled
342      */
343     @Override
344     public boolean isNotesEnabled() {
345         return getLegacyDataAdapter().areNotesSupported(dataObjectClass);
346     }
347 
348     /**
349      * @see MaintainableImpl#isExternalBusinessObject
350      */
351     @Override
352     public boolean isExternalBusinessObject() {
353         return false;
354     }
355 
356     /**
357      * @see MaintainableImpl#prepareExternalBusinessObject
358      */
359     @Override
360     @Deprecated
361     public void prepareExternalBusinessObject(BusinessObject businessObject) {
362         // by default do nothing
363     }
364 
365     /**
366      * Checks whether the data object is not null and has its primary key values populated
367      *
368      * @see MaintainableImpl#isOldDataObjectInDocument
369      */
370     @Override
371     public boolean isOldDataObjectInDocument() {
372         boolean isOldDataObjectInExistence = true;
373 
374         if (getDataObject() == null) {
375             isOldDataObjectInExistence = false;
376         } else {
377             Map<String, ?> keyFieldValues = getLegacyDataAdapter().getPrimaryKeyFieldValuesDOMDS(getDataObject());
378             for (Object keyValue : keyFieldValues.values()) {
379                 if (keyValue == null) {
380                     isOldDataObjectInExistence = false;
381                 } else if ((keyValue instanceof String) && StringUtils.isBlank((String) keyValue)) {
382                     isOldDataObjectInExistence = false;
383                 }
384 
385                 if (!isOldDataObjectInExistence) {
386                     break;
387                 }
388             }
389         }
390 
391         return isOldDataObjectInExistence;
392     }
393 
394     /**
395      * @see Maintainable#prepareForSave
396      */
397     @Override
398     public void prepareForSave() {
399         // by default do nothing
400     }
401 
402     /**
403      * @see Maintainable#processAfterRetrieve
404      */
405     @Override
406     public void processAfterRetrieve() {
407         // by default do nothing
408     }
409 
410     /**
411      * @see MaintainableImpl#setupNewFromExisting
412      */
413     @Override
414     public void setupNewFromExisting(MaintenanceDocument document, Map<String, String[]> parameters) {
415         // by default do nothing
416     }
417 
418     /**
419      * @see Maintainable#processAfterCopy
420      */
421     @Override
422     public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> requestParameters) {
423         // by default do nothing
424     }
425 
426     /**
427      * @see Maintainable#processAfterEdit
428      */
429     @Override
430     public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
431         // by default do nothing
432     }
433 
434     /**
435      * @see Maintainable#processAfterNew
436      */
437     @Override
438     public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
439         // by default do nothing
440     }
441 
442     /**
443      * @see Maintainable#processAfterPost
444      */
445     @Override
446     public void processAfterPost(MaintenanceDocument document, Map<String, String[]> requestParameters) {
447         // by default do nothing
448     }
449 
450     /**
451      * In the case of edit maintenance adds a new blank line to the old side
452      *
453      * TODO: should this write some sort of missing message on the old side
454      * instead?
455      *
456      */
457     @Override
458     public void processAfterAddLine(ViewModel viewModel, Object addLine, String collectionId, String collectionPath,
459                 boolean isValidLine) {
460         super.processAfterAddLine(viewModel, addLine, collectionId, collectionPath, isValidLine);
461 
462         // Check for maintenance documents in edit but exclude notes and ad hoc recipients
463         if (viewModel instanceof MaintenanceDocumentForm
464                 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(
465                 ((MaintenanceDocumentForm) viewModel).getMaintenanceAction())
466                 && !(addLine instanceof Note)
467                 && !(addLine instanceof AdHocRoutePerson)
468                 && !(addLine instanceof AdHocRouteWorkgroup)) {
469             MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) viewModel;
470             MaintenanceDocument document = maintenanceForm.getDocument();
471 
472             BindingInfo bindingInfo = (BindingInfo) viewModel.getViewPostMetadata().getComponentPostData(collectionId,
473                     UifConstants.PostMetadata.BINDING_INFO);
474 
475             // get the old object's collection
476             //KULRICE-7970 support multiple level objects
477             String bindingPrefix = bindingInfo.getBindByNamePrefix();
478             String propertyPath = bindingInfo.getBindingName();
479             if (bindingPrefix != "" && bindingPrefix != null) {
480                 propertyPath = bindingPrefix + "." + propertyPath;
481             }
482 
483             Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(
484                     document.getOldMaintainableObject().getDataObject(), propertyPath);
485 
486             Class<?> collectionObjectClass = (Class<?>) viewModel.getViewPostMetadata().getComponentPostData(collectionId,
487                     UifConstants.PostMetadata.COLL_OBJECT_CLASS);
488 
489             try {
490                 Object blankLine = collectionObjectClass.newInstance();
491                 //Add a blank line to the top of the collection
492                 if (oldCollection instanceof List) {
493                     ((List<Object>) oldCollection).add(0, blankLine);
494                 } else {
495                     oldCollection.add(blankLine);
496                 }
497             } catch (Exception e) {
498                 throw new RuntimeException("Unable to create new line instance for old maintenance object", e);
499             }
500         }
501     }
502 
503     /**
504      * In the case of edit maintenance deleted the item on the old side.
505      *
506      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterDeleteLine(org.kuali.rice.krad.uif.view.ViewModel, String, String, int)
507      */
508     @Override
509     public void processAfterDeleteLine(ViewModel model, String collectionId, String collectionPath, int lineIndex) {
510         super.processAfterDeleteLine(model, collectionId, collectionPath, lineIndex);
511 
512         Class<?> collectionObjectClass = (Class<?>) model.getViewPostMetadata().getComponentPostData(collectionId,
513                 UifConstants.PostMetadata.COLL_OBJECT_CLASS);
514 
515         // Check for maintenance documents in edit but exclude notes and ad hoc recipients
516         if (model instanceof MaintenanceDocumentForm
517                 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm)model).getMaintenanceAction())
518                 && !collectionObjectClass.getName().equals(Note.class.getName())
519                 && !collectionObjectClass.getName().equals(AdHocRoutePerson.class.getName())
520                 && !collectionObjectClass.getName().equals(AdHocRouteWorkgroup.class.getName())) {
521             MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model;
522             MaintenanceDocument document = maintenanceForm.getDocument();
523 
524             BindingInfo bindingInfo = (BindingInfo) model.getViewPostMetadata().getComponentPostData(collectionId,
525                     UifConstants.PostMetadata.BINDING_INFO);
526 
527             // get the old object's collection
528             //KULRICE-7970 support multiple level objects
529             String bindingPrefix = bindingInfo.getBindByNamePrefix();
530             String propertyPath = bindingInfo.getBindingName();
531             if (bindingPrefix != "" && bindingPrefix != null) {
532                 propertyPath = bindingPrefix + "." + propertyPath;
533             }
534 
535             Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(
536                                 document.getOldMaintainableObject().getDataObject(), propertyPath);
537 
538             try {
539                 // Remove the object at lineIndex from the collection
540                 oldCollection.remove(oldCollection.toArray()[lineIndex]);
541             } catch (Exception e) {
542                 throw new RuntimeException("Unable to delete line instance for old maintenance object", e);
543             }
544         }
545     }
546 
547     @Override
548     protected boolean performAddLineValidation(ViewModel viewModel, Object newLine, String collectionId,
549                 String collectionPath) {
550         boolean isValidLine = super.performAddLineValidation(viewModel, newLine, collectionId, collectionPath);
551 
552         BindingInfo bindingInfo = (BindingInfo) viewModel.getViewPostMetadata().getComponentPostData(collectionId,
553                             UifConstants.PostMetadata.BINDING_INFO);
554 
555         if (viewModel instanceof MaintenanceDocumentForm) {
556             MaintenanceDocumentForm form = ((MaintenanceDocumentForm) viewModel);
557             isValidLine &= getKualiRuleService()
558                     .applyRules(new AddCollectionLineEvent(form.getDocument(), bindingInfo.getBindingName(), newLine));
559         }
560 
561         return isValidLine;
562     }
563 
564     /**
565      * Retrieves the document number configured on this maintainable
566      *
567      * @return String document number
568      */
569     protected String getDocumentNumber() {
570         return this.documentNumber;
571     }
572 
573 
574 
575     /**
576      * Hook for service overrides to perform custom apply model logic on the component
577      *
578      * @param element element instance to apply model to
579      * @param model Top level object containing the data (could be the model or a top level business
580      *        object, dto)
581      */
582     @Override
583     public void performCustomApplyModel(LifecycleElement element, Object model) {
584 
585         MaintenanceDocumentForm form = (MaintenanceDocumentForm) model;
586 
587         /**
588          *  Primary keys should not be editable on maintenance edit action
589          *
590          *  Determines if the maintenance action matches MAINTENANCE_EDIT_ACTION, that the element is of type InputField and
591          *  if the bindingPath includes a new maintainable path
592          */
593         if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(form.getMaintenanceAction()) && element instanceof InputField
594                 && StringUtils.contains(((InputField) element).getName(), KRADConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
595             setPrimaryKeyReadOnly(element);
596 
597         }
598     }
599 
600     /**
601      * sets primary keys to read-only
602      */
603     private void setPrimaryKeyReadOnly(LifecycleElement element){
604 
605         String propertyName =  ((InputField) element).getPropertyName();
606         MaintenanceDocumentView maintenanceView = (MaintenanceDocumentView) ViewLifecycle.getView();
607 
608         /**
609          *   get a list of primary keys from the maintenance view dataObject
610          */
611         List<String> primaryKeys = KRADServiceLocatorWeb.getLegacyDataAdapter().listPrimaryKeyFieldNames(maintenanceView.getDataObjectClassName());
612 
613         /**
614          *  loop thru primary keys, match to our component field name and set it to read-only
615          */
616         for (String field : primaryKeys) {
617             if(propertyName.equals(field)){
618                 ((InputField) element).setReadOnly(true);
619 
620             }
621         }
622     }
623 
624 
625     /**
626      * For the copy action, clears out primary key values and replaces any new fields that the current user is
627      * unauthorized for with default values in the old record.
628      *
629      * {@inheritDoc}
630      */
631     @Override
632     public void performCustomFinalize(LifecycleElement element, Object model, LifecycleElement parent) {
633         if (!(model instanceof MaintenanceDocumentForm)) {
634             return;
635         }
636 
637         MaintenanceDocumentForm form = (MaintenanceDocumentForm) model;
638 
639         if (form.getDocument().isFieldsClearedOnCopy()) {
640             return;
641         }
642 
643         if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(form.getMaintenanceAction())) {
644             View view = ViewLifecycle.getView();
645 
646             if (element instanceof DataField) {
647                 DataField field = (DataField) element;
648 
649                 applyDefaultValuesForPreviouslyClearedFields(view, form, field);
650 
651                 clearUnauthorizedField(view, form, field);
652             } else if (element instanceof CollectionGroup) {
653                 CollectionGroup group = (CollectionGroup) element;
654 
655                 clearUnauthorizedLine(view, form, group);
656             }
657         }
658     }
659 
660     /**
661      * For the copy action, runs the custom processing after the copy and sets the indicator that fields have been
662      * copied as true.
663      *
664      * {@inheritDoc}
665      */
666     @Override
667     public void performCustomViewFinalize(Object model) {
668         if (!(model instanceof MaintenanceDocumentForm)) {
669             return;
670         }
671 
672         MaintenanceDocumentForm form = (MaintenanceDocumentForm) model;
673 
674         if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(form.getMaintenanceAction())) {
675             processAfterCopy(form.getDocument(), form.getInitialRequestParameters());
676 
677             form.getDocument().setFieldsClearedOnCopy(true);
678         }
679     }
680 
681     /**
682      * Applies the default value of a field if it was a field that was previously cleared.
683      *
684      * @param view view instance that contains the fields being checked
685      * @param model model instance that contains the fields being checked
686      * @param field field being checked to see if it has been cleared
687      */
688     private void applyDefaultValuesForPreviouslyClearedFields(View view, ViewModel model, DataField field) {
689         List<String> clearValueOnCopyPropertyNames =
690                 KRADServiceLocatorWeb.getDocumentDictionaryService().getClearValueOnCopyPropertyNames(
691                         ((MaintenanceDocumentView) view).getDataObjectClassName());
692 
693         for (String clearValueOnCopyPropertyName : clearValueOnCopyPropertyNames) {
694             if (field.getPropertyName().equalsIgnoreCase(clearValueOnCopyPropertyName)) {
695                 String bindingPath = field.getBindingInfo().getBindingPath();
696 
697                 view.getViewHelperService().populateDefaultValueForField(model, field, bindingPath);
698             }
699         }
700     }
701 
702     /**
703      * Determines if the current field is restricted and replaces its value with a default value if so.
704      *
705      * @param view view instance that contains the fields being checked
706      * @param model model instance that contains the fields being checked
707      * @param field field being checked for restrictions
708      */
709     private void clearUnauthorizedField(View view, ViewModel model, DataField field) {
710         ViewHelperService helper = ViewLifecycle.getHelper();
711         String bindingPath = field.getBindingInfo().getBindingPath();
712 
713         if (StringUtils.contains(bindingPath, KRADConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
714             // The field is restricted if it is hidden or read only
715             boolean isRestricted = field.isHidden() || Boolean.TRUE.equals(field.getReadOnly()) || field.isApplyMask();
716 
717             // If just the field (not its containing line) is restricted, clear it out and apply default values
718             if (isRestricted && !isLineRestricted(field)) {
719                 if (ObjectPropertyUtils.isWritableProperty(model, bindingPath)) {
720                     /* Modified by 'Sheik Salahudeen' for fixing the active flag issue while copying document.
721                      * Calling custom method to set the property values*/
722                     setPropertyValue(model, bindingPath, null);
723                 }
724 
725                 field.setReadOnlyDisplaySuffixPropertyName(null);
726                 field.setReadOnlyDisplaySuffix(null);
727 
728                 helper.populateDefaultValueForField(model, field, bindingPath);
729             }
730         }
731     }
732 
733     /**
734      * Returns whether a line that contains a field is restricted; that is, if the field is part of a group and that
735      * group has some unauthorized binding information.
736      *
737      * @param field field being checked for restrictions
738      *
739      * @return true if the field is in a line with restrictions, false otherwise
740      */
741     private boolean isLineRestricted(DataField field) {
742         CollectionGroup group = (CollectionGroup) MapUtils.getObject(field.getContext(),
743                 UifConstants.ContextVariableNames.COLLECTION_GROUP);
744 
745         return group != null && CollectionUtils.isNotEmpty(group.getUnauthorizedLineBindingInfos());
746     }
747 
748     /**
749      * Determines if the current group contains restricted lines and clears them if so.
750      *
751      * @param view view instance that contains the group being checked
752      * @param model model instance that contains the group being checked
753      * @param group group being checked for restrictions
754      */
755     private void clearUnauthorizedLine(View view, ViewModel model, CollectionGroup group) {
756         String bindingPath = group.getBindingInfo().getBindingPath();
757 
758         if (StringUtils.contains(bindingPath, KRADConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
759             // A line is restricted if it is hidden or read only
760             if (group.getUnauthorizedLineBindingInfos() != null) {
761                 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, bindingPath);
762 
763                 // If any lines are restricted, clear them out
764                 for (BindingInfo bindingInfo : group.getUnauthorizedLineBindingInfos()) {
765                     String lineBindingPath = bindingInfo.getBindingPath();
766                     Object line = ObjectPropertyUtils.getPropertyValue(model, lineBindingPath);
767 
768                     collection.remove(line);
769                 }
770             }
771         }
772     }
773 
774     @Override
775     @Deprecated // KNS Service
776     protected LegacyDataAdapter getLegacyDataAdapter() {
777         if (legacyDataAdapter == null) {
778             legacyDataAdapter = KRADServiceLocatorWeb.getLegacyDataAdapter();
779         }
780         return this.legacyDataAdapter;
781     }
782 
783     @Override
784     @Deprecated // KNS Service
785     public void setLegacyDataAdapter(LegacyDataAdapter legacyDataAdapter) {
786         this.legacyDataAdapter = legacyDataAdapter;
787     }
788 
789     protected DataObjectAuthorizationService getDataObjectAuthorizationService() {
790         if (dataObjectAuthorizationService == null) {
791             this.dataObjectAuthorizationService = KRADServiceLocatorWeb.getDataObjectAuthorizationService();
792         }
793         return dataObjectAuthorizationService;
794     }
795 
796     public void setDataObjectAuthorizationService(DataObjectAuthorizationService dataObjectAuthorizationService) {
797         this.dataObjectAuthorizationService = dataObjectAuthorizationService;
798     }
799 
800     public DocumentDictionaryService getDocumentDictionaryService() {
801         if (documentDictionaryService == null) {
802             this.documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
803         }
804         return documentDictionaryService;
805     }
806 
807     public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
808         this.documentDictionaryService = documentDictionaryService;
809     }
810 
811     protected EncryptionService getEncryptionService() {
812         if (encryptionService == null) {
813             encryptionService = CoreApiServiceLocator.getEncryptionService();
814         }
815         return encryptionService;
816     }
817 
818     public void setEncryptionService(EncryptionService encryptionService) {
819         this.encryptionService = encryptionService;
820     }
821 
822     @Override
823     protected DataObjectService getDataObjectService() {
824         if (dataObjectService == null) {
825             dataObjectService = KRADServiceLocator.getDataObjectService();
826         }
827         return dataObjectService;
828     }
829 
830     protected MaintenanceDocumentService getMaintenanceDocumentService() {
831         if (maintenanceDocumentService == null) {
832             maintenanceDocumentService = KRADServiceLocatorWeb.getMaintenanceDocumentService();
833         }
834         return maintenanceDocumentService;
835     }
836 
837     public void setMaintenanceDocumentService(MaintenanceDocumentService maintenanceDocumentService) {
838         this.maintenanceDocumentService = maintenanceDocumentService;
839     }
840 
841     public KualiRuleService getKualiRuleService() {
842         if (kualiRuleService == null) {
843             kualiRuleService = KRADServiceLocatorWeb.getKualiRuleService();
844         }
845         return kualiRuleService;
846     }
847 
848     public void setKualiRuleService(KualiRuleService kualiRuleService) {
849         this.kualiRuleService = kualiRuleService;
850     }
851 
852     @Override
853     public Object getPersistableBusinessObject() {
854         return getDataObject();
855     }
856 
857     /**
858      *  Added by 'Sheik Salahudeen' for fixing the active flag issue while copying document.
859      */
860     public static void setPropertyValue(Object object, String propertyPath, Object propertyValue) {
861         if (ProcessLogger.isTraceActive() && object != null) {
862             // May be uncommented for debugging high execution count
863             // ProcessLogger.ntrace(object.getClass().getSimpleName() + ":w:" + propertyPath + ":", "", 1000);
864             ProcessLogger.countBegin("bean-property-write");
865         }
866 
867         try {
868             OLEObjectPropertyReference.setWarning(true);
869 
870             OLEObjectPropertyReference.resolvePath(object, object.getClass(), propertyPath, true).set(propertyValue);
871 
872         } catch (RuntimeException e) {
873             throw new IllegalArgumentException(
874                     "Error setting property '" + propertyPath + "' on " + object + " with " + propertyValue, e);
875         } finally {
876             OLEObjectPropertyReference.setWarning(false);
877 
878             if (ProcessLogger.isTraceActive() && object != null) {
879                 ProcessLogger.countEnd("bean-property-write", object.getClass().getSimpleName() + ":" + propertyPath);
880             }
881         }
882 
883     }
884 
885 }
886