001/** 002 * Copyright 2005-2016 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.rice.krad.uif.widget; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.CoreApiServiceLocator; 020import org.kuali.rice.core.web.format.Formatter; 021import org.kuali.rice.krad.bo.ExternalizableBusinessObject; 022import org.kuali.rice.krad.service.KRADServiceLocator; 023import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 024import org.kuali.rice.krad.service.ModuleService; 025import org.kuali.rice.krad.uif.UifConstants; 026import org.kuali.rice.krad.uif.UifParameters; 027import org.kuali.rice.krad.uif.component.BindingInfo; 028import org.kuali.rice.krad.uif.component.Component; 029import org.kuali.rice.krad.uif.field.DataField; 030import org.kuali.rice.krad.uif.field.LinkField; 031import org.kuali.rice.krad.uif.util.LookupInquiryUtils; 032import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 033import org.kuali.rice.krad.uif.util.ViewModelUtils; 034import org.kuali.rice.krad.uif.view.View; 035import org.kuali.rice.krad.util.UrlFactory; 036 037import java.security.GeneralSecurityException; 038import java.util.HashMap; 039import java.util.List; 040import java.util.Map; 041import java.util.Map.Entry; 042import java.util.Properties; 043 044/** 045 * Widget for rendering an Inquiry link on a field's value 046 * 047 * @author Kuali Rice Team (rice.collab@kuali.org) 048 */ 049public class Inquiry extends WidgetBase { 050 private static final long serialVersionUID = -2154388007867302901L; 051 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(Inquiry.class); 052 053 public static final String INQUIRY_TITLE_PREFIX = "title.inquiry.url.value.prependtext"; 054 055 private String baseInquiryUrl; 056 057 private String dataObjectClassName; 058 private String viewName; 059 060 private Map<String, String> inquiryParameters; 061 062 private boolean forceInquiry; 063 064 private LinkField inquiryLinkField; 065 066 public Inquiry() { 067 super(); 068 069 forceInquiry = false; 070 inquiryParameters = new HashMap<String, String>(); 071 } 072 073 /** 074 * @see org.kuali.rice.krad.uif.widget.WidgetBase#performFinalize(org.kuali.rice.krad.uif.view.View, 075 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 076 */ 077 @Override 078 public void performFinalize(View view, Object model, Component parent) { 079 super.performFinalize(view, model, parent); 080 081 // only set inquiry if enabled 082 if (!isRender() || !isReadOnly()) { 083 return; 084 } 085 086 // set render to false until we find an inquiry class 087 setRender(false); 088 089 DataField field = (DataField) parent; 090 091 // check if field value is null, if so no inquiry 092 Object propertyValue = ObjectPropertyUtils.getPropertyValue(model, field.getBindingInfo().getBindingPath()); 093 if ((propertyValue == null) || StringUtils.isBlank(propertyValue.toString())) { 094 return; 095 } 096 097 setupLink(view, model, field); 098 } 099 100 /** 101 * Get parent object and field name and build the inquiry link 102 * This was moved from the performFinalize because overlapping and to be used 103 * by DirectInquiry 104 * 105 * @param view - Container View 106 * @param model - model 107 * @param field - The parent Attribute field 108 */ 109 public void setupLink(View view, Object model, DataField field) { 110 String propertyName = field.getBindingInfo().getBindingName(); 111 112 // if class and parameters configured, build link from those 113 if (StringUtils.isNotBlank(getDataObjectClassName()) && (getInquiryParameters() != null) && 114 !getInquiryParameters().isEmpty()) { 115 Class<?> inquiryObjectClass = null; 116 try { 117 inquiryObjectClass = Class.forName(getDataObjectClassName()); 118 } catch (ClassNotFoundException e) { 119 LOG.error("Unable to get class for: " + getDataObjectClassName()); 120 throw new RuntimeException(e); 121 } 122 123 updateInquiryParameters(field.getBindingInfo()); 124 125 buildInquiryLink(model, propertyName, inquiryObjectClass, getInquiryParameters()); 126 } 127 // get inquiry class and parameters from view helper 128 else { 129 // get parent object for inquiry metadata 130 Object parentObject = ViewModelUtils.getParentObjectForMetadata(view, model, field); 131 view.getViewHelperService().buildInquiryLink(parentObject, propertyName, this); 132 } 133 } 134 135 /** 136 * Adjusts the path on the inquiry parameter property to match the binding 137 * path prefix of the given <code>BindingInfo</code> 138 * 139 * @param bindingInfo - binding info instance to copy binding path prefix from 140 */ 141 public void updateInquiryParameters(BindingInfo bindingInfo) { 142 Map<String, String> adjustedInquiryParameters = new HashMap<String, String>(); 143 for (String fromField : inquiryParameters.keySet()) { 144 String toField = inquiryParameters.get(fromField); 145 String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromField); 146 147 adjustedInquiryParameters.put(adjustedFromFieldPath, toField); 148 } 149 150 this.inquiryParameters = adjustedInquiryParameters; 151 } 152 153 /** 154 * Builds the inquiry link based on the given inquiry class and parameters 155 * 156 * @param dataObject - parent object that contains the data (used to pull inquiry 157 * parameters) 158 * @param propertyName - name of the property the inquiry is set on 159 * @param inquiryObjectClass - class of the object the inquiry should point to 160 * @param inquiryParms - map of key field mappings for the inquiry 161 */ 162 public void buildInquiryLink(Object dataObject, String propertyName, Class<?> inquiryObjectClass, 163 Map<String, String> inquiryParms) { 164 Properties urlParameters = new Properties(); 165 166 urlParameters.put(UifParameters.DATA_OBJECT_CLASS_NAME, inquiryObjectClass.getName()); 167 urlParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.START); 168 169 for (Entry<String, String> inquiryParameter : inquiryParms.entrySet()) { 170 String parameterName = inquiryParameter.getKey(); 171 172 Object parameterValue = ObjectPropertyUtils.getPropertyValue(dataObject, parameterName); 173 174 // TODO: need general format util that uses spring 175 if (parameterValue == null) { 176 parameterValue = ""; 177 } else if (parameterValue instanceof java.sql.Date) { 178 if (Formatter.findFormatter(parameterValue.getClass()) != null) { 179 Formatter formatter = Formatter.getFormatter(parameterValue.getClass()); 180 parameterValue = formatter.format(parameterValue); 181 } 182 } else { 183 parameterValue = parameterValue.toString(); 184 } 185 186 // Encrypt value if it is a field that has restriction that prevents a value from being shown to 187 // user, because we don't want the browser history to store the restricted attributes value in the URL 188 if (KRADServiceLocatorWeb.getDataObjectAuthorizationService() 189 .attributeValueNeedsToBeEncryptedOnFormsAndLinks(inquiryObjectClass, inquiryParameter.getValue())) { 190 try { 191 if(CoreApiServiceLocator.getEncryptionService().isEnabled()) { 192 parameterValue = CoreApiServiceLocator.getEncryptionService().encrypt(parameterValue); 193 } 194 } catch (GeneralSecurityException e) { 195 LOG.error("Exception while trying to encrypted value for inquiry framework.", e); 196 throw new RuntimeException(e); 197 } 198 } 199 200 // add inquiry parameter to URL 201 urlParameters.put(inquiryParameter.getValue(), parameterValue); 202 } 203 204 // build inquiry URL 205 String inquiryUrl = ""; 206 207 // check for EBOs for an alternate inquiry URL 208 ModuleService responsibleModuleService = 209 KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(inquiryObjectClass); 210 if (responsibleModuleService != null && responsibleModuleService.isExternalizable(inquiryObjectClass)) { 211 inquiryUrl = responsibleModuleService.getExternalizableDataObjectLookupUrl(inquiryObjectClass, 212 urlParameters); 213 } else { 214 inquiryUrl = UrlFactory.parameterizeUrl(getBaseInquiryUrl(), urlParameters); 215 } 216 217 getInquiryLinkField().setHrefText(inquiryUrl); 218 219 // set inquiry title 220 String linkTitle = createTitleText(inquiryObjectClass); 221 linkTitle = LookupInquiryUtils.getLinkTitleText(linkTitle, inquiryObjectClass, getInquiryParameters()); 222 getInquiryLinkField().setTitle(linkTitle); 223 224 setRender(true); 225 } 226 227 /** 228 * Gets text to prepend to the inquiry link title 229 * 230 * @param dataObjectClass - data object class being inquired into 231 * @return String title prepend text 232 */ 233 public String createTitleText(Class<?> dataObjectClass) { 234 String titleText = ""; 235 236 String titlePrefixProp = 237 KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(INQUIRY_TITLE_PREFIX); 238 if (StringUtils.isNotBlank(titlePrefixProp)) { 239 titleText += titlePrefixProp + " "; 240 } 241 242 String objectLabel = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary() 243 .getDataObjectEntry(dataObjectClass.getName()).getObjectLabel(); 244 if (StringUtils.isNotBlank(objectLabel)) { 245 titleText += objectLabel + " "; 246 } 247 248 return titleText; 249 } 250 251 /** 252 * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle() 253 */ 254 @Override 255 public List<Component> getComponentsForLifecycle() { 256 List<Component> components = super.getComponentsForLifecycle(); 257 258 components.add(getInquiryLinkField()); 259 260 return components; 261 } 262 263 public String getBaseInquiryUrl() { 264 return this.baseInquiryUrl; 265 } 266 267 public void setBaseInquiryUrl(String baseInquiryUrl) { 268 this.baseInquiryUrl = baseInquiryUrl; 269 } 270 271 public String getDataObjectClassName() { 272 return this.dataObjectClassName; 273 } 274 275 public void setDataObjectClassName(String dataObjectClassName) { 276 this.dataObjectClassName = dataObjectClassName; 277 } 278 279 public String getViewName() { 280 return this.viewName; 281 } 282 283 public void setViewName(String viewName) { 284 this.viewName = viewName; 285 } 286 287 public boolean isForceInquiry() { 288 return this.forceInquiry; 289 } 290 291 public void setForceInquiry(boolean forceInquiry) { 292 this.forceInquiry = forceInquiry; 293 } 294 295 public Map<String, String> getInquiryParameters() { 296 return this.inquiryParameters; 297 } 298 299 public void setInquiryParameters(Map<String, String> inquiryParameters) { 300 this.inquiryParameters = inquiryParameters; 301 } 302 303 public LinkField getInquiryLinkField() { 304 return this.inquiryLinkField; 305 } 306 307 public void setInquiryLinkField(LinkField inquiryLinkField) { 308 this.inquiryLinkField = inquiryLinkField; 309 } 310}