View Javadoc
1   /*
2    * Copyright 2006 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.gl.businessobject.inquiry;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Properties;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.ole.gl.Constant;
27  import org.kuali.ole.gl.businessobject.AccountBalance;
28  import org.kuali.ole.gl.businessobject.lookup.BusinessObjectFieldConverter;
29  import org.kuali.ole.sys.OLEConstants;
30  import org.kuali.ole.sys.OLEPropertyConstants;
31  import org.kuali.ole.sys.businessobject.inquiry.KfsInquirableImpl;
32  import org.kuali.ole.sys.context.SpringContext;
33  import org.kuali.rice.kew.api.doctype.DocumentType;
34  import org.kuali.rice.kew.api.doctype.DocumentTypeService;
35  import org.kuali.rice.kew.doctype.bo.DocumentTypeEBO;
36  import org.kuali.rice.kns.lookup.HtmlData;
37  import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
38  import org.kuali.rice.kns.lookup.LookupUtils;
39  import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
40  import org.kuali.rice.kns.service.DataDictionaryService;
41  import org.kuali.rice.krad.bo.BusinessObject;
42  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
43  import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase;
44  import org.kuali.rice.krad.service.PersistenceStructureService;
45  import org.kuali.rice.krad.util.KRADConstants;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  import org.kuali.rice.krad.util.UrlFactory;
48  
49  /**
50   * This class is the template class for the customized inqurable implementations used to generate balance inquiry screens.
51   */
52  public abstract class AbstractGeneralLedgerInquirableImpl extends KfsInquirableImpl {
53      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerInquirableImpl.class);
54      
55      private BusinessObject businessObject; 
56      
57      /**
58       * @see org.kuali.ole.sys.businessobject.inquiry.KfsInquirableImpl#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String, boolean)
59       */
60      @Override
61      public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) {
62          return this.getInquiryUrl(businessObject, attributeName);
63      }
64  
65      /**
66       * Helper method to build an inquiry url for a result field.
67       * 
68       * @param businessObject the business object instance to build the urls for
69       * @param attributeName the attribute name which links to an inquirable
70       * @return String url to inquiry
71       */
72      public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName) {
73          this.setBusinessObject(businessObject);
74          AnchorHtmlData inquiryHref = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
75          BusinessObjectDictionaryService businessDictionary = SpringContext.getBean(BusinessObjectDictionaryService.class);
76          PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
77  
78          String baseUrl = OLEConstants.INQUIRY_ACTION;
79          Properties parameters = new Properties();
80          parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.START_METHOD);
81  
82          Object attributeValue = null;
83          Class inquiryBusinessObjectClass = null;
84          String attributeRefName = "";
85          boolean isPkReference = false;
86  
87          Map userDefinedAttributeMap = getUserDefinedAttributeMap();
88          boolean isUserDefinedAttribute = userDefinedAttributeMap == null ? false : userDefinedAttributeMap.containsKey(attributeName);
89  
90          // determine the type of the given attribute: user-defined, regular, nested-referenced or primitive reference
91          if (isUserDefinedAttribute) {
92              attributeName = getAttributeName(attributeName);
93              inquiryBusinessObjectClass = getInquiryBusinessObjectClass(attributeName);
94              isPkReference = true;
95          }
96          else if (attributeName.equals(businessDictionary.getTitleAttribute(businessObject.getClass()))) {
97              inquiryBusinessObjectClass = businessObject.getClass();
98              isPkReference = true;
99          }
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 }