View Javadoc

1   /**
2    * Copyright 2004-2013 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.kpme.core.inquirable;
17  
18  import java.security.GeneralSecurityException;
19  import java.text.SimpleDateFormat;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.Date;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  
29  import org.apache.commons.collections.BidiMap;
30  import org.apache.commons.collections.bidimap.DualHashBidiMap;
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.log4j.Logger;
33  import org.kuali.rice.core.web.format.Formatter;
34  import org.kuali.rice.kns.inquiry.KualiInquirableImpl;
35  import org.kuali.rice.kns.lookup.HtmlData;
36  import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
37  import org.kuali.rice.kns.lookup.LookupUtils;
38  import org.kuali.rice.kns.service.KNSServiceLocator;
39  import org.kuali.rice.krad.bo.BusinessObject;
40  import org.kuali.rice.krad.bo.DataObjectRelationship;
41  import org.kuali.rice.krad.bo.DocumentHeader;
42  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
43  import org.kuali.rice.krad.datadictionary.AttributeSecurity;
44  import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
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  public class KPMEInquirableImpl extends KualiInquirableImpl {
50  	
51  	private static final Logger LOG = Logger.getLogger(KPMEInquirableImpl.class);
52  	
53  	@Override
54  	// copied the getInquiryUrl() from KualiInquirableImpl and added effectiveDate to parameters
55      public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) {
56          Properties parameters = new Properties();
57          AnchorHtmlData hRef = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
58          parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "start");
59  
60          Class inquiryBusinessObjectClass = null;
61          String attributeRefName = "";
62          boolean isPkReference = false;
63  
64          boolean doesNestedReferenceHaveOwnPrimitiveReference = false;
65          BusinessObject nestedBusinessObject = null;
66  
67          if (attributeName.equals(getBusinessObjectDictionaryService().getTitleAttribute(businessObject.getClass()))) {
68              inquiryBusinessObjectClass = businessObject.getClass();
69              isPkReference = true;
70          }
71          else {
72              if (ObjectUtils.isNestedAttribute(attributeName)) {
73                  // if we have a reference object, we should determine if we should either provide an inquiry link to
74                  // the reference object itself, or some other nested primitive.
75  
76                  // for example, if the attribute is "referenceObject.someAttribute", and there is no primitive reference for
77                  // "someAttribute", then an inquiry link is provided to the "referenceObject".  If it does have a primitive reference, then
78                  // the inquiry link is directed towards it instead
79                  String nestedReferenceName = ObjectUtils.getNestedAttributePrefix(attributeName);
80                  Object nestedReferenceObject = ObjectUtils.getNestedValue(businessObject, nestedReferenceName);
81  
82                  if (ObjectUtils.isNotNull(nestedReferenceObject) && nestedReferenceObject instanceof BusinessObject) {
83                      nestedBusinessObject = (BusinessObject) nestedReferenceObject;
84                      String nestedAttributePrimitive = ObjectUtils.getNestedAttributePrimitive(attributeName);
85  
86                      if (nestedAttributePrimitive.equals(getBusinessObjectDictionaryService().getTitleAttribute(nestedBusinessObject.getClass()))) {
87                      	// we are going to inquiry the record that contains the attribute we're rendering an inquiry URL for
88                      	inquiryBusinessObjectClass = nestedBusinessObject.getClass();
89                          // I know it's already set to false, just to show how this variable is set
90                          doesNestedReferenceHaveOwnPrimitiveReference = false;
91                      }
92                      else {
93  	                    Map primitiveReference = LookupUtils.getPrimitiveReference(nestedBusinessObject, nestedAttributePrimitive);
94  	                    if (primitiveReference != null && !primitiveReference.isEmpty()) {
95  	                        attributeRefName = (String) primitiveReference.keySet().iterator().next();
96  	                        inquiryBusinessObjectClass = (Class) primitiveReference.get(attributeRefName);
97  	                        doesNestedReferenceHaveOwnPrimitiveReference = true;
98  	                    }
99  	                    else {
100 	                    	// we are going to inquiry the record that contains the attribute we're rendering an inquiry URL for
101 	                		inquiryBusinessObjectClass = nestedBusinessObject.getClass();
102 	                        // I know it's already set to false, just to show how this variable is set
103 	                        doesNestedReferenceHaveOwnPrimitiveReference = false;
104 	                    }
105                     }
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             }
115         }
116 
117         if (inquiryBusinessObjectClass != null && DocumentHeader.class.isAssignableFrom(inquiryBusinessObjectClass)) {
118             String documentNumber = (String) ObjectUtils.getPropertyValue(businessObject, attributeName);
119             if (!StringUtils.isBlank(documentNumber)) {
120                 // if NullPointerException on the following line, maybe the Spring bean wasn't injected w/ KualiConfigurationException, or if
121                 // instances of a sub-class of this class are not Spring created, then override getKualiConfigurationService() in the subclass
122                 // to return the configuration service from a Spring service locator (or set it).
123                 hRef.setHref(getKualiConfigurationService().getPropertyValueAsString(KRADConstants.WORKFLOW_URL_KEY) + KRADConstants.DOCHANDLER_DO_URL + documentNumber + KRADConstants.DOCHANDLER_URL_CHUNK);
124             }
125             return hRef;
126         }
127 
128         if (inquiryBusinessObjectClass == null || getBusinessObjectDictionaryService().isInquirable(inquiryBusinessObjectClass) == null || !getBusinessObjectDictionaryService().isInquirable(inquiryBusinessObjectClass).booleanValue()) {
129             return hRef;
130         }
131 
132         synchronized (SUPER_CLASS_TRANSLATOR_LIST) {
133             for (Class clazz : SUPER_CLASS_TRANSLATOR_LIST) {
134                 if (clazz.isAssignableFrom(inquiryBusinessObjectClass)) {
135                     inquiryBusinessObjectClass = clazz;
136                     break;
137                 }
138             }
139         }
140 
141         if (!inquiryBusinessObjectClass.isInterface() && ExternalizableBusinessObject.class.isAssignableFrom(inquiryBusinessObjectClass)) {
142         	inquiryBusinessObjectClass = ExternalizableBusinessObjectUtils.determineExternalizableBusinessObjectSubInterface(inquiryBusinessObjectClass);
143         }
144 
145         parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, inquiryBusinessObjectClass.getName());
146 
147 
148         // listPrimaryKeyFieldNames returns an unmodifiable list.  So a copy is necessary.
149         List<String> keys = new ArrayList<String>(getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(inquiryBusinessObjectClass));
150 
151         if (keys == null) {
152         	keys = Collections.emptyList();
153         }
154 
155         DataObjectRelationship businessObjectRelationship = null;
156 
157         if(attributeRefName != null && !"".equals(attributeRefName)){
158 	        businessObjectRelationship =
159 	    		getBusinessObjectMetaDataService().getBusinessObjectRelationship(
160 	    				businessObject, attributeRefName);
161 
162 	    	if (businessObjectRelationship != null && businessObjectRelationship.getParentToChildReferences() != null) {
163 		    	for (String targetNamePrimaryKey : businessObjectRelationship.getParentToChildReferences().values()) {
164 		    		keys.add(targetNamePrimaryKey);
165 		    	}
166 	    	}
167         }
168         // build key value url parameters used to retrieve the business object
169         String keyName = null;
170         String keyConversion = null;
171         Map<String, String> fieldList = new HashMap<String,String>();
172         for (Iterator iter = keys.iterator(); iter.hasNext();) {
173             keyName = (String) iter.next();
174             keyConversion = keyName;
175             if (ObjectUtils.isNestedAttribute(attributeName)) {
176                 if (doesNestedReferenceHaveOwnPrimitiveReference) {
177                     String nestedAttributePrefix = ObjectUtils.getNestedAttributePrefix(attributeName);
178                     //String foreignKeyFieldName = getBusinessObjectMetaDataService().getForeignKeyFieldName(
179                     //        inquiryBusinessObjectClass.getClass(), attributeRefName, keyName);
180 
181                     String foreignKeyFieldName = getBusinessObjectMetaDataService().getForeignKeyFieldName(
182                     								nestedBusinessObject.getClass(), attributeRefName, keyName);
183                     keyConversion = nestedAttributePrefix + "." + foreignKeyFieldName;
184                 }
185                 else {
186                     keyConversion = ObjectUtils.getNestedAttributePrefix(attributeName) + "." + keyName;
187                 }
188             }
189             else {
190                 if (isPkReference) {
191                     keyConversion = keyName;
192                 }
193                 else if (businessObjectRelationship != null) {
194                 	//Using BusinessObjectMetaDataService instead of PersistenceStructureService
195                 	//since otherwise, relationship information from datadictionary is not used at all
196                 	//Also, BOMDS.getBusinessObjectRelationship uses PersistenceStructureService,
197                 	//so both datadictionary and the persistance layer get covered
198                 	/*
199                 	BusinessObjectRelationship businessObjectRelationship =
200                 		getBusinessObjectMetaDataService().getBusinessObjectRelationship(
201                 				businessObject, attributeRefName);
202                 				*/
203                 	BidiMap bidiMap = new DualHashBidiMap(businessObjectRelationship.getParentToChildReferences());
204                 	keyConversion = (String)bidiMap.getKey(keyName);
205                     //keyConversion = getPersistenceStructureService().getForeignKeyFieldName(businessObject.getClass(), attributeRefName, keyName);
206                 }
207             }
208             Object keyValue = null;
209             if (keyConversion != null) {
210                 keyValue = ObjectUtils.getPropertyValue(businessObject, keyConversion);
211             }
212 
213             if (keyValue == null) {
214                 keyValue = "";
215             } else if (keyValue instanceof Date) { //format the date for passing in url
216                 if (Formatter.findFormatter(keyValue.getClass()) != null) {
217                     Formatter formatter = Formatter.getFormatter(keyValue.getClass());
218                     keyValue = (String) formatter.format(keyValue);
219                 }
220             } else {
221                 keyValue = keyValue.toString();
222             }
223 
224             // Encrypt value if it is a field that has restriction that prevents a value from being shown to user,
225             // because we don't want the browser history to store the restricted attribute's value in the URL
226             AttributeSecurity attributeSecurity = KNSServiceLocator.getDataDictionaryService().getAttributeSecurity(businessObject.getClass().getName(), keyName);
227             if(attributeSecurity != null && attributeSecurity.hasRestrictionThatRemovesValueFromUI()){
228             	try {
229                     keyValue = getEncryptionService().encrypt(keyValue);
230                 }
231                 catch (GeneralSecurityException e) {
232                     LOG.error("Exception while trying to encrypted value for inquiry framework.", e);
233                     throw new RuntimeException(e);
234                 }
235             }
236 
237             parameters.put(keyName, keyValue);
238             fieldList.put(keyName, keyValue.toString());
239         }
240         
241         // pass in effective date of the businessObject
242         Date aDate = (Date) ObjectUtils.getPropertyValue(businessObject, "effectiveDate");
243         if(aDate != null) {
244         	parameters.put("effectiveDate", new SimpleDateFormat("MM/dd/yyyy").format(aDate));
245         }
246                 	
247         return getHyperLink(inquiryBusinessObjectClass, fieldList, UrlFactory.parameterizeUrl(KRADConstants.INQUIRY_ACTION, parameters));
248     }
249 }