001/*
002 * Copyright 2007 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.coa.document;
017
018import java.security.GeneralSecurityException;
019import java.sql.Date;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.commons.lang.StringUtils;
024import org.kuali.ole.coa.businessobject.AccountDelegate;
025import org.kuali.ole.coa.businessobject.AccountDelegateGlobal;
026import org.kuali.ole.coa.service.AccountDelegateService;
027import org.kuali.ole.sys.OLEConstants;
028import org.kuali.ole.sys.context.SpringContext;
029import org.kuali.ole.sys.document.FinancialSystemMaintainable;
030import org.kuali.rice.core.api.datetime.DateTimeService;
031import org.kuali.rice.core.api.encryption.EncryptionService;
032import org.kuali.rice.kns.document.MaintenanceDocument;
033import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
034import org.kuali.rice.kns.service.DataDictionaryService;
035import org.kuali.rice.krad.maintenance.MaintenanceLock;
036import org.kuali.rice.krad.util.ObjectUtils;
037
038/**
039 * This class is a special implementation of Maintainable specifically for Account Delegates. It was created to correctly update the
040 * default Start Date on edits and copies, ala JIRA #KULRNE-62.
041 */
042public class AccountDelegateMaintainableImpl extends FinancialSystemMaintainable {
043    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountDelegateMaintainableImpl.class);
044
045    /**
046     * This method will reset AccountDelegate's Start Date to the current timestamp on edits and copies
047     * 
048     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#processAfterRetrieve()
049     */
050    @Override
051    public void processAfterCopy( MaintenanceDocument document, Map<String,String[]> parameters ) {
052        this.setStartDateDefault();
053        super.processAfterCopy( document, parameters );
054    }
055
056    /**
057     * This method will reset AccountDelegate's Start Date to the current timestamp on edits and copies
058     * 
059     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#processAfterEdit()
060     */
061    @Override
062    public void processAfterEdit( MaintenanceDocument document, Map<String,String[]> parameters ) {
063        this.setStartDateDefault();
064        super.processAfterEdit( document, parameters );
065    }
066
067    /**
068     * This method sets the start date on {@link Delegate} BO
069     */
070    protected void setStartDateDefault() {
071        if (this.businessObject != null && this.businessObject instanceof AccountDelegate) {
072            AccountDelegate delegate = (AccountDelegate) this.businessObject;
073            delegate.setAccountDelegateStartDate(new Date(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime()));
074        }
075    }
076
077    /**
078     * Generates the appropriate maintenance locks for the {@link Delegate}
079     * 
080     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#generateMaintenanceLocks()
081     */
082    @Override
083    public List<MaintenanceLock> generateMaintenanceLocks() {
084        AccountDelegate delegate = (AccountDelegate) this.businessObject;
085        List<MaintenanceLock> locks = super.generateMaintenanceLocks();
086        if (delegate.isAccountsDelegatePrmrtIndicator()) {
087            locks.add(createMaintenanceLock(new String[] { "chartOfAccountsCode", "accountNumber", "financialDocumentTypeCode", "accountsDelegatePrmrtIndicator" }));
088        }
089        return locks;
090    }
091
092    @Override
093    public String getLockingDocumentId() {
094       String lock = super.getLockingDocumentId();
095       if (StringUtils.isNotBlank(lock))
096           return lock;
097       else {
098           AccountDelegateService accountDelegateService = SpringContext.getBean(AccountDelegateService.class);
099           lock = accountDelegateService.getLockingDocumentId(this, getDocumentNumber());
100           return lock;
101       }
102    }
103    
104    /**
105     * This method creates a maintenance lock for the field names supplied
106     * 
107     * @param fieldNames
108     * @return the maintenance lock for supplied field names
109     */
110    protected MaintenanceLock createMaintenanceLock(String[] fieldNames) {
111        MaintenanceLock lock = new MaintenanceLock();
112        lock.setDocumentNumber(getDocumentNumber());
113        lock.setLockingRepresentation(createLockingRepresentation(fieldNames));
114        return lock;
115
116    }
117
118    /**
119     * This method create a locking representation for the field names supplied
120     * 
121     * @param fieldNames
122     * @return locking representation string
123     */
124    protected String createLockingRepresentation(String[] fieldNames) {
125        StringBuilder lockRepresentation = new StringBuilder();
126
127        lockRepresentation.append(AccountDelegate.class.getName());
128        lockRepresentation.append(OLEConstants.Maintenance.AFTER_CLASS_DELIM);
129
130        DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class); 
131        EncryptionService encryptionService = SpringContext.getBean(EncryptionService.class); 
132
133        int count = 0;
134        for (String fieldName : fieldNames) {
135            lockRepresentation.append(fieldName);
136            lockRepresentation.append(OLEConstants.Maintenance.AFTER_FIELDNAME_DELIM);
137            lockRepresentation.append(retrieveFieldValueForLock(fieldName, dataDictionaryService, encryptionService));
138            if (count < (fieldNames.length - 1)) {
139                lockRepresentation.append(OLEConstants.Maintenance.AFTER_VALUE_DELIM);
140            }
141            count += 1;
142        }
143
144
145        return lockRepresentation.toString();
146    }
147
148    /**
149     * This method returns the field value of a given field, converting the value to a String and encrypting it if necessary
150     * 
151     * @param fieldName
152     * @param ddService
153     * @return string field value for a lock
154     */
155    protected String retrieveFieldValueForLock(String fieldName, DataDictionaryService ddService, EncryptionService encryptionService) {
156        Object fieldValue = ObjectUtils.getPropertyValue(this.businessObject, fieldName);
157        if (fieldValue == null) {
158            fieldValue = "";
159        }
160
161        // check if field is a secure
162        if (SpringContext.getBean(BusinessObjectAuthorizationService.class).attributeValueNeedsToBeEncryptedOnFormsAndLinks(getBoClass(), fieldName)) {
163            try {
164                fieldValue = encryptionService.encrypt(fieldValue);
165            }
166            catch (GeneralSecurityException e) {
167                LOG.error("Unable to encrypt secure field for locking representation " + e.getMessage());
168                throw new RuntimeException("Unable to encrypt secure field for locking representation " + e.getMessage());
169            }
170        }
171        return String.valueOf(fieldValue);
172    }
173    
174    /**
175     * This method created a MaintenanceLock for the chartOfAccountsCode and accountNumber for an AccountDelegateGlobal.
176     *
177     * @return the MainenanceLock
178     */
179    
180    public MaintenanceLock createGlobalAccountLock() {
181        
182        String[] fields = {"chartOfAccountsCode", "accountNumber"};
183        MaintenanceLock lock = new MaintenanceLock();
184        lock.setDocumentNumber(getDocumentNumber());
185        
186        StringBuilder lockRepresentation = new StringBuilder();
187
188        lockRepresentation.append(AccountDelegateGlobal.class.getName());
189        lockRepresentation.append(OLEConstants.Maintenance.AFTER_CLASS_DELIM);
190
191        DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class); 
192        EncryptionService encryptionService = SpringContext.getBean(EncryptionService.class); 
193        
194        int count = 0;
195        for (String fieldName : fields) {
196            lockRepresentation.append(fieldName);
197            lockRepresentation.append(OLEConstants.Maintenance.AFTER_FIELDNAME_DELIM);
198            lockRepresentation.append(retrieveFieldValueForLock(fieldName, dataDictionaryService, encryptionService));
199            if (count < (fields.length - 1)) {
200                lockRepresentation.append(OLEConstants.Maintenance.AFTER_VALUE_DELIM);
201            }
202            count += 1;
203        }
204
205        lock.setLockingRepresentation(lockRepresentation.toString());
206        
207        return lock;
208    }
209
210    /**
211     * Overridden so that after account delegate is saved, it updates the proper account delegate role
212     * Defers saving to a service to guarantee that the delegate saves in a separate transaction
213     * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#saveBusinessObject()
214     */
215    @Override
216    public void saveBusinessObject() {
217        final AccountDelegate accountDelegate = (AccountDelegate)getBusinessObject();
218        final AccountDelegateService accountDelegateService = SpringContext.getBean(AccountDelegateService.class);
219        
220        accountDelegateService.saveForMaintenanceDocument(accountDelegate);
221        
222        accountDelegateService.updateDelegationRole();
223    }
224
225    
226}