001 /**
002 * Copyright 2004-2012 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 */
016 package org.kuali.hr.time.base.web;
017
018 import java.security.GeneralSecurityException;
019 import java.sql.Date;
020 import java.text.SimpleDateFormat;
021 import java.util.ArrayList;
022 import java.util.Collections;
023 import java.util.HashMap;
024 import java.util.Iterator;
025 import java.util.List;
026 import java.util.Map;
027 import java.util.Properties;
028
029 import org.apache.commons.collections.BidiMap;
030 import org.apache.commons.collections.bidimap.DualHashBidiMap;
031 import org.apache.commons.lang.StringUtils;
032 import org.apache.log4j.Logger;
033 import org.kuali.rice.core.web.format.Formatter;
034 import org.kuali.rice.kns.inquiry.KualiInquirableImpl;
035 import org.kuali.rice.kns.lookup.HtmlData;
036 import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
037 import org.kuali.rice.kns.lookup.LookupUtils;
038 import org.kuali.rice.kns.service.KNSServiceLocator;
039 import org.kuali.rice.krad.bo.BusinessObject;
040 import org.kuali.rice.krad.bo.DataObjectRelationship;
041 import org.kuali.rice.krad.bo.DocumentHeader;
042 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
043 import org.kuali.rice.krad.datadictionary.AttributeSecurity;
044 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
045 import org.kuali.rice.krad.util.KRADConstants;
046 import org.kuali.rice.krad.util.ObjectUtils;
047 import org.kuali.rice.krad.util.UrlFactory;
048
049 public class TkInquirableImpl extends KualiInquirableImpl {
050
051 private static final Logger LOG = Logger.getLogger(TkInquirableImpl.class);
052
053 @Override
054 // copied the getInquiryUrl() from KualiInquirableImpl and added effectiveDate to parameters
055 public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) {
056 Properties parameters = new Properties();
057 AnchorHtmlData hRef = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
058 parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "start");
059
060 Class inquiryBusinessObjectClass = null;
061 String attributeRefName = "";
062 boolean isPkReference = false;
063
064 boolean doesNestedReferenceHaveOwnPrimitiveReference = false;
065 BusinessObject nestedBusinessObject = null;
066
067 if (attributeName.equals(getBusinessObjectDictionaryService().getTitleAttribute(businessObject.getClass()))) {
068 inquiryBusinessObjectClass = businessObject.getClass();
069 isPkReference = true;
070 }
071 else {
072 if (ObjectUtils.isNestedAttribute(attributeName)) {
073 // if we have a reference object, we should determine if we should either provide an inquiry link to
074 // the reference object itself, or some other nested primitive.
075
076 // for example, if the attribute is "referenceObject.someAttribute", and there is no primitive reference for
077 // "someAttribute", then an inquiry link is provided to the "referenceObject". If it does have a primitive reference, then
078 // the inquiry link is directed towards it instead
079 String nestedReferenceName = ObjectUtils.getNestedAttributePrefix(attributeName);
080 Object nestedReferenceObject = ObjectUtils.getNestedValue(businessObject, nestedReferenceName);
081
082 if (ObjectUtils.isNotNull(nestedReferenceObject) && nestedReferenceObject instanceof BusinessObject) {
083 nestedBusinessObject = (BusinessObject) nestedReferenceObject;
084 String nestedAttributePrimitive = ObjectUtils.getNestedAttributePrimitive(attributeName);
085
086 if (nestedAttributePrimitive.equals(getBusinessObjectDictionaryService().getTitleAttribute(nestedBusinessObject.getClass()))) {
087 // we are going to inquiry the record that contains the attribute we're rendering an inquiry URL for
088 inquiryBusinessObjectClass = nestedBusinessObject.getClass();
089 // I know it's already set to false, just to show how this variable is set
090 doesNestedReferenceHaveOwnPrimitiveReference = false;
091 }
092 else {
093 Map primitiveReference = LookupUtils.getPrimitiveReference(nestedBusinessObject, nestedAttributePrimitive);
094 if (primitiveReference != null && !primitiveReference.isEmpty()) {
095 attributeRefName = (String) primitiveReference.keySet().iterator().next();
096 inquiryBusinessObjectClass = (Class) primitiveReference.get(attributeRefName);
097 doesNestedReferenceHaveOwnPrimitiveReference = true;
098 }
099 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 java.sql.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 }