001 /** 002 * Copyright 2005-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.rice.kns.util; 017 018 import org.apache.commons.lang.StringEscapeUtils; 019 import org.apache.commons.lang.StringUtils; 020 import org.apache.log4j.Level; 021 import org.apache.log4j.Logger; 022 import org.apache.struts.Globals; 023 import org.apache.struts.action.ActionForm; 024 import org.apache.struts.action.ActionMapping; 025 import org.apache.struts.action.ActionServletWrapper; 026 import org.apache.struts.upload.CommonsMultipartRequestHandler; 027 import org.apache.struts.upload.FormFile; 028 import org.apache.struts.upload.MultipartRequestHandler; 029 import org.apache.struts.upload.MultipartRequestWrapper; 030 import org.kuali.rice.core.api.config.property.ConfigurationService; 031 import org.kuali.rice.core.api.util.RiceKeyConstants; 032 import org.kuali.rice.kns.datadictionary.KNSDocumentEntry; 033 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry; 034 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer; 035 import org.kuali.rice.kns.service.KNSServiceLocator; 036 import org.kuali.rice.kns.web.struts.action.KualiMultipartRequestHandler; 037 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 038 import org.kuali.rice.kns.web.struts.form.KualiForm; 039 import org.kuali.rice.kns.web.struts.form.KualiMaintenanceForm; 040 import org.kuali.rice.kns.web.struts.form.pojo.PojoFormBase; 041 import org.kuali.rice.krad.datadictionary.AttributeDefinition; 042 import org.kuali.rice.krad.datadictionary.AttributeSecurity; 043 import org.kuali.rice.krad.datadictionary.DataDictionary; 044 import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase; 045 import org.kuali.rice.krad.datadictionary.mask.MaskFormatter; 046 import org.kuali.rice.krad.document.Document; 047 import org.kuali.rice.krad.exception.ValidationException; 048 import org.kuali.rice.krad.service.KRADServiceLocator; 049 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 050 import org.kuali.rice.krad.util.GlobalVariables; 051 import org.kuali.rice.krad.util.KRADConstants; 052 import org.kuali.rice.krad.util.MessageMap; 053 import org.kuali.rice.krad.util.ObjectUtils; 054 055 import javax.servlet.ServletException; 056 import javax.servlet.http.HttpServletRequest; 057 import javax.servlet.http.HttpServletResponse; 058 import javax.servlet.http.HttpSession; 059 import javax.servlet.jsp.PageContext; 060 import java.io.ByteArrayOutputStream; 061 import java.io.IOException; 062 import java.io.InputStream; 063 import java.io.OutputStream; 064 import java.util.Arrays; 065 import java.util.Collection; 066 import java.util.Enumeration; 067 import java.util.HashMap; 068 import java.util.Hashtable; 069 import java.util.Iterator; 070 import java.util.List; 071 import java.util.Map; 072 import java.util.Set; 073 import java.util.regex.Matcher; 074 import java.util.regex.Pattern; 075 076 /** 077 * General helper methods for handling requests. 078 */ 079 public class WebUtils { 080 private static final Logger LOG = Logger.getLogger(WebUtils.class); 081 082 private static final String IMAGE_COORDINATE_CLICKED_X_EXTENSION = ".x"; 083 private static final String IMAGE_COORDINATE_CLICKED_Y_EXTENSION = ".y"; 084 085 private static final String APPLICATION_IMAGE_URL_PROPERTY_PREFIX = "application.custom.image.url"; 086 private static final String DEFAULT_IMAGE_URL_PROPERTY_NAME = "kr.externalizable.images.url"; 087 088 /** 089 * A request attribute name that indicates that a 090 * {@link org.kuali.rice.kns.exception.FileUploadLimitExceededException} has already been thrown for the 091 * request. 092 */ 093 public static final String FILE_UPLOAD_LIMIT_EXCEEDED_EXCEPTION_ALREADY_THROWN = "fileUploadLimitExceededExceptionAlreadyThrown"; 094 095 private static ConfigurationService configurationService; 096 097 /** 098 * Checks for methodToCall parameter, and picks off the value using set dot 099 * notation. Handles the problem of image submits. 100 * 101 * @param request 102 * @return methodToCall String 103 */ 104 public static String parseMethodToCall(ActionForm form, HttpServletRequest request) { 105 String methodToCall = null; 106 107 // check if is specified cleanly 108 if (StringUtils.isNotBlank(request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER))) { 109 if (form instanceof KualiForm 110 && !((KualiForm) form).shouldMethodToCallParameterBeUsed(KRADConstants.DISPATCH_REQUEST_PARAMETER, 111 request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER), request)) { 112 throw new RuntimeException("Cannot verify that the methodToCall should be " 113 + request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER)); 114 } 115 methodToCall = request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER); 116 // include .x at the end of the parameter to make it consistent w/ 117 // other parameters 118 request.setAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE, KRADConstants.DISPATCH_REQUEST_PARAMETER + "." 119 + methodToCall + IMAGE_COORDINATE_CLICKED_X_EXTENSION); 120 } 121 122 /** 123 * The reason why we are checking for a ".x" at the end of the parameter 124 * name: It is for the image names that in addition to sending the form 125 * data, the web browser sends the x,y coordinate of where the user 126 * clicked on the image. If the image input is not given a name then the 127 * browser sends the x and y coordinates as the "x" and "y" input 128 * fields. If the input image does have a name, the x and y coordinates 129 * are sent using the format name.x and name.y. 130 */ 131 if (methodToCall == null) { 132 // iterate through parameters looking for methodToCall 133 for (Enumeration i = request.getParameterNames(); i.hasMoreElements();) { 134 String parameterName = (String) i.nextElement(); 135 136 // check if the parameter name is a specifying the methodToCall 137 if (isMethodToCall(parameterName)) { 138 methodToCall = getMethodToCallSettingAttribute(form, request, parameterName); 139 break; 140 } 141 else { 142 // KULRICE-1218: Check if the parameter's values match (not 143 // just the name) 144 for (String value : request.getParameterValues(parameterName)) { 145 // adding period to startsWith check - don't want to get 146 // confused with methodToCallFoobar 147 if (isMethodToCall(value)) { 148 methodToCall = getMethodToCallSettingAttribute(form, request, value); 149 // why is there not a break outer loop here? 150 } 151 } 152 } 153 } 154 } 155 156 return methodToCall; 157 } 158 159 /** 160 * Checks if a string signifies a methodToCall string 161 * 162 * @param string 163 * the string to check 164 * @return true if is a methodToCall 165 */ 166 private static boolean isMethodToCall(String string) { 167 // adding period to startsWith check - don't want to get confused with 168 // methodToCallFoobar 169 return string.startsWith(KRADConstants.DISPATCH_REQUEST_PARAMETER + "."); 170 } 171 172 /** 173 * Parses out the methodToCall command and also sets the request attribute 174 * for the methodToCall. 175 * 176 * @param form 177 * the ActionForm 178 * @param request 179 * the request to set the attribute on 180 * @param string 181 * the methodToCall string 182 * @return the methodToCall command 183 */ 184 private static String getMethodToCallSettingAttribute(ActionForm form, HttpServletRequest request, String string) { 185 186 if (form instanceof ActionForm 187 && !((KualiForm) form).shouldMethodToCallParameterBeUsed(string, request.getParameter(string), request)) { 188 throw new RuntimeException("Cannot verify that the methodToCall should be " + string); 189 } 190 // always adding a coordinate even if not an image 191 final String attributeValue = endsWithCoordinates(string) ? string : string 192 + IMAGE_COORDINATE_CLICKED_X_EXTENSION; 193 final String methodToCall = StringUtils.substringBetween(attributeValue, 194 KRADConstants.DISPATCH_REQUEST_PARAMETER + ".", "."); 195 request.setAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE, attributeValue); 196 return methodToCall; 197 } 198 199 /** 200 * Iterates through and logs (at the given level) all attributes and 201 * parameters of the given request onto the given Logger 202 * 203 * @param request 204 * @param logger 205 */ 206 public static void logRequestContents(Logger logger, Level level, HttpServletRequest request) { 207 if (logger.isEnabledFor(level)) { 208 logger.log(level, "--------------------"); 209 logger.log(level, "HttpRequest attributes:"); 210 for (Enumeration e = request.getAttributeNames(); e.hasMoreElements();) { 211 String attrName = (String) e.nextElement(); 212 Object attrValue = request.getAttribute(attrName); 213 214 if (attrValue.getClass().isArray()) { 215 logCollection(logger, level, attrName, Arrays.asList((Object[]) attrValue)); 216 } 217 else if (attrValue instanceof Collection) { 218 logCollection(logger, level, attrName, (Collection) attrValue); 219 } 220 else if (attrValue instanceof Map) { 221 logMap(logger, level, attrName, (Map) attrValue); 222 } 223 else { 224 logObject(logger, level, attrName, attrValue); 225 } 226 } 227 228 logger.log(level, "--------------------"); 229 logger.log(level, "HttpRequest parameters:"); 230 for (Enumeration i = request.getParameterNames(); i.hasMoreElements();) { 231 String paramName = (String) i.nextElement(); 232 String[] paramValues = (String[]) request.getParameterValues(paramName); 233 234 logArray(logger, level, paramName, paramValues); 235 } 236 237 logger.log(level, "--------------------"); 238 } 239 } 240 241 private static void logArray(Logger logger, Level level, String arrayName, Object[] array) { 242 StringBuffer value = new StringBuffer("["); 243 for (int i = 0; i < array.length; ++i) { 244 if (i > 0) { 245 value.append(","); 246 } 247 value.append(array[i]); 248 } 249 value.append("]"); 250 251 logThing(logger, level, arrayName, value); 252 } 253 254 private static void logCollection(Logger logger, Level level, String collectionName, Collection c) { 255 StringBuffer value = new StringBuffer("{"); 256 for (Iterator i = c.iterator(); i.hasNext();) { 257 value.append(i.next()); 258 if (i.hasNext()) { 259 value.append(","); 260 } 261 } 262 value.append("}"); 263 264 logThing(logger, level, collectionName, value); 265 } 266 267 private static void logMap(Logger logger, Level level, String mapName, Map m) { 268 StringBuffer value = new StringBuffer("{"); 269 for (Iterator i = m.entrySet().iterator(); i.hasNext();) { 270 Map.Entry e = (Map.Entry) i.next(); 271 value.append("('" + e.getKey() + "','" + e.getValue() + "')"); 272 } 273 value.append("}"); 274 275 logThing(logger, level, mapName, value); 276 } 277 278 private static void logObject(Logger logger, Level level, String objectName, Object o) { 279 logThing(logger, level, objectName, "'" + o + "'"); 280 } 281 282 private static void logThing(Logger logger, Level level, String thingName, Object thing) { 283 logger.log(level, " '" + thingName + "' => " + thing); 284 } 285 286 /** 287 * A file that is not of type text/plain or text/html can be output through 288 * the response using this method. 289 * 290 * @param response 291 * @param contentType 292 * @param outStream 293 * @param fileName 294 */ 295 public static void saveMimeOutputStreamAsFile(HttpServletResponse response, String contentType, 296 ByteArrayOutputStream byteArrayOutputStream, String fileName) throws IOException { 297 298 // set response 299 response.setContentType(contentType); 300 response.setHeader("Content-disposition", "attachment; filename=" + fileName); 301 response.setHeader("Expires", "0"); 302 response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); 303 response.setHeader("Pragma", "public"); 304 response.setContentLength(byteArrayOutputStream.size()); 305 306 // write to output 307 OutputStream outputStream = response.getOutputStream(); 308 byteArrayOutputStream.writeTo(response.getOutputStream()); 309 outputStream.flush(); 310 outputStream.close(); 311 } 312 313 /** 314 * A file that is not of type text/plain or text/html can be output through 315 * the response using this method. 316 * 317 * @param response 318 * @param contentType 319 * @param outStream 320 * @param fileName 321 */ 322 public static void saveMimeInputStreamAsFile(HttpServletResponse response, String contentType, 323 InputStream inStream, String fileName, int fileSize) throws IOException { 324 325 // set response 326 response.setContentType(contentType); 327 response.setHeader("Content-disposition", "attachment; filename=" + fileName); 328 response.setHeader("Expires", "0"); 329 response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); 330 response.setHeader("Pragma", "public"); 331 response.setContentLength(fileSize); 332 333 // write to output 334 OutputStream out = response.getOutputStream(); 335 while (inStream.available() > 0) { 336 out.write(inStream.read()); 337 } 338 out.flush(); 339 } 340 341 /** 342 * JSTL function to return the tab state of the tab from the form. 343 * 344 * @param form 345 * @param tabKey 346 * @return 347 */ 348 public static String getTabState(KualiForm form, String tabKey) { 349 return form.getTabState(tabKey); 350 } 351 352 public static void incrementTabIndex(KualiForm form, String tabKey) { 353 form.incrementTabIndex(); 354 } 355 356 /** 357 * Generates a String from the title that can be used as a Map key. 358 * 359 * @param tabTitle 360 * @return 361 */ 362 public static String generateTabKey(String tabTitle) { 363 String key = ""; 364 if (!StringUtils.isBlank(tabTitle)) { 365 key = tabTitle.replaceAll("\\W", ""); 366 // if (key.length() > 25) { 367 // key = key.substring(0, 24); 368 // } 369 } 370 371 return key; 372 } 373 374 public static void getMultipartParameters(HttpServletRequest request, ActionServletWrapper servletWrapper, 375 ActionForm form, ActionMapping mapping) { 376 Map params = new HashMap(); 377 378 // Get the ActionServletWrapper from the form bean 379 // ActionServletWrapper servletWrapper = getServletWrapper(); 380 381 try { 382 CommonsMultipartRequestHandler multipartHandler = new CommonsMultipartRequestHandler(); 383 if (multipartHandler != null) { 384 // Set servlet and mapping info 385 if (servletWrapper != null) { 386 // from pojoformbase 387 // servlet only affects tempdir on local disk 388 servletWrapper.setServletFor(multipartHandler); 389 } 390 multipartHandler.setMapping((ActionMapping) request.getAttribute(Globals.MAPPING_KEY)); 391 // Initialize multipart request class handler 392 multipartHandler.handleRequest(request); 393 394 Collection<FormFile> files = multipartHandler.getFileElements().values(); 395 Enumeration keys = multipartHandler.getFileElements().keys(); 396 397 while (keys.hasMoreElements()) { 398 Object key = keys.nextElement(); 399 FormFile file = (FormFile) multipartHandler.getFileElements().get(key); 400 long maxSize = WebUtils.getMaxUploadSize(form); 401 if (LOG.isDebugEnabled()) { 402 LOG.debug(file.getFileSize()); 403 } 404 if (maxSize > 0 && Long.parseLong(file.getFileSize() + "") > maxSize) { 405 406 GlobalVariables.getMessageMap().putError(key.toString(), 407 RiceKeyConstants.ERROR_UPLOADFILE_SIZE, 408 new String[] { file.getFileName(), Long.toString(maxSize) }); 409 410 } 411 } 412 413 // get file elements for kualirequestprocessor 414 if (servletWrapper == null) { 415 request.setAttribute(KRADConstants.UPLOADED_FILE_REQUEST_ATTRIBUTE_KEY, 416 getFileParametersForMultipartRequest(request, multipartHandler)); 417 } 418 } 419 } 420 catch (ServletException e) { 421 throw new ValidationException("unable to handle multipart request " + e.getMessage(), e); 422 } 423 } 424 425 public static long getMaxUploadSize(ActionForm form) { 426 long max = 0L; 427 KualiMultipartRequestHandler multipartHandler = new KualiMultipartRequestHandler(); 428 if (form instanceof PojoFormBase) { 429 max = multipartHandler.calculateMaxUploadSizeToMaxOfList(((PojoFormBase) form).getMaxUploadSizes()); 430 } 431 if (LOG.isDebugEnabled()) { 432 LOG.debug("Max File Upload Size: " + max); 433 } 434 return max; 435 } 436 437 private static Map getFileParametersForMultipartRequest(HttpServletRequest request, 438 MultipartRequestHandler multipartHandler) { 439 Map parameters = new HashMap(); 440 Hashtable elements = multipartHandler.getFileElements(); 441 Enumeration e = elements.keys(); 442 while (e.hasMoreElements()) { 443 String key = (String) e.nextElement(); 444 parameters.put(key, elements.get(key)); 445 } 446 447 if (request instanceof MultipartRequestWrapper) { 448 request = (HttpServletRequest) ((MultipartRequestWrapper) request).getRequest(); 449 e = request.getParameterNames(); 450 while (e.hasMoreElements()) { 451 String key = (String) e.nextElement(); 452 parameters.put(key, request.getParameterValues(key)); 453 } 454 } 455 else { 456 LOG.debug("Gathering multipart parameters for unwrapped request"); 457 } 458 return parameters; 459 } 460 461 // end multipart 462 463 public static void registerEditableProperty(PojoFormBase form, String editablePropertyName) { 464 form.registerEditableProperty(editablePropertyName); 465 } 466 467 public static boolean isDocumentSession(Document document, PojoFormBase docForm) { 468 boolean sessionDoc = document instanceof org.kuali.rice.krad.document.SessionDocument; 469 boolean dataDictionarySessionDoc = false; 470 if (!sessionDoc) { 471 DataDictionary dataDictionary = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary(); 472 if (docForm instanceof KualiMaintenanceForm) { 473 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) docForm; 474 if (dataDictionary != null) { 475 if (maintenanceForm.getDocTypeName() != null) { 476 MaintenanceDocumentEntry maintenanceDocumentEntry = (MaintenanceDocumentEntry) dataDictionary.getDocumentEntry(maintenanceForm.getDocTypeName()); 477 dataDictionarySessionDoc = maintenanceDocumentEntry.isSessionDocument(); 478 } 479 } 480 } 481 else { 482 if (document != null && dataDictionary != null) { 483 KNSDocumentEntry documentEntry = (KNSDocumentEntry) dataDictionary.getDocumentEntry(document.getClass().getName()); 484 dataDictionarySessionDoc = documentEntry.isSessionDocument(); 485 } 486 } 487 } 488 return sessionDoc || dataDictionarySessionDoc; 489 } 490 491 public static boolean isFormSessionDocument(PojoFormBase form) { 492 Document document = null; 493 if (KualiDocumentFormBase.class.isAssignableFrom(form.getClass())) { 494 KualiDocumentFormBase docForm = (KualiDocumentFormBase) form; 495 document = docForm.getDocument(); 496 } 497 return isDocumentSession(document, form); 498 } 499 500 public static String KEY_KUALI_FORM_IN_SESSION = "KualiForm"; 501 502 public static ActionForm getKualiForm(PageContext pageContext) { 503 return getKualiForm((HttpServletRequest) pageContext.getRequest()); 504 } 505 506 public static ActionForm getKualiForm(HttpServletRequest request) { 507 if (request.getAttribute(KEY_KUALI_FORM_IN_SESSION) != null) { 508 return (ActionForm) request.getAttribute(KEY_KUALI_FORM_IN_SESSION); 509 } 510 else { 511 final HttpSession session = request.getSession(false); 512 return session != null ? (ActionForm) session.getAttribute(KEY_KUALI_FORM_IN_SESSION) : null; 513 } 514 } 515 516 public static boolean isPropertyEditable(Set<String> editableProperties, String propertyName) { 517 if (LOG.isDebugEnabled()) { 518 LOG.debug("isPropertyEditable(" + propertyName + ")"); 519 } 520 521 boolean returnVal = editableProperties == null 522 || editableProperties.contains(propertyName) 523 || (getIndexOfCoordinateExtension(propertyName) == -1 ? false : editableProperties 524 .contains(propertyName.substring(0, getIndexOfCoordinateExtension(propertyName)))); 525 if (!returnVal) { 526 if (LOG.isDebugEnabled()) { 527 LOG.debug("isPropertyEditable(" + propertyName + ") == false / editableProperties: " 528 + editableProperties); 529 } 530 } 531 return returnVal; 532 } 533 534 public static boolean endsWithCoordinates(String parameter) { 535 return parameter.endsWith(WebUtils.IMAGE_COORDINATE_CLICKED_X_EXTENSION) 536 || parameter.endsWith(WebUtils.IMAGE_COORDINATE_CLICKED_Y_EXTENSION); 537 } 538 539 public static int getIndexOfCoordinateExtension(String parameter) { 540 int indexOfCoordinateExtension = parameter.lastIndexOf(WebUtils.IMAGE_COORDINATE_CLICKED_X_EXTENSION); 541 if (indexOfCoordinateExtension == -1) 542 indexOfCoordinateExtension = parameter.lastIndexOf(WebUtils.IMAGE_COORDINATE_CLICKED_Y_EXTENSION); 543 return indexOfCoordinateExtension; 544 } 545 546 public static boolean isInquiryHiddenField(String className, String fieldName, Object formObject, String propertyName) { 547 boolean isHidden = false; 548 String hiddenInquiryFields = getKualiConfigurationService().getPropertyValueAsString(className + ".hidden"); 549 if (StringUtils.isEmpty(hiddenInquiryFields)) { 550 return isHidden; 551 } 552 List hiddenFields = Arrays.asList(hiddenInquiryFields.replaceAll(" ", "").split(",")); 553 if (hiddenFields.contains(fieldName.trim())) { 554 isHidden = true; 555 } 556 return isHidden; 557 } 558 559 public static boolean isHiddenKimObjectType(String type, String configParameter) { 560 boolean hideType = false; 561 String hiddenTypes = getKualiConfigurationService().getPropertyValueAsString(configParameter); 562 if (StringUtils.isEmpty(hiddenTypes)) { 563 return hideType; 564 } 565 List hiddenTypeValues = Arrays.asList(hiddenTypes.replaceAll(" ", "").split(",")); 566 if (hiddenTypeValues.contains(type.trim())) { 567 hideType = true; 568 } 569 return hideType; 570 } 571 572 public static String getFullyMaskedValue(String className, String fieldName, Object formObject, String propertyName) { 573 String displayMaskValue = null; 574 Object propertyValue = ObjectUtils.getPropertyValue(formObject, propertyName); 575 576 DataDictionaryEntryBase entry = (DataDictionaryEntryBase) KRADServiceLocatorWeb.getDataDictionaryService() 577 .getDataDictionary().getDictionaryObjectEntry(className); 578 AttributeDefinition a = entry.getAttributeDefinition(fieldName); 579 580 AttributeSecurity attributeSecurity = a.getAttributeSecurity(); 581 if (attributeSecurity != null && attributeSecurity.isMask()) { 582 MaskFormatter maskFormatter = attributeSecurity.getMaskFormatter(); 583 displayMaskValue = maskFormatter.maskValue(propertyValue); 584 585 } 586 return displayMaskValue; 587 } 588 589 public static String getPartiallyMaskedValue(String className, String fieldName, Object formObject, 590 String propertyName) { 591 String displayMaskValue = null; 592 Object propertyValue = ObjectUtils.getPropertyValue(formObject, propertyName); 593 594 DataDictionaryEntryBase entry = (DataDictionaryEntryBase) KRADServiceLocatorWeb.getDataDictionaryService() 595 .getDataDictionary().getDictionaryObjectEntry(className); 596 AttributeDefinition a = entry.getAttributeDefinition(fieldName); 597 598 AttributeSecurity attributeSecurity = a.getAttributeSecurity(); 599 if (attributeSecurity != null && attributeSecurity.isPartialMask()) { 600 MaskFormatter partialMaskFormatter = attributeSecurity.getPartialMaskFormatter(); 601 displayMaskValue = partialMaskFormatter.maskValue(propertyValue); 602 603 } 604 return displayMaskValue; 605 } 606 607 public static boolean canFullyUnmaskField(String businessObjectClassName, String fieldName, KualiForm form) { 608 Class businessObjClass = null; 609 try { 610 businessObjClass = Class.forName(businessObjectClassName); 611 } 612 catch (Exception e) { 613 throw new RuntimeException("Unable to resolve class name: " + businessObjectClassName); 614 } 615 if (form instanceof KualiDocumentFormBase) { 616 return KNSServiceLocator.getBusinessObjectAuthorizationService().canFullyUnmaskField( 617 GlobalVariables.getUserSession().getPerson(), businessObjClass, fieldName, 618 ((KualiDocumentFormBase) form).getDocument()); 619 } 620 else { 621 return KNSServiceLocator.getBusinessObjectAuthorizationService().canFullyUnmaskField( 622 GlobalVariables.getUserSession().getPerson(), businessObjClass, fieldName, null); 623 } 624 } 625 626 public static boolean canPartiallyUnmaskField(String businessObjectClassName, String fieldName, KualiForm form) { 627 Class businessObjClass = null; 628 try { 629 businessObjClass = Class.forName(businessObjectClassName); 630 } 631 catch (Exception e) { 632 throw new RuntimeException("Unable to resolve class name: " + businessObjectClassName); 633 } 634 if (form instanceof KualiDocumentFormBase) { 635 return KNSServiceLocator.getBusinessObjectAuthorizationService().canPartiallyUnmaskField( 636 GlobalVariables.getUserSession().getPerson(), businessObjClass, fieldName, 637 ((KualiDocumentFormBase) form).getDocument()); 638 } 639 else { 640 return KNSServiceLocator.getBusinessObjectAuthorizationService().canPartiallyUnmaskField( 641 GlobalVariables.getUserSession().getPerson(), businessObjClass, fieldName, null); 642 } 643 } 644 645 public static boolean canAddNoteAttachment(Document document) { 646 boolean canViewNoteAttachment = false; 647 DocumentAuthorizer documentAuthorizer = KNSServiceLocator.getDocumentHelperService().getDocumentAuthorizer( 648 document); 649 canViewNoteAttachment = documentAuthorizer.canAddNoteAttachment(document, null, GlobalVariables 650 .getUserSession().getPerson()); 651 return canViewNoteAttachment; 652 } 653 654 public static boolean canViewNoteAttachment(Document document, String attachmentTypeCode) { 655 boolean canViewNoteAttachment = false; 656 DocumentAuthorizer documentAuthorizer = KNSServiceLocator.getDocumentHelperService().getDocumentAuthorizer( 657 document); 658 canViewNoteAttachment = documentAuthorizer.canViewNoteAttachment(document, attachmentTypeCode, GlobalVariables 659 .getUserSession().getPerson()); 660 return canViewNoteAttachment; 661 } 662 663 public static boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode, 664 String authorUniversalIdentifier) { 665 boolean canDeleteNoteAttachment = false; 666 DocumentAuthorizer documentAuthorizer = KNSServiceLocator.getDocumentHelperService().getDocumentAuthorizer( 667 document); 668 canDeleteNoteAttachment = documentAuthorizer.canDeleteNoteAttachment(document, attachmentTypeCode, "false", 669 GlobalVariables.getUserSession().getPerson()); 670 if (canDeleteNoteAttachment) { 671 return canDeleteNoteAttachment; 672 } 673 else { 674 canDeleteNoteAttachment = documentAuthorizer.canDeleteNoteAttachment(document, attachmentTypeCode, "true", 675 GlobalVariables.getUserSession().getPerson()); 676 if (canDeleteNoteAttachment 677 && !authorUniversalIdentifier.equals(GlobalVariables.getUserSession().getPerson().getPrincipalId())) { 678 canDeleteNoteAttachment = false; 679 } 680 } 681 return canDeleteNoteAttachment; 682 } 683 684 public static void reuseErrorMapFromPreviousRequest(KualiDocumentFormBase kualiDocumentFormBase) { 685 if (kualiDocumentFormBase.getMessageMapFromPreviousRequest() == null) { 686 LOG.error("Error map from previous request is null!"); 687 return; 688 } 689 MessageMap errorMapFromGlobalVariables = GlobalVariables.getMessageMap(); 690 if (kualiDocumentFormBase.getMessageMapFromPreviousRequest() == errorMapFromGlobalVariables) { 691 // if we've switched them already, then return early and do nothing 692 return; 693 } 694 if (!errorMapFromGlobalVariables.hasNoErrors()) { 695 throw new RuntimeException("Cannot replace error map because it is not empty"); 696 } 697 GlobalVariables.setMessageMap(kualiDocumentFormBase.getMessageMapFromPreviousRequest()); 698 GlobalVariables.getMessageMap().clearErrorPath(); 699 } 700 701 /** 702 * Excapes out HTML to prevent XSS attacks, and replaces the following 703 * strings to allow for a limited set of HTML tags 704 * 705 * <li>[X] and [/X], where X represents any 1 or 2 letter string may be used 706 * to specify the equivalent tag in HTML (i.e. <X> and </X>) <li> 707 * [font COLOR], where COLOR represents any valid html color (i.e. color 708 * name or hexcode preceeded by #) will be filtered into <font 709 * color="COLOR"/> <li>[/font] will be filtered into </font> <li> 710 * [table CLASS], where CLASS gives the style class to use, will be filter 711 * into <table class="CLASS"/> <li>[/table] will be filtered into 712 * </table> <li>[td CLASS], where CLASS gives the style class to use, 713 * will be filter into <td class="CLASS"/> 714 * 715 * @param inputString 716 * @return 717 */ 718 public static String filterHtmlAndReplaceRiceMarkup(String inputString) { 719 String outputString = StringEscapeUtils.escapeHtml(inputString); 720 // string has been escaped of all <, >, and & (and other characters) 721 722 Map<String, String> findAndReplacePatterns = new HashMap<String, String>(); 723 724 // now replace our rice custom markup into html 725 726 // DON'T ALLOW THE SCRIPT TAG OR ARBITRARY IMAGES/URLS/ETC. THROUGH 727 728 // filter any one character tags 729 findAndReplacePatterns.put("\\[([A-Za-z])\\]", "<$1>"); 730 findAndReplacePatterns.put("\\[/([A-Za-z])\\]", "</$1>"); 731 // filter any two character tags 732 findAndReplacePatterns.put("\\[([A-Za-z]{2})\\]", "<$1>"); 733 findAndReplacePatterns.put("\\[/([A-Za-z]{2})\\]", "</$1>"); 734 // filter the font tag 735 findAndReplacePatterns.put("\\[font (#[0-9A-Fa-f]{1,6}|[A-Za-z]+)\\]", "<font color=\"$1\">"); 736 findAndReplacePatterns.put("\\[/font\\]", "</font>"); 737 // filter the table tag 738 findAndReplacePatterns.put("\\[table\\]", "<table>"); 739 findAndReplacePatterns.put("\\[table ([A-Za-z]+)\\]", "<table class=\"$1\">"); 740 findAndReplacePatterns.put("\\[/table\\]", "</table>"); 741 // fiter td with class 742 findAndReplacePatterns.put("\\[td ([A-Za-z]+)\\]", "<td class=\"$1\">"); 743 744 for (String findPattern : findAndReplacePatterns.keySet()) { 745 Pattern p = Pattern.compile(findPattern); 746 Matcher m = p.matcher(outputString); 747 if (m.find()) { 748 String replacePattern = findAndReplacePatterns.get(findPattern); 749 outputString = m.replaceAll(replacePattern); 750 } 751 } 752 753 return outputString; 754 } 755 756 /** 757 * Determines and returns the URL for question button images; looks first 758 * for a property "application.custom.image.url", and if that is missing, 759 * uses the image url returned by getDefaultButtonImageUrl() 760 * 761 * @param imageName 762 * the name of the image to find a button for 763 * @return the URL where question button images are located 764 */ 765 public static String getButtonImageUrl(String imageName) { 766 String buttonImageUrl = getKualiConfigurationService().getPropertyValueAsString( 767 WebUtils.APPLICATION_IMAGE_URL_PROPERTY_PREFIX + "." + imageName); 768 if (StringUtils.isBlank(buttonImageUrl)) { 769 buttonImageUrl = getDefaultButtonImageUrl(imageName); 770 } 771 return buttonImageUrl; 772 } 773 774 /** 775 * Generates a default button image URL, in the form of: 776 * ${kr.externalizable.images.url}buttonsmall_${imageName}.gif 777 * 778 * @param imageName 779 * the image name to generate a default button name for 780 * @return the default button image url 781 */ 782 public static String getDefaultButtonImageUrl(String imageName) { 783 return getKualiConfigurationService().getPropertyValueAsString(WebUtils.DEFAULT_IMAGE_URL_PROPERTY_NAME) 784 + "buttonsmall_" + imageName + ".gif"; 785 } 786 787 /** 788 * @return an implementation of the KualiConfigurationService 789 */ 790 public static ConfigurationService getKualiConfigurationService() { 791 if (configurationService == null) { 792 configurationService = KRADServiceLocator.getKualiConfigurationService(); 793 } 794 return configurationService; 795 } 796 797 /** 798 * Takes a string an converts the whitespace which would be ignored in an 799 * HTML document into HTML elements so the whitespace is preserved 800 * 801 * @param startingString The string to preserve whitespace in 802 * @return A string whose whitespace has been converted to HTML elements to preserve the whitespace in an HTML document 803 */ 804 public static String preserveWhitespace(String startingString) { 805 String convertedString = startingString.replaceAll("\n", "<br />"); 806 convertedString = convertedString.replaceAll(" ", " ").replaceAll("( | )", " "); 807 return convertedString; 808 } 809 }