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