001/* 002 * Copyright 2006 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.gl.businessobject.inquiry; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.Iterator; 021import java.util.List; 022import java.util.Map; 023import java.util.Properties; 024 025import org.apache.commons.lang.StringUtils; 026import org.kuali.ole.gl.Constant; 027import org.kuali.ole.gl.businessobject.AccountBalance; 028import org.kuali.ole.gl.businessobject.lookup.BusinessObjectFieldConverter; 029import org.kuali.ole.sys.OLEConstants; 030import org.kuali.ole.sys.OLEPropertyConstants; 031import org.kuali.ole.sys.businessobject.inquiry.KfsInquirableImpl; 032import org.kuali.ole.sys.context.SpringContext; 033import org.kuali.rice.kew.api.doctype.DocumentType; 034import org.kuali.rice.kew.api.doctype.DocumentTypeService; 035import org.kuali.rice.kew.doctype.bo.DocumentTypeEBO; 036import org.kuali.rice.kns.lookup.HtmlData; 037import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData; 038import org.kuali.rice.kns.lookup.LookupUtils; 039import org.kuali.rice.kns.service.BusinessObjectDictionaryService; 040import org.kuali.rice.kns.service.DataDictionaryService; 041import org.kuali.rice.krad.bo.BusinessObject; 042import org.kuali.rice.krad.datadictionary.AttributeDefinition; 043import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase; 044import org.kuali.rice.krad.service.PersistenceStructureService; 045import org.kuali.rice.krad.util.KRADConstants; 046import org.kuali.rice.krad.util.ObjectUtils; 047import org.kuali.rice.krad.util.UrlFactory; 048 049/** 050 * This class is the template class for the customized inqurable implementations used to generate balance inquiry screens. 051 */ 052public abstract class AbstractGeneralLedgerInquirableImpl extends KfsInquirableImpl { 053 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerInquirableImpl.class); 054 055 private BusinessObject businessObject; 056 057 /** 058 * @see org.kuali.ole.sys.businessobject.inquiry.KfsInquirableImpl#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String, boolean) 059 */ 060 @Override 061 public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) { 062 return this.getInquiryUrl(businessObject, attributeName); 063 } 064 065 /** 066 * Helper method to build an inquiry url for a result field. 067 * 068 * @param businessObject the business object instance to build the urls for 069 * @param attributeName the attribute name which links to an inquirable 070 * @return String url to inquiry 071 */ 072 public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName) { 073 this.setBusinessObject(businessObject); 074 AnchorHtmlData inquiryHref = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING); 075 BusinessObjectDictionaryService businessDictionary = SpringContext.getBean(BusinessObjectDictionaryService.class); 076 PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class); 077 078 String baseUrl = OLEConstants.INQUIRY_ACTION; 079 Properties parameters = new Properties(); 080 parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.START_METHOD); 081 082 Object attributeValue = null; 083 Class inquiryBusinessObjectClass = null; 084 String attributeRefName = ""; 085 boolean isPkReference = false; 086 087 Map userDefinedAttributeMap = getUserDefinedAttributeMap(); 088 boolean isUserDefinedAttribute = userDefinedAttributeMap == null ? false : userDefinedAttributeMap.containsKey(attributeName); 089 090 // determine the type of the given attribute: user-defined, regular, nested-referenced or primitive reference 091 if (isUserDefinedAttribute) { 092 attributeName = getAttributeName(attributeName); 093 inquiryBusinessObjectClass = getInquiryBusinessObjectClass(attributeName); 094 isPkReference = true; 095 } 096 else if (attributeName.equals(businessDictionary.getTitleAttribute(businessObject.getClass()))) { 097 inquiryBusinessObjectClass = businessObject.getClass(); 098 isPkReference = true; 099 } 100 else if (ObjectUtils.isNestedAttribute(attributeName)) { 101 if (!"financialObject.financialObjectType.financialReportingSortCode".equals(attributeName)) { 102 inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName); 103 } 104 else { 105 return inquiryHref; 106 } 107 } 108 else { 109 Map primitiveReference = LookupUtils.getPrimitiveReference(businessObject, attributeName); 110 if (primitiveReference != null && !primitiveReference.isEmpty()) { 111 attributeRefName = (String) primitiveReference.keySet().iterator().next(); 112 inquiryBusinessObjectClass = (Class) primitiveReference.get(attributeRefName); 113 } 114 attributeValue = ObjectUtils.getPropertyValue(businessObject, attributeName); 115 attributeValue = (attributeValue == null) ? "" : attributeValue.toString(); 116 } 117 118 // process the business object class if the attribute name is not user-defined 119 if (!isUserDefinedAttribute) { 120 if (isExclusiveField(attributeName, attributeValue)) { 121 return inquiryHref; 122 } 123 124 if (inquiryBusinessObjectClass == null || businessDictionary.isInquirable(inquiryBusinessObjectClass) == null || !businessDictionary.isInquirable(inquiryBusinessObjectClass).booleanValue()) { 125 return inquiryHref; 126 } 127 } 128 parameters.put(OLEConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, inquiryBusinessObjectClass.getName()); 129 130 List keys = new ArrayList(); 131 Map<String,String> inquiryFields = new HashMap<String, String>(); 132 if (isUserDefinedAttribute) { 133 baseUrl = getBaseUrl(); 134 keys = buildUserDefinedAttributeKeyList(); 135 136 parameters.put(OLEConstants.RETURN_LOCATION_PARAMETER, Constant.RETURN_LOCATION_VALUE); 137 parameters.put(OLEConstants.GL_BALANCE_INQUIRY_FLAG, "true"); 138 parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.SEARCH_METHOD); 139 parameters.put(OLEConstants.DOC_FORM_KEY, "88888888"); 140 141 // add more customized parameters into the current parameter map 142 addMoreParameters(parameters, attributeName); 143 } 144 else if (persistenceStructureService.isPersistable(inquiryBusinessObjectClass)) { 145 keys = persistenceStructureService.listPrimaryKeyFieldNames(inquiryBusinessObjectClass); 146 } 147 148 // build key value url parameters used to retrieve the business object 149 if (keys != null) { 150 for (Iterator keyIterator = keys.iterator(); keyIterator.hasNext();) { 151 String keyName = (String) keyIterator.next(); 152 153 // convert the key names based on their formats and types 154 String keyConversion = keyName; 155 if (ObjectUtils.isNestedAttribute(attributeName)) { 156 if (isUserDefinedAttribute) { 157 keyConversion = keyName; 158 } 159 else { 160 keyConversion = ObjectUtils.getNestedAttributePrefix(attributeName) + "." + keyName; 161 } 162 } 163 else { 164 if (isPkReference) { 165 keyConversion = keyName; 166 } 167 else { 168 keyConversion = persistenceStructureService.getForeignKeyFieldName(businessObject.getClass(), attributeRefName, keyName); 169 } 170 } 171 172 Object keyValue = ObjectUtils.getPropertyValue(businessObject, keyConversion); 173 keyValue = (keyValue == null) ? "" : keyValue.toString(); 174 175 // convert the key value and name into the given ones 176 Object tempKeyValue = this.getKeyValue(keyName, keyValue); 177 keyValue = tempKeyValue == null ? keyValue : tempKeyValue; 178 179 String tempKeyName = this.getKeyName(keyName); 180 keyName = tempKeyName == null ? keyName : tempKeyName; 181 182 // add the key-value pair into the parameter map 183 if (keyName != null){ 184 parameters.put(keyName, keyValue); 185 inquiryFields.put(keyName, keyValue.toString()); 186 } 187 } 188 } 189 190 // 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 191 // KualiInquirableImpl 192 // broke all of this 193 if (businessObject instanceof AccountBalance) { 194 AccountBalance ab = (AccountBalance) businessObject; 195 if ("financialObject.financialObjectLevel.financialConsolidationObject.finConsolidationObjectCode".equals(attributeName)) { 196 parameters.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode()); 197 } 198 else if ("financialObject.financialObjectLevel.financialObjectLevelCode".equals(attributeName)) { 199 parameters.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode()); 200 } 201 } 202 203 return getHyperLink(inquiryBusinessObjectClass, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters)); 204 } 205 206 /** 207 * This method builds the inquiry url for user-defined attribute 208 * 209 * @return a List of attribute keys for the inquiry url 210 */ 211 protected abstract List buildUserDefinedAttributeKeyList(); 212 213 /** 214 * This method defines the user-defined attribute map 215 * 216 * @return the user-defined attribute map 217 */ 218 protected abstract Map getUserDefinedAttributeMap(); 219 220 /** 221 * This method finds the matching attribute name of given one 222 * 223 * @param attributeName the given attribute name 224 * @return the attribute name from the given one 225 */ 226 protected abstract String getAttributeName(String attributeName); 227 228 /** 229 * This method finds the matching the key value of the given one 230 * 231 * @param keyName the given key name 232 * @param keyValue the given key value 233 * @return the key value from the given key value 234 */ 235 protected abstract Object getKeyValue(String keyName, Object keyValue); 236 237 /** 238 * This method finds the matching the key name of the given one 239 * 240 * @param keyName the given key name 241 * @return the key value from the given key name 242 */ 243 protected abstract String getKeyName(String keyName); 244 245 /** 246 * This method defines the lookupable implementation attribute name 247 * 248 * @return the lookupable implementation attribute name 249 */ 250 protected abstract String getLookupableImplAttributeName(); 251 252 /** 253 * This method defines the base inquiry url 254 * 255 * @return the base inquiry url 256 */ 257 protected abstract String getBaseUrl(); 258 259 /** 260 * This method gets the class name of the inquiry business object for a given attribute. 261 * 262 * @return the class name of the inquiry business object for a given attribute 263 */ 264 protected abstract Class getInquiryBusinessObjectClass(String attributeName); 265 266 /** 267 * This method adds more parameters into the curren parameter map 268 * 269 * @param parameter the current parameter map 270 */ 271 protected abstract void addMoreParameters(Properties parameter, String attributeName); 272 273 /** 274 * This method determines whether the input name-value pair is exclusive from the processing 275 * 276 * @param keyName the name of the name-value pair 277 * @param keyValue the value of the name-value pair 278 * @return true if the input key is in the exclusive list; otherwise, false 279 */ 280 protected boolean isExclusiveField(Object keyName, Object keyValue) { 281 282 if (keyName != null && keyValue != null) { 283 String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString()); 284 285 if (convertedKeyName.equals(OLEPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) { 286 return true; 287 } 288 else if (convertedKeyName.equals(OLEPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) { 289 return true; 290 } 291 else if (convertedKeyName.equals(OLEPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) { 292 return true; 293 } 294 if (convertedKeyName.equals(OLEPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(OLEConstants.getDashSubAccountNumber())) { 295 return true; 296 } 297 else if (convertedKeyName.equals(OLEPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(OLEConstants.getDashFinancialSubObjectCode())) { 298 return true; 299 } 300 else if (convertedKeyName.equals(OLEPropertyConstants.PROJECT_CODE) && keyValue.equals(OLEConstants.getDashProjectCode())) { 301 return true; 302 } 303 } 304 return false; 305 } 306 307 /** 308 * This method recovers the values of the given keys 309 * 310 * @param fieldValues unconsolidated values 311 * @param keyName a key name that may be in the fieldValues map 312 * @param keyValue a key value that may be in the fieldValues map 313 * @return the original value for a previously consolidated value 314 */ 315 protected String recoverFieldValueFromConsolidation(Map fieldValues, Object keyName, Object keyValue) { 316 if (fieldValues == null || keyName == null || keyValue == null) { 317 return Constant.EMPTY_STRING; 318 } 319 320 Map convertedFieldValues = BusinessObjectFieldConverter.convertFromTransactionFieldValues(fieldValues); 321 String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString()); 322 323 if (convertedKeyName.equals(OLEPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) { 324 return this.getValueFromFieldValues(convertedFieldValues, keyName); 325 } 326 else if (convertedKeyName.equals(OLEPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) { 327 return this.getValueFromFieldValues(convertedFieldValues, keyName); 328 } 329 else if (convertedKeyName.equals(OLEPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) { 330 return this.getValueFromFieldValues(convertedFieldValues, keyName); 331 } 332 333 return Constant.EMPTY_STRING; 334 } 335 336 /** 337 * Utility method to get the value of the given key from the field values 338 * 339 * @param fieldValues a Map of key values 340 * @param keyName the name of the key to retrieve the value from 341 * @return the value for the key, or, if not found, an empty String 342 */ 343 private String getValueFromFieldValues(Map fieldValues, Object keyName) { 344 String keyValue = Constant.EMPTY_STRING; 345 346 if (fieldValues.containsKey(keyName)) { 347 keyValue = (String) fieldValues.get(keyName); 348 } 349 return keyValue; 350 } 351 352 /** 353 * This takes a map of field values and then returns it without processing it, making this a sort 354 * of identity method for Maps 355 * 356 * @param fieldValues field values to return to the user 357 * @return the Map you sent in as a parameter 358 */ 359 public Map getFieldValues(Map fieldValues) { 360 return fieldValues; 361 } 362 363 /** 364 * Given the nested name of an attribute in an object, returns the class that attribute will return 365 * 366 * @param businessObject the business object to find the propery class for 367 * @param attributeName the nested name of the attribute to find the class for 368 * @return the class of the nested attribute 369 */ 370 public Class getNestedInquiryBusinessObjectClass(BusinessObject businessObject, String attributeName) { 371 // TODO: not finished 372 Class inquiryBusinessObjectClass = null; 373 String entryName = businessObject.getClass().getName(); 374 if (LOG.isDebugEnabled()) { 375 LOG.debug("businessObject: " + entryName); 376 LOG.debug("attributeName: " + attributeName); 377 } 378 DataDictionaryService dataDictionary = SpringContext.getBean(DataDictionaryService.class); 379 AttributeDefinition attributeDefinition = null; 380 381 if (StringUtils.isBlank(attributeName)) { 382 throw new IllegalArgumentException("invalid (blank) attributeName"); 383 } 384 385 DataDictionaryEntryBase entry = (DataDictionaryEntryBase) dataDictionary.getDataDictionary().getDictionaryObjectEntry(entryName); 386 if (entry != null) { 387 attributeDefinition = entry.getAttributeDefinition(attributeName); 388 inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName); 389 } 390 391 // TODO: need to get class for which this property belongs 392// if (attributeDefinition instanceof AttributeReferenceDefinition) { 393// AttributeReferenceDefinition attributeReferenceDefinition = (AttributeReferenceDefinition) attributeDefinition; 394// LOG.debug("Source Classname = " + attributeReferenceDefinition.getSourceClassName()); 395// LOG.debug("Source Attribute = " + attributeReferenceDefinition.getSourceAttributeName()); 396// 397// try { 398// inquiryBusinessObjectClass = Class.forName(attributeReferenceDefinition.getSourceClassName()); 399// } 400// catch (Exception e) { 401// throw new IllegalArgumentException("fail to construct a Class"); 402// } 403// } 404 405 return inquiryBusinessObjectClass; 406 } 407 408 /** 409 * Builds URL to document type inquiry based on a given document type code 410 * 411 * @param docTypeCode - document type code to inquiry on 412 * @return {@link HtmlData} representing inquiry URL 413 */ 414 protected HtmlData getDocTypeInquiryUrl(String docTypeCode) { 415 DocumentType docTypeDTO = SpringContext.getBean(DocumentTypeService.class).getDocumentTypeByName(docTypeCode); 416 if ( docTypeDTO == null ) { 417 return new AnchorHtmlData(); 418 } 419 String baseUrl = OLEConstants.INQUIRY_ACTION; 420 421 Properties parameters = new Properties(); 422 parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.START_METHOD); 423 parameters.put(OLEConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, DocumentTypeEBO.class.getName()); 424 parameters.put(OLEConstants.DOC_FORM_KEY, "88888888"); 425 parameters.put(OLEPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getId().toString()); 426 427 Map<String, String> inquiryFields = new HashMap<String, String>(); 428 inquiryFields.put(OLEPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getId().toString()); 429 430 return getHyperLink(DocumentTypeEBO.class, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters)); 431 } 432 433 /** 434 * Gets the businessObject attribute. 435 * @return Returns the businessObject. 436 */ 437 public BusinessObject getBusinessObject() { 438 return businessObject; 439 } 440 441 /** 442 * Sets the businessObject attribute value. 443 * @param businessObject The businessObject to set. 444 */ 445 public void setBusinessObject(BusinessObject businessObject) { 446 this.businessObject = businessObject; 447 } 448}