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