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.kns.web.struts.action; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.struts.action.ActionForm; 020import org.apache.struts.action.ActionForward; 021import org.apache.struts.action.ActionMapping; 022import org.kuali.rice.core.api.CoreApiServiceLocator; 023import org.kuali.rice.core.api.config.property.ConfigContext; 024import org.kuali.rice.core.api.config.property.ConfigurationService; 025import org.kuali.rice.core.api.util.RiceConstants; 026import org.kuali.rice.core.api.util.RiceKeyConstants; 027import org.kuali.rice.coreservice.framework.parameter.ParameterService; 028import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 029import org.kuali.rice.kew.api.KewApiServiceLocator; 030import org.kuali.rice.kew.api.doctype.DocumentType; 031import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 032import org.kuali.rice.kns.datadictionary.HeaderNavigation; 033import org.kuali.rice.kns.datadictionary.KNSDocumentEntry; 034import org.kuali.rice.kns.datadictionary.LookupDefinition; 035import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition; 036import org.kuali.rice.kns.service.KNSServiceLocator; 037import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 038import org.kuali.rice.kns.util.WebUtils; 039import org.kuali.rice.kns.web.struts.form.KualiHelpForm; 040import org.kuali.rice.krad.datadictionary.AttributeDefinition; 041import org.kuali.rice.krad.datadictionary.DataDictionary; 042import org.kuali.rice.krad.datadictionary.DataDictionaryEntry; 043import org.kuali.rice.krad.datadictionary.HelpDefinition; 044import org.kuali.rice.krad.service.DataDictionaryService; 045import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 046import org.kuali.rice.krad.util.KRADConstants; 047 048import javax.servlet.http.HttpServletRequest; 049import javax.servlet.http.HttpServletResponse; 050 051/** 052 * This class handles requests for help text. 053 * 054 * 055 */ 056public class KualiHelpAction extends KualiAction { 057 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiHelpAction.class); 058 059 private static final String VALIDATION_PATTERN_STRING = "ValidationPattern"; 060 private static final String NO = "No"; 061 private static final String YES = "Yes"; 062 static final String DEFAULT_LOOKUP_HELP_TEXT_RESOURCE_KEY = "lookupHelpText"; 063 064 private static DataDictionaryService dataDictionaryService; 065 private static ConfigurationService kualiConfigurationService; 066 private static ParameterService parameterService; 067 private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService; 068 069 private DataDictionaryService getDataDictionaryService() { 070 if ( dataDictionaryService == null ) { 071 dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService(); 072 } 073 return dataDictionaryService; 074 } 075 private ConfigurationService getConfigurationService() { 076 if ( kualiConfigurationService == null ) { 077 kualiConfigurationService = CoreApiServiceLocator.getKualiConfigurationService(); 078 } 079 return kualiConfigurationService; 080 } 081 private ParameterService getParameterService() { 082 if ( parameterService == null ) { 083 parameterService = CoreFrameworkServiceLocator.getParameterService(); 084 } 085 return parameterService; 086 } 087 088 private MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() { 089 if ( maintenanceDocumentDictionaryService == null ) { 090 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService(); 091 } 092 return maintenanceDocumentDictionaryService; 093 } 094 095 /** 096 * Convenience method for accessing <code>{@link DataDictionaryEntry}</code> for the given business object 097 * 098 * @param businessObjectClassName 099 * @return DataDictionaryEntry 100 */ 101 private DataDictionaryEntry getDataDictionaryEntry(String businessObjectClassName) { 102 return getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(businessObjectClassName); 103 } 104 105 /** 106 * Convenience method for accessing the <code>{@link AttributeDefinition}</code> for a specific business object attribute 107 * defined in the DataDictionary. 108 * 109 * @param businessObjectClassName 110 * @param attributeName 111 * @return AttributeDefinition 112 */ 113 private AttributeDefinition getAttributeDefinition(String businessObjectClassName, String attributeName) throws ClassNotFoundException { 114 AttributeDefinition retval = null; 115 116 if (getDataDictionaryEntry(businessObjectClassName) != null) { 117 retval = getDataDictionaryEntry(businessObjectClassName).getAttributeDefinition(attributeName); 118 } 119 return retval; 120 } 121 122 /** 123 * @param attribute <code>{@link AttributeDefinition}</code> 124 * @return String 125 */ 126 private String getAttributeMaxLength(AttributeDefinition attribute) throws Exception { 127 return attribute.getMaxLength().toString(); 128 } 129 130 /** 131 * @param attribute <code>{@link AttributeDefinition}</code> 132 * @return String 133 */ 134 private String getAttributeValidationPatternName(AttributeDefinition attribute) throws Exception { 135 String retval = new String(); 136 if (attribute.getValidationPattern() != null) { 137 retval = attribute.getValidationPattern().getClass().getName(); 138 } 139 140 if (retval.indexOf(".") > 0) { 141 retval = retval.substring(retval.lastIndexOf(".") + 1); 142 } 143 if (retval.endsWith(VALIDATION_PATTERN_STRING)) { 144 retval = retval.substring(0, retval.lastIndexOf(VALIDATION_PATTERN_STRING)); 145 } 146 147 return retval; 148 } 149 150 /** 151 * Retrieves help information from the data dictionary for the business object attribute. 152 * 153 * @return ActionForward 154 */ 155 public ActionForward getAttributeHelpText(ActionMapping mapping, KualiHelpForm helpForm, HttpServletRequest request, HttpServletResponse response) throws Exception { 156 157 AttributeDefinition attribute; 158 159 if (StringUtils.isBlank(helpForm.getBusinessObjectClassName()) || StringUtils.isBlank(helpForm.getAttributeName())) { 160 throw new RuntimeException("Business object and attribute name not specified."); 161 } 162 attribute = getAttributeDefinition(helpForm.getBusinessObjectClassName(), helpForm.getAttributeName()); 163 164 if ( LOG.isDebugEnabled() ) { 165 LOG.debug( "Request for help on: " + helpForm.getBusinessObjectClassName() + " -- " + helpForm.getAttributeName() ); 166 LOG.debug( " attribute: " + attribute ); 167 } 168 169 if (attribute == null || StringUtils.isBlank(attribute.getSummary())) { 170 helpForm.setResourceKey(RiceKeyConstants.MESSAGE_NO_HELP_TEXT); 171 return getResourceHelpText(mapping, helpForm, request, response); 172 } 173 174 boolean required = attribute.isRequired().booleanValue(); 175 // KULRNE-4392 - pull the required attribute on BO maintenance documents from the document def rather than the BO 176 try { 177 Class boClass = Class.forName( helpForm.getBusinessObjectClassName() ); 178 String docTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName( boClass ); 179 if (StringUtils.isNotBlank(docTypeName)) { 180 // maybe it's not a maint doc 181 MaintainableFieldDefinition field = getMaintenanceDocumentDictionaryService().getMaintainableField( docTypeName, helpForm.getAttributeName() ); 182 if ( field != null ) { 183 required = field.isRequired(); 184 } 185 } 186 else { 187 if (log.isInfoEnabled()) { 188 log.info("BO class " + boClass.getName() + " does not have a maint doc definition. Defaulting to using DD for definition"); 189 } 190 } 191 } catch ( ClassNotFoundException ex ) { 192 // do nothing 193 LOG.warn( "Unable to obtain maintainable field for BO property.", ex ); 194 } 195 196 helpForm.setHelpLabel(attribute.getLabel()); 197 helpForm.setHelpSummary(attribute.getSummary()); 198 helpForm.setHelpDescription(attribute.getDescription()); 199 helpForm.setHelpRequired(required?YES:NO); 200 helpForm.setHelpMaxLength(getAttributeMaxLength(attribute)); 201 helpForm.setValidationPatternName(getAttributeValidationPatternName(attribute)); 202 203 return mapping.findForward(RiceConstants.MAPPING_BASIC); 204 } 205 206 /** 207 * Retrieves help information from the data dictionary for the business object attribute. 208 * 209 * @return ActionForward 210 */ 211 public ActionForward getAttributeHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 212 return getAttributeHelpText(mapping, (KualiHelpForm) form, request, response); 213 } 214 215 /** 216 * Retrieves help information from the data dictionary for the document type. 217 */ 218 public ActionForward getDocumentHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 219 KualiHelpForm helpForm = (KualiHelpForm) form; 220 221 String documentTypeName = helpForm.getDocumentTypeName(); 222 223 if (StringUtils.isBlank(documentTypeName)) { 224 throw new RuntimeException("Document type name not specified."); 225 } 226 227 DataDictionary dataDictionary = getDataDictionaryService().getDataDictionary(); 228 org.kuali.rice.krad.datadictionary.DocumentEntry entry = (org.kuali.rice.krad.datadictionary.DocumentEntry ) dataDictionary.getDocumentEntry(documentTypeName); 229 230 String label = ""; 231 String summary = ""; 232 String description = ""; 233 HelpDefinition helpDefinition = null; 234 String apcHelpUrl = null; 235 if (entry != null) { 236 DocumentType docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(entry.getDocumentTypeName()); 237 label = docType.getLabel(); 238 description = docType.getDescription(); 239 if (StringUtils.isNotBlank(docType.getHelpDefinitionUrl())) { 240 apcHelpUrl = WebUtils.toAbsoluteURL(ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.EXTERNALIZABLE_HELP_URL_KEY), docType.getHelpDefinitionUrl()); 241 } 242 } 243 244 if ( StringUtils.isNotBlank(apcHelpUrl) ) { 245 response.sendRedirect(apcHelpUrl); 246 return null; 247 } 248 249 helpForm.setHelpLabel(label); 250 helpForm.setHelpSummary(summary); 251 helpForm.setHelpDescription(description); 252 helpForm.setHelpDefinition(helpDefinition); 253 254 return mapping.findForward(RiceConstants.MAPPING_BASIC); 255 } 256 257 /** 258 * Retrieves help information from the data dictionary for the document type. 259 */ 260 public ActionForward getBusinessObjectHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 261 KualiHelpForm helpForm = (KualiHelpForm) form; 262 263 String objectClassName = helpForm.getBusinessObjectClassName(); 264 265 if (StringUtils.isBlank(objectClassName)) { 266 throw new RuntimeException("Document type name not specified."); 267 } 268 269 DataDictionary dataDictionary = getDataDictionaryService().getDataDictionary(); 270 BusinessObjectEntry entry = (BusinessObjectEntry) dataDictionary.getBusinessObjectEntry(objectClassName); 271 272 HelpDefinition helpDefinition = null; 273 String apcHelpUrl = null; 274 String label = ""; 275 String objectDescription = ""; 276 if (entry != null) { 277 helpDefinition = entry.getHelpDefinition(); 278 label = entry.getObjectLabel(); 279 objectDescription = entry.getObjectDescription(); 280 if (null != helpDefinition && null != helpDefinition.getParameterNamespace() && null != helpDefinition.getParameterDetailType() && null != helpDefinition.getParameterName()) { 281 apcHelpUrl = getHelpUrl(helpDefinition.getParameterNamespace(), helpDefinition.getParameterDetailType(), helpDefinition.getParameterName()); 282 } 283 } 284 285 if ( !StringUtils.isBlank(apcHelpUrl) ) { 286 response.sendRedirect(apcHelpUrl); 287 return null; 288 } 289 helpForm.setHelpLabel(label); 290 helpForm.setHelpDescription(objectDescription); 291 292 return mapping.findForward(RiceConstants.MAPPING_BASIC); 293 } 294 295 /** 296 * Retrieves help information from the data dictionary for the document type. 297 */ 298 public ActionForward getPageHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 299 KualiHelpForm helpForm = (KualiHelpForm) form; 300 301 String documentTypeName = helpForm.getDocumentTypeName(); 302 String pageName = helpForm.getPageName(); 303 304 if (StringUtils.isBlank(documentTypeName)) { 305 throw new RuntimeException("Document type name not specified."); 306 } 307 308 if (StringUtils.isBlank(pageName)) { 309 throw new RuntimeException("Page name not specified."); 310 } 311 312 DataDictionary dataDictionary = getDataDictionaryService().getDataDictionary(); 313 KNSDocumentEntry entry = (KNSDocumentEntry) dataDictionary.getDocumentEntry(documentTypeName); 314 315 String apcHelpUrl = null; 316 String label = ""; 317 String objectDescription = ""; 318 if (entry != null) { 319 for ( HeaderNavigation headerNavigation : entry.getHeaderNavigationList() ) { 320 if (headerNavigation.getHeaderTabDisplayName().equals(pageName)) { 321 HelpDefinition helpDefinition = headerNavigation.getHelpDefinition(); 322 if (null != helpDefinition && null != helpDefinition.getParameterNamespace() && null != helpDefinition.getParameterDetailType() && null != helpDefinition.getParameterName()) { 323 apcHelpUrl = getHelpUrl(helpDefinition.getParameterNamespace(), helpDefinition.getParameterDetailType(), helpDefinition.getParameterName()); 324 } 325 } 326 } 327 } 328 329 if ( !StringUtils.isBlank(apcHelpUrl) ) { 330 response.sendRedirect(apcHelpUrl); 331 return null; 332 } 333 helpForm.setHelpLabel(pageName); 334 helpForm.setHelpDescription("No help content available."); 335 336 return mapping.findForward(RiceConstants.MAPPING_BASIC); 337 } 338 339 /** 340 * Retrieves help content to link to based on security group/parameter 341 */ 342 public ActionForward getStoredHelpUrl(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 343 KualiHelpForm helpForm = (KualiHelpForm) form; 344 345 String helpParameterNamespace = helpForm.getHelpParameterNamespace(); 346 String helpParameterDetailType = helpForm.getHelpParameterDetailType(); 347 String helpParameterName = helpForm.getHelpParameterName(); 348 349 if (StringUtils.isBlank(helpParameterNamespace)) { 350 throw new RuntimeException("Parameter Namespace not specified."); 351 } 352 353 if (StringUtils.isBlank(helpParameterDetailType)) { 354 throw new RuntimeException("Detail Type not specified."); 355 } 356 357 if (StringUtils.isBlank(helpParameterName)) { 358 throw new RuntimeException("Parameter Name not specified."); 359 } 360 361 String apcHelpUrl = getHelpUrl(helpParameterNamespace, helpParameterDetailType, helpParameterName); 362 363 if ( !StringUtils.isBlank(apcHelpUrl) ) { 364 response.sendRedirect(apcHelpUrl); 365 return null; 366 } 367 368 helpForm.setHelpDescription("No help content available."); 369 return mapping.findForward(RiceConstants.MAPPING_BASIC); 370 } 371 372 /** 373 * Retrieves help information from resources by key. 374 */ 375 public ActionForward getResourceHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 376 KualiHelpForm helpForm = (KualiHelpForm) form; 377 378 String resourceKey = helpForm.getResourceKey(); 379 populateHelpFormForResourceText(helpForm, resourceKey); 380 381 return mapping.findForward(RiceConstants.MAPPING_BASIC); 382 } 383 384 /** 385 * Utility method that populates a KualiHelpForm with the description from a given resource key 386 * @param helpForm the KualiHelpForm to populate with help text 387 * @param resourceKey the resource key to use as help text 388 */ 389 protected void populateHelpFormForResourceText(KualiHelpForm helpForm, String resourceKey) { 390 if (StringUtils.isBlank(resourceKey)) { 391 throw new RuntimeException("Help resource key not specified."); 392 } 393 394 helpForm.setHelpLabel(""); 395 helpForm.setHelpSummary(""); 396 helpForm.setHelpDescription(getConfigurationService().getPropertyValueAsString(resourceKey)); 397 } 398 399 /** 400 * Retrieves help for a lookup 401 */ 402 public ActionForward getLookupHelpText(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 403 KualiHelpForm helpForm = (KualiHelpForm) form; 404 405 // handle doc search custom help urls 406 if (!StringUtils.isEmpty(helpForm.getSearchDocumentTypeName())) { 407 DocumentType docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(helpForm.getSearchDocumentTypeName()); 408 if (docType != null && !StringUtils.isEmpty(docType.getDocSearchHelpUrl())) { 409 String docSearchHelpUrl = WebUtils.toAbsoluteURL(ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.EXTERNALIZABLE_HELP_URL_KEY), docType.getDocSearchHelpUrl()); 410 411 if ( StringUtils.isNotBlank(docSearchHelpUrl) ) { 412 response.sendRedirect(docSearchHelpUrl); 413 return null; 414 } 415 } 416 } 417 418 final String lookupBusinessObjectClassName = helpForm.getLookupBusinessObjectClassName(); 419 if (!StringUtils.isBlank(lookupBusinessObjectClassName)) { 420 final DataDictionary dataDictionary = getDataDictionaryService().getDataDictionary(); 421 final BusinessObjectEntry entry = (BusinessObjectEntry) dataDictionary.getBusinessObjectEntry(lookupBusinessObjectClassName); 422 final LookupDefinition lookupDefinition = entry.getLookupDefinition(); 423 424 if (lookupDefinition != null) { 425 if (lookupDefinition.getHelpDefinition() != null && !StringUtils.isBlank(lookupDefinition.getHelpDefinition().getParameterNamespace()) && !StringUtils.isBlank(lookupDefinition.getHelpDefinition().getParameterDetailType()) && !StringUtils.isBlank(lookupDefinition.getHelpDefinition().getParameterName())) { 426 final String apcHelpUrl = getHelpUrl(lookupDefinition.getHelpDefinition().getParameterNamespace(), lookupDefinition.getHelpDefinition().getParameterDetailType(), lookupDefinition.getHelpDefinition().getParameterName()); 427 428 if ( !StringUtils.isBlank(apcHelpUrl) ) { 429 response.sendRedirect(apcHelpUrl); 430 return null; 431 } 432 } else if (!StringUtils.isBlank(lookupDefinition.getHelpUrl())) { 433 final String apcHelpUrl = WebUtils.toAbsoluteURL(ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.EXTERNALIZABLE_HELP_URL_KEY), lookupDefinition.getHelpUrl()); 434 response.sendRedirect(apcHelpUrl); 435 return null; 436 } 437 } 438 } 439 440 // still here? guess we're defaulting... 441 populateHelpFormForResourceText(helpForm, getDefaultLookupHelpResourceKey()); 442 return mapping.findForward(RiceConstants.MAPPING_BASIC); 443 } 444 445 /** 446 * @return the key of the default lookup help resource text 447 */ 448 protected String getDefaultLookupHelpResourceKey() { 449 return KualiHelpAction.DEFAULT_LOOKUP_HELP_TEXT_RESOURCE_KEY; 450 } 451 452 private String getHelpUrl(String parameterNamespace, String parameterDetailTypeCode, String parameterName) { 453 return WebUtils.toAbsoluteURL(getConfigurationService().getPropertyValueAsString(KRADConstants.EXTERNALIZABLE_HELP_URL_KEY), getParameterService().getParameterValueAsString(parameterNamespace, parameterDetailTypeCode, parameterName)); 454 } 455 456 /** 457 * Retrieves help content to link to based on parameterNamespace and parameterName 458 */ 459 public ActionForward getHelpUrlByNamespace(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 460 KualiHelpForm helpForm = (KualiHelpForm) form; 461 return getStoredHelpUrl(mapping, form, request, response); 462 } 463}