001/*
002 * Copyright 2008 The Kuali Foundation
003 * 
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 * http://www.opensource.org/licenses/ecl2.php
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.ole.module.purap.document;
017
018import org.kuali.ole.module.purap.businessobject.ReceivingAddress;
019import org.kuali.ole.module.purap.document.service.ReceivingAddressService;
020import org.kuali.ole.sys.OLEConstants;
021import org.kuali.ole.sys.context.SpringContext;
022import org.kuali.ole.sys.document.FinancialSystemMaintainable;
023import org.kuali.rice.core.api.encryption.EncryptionService;
024import org.kuali.rice.kew.api.WorkflowDocument;
025import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
026import org.kuali.rice.kns.service.DataDictionaryService;
027import org.kuali.rice.krad.bo.DocumentHeader;
028import org.kuali.rice.krad.maintenance.MaintenanceLock;
029import org.kuali.rice.krad.service.BusinessObjectService;
030import org.kuali.rice.krad.util.ObjectUtils;
031
032import java.security.GeneralSecurityException;
033import java.util.Collection;
034import java.util.List;
035
036/**
037 * ReceivingAddressMaintainableImpl is a special implementation of FinancialSystemMaintainable for ReceivingAddresss.
038 * It generates extra locks for other receiving addresses related to the one being updated in the maintenance document,
039 * and updates the ones affected during post-processing to enforce certain contraints among these objects.
040 */
041public class ReceivingAddressMaintainableImpl extends FinancialSystemMaintainable {
042    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ReceivingAddressMaintainableImpl.class);
043
044    /**
045     * Generates the appropriate maintenance locks for {@link ReceivingAddress}
046     *
047     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#generateMaintenanceLocks()
048     */
049    @Override
050    public List<MaintenanceLock> generateMaintenanceLocks() {
051        ReceivingAddress receivingAddress = (ReceivingAddress) this.businessObject;
052        List<MaintenanceLock> locks = super.generateMaintenanceLocks();
053        if (receivingAddress.isDefaultIndicator() && receivingAddress.isActive()) {
054            locks.add(createMaintenanceLock(new String[]{"chartOfAccountsCode", "organizationCode", "defaultIndicator", "active"}));
055        }
056        return locks;
057    }
058
059    /**
060     * Creates a maintenance lock for the field names supplied.
061     *
062     * @param fieldNames
063     * @return the maintenance lock for supplied field names
064     */
065    private MaintenanceLock createMaintenanceLock(String[] fieldNames) {
066        MaintenanceLock lock = new MaintenanceLock();
067        lock.setDocumentNumber(getDocumentNumber());
068        lock.setLockingRepresentation(createLockingRepresentation(fieldNames));
069        return lock;
070    }
071
072    /**
073     * Creates a locking representation for the field names supplied.
074     *
075     * @param fieldNames
076     * @return locking representation string
077     */
078    private String createLockingRepresentation(String[] fieldNames) {
079        StringBuilder lockRepresentation = new StringBuilder();
080
081        lockRepresentation.append(ReceivingAddress.class.getName());
082        lockRepresentation.append(OLEConstants.Maintenance.AFTER_CLASS_DELIM);
083
084        DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class);
085        EncryptionService encryptionService = SpringContext.getBean(EncryptionService.class);
086
087        int count = 0;
088        for (String fieldName : fieldNames) {
089            lockRepresentation.append(fieldName);
090            lockRepresentation.append(OLEConstants.Maintenance.AFTER_FIELDNAME_DELIM);
091            lockRepresentation.append(retrieveFieldValueForLock(fieldName, dataDictionaryService, encryptionService));
092            if (count < (fieldNames.length - 1)) {
093                lockRepresentation.append(OLEConstants.Maintenance.AFTER_VALUE_DELIM);
094            }
095            count += 1;
096        }
097
098        return lockRepresentation.toString();
099    }
100
101    /**
102     * Returns the field value of a given field, converting the value to a String and encrypting it if necessary.
103     *
104     * @param fieldName
105     * @param ddService
106     * @return string field value for a lock
107     */
108    private String retrieveFieldValueForLock(String fieldName, DataDictionaryService ddService, EncryptionService encryptionService) {
109        Object fieldValue = ObjectUtils.getPropertyValue(this.businessObject, fieldName);
110        if (fieldValue == null) {
111            fieldValue = "";
112        }
113
114        // check if field is a secure
115        if (SpringContext.getBean(BusinessObjectAuthorizationService.class).attributeValueNeedsToBeEncryptedOnFormsAndLinks(getBoClass(), fieldName)) {
116            try {
117                fieldValue = encryptionService.encrypt(fieldValue);
118            } catch (GeneralSecurityException e) {
119                LOG.error("Unable to encrypt secure field for locking representation " + e.getMessage());
120                throw new RuntimeException("Unable to encrypt secure field for locking representation " + e.getMessage());
121            }
122        }
123        return String.valueOf(fieldValue);
124    }
125
126    /**
127     * Checks if there's any active receiving address set to default other than this one;
128     * if so, set them to non-default.
129     *
130     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#doRouteStatusChange(org.kuali.rice.krad.bo.DocumentHeader)
131     */
132    @Override
133    public void doRouteStatusChange(DocumentHeader header) {
134        super.doRouteStatusChange(header);
135
136        ReceivingAddress ra = (ReceivingAddress) getBusinessObject();
137        // proceed only if this bo is active and default.
138        if (!ra.isActive() || !ra.isDefaultIndicator())
139            return;
140
141        WorkflowDocument workflowDoc = header.getWorkflowDocument();
142        // this code is only executed when the final approval occurs
143        if (workflowDoc.isProcessed()) {
144            /*
145            Map criteria = new HashMap();
146            criteria.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, ra.getChartOfAccountsCode());
147            criteria.put(OLEPropertyConstants.ORGANIZATION_CODE, ra.getOrganizationCode());
148            criteria.put(PurapPropertyConstants.RCVNG_ADDR_DFLT_IND, true);        
149            criteria.put(PurapPropertyConstants.RCVNG_ADDR_ACTIVE, true);        
150            List<ReceivingAddress> addresses = (List)SpringContext.getBean(BusinessObjectService.class).findMatching(ReceivingAddress.class, criteria);
151            */
152            Collection<ReceivingAddress> addresses = SpringContext.getBean(ReceivingAddressService.class).findDefaultByChartOrg(ra.getChartOfAccountsCode(), ra.getOrganizationCode());
153            for (ReceivingAddress rai : addresses) {
154                if (!rai.getReceivingAddressIdentifier().equals(ra.getReceivingAddressIdentifier())) {
155                    rai.setDefaultIndicator(false);
156                    SpringContext.getBean(BusinessObjectService.class).save(rai);
157                }
158            }
159        }
160    }
161
162}