/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.gl.businessobject.inquiry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.gl.Constant;
import org.kuali.kfs.gl.businessobject.AccountBalance;
import org.kuali.kfs.gl.businessobject.lookup.BusinessObjectFieldConverter;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.inquiry.KfsInquirableImpl;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.kew.api.doctype.DocumentType;
import org.kuali.rice.kew.api.doctype.DocumentTypeService;
import org.kuali.rice.kew.doctype.bo.DocumentTypeEBO;
import org.kuali.rice.kns.lookup.HtmlData;
import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
import org.kuali.rice.kns.lookup.LookupUtils;
import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.krad.bo.BusinessObject;
import org.kuali.rice.krad.datadictionary.AttributeDefinition;
import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase;
import org.kuali.rice.krad.service.PersistenceStructureService;
import org.kuali.rice.krad.util.KRADConstants;
import org.kuali.rice.krad.util.ObjectUtils;
import org.kuali.rice.krad.util.UrlFactory;
/**
* This class is the template class for the customized inqurable implementations used to generate balance inquiry screens.
*/
public abstract class AbstractGeneralLedgerInquirableImpl extends KfsInquirableImpl {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerInquirableImpl.class);
private BusinessObject businessObject;
/**
* @see org.kuali.kfs.sys.businessobject.inquiry.KfsInquirableImpl#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String, boolean)
*/
@Override
public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) {
return this.getInquiryUrl(businessObject, attributeName);
}
/**
* Helper method to build an inquiry url for a result field.
*
* @param businessObject the business object instance to build the urls for
* @param attributeName the attribute name which links to an inquirable
* @return String url to inquiry
*/
public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName) {
this.setBusinessObject(businessObject);
AnchorHtmlData inquiryHref = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
BusinessObjectDictionaryService businessDictionary = SpringContext.getBean(BusinessObjectDictionaryService.class);
PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
String baseUrl = KFSConstants.INQUIRY_ACTION;
Properties parameters = new Properties();
parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
Object attributeValue = null;
Class inquiryBusinessObjectClass = null;
String attributeRefName = "";
boolean isPkReference = false;
Map userDefinedAttributeMap = getUserDefinedAttributeMap();
boolean isUserDefinedAttribute = userDefinedAttributeMap == null ? false : userDefinedAttributeMap.containsKey(attributeName);
// determine the type of the given attribute: user-defined, regular, nested-referenced or primitive reference
if (isUserDefinedAttribute) {
attributeName = getAttributeName(attributeName);
inquiryBusinessObjectClass = getInquiryBusinessObjectClass(attributeName);
isPkReference = true;
}
else if (attributeName.equals(businessDictionary.getTitleAttribute(businessObject.getClass()))) {
inquiryBusinessObjectClass = businessObject.getClass();
isPkReference = true;
}
else if (ObjectUtils.isNestedAttribute(attributeName)) {
if (!"financialObject.financialObjectType.financialReportingSortCode".equals(attributeName)) {
inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName);
}
else {
return inquiryHref;
}
}
else {
Map primitiveReference = LookupUtils.getPrimitiveReference(businessObject, attributeName);
if (primitiveReference != null && !primitiveReference.isEmpty()) {
attributeRefName = (String) primitiveReference.keySet().iterator().next();
inquiryBusinessObjectClass = (Class) primitiveReference.get(attributeRefName);
}
attributeValue = ObjectUtils.getPropertyValue(businessObject, attributeName);
attributeValue = (attributeValue == null) ? "" : attributeValue.toString();
}
// process the business object class if the attribute name is not user-defined
if (!isUserDefinedAttribute) {
if (isExclusiveField(attributeName, attributeValue)) {
return inquiryHref;
}
if (inquiryBusinessObjectClass == null || businessDictionary.isInquirable(inquiryBusinessObjectClass) == null || !businessDictionary.isInquirable(inquiryBusinessObjectClass).booleanValue()) {
return inquiryHref;
}
}
parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, inquiryBusinessObjectClass.getName());
List keys = new ArrayList();
Map<String,String> inquiryFields = new HashMap<String, String>();
if (isUserDefinedAttribute) {
baseUrl = getBaseUrl();
keys = buildUserDefinedAttributeKeyList();
parameters.put(KFSConstants.RETURN_LOCATION_PARAMETER, Constant.RETURN_LOCATION_VALUE);
parameters.put(KFSConstants.GL_BALANCE_INQUIRY_FLAG, "true");
parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD);
parameters.put(KFSConstants.DOC_FORM_KEY, "88888888");
// add more customized parameters into the current parameter map
addMoreParameters(parameters, attributeName);
}
else if (persistenceStructureService.isPersistable(inquiryBusinessObjectClass)) {
keys = persistenceStructureService.listPrimaryKeyFieldNames(inquiryBusinessObjectClass);
}
// build key value url parameters used to retrieve the business object
if (keys != null) {
for (Iterator keyIterator = keys.iterator(); keyIterator.hasNext();) {
String keyName = (String) keyIterator.next();
// convert the key names based on their formats and types
String keyConversion = keyName;
if (ObjectUtils.isNestedAttribute(attributeName)) {
if (isUserDefinedAttribute) {
keyConversion = keyName;
}
else {
keyConversion = ObjectUtils.getNestedAttributePrefix(attributeName) + "." + keyName;
}
}
else {
if (isPkReference) {
keyConversion = keyName;
}
else {
keyConversion = persistenceStructureService.getForeignKeyFieldName(businessObject.getClass(), attributeRefName, keyName);
}
}
Object keyValue = ObjectUtils.getPropertyValue(businessObject, keyConversion);
keyValue = (keyValue == null) ? "" : keyValue.toString();
// convert the key value and name into the given ones
Object tempKeyValue = this.getKeyValue(keyName, keyValue);
keyValue = tempKeyValue == null ? keyValue : tempKeyValue;
String tempKeyName = this.getKeyName(keyName);
keyName = tempKeyName == null ? keyName : tempKeyName;
// add the key-value pair into the parameter map
if (keyName != null){
parameters.put(keyName, keyValue);
inquiryFields.put(keyName, keyValue.toString());
}
}
}
// Hack to make this work. I don't know why it doesn't pick up the whole primary key for these. The last big change to
// KualiInquirableImpl
// broke all of this
if (businessObject instanceof AccountBalance) {
AccountBalance ab = (AccountBalance) businessObject;
if ("financialObject.financialObjectLevel.financialConsolidationObject.finConsolidationObjectCode".equals(attributeName)) {
parameters.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode());
}
else if ("financialObject.financialObjectLevel.financialObjectLevelCode".equals(attributeName)) {
parameters.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode());
}
}
return getHyperLink(inquiryBusinessObjectClass, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters));
}
/**
* This method builds the inquiry url for user-defined attribute
*
* @return a List of attribute keys for the inquiry url
*/
protected abstract List buildUserDefinedAttributeKeyList();
/**
* This method defines the user-defined attribute map
*
* @return the user-defined attribute map
*/
protected abstract Map getUserDefinedAttributeMap();
/**
* This method finds the matching attribute name of given one
*
* @param attributeName the given attribute name
* @return the attribute name from the given one
*/
protected abstract String getAttributeName(String attributeName);
/**
* This method finds the matching the key value of the given one
*
* @param keyName the given key name
* @param keyValue the given key value
* @return the key value from the given key value
*/
protected abstract Object getKeyValue(String keyName, Object keyValue);
/**
* This method finds the matching the key name of the given one
*
* @param keyName the given key name
* @return the key value from the given key name
*/
protected abstract String getKeyName(String keyName);
/**
* This method defines the lookupable implementation attribute name
*
* @return the lookupable implementation attribute name
*/
protected abstract String getLookupableImplAttributeName();
/**
* This method defines the base inquiry url
*
* @return the base inquiry url
*/
protected abstract String getBaseUrl();
/**
* This method gets the class name of the inquiry business object for a given attribute.
*
* @return the class name of the inquiry business object for a given attribute
*/
protected abstract Class getInquiryBusinessObjectClass(String attributeName);
/**
* This method adds more parameters into the curren parameter map
*
* @param parameter the current parameter map
*/
protected abstract void addMoreParameters(Properties parameter, String attributeName);
/**
* This method determines whether the input name-value pair is exclusive from the processing
*
* @param keyName the name of the name-value pair
* @param keyValue the value of the name-value pair
* @return true if the input key is in the exclusive list; otherwise, false
*/
protected boolean isExclusiveField(Object keyName, Object keyValue) {
if (keyName != null && keyValue != null) {
String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString());
if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) {
return true;
}
else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) {
return true;
}
else if (convertedKeyName.equals(KFSPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) {
return true;
}
if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(KFSConstants.getDashSubAccountNumber())) {
return true;
}
else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(KFSConstants.getDashFinancialSubObjectCode())) {
return true;
}
else if (convertedKeyName.equals(KFSPropertyConstants.PROJECT_CODE) && keyValue.equals(KFSConstants.getDashProjectCode())) {
return true;
}
}
return false;
}
/**
* This method recovers the values of the given keys
*
* @param fieldValues unconsolidated values
* @param keyName a key name that may be in the fieldValues map
* @param keyValue a key value that may be in the fieldValues map
* @return the original value for a previously consolidated value
*/
protected String recoverFieldValueFromConsolidation(Map fieldValues, Object keyName, Object keyValue) {
if (fieldValues == null || keyName == null || keyValue == null) {
return Constant.EMPTY_STRING;
}
Map convertedFieldValues = BusinessObjectFieldConverter.convertFromTransactionFieldValues(fieldValues);
String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString());
if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) {
return this.getValueFromFieldValues(convertedFieldValues, keyName);
}
else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) {
return this.getValueFromFieldValues(convertedFieldValues, keyName);
}
else if (convertedKeyName.equals(KFSPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) {
return this.getValueFromFieldValues(convertedFieldValues, keyName);
}
return Constant.EMPTY_STRING;
}
/**
* Utility method to get the value of the given key from the field values
*
* @param fieldValues a Map of key values
* @param keyName the name of the key to retrieve the value from
* @return the value for the key, or, if not found, an empty String
*/
private String getValueFromFieldValues(Map fieldValues, Object keyName) {
String keyValue = Constant.EMPTY_STRING;
if (fieldValues.containsKey(keyName)) {
keyValue = (String) fieldValues.get(keyName);
}
return keyValue;
}
/**
* This takes a map of field values and then returns it without processing it, making this a sort
* of identity method for Maps
*
* @param fieldValues field values to return to the user
* @return the Map you sent in as a parameter
*/
public Map getFieldValues(Map fieldValues) {
return fieldValues;
}
/**
* Given the nested name of an attribute in an object, returns the class that attribute will return
*
* @param businessObject the business object to find the propery class for
* @param attributeName the nested name of the attribute to find the class for
* @return the class of the nested attribute
*/
public Class getNestedInquiryBusinessObjectClass(BusinessObject businessObject, String attributeName) {
// TODO: not finished
Class inquiryBusinessObjectClass = null;
String entryName = businessObject.getClass().getName();
if (LOG.isDebugEnabled()) {
LOG.debug("businessObject: " + entryName);
LOG.debug("attributeName: " + attributeName);
}
DataDictionaryService dataDictionary = SpringContext.getBean(DataDictionaryService.class);
AttributeDefinition attributeDefinition = null;
if (StringUtils.isBlank(attributeName)) {
throw new IllegalArgumentException("invalid (blank) attributeName");
}
DataDictionaryEntryBase entry = (DataDictionaryEntryBase) dataDictionary.getDataDictionary().getDictionaryObjectEntry(entryName);
if (entry != null) {
attributeDefinition = entry.getAttributeDefinition(attributeName);
inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName);
}
// TODO: need to get class for which this property belongs
// if (attributeDefinition instanceof AttributeReferenceDefinition) {
// AttributeReferenceDefinition attributeReferenceDefinition = (AttributeReferenceDefinition) attributeDefinition;
// LOG.debug("Source Classname = " + attributeReferenceDefinition.getSourceClassName());
// LOG.debug("Source Attribute = " + attributeReferenceDefinition.getSourceAttributeName());
//
// try {
// inquiryBusinessObjectClass = Class.forName(attributeReferenceDefinition.getSourceClassName());
// }
// catch (Exception e) {
// throw new IllegalArgumentException("fail to construct a Class");
// }
// }
return inquiryBusinessObjectClass;
}
/**
* Builds URL to document type inquiry based on a given document type code
*
* @param docTypeCode - document type code to inquiry on
* @return {@link HtmlData} representing inquiry URL
*/
protected HtmlData getDocTypeInquiryUrl(String docTypeCode) {
DocumentType docTypeDTO = SpringContext.getBean(DocumentTypeService.class).getDocumentTypeByName(docTypeCode);
if ( docTypeDTO == null ) {
return new AnchorHtmlData();
}
String baseUrl = KFSConstants.INQUIRY_ACTION;
Properties parameters = new Properties();
parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, DocumentTypeEBO.class.getName());
parameters.put(KFSConstants.DOC_FORM_KEY, "88888888");
parameters.put(KFSPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getId().toString());
Map<String, String> inquiryFields = new HashMap<String, String>();
inquiryFields.put(KFSPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getId().toString());
return getHyperLink(DocumentTypeEBO.class, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters));
}
/**
* Gets the businessObject attribute.
* @return Returns the businessObject.
*/
public BusinessObject getBusinessObject() {
return businessObject;
}
/**
* Sets the businessObject attribute value.
* @param businessObject The businessObject to set.
*/
public void setBusinessObject(BusinessObject businessObject) {
this.businessObject = businessObject;
}
}