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    }