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 }