001package org.kuali.rice.krad.maintenance;
002
003import java.io.Serializable;
004import java.security.GeneralSecurityException;
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.Iterator;
008import java.util.List;
009import java.util.Map;
010
011import org.apache.commons.collections.CollectionUtils;
012import org.apache.commons.collections.MapUtils;
013import org.apache.commons.lang.StringUtils;
014import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
015import org.kuali.ole.olekrad.util.OLEObjectPropertyReference;
016import org.kuali.rice.core.api.CoreApiServiceLocator;
017import org.kuali.rice.core.api.encryption.EncryptionService;
018import org.kuali.rice.kim.api.identity.Person;
019import org.kuali.rice.krad.bo.AdHocRoutePerson;
020import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
021import org.kuali.rice.krad.bo.BusinessObject;
022import org.kuali.rice.krad.bo.DocumentHeader;
023import org.kuali.rice.krad.bo.Note;
024import org.kuali.rice.krad.data.CompoundKey;
025import org.kuali.rice.krad.data.DataObjectService;
026import org.kuali.rice.krad.data.DataObjectWrapper;
027import org.kuali.rice.krad.exception.PessimisticLockingException;
028import org.kuali.rice.krad.rules.rule.event.AddCollectionLineEvent;
029import org.kuali.rice.krad.service.DataObjectAuthorizationService;
030import org.kuali.rice.krad.service.DocumentDictionaryService;
031import org.kuali.rice.krad.service.KRADServiceLocator;
032import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
033import org.kuali.rice.krad.service.KualiRuleService;
034import org.kuali.rice.krad.service.LegacyDataAdapter;
035import org.kuali.rice.krad.service.MaintenanceDocumentService;
036import org.kuali.rice.krad.uif.UifConstants;
037import org.kuali.rice.krad.uif.component.BindingInfo;
038import org.kuali.rice.krad.uif.container.CollectionGroup;
039import org.kuali.rice.krad.uif.field.DataField;
040import org.kuali.rice.krad.uif.field.InputField;
041import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
042import org.kuali.rice.krad.uif.service.ViewHelperService;
043import org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl;
044import org.kuali.rice.krad.uif.util.LifecycleElement;
045import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
046import org.kuali.rice.krad.uif.util.ProcessLogger;
047import org.kuali.rice.krad.uif.view.MaintenanceDocumentView;
048import org.kuali.rice.krad.uif.view.View;
049import org.kuali.rice.krad.uif.view.ViewModel;
050import org.kuali.rice.krad.util.KRADConstants;
051import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
052
053/**
054 * Created by sheiksalahudeenm on 10/23/14.
055 *
056 * Overridden for fixing the active flag issue while copying document.
057 * Modified method name: clearUnauthorizedField.
058 * Newly added method name: setPropertyValue.
059 * Changes description : Passing the property value to OLEObjectPropertyReference.resolvePath(..) method to fix the active flag issue.
060 */
061public class MaintainableImpl extends ViewHelperServiceImpl implements Maintainable {
062    private static final long serialVersionUID = 9125271369161634992L;
063    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintainableImpl.class);
064
065    private String documentNumber;
066    private Object dataObject;
067    private Class<?> dataObjectClass;
068    private String maintenanceAction;
069
070    private transient LegacyDataAdapter legacyDataAdapter;
071    private transient DataObjectAuthorizationService dataObjectAuthorizationService;
072    private transient DocumentDictionaryService documentDictionaryService;
073    private transient EncryptionService encryptionService;
074    private transient DataObjectService dataObjectService;
075    private transient MaintenanceDocumentService maintenanceDocumentService;
076    private transient KualiRuleService kualiRuleService;
077
078    /**
079     * @see org.kuali.rice.krad.maintenance.Maintainable#retrieveObjectForEditOrCopy(MaintenanceDocument, java.util.Map)
080     */
081    @Override
082    public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
083        Object dataObject = null;
084        if ( getDataObjectService().supports(getDataObjectClass())) {
085            dataObject = getDataObjectService().find(getDataObjectClass(), new CompoundKey(dataObjectKeys));
086        } else {
087            try {
088                dataObject = getLegacyDataAdapter().findObjectBySearch(getDataObjectClass(), dataObjectKeys);
089            } catch (Exception ex) {
090                if ( ex.getClass().equals( LegacyDataAdapter.CLASS_NOT_PERSISTABLE_OJB_EXCEPTION_CLASS )
091                        && !document.getOldMaintainableObject().isExternalBusinessObject()) {
092                    throw new RuntimeException("Data Object Class: "
093                            + getDataObjectClass()
094                            + " is not persistable and is not externalizable - configuration error");
095                }
096                // otherwise, let fall through
097            }
098        }
099
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