001/**
002 * Copyright 2005-2018 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 java.io.Serializable;
019import java.util.Enumeration;
020import java.util.HashMap;
021import java.util.Map;
022
023import javax.servlet.http.HttpServletRequest;
024import javax.servlet.http.HttpServletResponse;
025
026import org.apache.log4j.Logger;
027import org.apache.struts.Globals;
028import org.apache.struts.action.Action;
029import org.apache.struts.action.ActionForm;
030import org.apache.struts.action.ActionForward;
031import org.apache.struts.action.ActionMapping;
032import org.kuali.rice.core.api.config.property.ConfigContext;
033import org.kuali.rice.core.api.util.RiceConstants;
034import org.kuali.rice.kns.util.IncidentReportUtils;
035import org.kuali.rice.kns.web.struts.form.KualiExceptionIncidentForm;
036import org.kuali.rice.krad.exception.ExceptionIncident;
037import org.kuali.rice.krad.exception.KualiExceptionIncident;
038import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
039import org.kuali.rice.krad.service.KualiExceptionIncidentService;
040import org.kuali.rice.krad.util.GlobalVariables;
041import org.kuali.rice.krad.util.KRADConstants;
042
043/**
044 * This is the struts action class for handling the exception for Kuali
045 * applications.
046 *
047 * @deprecated KNS Struts deprecated, use KRAD and the Spring MVC framework.
048 */
049@Deprecated
050public class KualiExceptionHandlerAction extends Action {
051    private static final Logger LOG = Logger
052            .getLogger(KualiExceptionHandlerAction.class);
053
054    private static final String EXCEPTION_TIME_STAMP = "exception-timeStamp";
055    private static final String EXCEPTION_DOCUMENT_ID = "exception-" + ExceptionIncident.DOCUMENT_ID;
056    private static final String EXCEPTION_USER_EMAIL = "exception-" + ExceptionIncident.USER_EMAIL;
057    private static final String EXCEPTION_USER_NAME = "exception-" + ExceptionIncident.USER_NAME;
058    private static final String EXCEPTION_UUID = "exception-" + ExceptionIncident.UUID;
059    private static final String EXCEPTION_COMPONENT_NAME = "exception-" + ExceptionIncident.COMPONENT_NAME;
060    private static final String EXCEPTION_EXCEPTION_REPORT_SUBJECT = "exception-" + ExceptionIncident.EXCEPTION_REPORT_SUBJECT;
061    private static final String EXCEPTION_EXCEPTION_MESSAGE = "exception-" + ExceptionIncident.EXCEPTION_MESSAGE;
062    private static final String EXCEPTION_STACK_TRACE = "exception-" + ExceptionIncident.STACK_TRACE;
063
064    /**
065     * This overridden method dispatches action to be taken based on
066     * "methodToCall" parameter. The exception is processed when there is no
067     * "methodToCall" specified.
068     *
069     * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping,
070     *      org.apache.struts.action.ActionForm,
071     *      javax.servlet.http.HttpServletRequest,
072     *      javax.servlet.http.HttpServletResponse)
073     */
074    public ActionForward execute(ActionMapping mapping, ActionForm form,
075            HttpServletRequest request, HttpServletResponse response)
076            throws Exception {
077        return executeException(mapping, form, request, response);
078    }
079
080    /**
081     * This overridden method processes the exception and post exception (when
082     * user either submit/cancel the exception JSP page).
083     * <ul>
084     * <li>ProcessDefinition application Exception - Exception is stored in Http Request</li>
085     * <li>ProcessDefinition exception incident reporting - No exception, only form data</li>
086     * </ul>
087     *
088     * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping,
089     *      org.apache.struts.action.ActionForm,
090     *      javax.servlet.http.HttpServletRequest,
091     *      javax.servlet.http.HttpServletResponse)
092     */
093    public ActionForward executeException(ActionMapping mapping,
094            ActionForm form, HttpServletRequest request,
095            HttpServletResponse response) throws Exception {
096
097        if (LOG.isDebugEnabled()) {
098            String lm = String.format("ENTRY %s%n%s", form.getClass()
099                    .getSimpleName(), request.getRequestURI());
100            LOG.debug(lm);
101        }
102
103        // Get exception thrown
104        Exception e = (Exception) request.getAttribute(Globals.EXCEPTION_KEY);
105
106        // Initialize defined action mapping from struts-config
107        ActionForward returnForward = null;
108
109        // In case there is no exception, either a post back after page was
110        // filled in
111        // or just an error from directly accessing this struts action
112        if (e == null) {
113            if (form instanceof KualiExceptionIncidentForm) {
114                KualiExceptionIncidentForm formObject = (KualiExceptionIncidentForm) form;
115                // Manage conditions: submit or cancel
116                if (!formObject.isCancel()) {
117                    // Locate the post exception handler service. The service id
118                    // is
119                    // defined in the application properties
120                    // Only process the post exception handling when the
121                    // service
122                    // is specified
123                    KualiExceptionIncidentService reporterService = KRADServiceLocatorWeb
124                            .getKualiExceptionIncidentService();
125                    // An instance of the ExceptionIncident is created by
126                    // the
127                    // ExceptionIncidentService
128                    Map reducedMap = new HashMap();
129                    Enumeration<String> names = request.getParameterNames();
130                    while (names.hasMoreElements()) {
131                        String name = names.nextElement();
132                        reducedMap.put(name, request.getParameter(name));
133                    }
134
135                    // Sensitive data stored in user session
136                    Map<String, Serializable> userSessionMap = GlobalVariables.getUserSession().getObjectMap();
137
138                    // Only display if this is the right exception
139                    if(userSessionMap.get("EXCEPTION_TIME_STAMP").toString().equals(reducedMap.get(ExceptionIncident.STACK_TRACE))) {
140                        reducedMap.put(ExceptionIncident.DOCUMENT_ID, userSessionMap.get("EXCEPTION_DOCUMENT_ID").toString());
141                        reducedMap.put(ExceptionIncident.USER_EMAIL, userSessionMap.get("EXCEPTION_USER_EMAIL").toString());
142                        reducedMap.put(ExceptionIncident.USER_NAME, userSessionMap.get("EXCEPTION_USER_NAME").toString());
143                        reducedMap.put(ExceptionIncident.UUID, userSessionMap.get("EXCEPTION_UUID").toString());
144                        reducedMap.put(ExceptionIncident.COMPONENT_NAME, userSessionMap.get("EXCEPTION_COMPONENT_NAME").toString());
145                        reducedMap.put(ExceptionIncident.EXCEPTION_REPORT_SUBJECT, userSessionMap.get("EXCEPTION_EXCEPTION_REPORT_SUBJECT").toString());
146                        reducedMap.put(ExceptionIncident.EXCEPTION_MESSAGE, userSessionMap.get("EXCEPTION_EXCEPTION_MESSAGE").toString());
147                        reducedMap.put(ExceptionIncident.STACK_TRACE, userSessionMap.get("EXCEPTION_STACK_TRACE").toString());
148
149                    } else {
150                        reducedMap.put(ExceptionIncident.STACK_TRACE,"Not available.");
151                    }
152
153                    KualiExceptionIncident exceptionIncident = reporterService
154                            .getExceptionIncident(reducedMap);
155
156                    // Report the incident
157                    reporterService.report(exceptionIncident);
158                } else {
159                    // Set return after canceling
160                    ActionForward cancelForward = mapping
161                            .findForward(KRADConstants.MAPPING_CANCEL);
162                    if (cancelForward == null) {
163                        cancelForward = returnForward;
164                    } else {
165                        returnForward = cancelForward;
166                    }
167                }
168            }
169        } else {
170            // ProcessDefinition the received exception from HTTP request
171            returnForward = processException(mapping, form, request, e);
172        }
173
174        // Not specified, return
175        if (returnForward == null) {
176            returnForward = mapping.findForward(KRADConstants.MAPPING_CLOSE);
177        }
178
179        if (LOG.isDebugEnabled()) {
180            String lm = String.format("EXIT %s",
181                    (returnForward == null) ? "null" : returnForward.getPath());
182            LOG.debug(lm);
183        }
184
185        return returnForward;
186    }
187
188    /**
189     * This method process the caught exception by creating an exception
190     * information properties list and forward these properties to the exception
191     * incident handler JSP.
192     *
193     * @param exception
194     * @param mapping
195     * @param request
196     * @param documentId
197     *            Id of the document that Struts threw exception during its
198     *            processing. null if not the document processing that caused
199     *            the exception
200     * @return
201     * @throws Exception
202     */
203    @SuppressWarnings("unchecked")
204    protected ActionForward processException(ActionMapping mapping,
205            ActionForm form, HttpServletRequest request, Exception exception)
206            throws Exception {
207        // Only process the exception handling when the service
208        // is specified
209        KualiExceptionIncidentService reporterService = KRADServiceLocatorWeb
210                .getKualiExceptionIncidentService();
211        // Get exception properties from the Http Request
212        Map<String, String> properties = (Map<String, String>) request
213                .getAttribute(IncidentReportUtils.EXCEPTION_PROPERTIES);
214
215        // Construct the exception incident object
216        KualiExceptionIncident ei = reporterService.getExceptionIncident(
217                exception, properties);
218
219        // Add sensitive data to user session
220        String exceptionTimeStamp = String.valueOf(System.currentTimeMillis());
221        GlobalVariables.getUserSession().addObject("EXCEPTION_TIME_STAMP", exceptionTimeStamp);
222        GlobalVariables.getUserSession().addObject("EXCEPTION_DOCUMENT_ID", ei.getProperty(ExceptionIncident.DOCUMENT_ID));
223        GlobalVariables.getUserSession().addObject("EXCEPTION_USER_EMAIL", ei.getProperty(ExceptionIncident.USER_EMAIL));
224        GlobalVariables.getUserSession().addObject("EXCEPTION_USER_NAME", ei.getProperty(ExceptionIncident.USER_NAME));
225        GlobalVariables.getUserSession().addObject("EXCEPTION_UUID", ei.getProperty(ExceptionIncident.UUID));
226        GlobalVariables.getUserSession().addObject("EXCEPTION_COMPONENT_NAME", ei.getProperty(ExceptionIncident.COMPONENT_NAME));
227        GlobalVariables.getUserSession().addObject("EXCEPTION_EXCEPTION_REPORT_SUBJECT", ei.getProperty(ExceptionIncident.EXCEPTION_REPORT_SUBJECT));
228        GlobalVariables.getUserSession().addObject("EXCEPTION_EXCEPTION_MESSAGE", ei.getProperty(ExceptionIncident.EXCEPTION_MESSAGE));
229        GlobalVariables.getUserSession().addObject("EXCEPTION_STACK_TRACE", ei.getProperty(ExceptionIncident.STACK_TRACE));
230
231        // Hide sensitive data from form in production only
232        if(ConfigContext.getCurrentContextConfig().isProductionEnvironment()) {
233            Map<String, String> prodProperties = ei.toProperties();
234            prodProperties.put(ExceptionIncident.DOCUMENT_ID, "");
235            prodProperties.put(ExceptionIncident.USER_EMAIL, "");
236            prodProperties.put(ExceptionIncident.USER_NAME, "");
237            prodProperties.put(ExceptionIncident.UUID, "");
238            prodProperties.put(ExceptionIncident.COMPONENT_NAME, "");
239            prodProperties.put(ExceptionIncident.EXCEPTION_REPORT_SUBJECT, "");
240            prodProperties.put(ExceptionIncident.EXCEPTION_MESSAGE, "");
241            prodProperties.put(ExceptionIncident.STACK_TRACE, exceptionTimeStamp);
242            ei = reporterService.getExceptionIncident(
243                    null, prodProperties);
244        }
245
246        // Set full exception properties in Http Request and forward to JSP
247        request.setAttribute(KualiExceptionHandlerAction.class
248                .getSimpleName(), ei.toProperties());
249        return mapping.findForward(RiceConstants.MAPPING_BASIC);
250    }
251}