Coverage Report - org.kuali.rice.kns.web.struts.action.KualiRequestProcessor
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiRequestProcessor
0%
0/259
0%
0/168
7.579
KualiRequestProcessor$1
0%
0/27
0%
0/8
7.579
KualiRequestProcessor$WrappedRuntimeException
0%
0/2
N/A
7.579
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in
 5  
  * compliance with the License. You may obtain a copy of the License at
 6  
  * 
 7  
  * http://www.opensource.org/licenses/ecl2.php
 8  
  * 
 9  
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS
 10  
  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 11  
  * language governing permissions and limitations under the License.
 12  
  */
 13  
 package org.kuali.rice.kns.web.struts.action;
 14  
 
 15  
 import org.apache.commons.lang.StringUtils;
 16  
 import org.apache.log4j.Logger;
 17  
 import org.apache.log4j.MDC;
 18  
 import org.apache.ojb.broker.OptimisticLockException;
 19  
 import org.apache.struts.Globals;
 20  
 import org.apache.struts.action.Action;
 21  
 import org.apache.struts.action.ActionForm;
 22  
 import org.apache.struts.action.ActionForward;
 23  
 import org.apache.struts.action.ActionMapping;
 24  
 import org.apache.struts.action.InvalidCancelException;
 25  
 import org.apache.struts.action.RequestProcessor;
 26  
 import org.apache.struts.config.FormBeanConfig;
 27  
 import org.apache.struts.config.ForwardConfig;
 28  
 import org.apache.struts.util.RequestUtils;
 29  
 import org.kuali.rice.core.api.util.RiceConstants;
 30  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 31  
 import org.kuali.rice.kns.exception.FileUploadLimitExceededException;
 32  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 33  
 import org.kuali.rice.kns.service.SessionDocumentService;
 34  
 import org.kuali.rice.kns.util.ErrorContainer;
 35  
 import org.kuali.rice.kns.util.InfoContainer;
 36  
 import org.kuali.rice.kns.util.KNSConstants;
 37  
 import org.kuali.rice.kns.util.KNSGlobalVariables;
 38  
 import org.kuali.rice.kns.util.WarningContainer;
 39  
 import org.kuali.rice.kns.util.WebUtils;
 40  
 import org.kuali.rice.kns.web.EditablePropertiesHistoryHolder;
 41  
 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
 42  
 import org.kuali.rice.kns.web.struts.form.KualiForm;
 43  
 import org.kuali.rice.kns.web.struts.form.pojo.PojoForm;
 44  
 import org.kuali.rice.krad.UserSession;
 45  
 import org.kuali.rice.krad.document.Document;
 46  
 import org.kuali.rice.krad.exception.ValidationException;
 47  
 import org.kuali.rice.krad.service.KRADServiceLocatorInternal;
 48  
 import org.kuali.rice.krad.util.GlobalVariables;
 49  
 import org.kuali.rice.krad.util.KRADConstants;
 50  
 import org.kuali.rice.krad.util.KRADUtils;
 51  
 import org.kuali.rice.krad.util.MessageMap;
 52  
 import org.springframework.transaction.PlatformTransactionManager;
 53  
 import org.springframework.transaction.TransactionStatus;
 54  
 import org.springframework.transaction.support.TransactionCallback;
 55  
 import org.springframework.transaction.support.TransactionTemplate;
 56  
 import org.springmodules.orm.ojb.OjbOperationException;
 57  
 
 58  
 import javax.servlet.ServletException;
 59  
 import javax.servlet.http.HttpServletRequest;
 60  
 import javax.servlet.http.HttpServletResponse;
 61  
 import javax.servlet.http.HttpSession;
 62  
 import java.io.IOException;
 63  
 
 64  
 /**
 65  
  * This class handles setup of user session and restoring of action form.
 66  
  * 
 67  
  * 
 68  
  */
 69  0
 public class KualiRequestProcessor extends RequestProcessor {
 70  
         
 71  
         private static final String MDC_DOC_ID = "docId";
 72  
         private static final String PREVIOUS_REQUEST_EDITABLE_PROPERTIES_GUID_PARAMETER_NAME = "actionEditablePropertiesGuid";
 73  
 
 74  0
         private static Logger LOG = Logger.getLogger(KualiRequestProcessor.class);
 75  
 
 76  
         private SessionDocumentService sessionDocumentService;
 77  
         private PlatformTransactionManager transactionManager;
 78  
         
 79  
         @Override
 80  
         public void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
 81  0
                 if ( LOG.isInfoEnabled() ) {
 82  0
                         LOG.info(new StringBuffer("Started processing request: '").append(request.getRequestURI()).append("' w/ query string: '").append(request.getQueryString()).append("'"));
 83  
                 }
 84  
 
 85  
                 try { 
 86  0
                         strutsProcess(request, response);
 87  0
                 } catch (FileUploadLimitExceededException e) {
 88  0
                         ActionForward actionForward = processException(request, response, e, e.getActionForm(), e.getActionMapping());
 89  0
                         processForwardConfig(request, response, actionForward);
 90  
                 } finally {
 91  0
                         KNSGlobalVariables.setKualiForm(null);
 92  0
                 }
 93  
                         
 94  
                 try {
 95  0
                         ActionForm form = WebUtils.getKualiForm(request);
 96  
                         
 97  0
                         if (form != null && form instanceof KualiDocumentFormBase) {
 98  0
                                 String docId = ((KualiDocumentFormBase) form).getDocId();
 99  0
                                 if (docId != null) { MDC.put(MDC_DOC_ID, docId); }
 100  
                         }
 101  
 
 102  0
                         String refreshCaller = request.getParameter(KRADConstants.REFRESH_CALLER);
 103  0
                         if (form!=null && KualiDocumentFormBase.class.isAssignableFrom(form.getClass()) 
 104  
                                         && !KRADConstants.QUESTION_REFRESH.equalsIgnoreCase(refreshCaller)) {
 105  0
                                 KualiDocumentFormBase docForm = (KualiDocumentFormBase) form;
 106  0
                                 Document document = docForm.getDocument();
 107  0
                                 String docFormKey = docForm.getFormKey();
 108  
 
 109  0
                                 UserSession userSession = (UserSession) request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY);
 110  
 
 111  0
                                 if (WebUtils.isDocumentSession(document, docForm)) {
 112  0
                                         getSessionDocumentService().setDocumentForm(docForm, userSession, request.getRemoteAddr());
 113  
                                 }
 114  
 
 115  0
                                 Boolean exitingDocument = (Boolean) request.getAttribute(KRADConstants.EXITING_DOCUMENT);
 116  
 
 117  0
                                 if (exitingDocument != null && exitingDocument.booleanValue()) {
 118  
                                         // remove KualiDocumentFormBase object from session and
 119  
                                         // table.
 120  0
                                         getSessionDocumentService().purgeDocumentForm(docForm.getDocument().getDocumentNumber(), docFormKey, userSession, request.getRemoteAddr());
 121  
                                 }
 122  
                         }
 123  
 
 124  0
                         if ( LOG.isInfoEnabled() ) {
 125  0
                                 LOG.info(new StringBuffer("Finished processing request: '").append(request.getRequestURI()).append("' w/ query string: '").append(request.getQueryString()).append("'"));
 126  
                         }
 127  
 
 128  
                 } finally {
 129  
                         // MDC docId key is set above, and also during super.process() in the call to processActionForm
 130  0
                         MDC.remove(MDC_DOC_ID);
 131  0
                 }
 132  
 
 133  0
         }
 134  
         
 135  
         @Override
 136  
         protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {
 137  0
         final UserSession session = KRADUtils.getUserSessionFromRequest(request);
 138  
         
 139  0
         if (session == null) {
 140  0
                 throw new IllegalStateException("the user session has not been established");
 141  
         }
 142  0
             GlobalVariables.setUserSession(session);
 143  0
             KNSGlobalVariables.clear();
 144  0
                 return true;
 145  
         }
 146  
         
 147  
         /**
 148  
      * <p>Process an <code>HttpServletRequest</code> and create the
 149  
      * corresponding <code>HttpServletResponse</code> or dispatch
 150  
      * to another resource.</p>
 151  
      *
 152  
      * @param request The servlet request we are processing
 153  
      * @param response The servlet response we are creating
 154  
      *
 155  
      * @exception IOException if an input/output error occurs
 156  
      * @exception ServletException if a processing exception occurs
 157  
      */
 158  
     public void strutsProcess(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
 159  
 
 160  
         // Wrap multipart requests with a special wrapper
 161  0
         request = processMultipart(request);
 162  
 
 163  
         // Identify the path component we will use to select a mapping
 164  0
         String path = processPath(request, response);
 165  0
         if (path == null) {
 166  0
             return;
 167  
         }
 168  
         
 169  0
         if (log.isDebugEnabled()) {
 170  0
             log.debug("Processing a '" + request.getMethod() +
 171  
                       "' for path '" + path + "'");
 172  
         }
 173  
 
 174  
         // Select a Locale for the current user if requested
 175  0
         processLocale(request, response);
 176  
 
 177  
         // Set the content type and no-caching headers if requested
 178  0
         processContent(request, response);
 179  0
         processNoCache(request, response);
 180  
 
 181  
         // General purpose preprocessing hook
 182  0
         if (!processPreprocess(request, response)) {
 183  0
             return;
 184  
         }
 185  
         
 186  0
         this.processCachedMessages(request, response);
 187  
 
 188  
         // Identify the mapping for this request
 189  0
         ActionMapping mapping = processMapping(request, response, path);
 190  0
         if (mapping == null) {
 191  0
             return;
 192  
         }
 193  
 
 194  
         // Check for any role required to perform this action
 195  0
         if (!processRoles(request, response, mapping)) {
 196  0
             return;
 197  
         }
 198  
 
 199  0
         processFormActionAndForward(request, response, mapping);
 200  
 
 201  0
     }
 202  
     
 203  
     public void processFormActionAndForward(final HttpServletRequest request, final HttpServletResponse response, final ActionMapping mapping) throws ServletException, IOException {
 204  0
             TransactionTemplate template = new TransactionTemplate(getTransactionManager());
 205  
             try {
 206  0
                         template.execute(new TransactionCallback() {
 207  
                                 @Override
 208  
                                 public Object doInTransaction(TransactionStatus status) {
 209  
                                         try {
 210  
                                                 // Process any ActionForm bean related to this request
 211  0
                                         ActionForm form = processActionForm(request, response, mapping);
 212  0
                                         processPopulate(request, response, form, mapping);
 213  
                                         
 214  
                                         // Validate any fields of the ActionForm bean, if applicable
 215  
                                         try {
 216  0
                                             if (!processValidate(request, response, form, mapping)) {
 217  0
                                                 return null;
 218  
                                             }
 219  0
                                         } catch (InvalidCancelException e) {
 220  0
                                             ActionForward forward = processException(request, response, e, form, mapping);
 221  0
                                             processForwardConfig(request, response, forward);
 222  0
                                             return null;
 223  0
                                         } catch (IOException e) {
 224  0
                                             throw e;
 225  0
                                         } catch (ServletException e) {
 226  0
                                             throw e;
 227  0
                                         }
 228  
                                             
 229  
                                         // Process a forward or include specified by this mapping
 230  0
                                         if (!processForward(request, response, mapping)) {
 231  0
                                             return null;
 232  
                                         }
 233  
                                         
 234  0
                                         if (!processInclude(request, response, mapping)) {
 235  0
                                             return null;
 236  
                                         }
 237  
 
 238  
                                         // Create or acquire the Action instance to process this request
 239  0
                                         Action action = processActionCreate(request, response, mapping);
 240  0
                                         if (action == null) {
 241  0
                                             return null;
 242  
                                         }
 243  
                                                 
 244  
                                             // Call the Action instance itself
 245  0
                                         ActionForward forward = processActionPerform(request, response, action, form, mapping);
 246  
                                 
 247  
                                         // Process the returned ActionForward instance
 248  0
                                         processForwardConfig(request, response, forward);
 249  0
                                         } catch (Exception e) {
 250  
                                                 // the doInTransaction method has no means for
 251  
                                                 // throwing exceptions, so we will wrap the
 252  
                                                 // exception in
 253  
                                                 // a RuntimeException and re-throw. The one caveat
 254  
                                                 // here is that this will always result in
 255  
                                                 // the
 256  
                                                 // transaction being rolled back (since
 257  
                                                 // WrappedRuntimeException is a runtime exception).
 258  0
                                                 throw new WrappedRuntimeException(e);
 259  0
                                         }
 260  0
                                         return null;
 261  
                                 }
 262  
                         });
 263  0
                 } catch (WrappedRuntimeException wre) {
 264  0
                         throw new RuntimeException(wre.getCause());
 265  0
                 }
 266  0
     }
 267  
 
 268  
 
 269  
         /**
 270  
          * This method gets the document number from the request.  The request should have been processed already 
 271  
          * before this is called if it is multipart.  
 272  
          * 
 273  
          * @param request
 274  
          * @return the document number, or null if one can't be found in the request.
 275  
          */
 276  
         private String getDocumentNumber(HttpServletRequest request) {
 277  0
                 String documentNumber = request.getParameter(KRADConstants.DOCUMENT_DOCUMENT_NUMBER);
 278  
 
 279  
                 // from lookup pages.
 280  0
                 if (documentNumber == null) {
 281  0
                         documentNumber = request.getParameter(KRADConstants.DOC_NUM);
 282  
                 }
 283  
                 
 284  0
                 if (documentNumber == null) {
 285  0
                         documentNumber = request.getParameter("documentId");
 286  
                 }
 287  
                 
 288  0
                 return documentNumber;
 289  
         }
 290  
 
 291  
         /**
 292  
          * Hooks into populate process to call form populate method if form is an
 293  
          * instanceof PojoForm.
 294  
          */
 295  
         @Override
 296  
         protected void processPopulate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping) throws ServletException {
 297  0
                 if (form instanceof KualiForm) {
 298  
                         // Add the ActionForm to GlobalVariables
 299  
                         // This will allow developers to retrieve both the Document and any
 300  
                         // request parameters that are not
 301  
                         // part of the Form and make them available in ValueFinder classes
 302  
                         // and other places where they are needed.
 303  0
                         KNSGlobalVariables.setKualiForm((KualiForm) form);
 304  
                 }
 305  
 
 306  
                 // if not PojoForm, call struts populate
 307  0
                 if (!(form instanceof PojoForm)) {
 308  0
                         super.processPopulate(request, response, form, mapping);
 309  0
                         return;
 310  
                 }
 311  
                 
 312  0
                 final String previousRequestGuid = request.getParameter(KualiRequestProcessor.PREVIOUS_REQUEST_EDITABLE_PROPERTIES_GUID_PARAMETER_NAME);
 313  
 
 314  0
                 ((PojoForm)form).clearEditablePropertyInformation();
 315  0
                 ((PojoForm)form).registerStrutsActionMappingScope(mapping.getScope());
 316  
                 
 317  0
                 String multipart = mapping.getMultipartClass();
 318  0
                 if (multipart != null) {
 319  0
                         request.setAttribute(Globals.MULTIPART_KEY, multipart);
 320  
                 }
 321  
 
 322  0
                 form.setServlet(this.servlet);
 323  0
                 form.reset(mapping, request);
 324  
 
 325  0
                 ((PojoForm)form).setPopulateEditablePropertiesGuid(previousRequestGuid);
 326  
                 // call populate on ActionForm
 327  0
                 ((PojoForm) form).populate(request);
 328  0
                 request.setAttribute("UnconvertedValues", ((PojoForm) form).getUnconvertedValues().keySet());
 329  0
                 request.setAttribute("UnconvertedHash", ((PojoForm) form).getUnconvertedValues());
 330  0
         }
 331  
 
 332  
         /**
 333  
          * Hooks into validate to catch any errors from the populate, and translate
 334  
          * the ErrorMap to ActionMessages.
 335  
          */
 336  
         @Override
 337  
         protected boolean processValidate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping) throws IOException, ServletException, InvalidCancelException {
 338  
 
 339  
                 // skip form validate if we had errors from populate
 340  0
                 if (GlobalVariables.getMessageMap().hasNoErrors()) {
 341  0
                         if (form == null) {
 342  0
                                 return (true);
 343  
                         }
 344  
                         // Was this request cancelled?
 345  0
                         if (request.getAttribute(Globals.CANCEL_KEY) != null) {
 346  0
                                 if (LOG.isDebugEnabled()) {
 347  0
                                         LOG.debug(" Cancelled transaction, skipping validation");
 348  
                                 }
 349  0
                                 return (true);
 350  
                         }
 351  
 
 352  
                         // Has validation been turned off for this mapping?
 353  0
                         if (!mapping.getValidate()) {
 354  0
                                 return (true);
 355  
                         }
 356  
 
 357  
                         // call super to call forms validate
 358  0
                         super.processValidate(request, response, form, mapping);
 359  
                 }
 360  
 
 361  0
                 publishMessages(request);
 362  0
                 if (!GlobalVariables.getMessageMap().hasNoErrors()) {
 363  
                         // Special handling for multipart request
 364  0
                         if (form.getMultipartRequestHandler() != null) {
 365  0
                                 if (LOG.isDebugEnabled()) {
 366  0
                                         LOG.debug("  Rolling back multipart request");
 367  
                                 }
 368  0
                                 form.getMultipartRequestHandler().rollback();
 369  
                         }
 370  
 
 371  
                         // Fix state that could be incorrect because of validation failure
 372  0
                         if (form instanceof PojoForm) {
 373  0
                                 ((PojoForm) form).processValidationFail();
 374  
                         }
 375  
 
 376  
                         // Was an input path (or forward) specified for this mapping?
 377  0
                         String input = mapping.getInput();
 378  0
                         if (input == null) {
 379  0
                                 if (LOG.isDebugEnabled()) {
 380  0
                                         LOG.debug("  Validation failed but no input form available");
 381  
                                 }
 382  0
                                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getInternal().getMessage("noInput", mapping.getPath()));
 383  0
                                 return (false);
 384  
                         }
 385  
 
 386  0
                         if (moduleConfig.getControllerConfig().getInputForward()) {
 387  0
                                 ForwardConfig forward = mapping.findForward(input);
 388  0
                                 processForwardConfig(request, response, forward);
 389  0
                         } else {
 390  0
                                 internalModuleRelativeForward(input, request, response);
 391  
                         }
 392  
 
 393  0
                         return (false);
 394  
                 }
 395  0
                 return true;
 396  
         }
 397  
 
 398  
         /**
 399  
          * Checks for return from a lookup or question, and restores the action form
 400  
          * stored under the request parameter docFormKey.
 401  
          */
 402  
         @Override
 403  
         protected ActionForm processActionForm(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) {
 404  
                 
 405  0
                 String documentNumber = getDocumentNumber(request);
 406  0
                 if (documentNumber != null) { MDC.put(MDC_DOC_ID, documentNumber); }
 407  
                 
 408  0
                 UserSession userSession = (UserSession) request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY);
 409  
 
 410  0
                 String docFormKey = request.getParameter(KRADConstants.DOC_FORM_KEY);
 411  0
                 String methodToCall = request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER);
 412  0
                 String refreshCaller = request.getParameter(KRADConstants.REFRESH_CALLER);
 413  
 //                String searchListRequestKey = request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY);
 414  0
                 String documentWebScope = request.getParameter(KRADConstants.DOCUMENT_WEB_SCOPE);
 415  
 
 416  0
                 if (mapping.getPath().startsWith(KRADConstants.REFRESH_MAPPING_PREFIX) || KRADConstants.RETURN_METHOD_TO_CALL.equalsIgnoreCase(methodToCall) ||
 417  
                                 KRADConstants.QUESTION_REFRESH.equalsIgnoreCase(refreshCaller) || KRADConstants.TEXT_AREA_REFRESH.equalsIgnoreCase(refreshCaller) || KRADConstants
 418  
                 .SESSION_SCOPE.equalsIgnoreCase(documentWebScope)) {
 419  0
                         ActionForm form = null;
 420  
                         // check for search result storage and clear
 421  0
                         GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_LIST_KEY_PREFIX);
 422  
 
 423  
                         // We put different type of forms such as document form, lookup form
 424  
                         // in session but we only store document form in
 425  
                         // database.
 426  0
                         if (userSession.retrieveObject(docFormKey) != null) {
 427  0
                                 LOG.debug("getDecomentForm KualiDocumentFormBase from session");
 428  0
                                 form = (ActionForm) userSession.retrieveObject(docFormKey);
 429  0
                         } else if (StringUtils.isNotBlank(documentNumber)) {
 430  0
                                 form = getSessionDocumentService().getDocumentForm(documentNumber, docFormKey, userSession, request.getRemoteAddr());
 431  
                         }
 432  0
                         request.setAttribute(mapping.getAttribute(), form);
 433  0
                         if (!KRADConstants.SESSION_SCOPE.equalsIgnoreCase(documentWebScope)) {
 434  0
                                 userSession.removeObject(docFormKey);
 435  
                         }
 436  
                         // we should check whether this is a multipart request because we
 437  
                         // could have had a combination of query parameters and a multipart
 438  
                         // request
 439  0
                         String contentType = request.getContentType();
 440  0
                         String method = request.getMethod();
 441  0
                         if (("POST".equalsIgnoreCase(method) && contentType != null && contentType.startsWith("multipart/form-data"))) {
 442  
                                 // this method parses the multipart request and adds new
 443  
                                 // non-file parameters into the request
 444  0
                                 WebUtils.getMultipartParameters(request, null, form, mapping);
 445  
                         }
 446  
                         // The form can be null if the document is not a session document
 447  0
                         if (form != null) {
 448  0
                                 return form;
 449  
                         }
 450  
                 }
 451  
 
 452  
                 // Rice has the ability to limit file upload sizes on a per-form basis,
 453  
                 // so the max upload sizes may be accessed by calling methods on
 454  
                 // PojoFormBase.
 455  
                 // This requires that we are able know the file upload size limit (i.e.
 456  
                 // retrieve a form instance) before we parse a mulitpart request.
 457  0
                 ActionForm form = super.processActionForm(request, response, mapping);
 458  
 
 459  
                 // for sessiondocument with multipart request
 460  0
                 String contentType = request.getContentType();
 461  0
                 String method = request.getMethod();
 462  
 
 463  0
                 if ("GET".equalsIgnoreCase(method) && StringUtils.isNotBlank(methodToCall) && form instanceof PojoForm &&
 464  
                                 ((PojoForm) form).getMethodToCallsToBypassSessionRetrievalForGETRequests().contains(methodToCall)) {
 465  0
                         return createNewActionForm(mapping, request);
 466  
                 }
 467  
                 
 468  
                 // if we have a multipart request, parse it and return the stored form
 469  
                 // from session if the doc form key is not blank. If it is blank, then
 470  
                 // we just return the form
 471  
                 // generated from the superclass processActionForm method. Either way,
 472  
                 // we need to parse the mulitpart request now so that we may determine
 473  
                 // what the value of the doc form key is.
 474  
                 // This is generally against the contract of processActionForm, because
 475  
                 // processPopulate should be responsible for parsing the mulitpart
 476  
                 // request, but we need to parse it now
 477  
                 // to determine the doc form key value.
 478  0
                 if (("POST".equalsIgnoreCase(method) && contentType != null && contentType.startsWith("multipart/form-data"))) {
 479  0
                         WebUtils.getMultipartParameters(request, null, form, mapping);
 480  0
                         docFormKey = request.getParameter(KRADConstants.DOC_FORM_KEY);
 481  0
                         documentWebScope = request.getParameter(KRADConstants.DOCUMENT_WEB_SCOPE);
 482  
 
 483  0
                         documentNumber = getDocumentNumber(request);
 484  
 
 485  0
                         if (KRADConstants.SESSION_SCOPE.equalsIgnoreCase(documentWebScope) ||
 486  
                                         (form instanceof KualiDocumentFormBase && WebUtils
 487  
                             .isDocumentSession(((KualiDocumentFormBase) form).getDocument(),
 488  
                                     (KualiDocumentFormBase) form))) {
 489  
 
 490  0
                                 Object userSessionObject = userSession.retrieveObject(docFormKey);
 491  0
                                 if ( userSessionObject != null &&  userSessionObject instanceof ActionForm ) {
 492  0
                                         LOG.debug("getDocumentForm KualiDocumentFormBase from session");
 493  0
                                         form = (ActionForm) userSessionObject;
 494  
                                 } else {
 495  0
                                         ActionForm tempForm = getSessionDocumentService().getDocumentForm(documentNumber, docFormKey, userSession, request.getRemoteAddr());
 496  0
                                         if ( tempForm != null ) {
 497  0
                                                 form = tempForm;
 498  
                                         }
 499  
                                 }
 500  
 
 501  0
                                 request.setAttribute(mapping.getAttribute(), form);
 502  0
                                 if (form != null) {
 503  0
                                         return form;
 504  
                                 }
 505  
                         }
 506  
                 }
 507  0
                 return form;
 508  
         }
 509  
 
 510  
         /**
 511  
          * Hook into action perform to handle errors in the error map and catch
 512  
          * exceptions.
 513  
          * 
 514  
          * <p>
 515  
          * A transaction is started prior to the execution of the action. This
 516  
          * allows for the action code to execute efficiently without the need for
 517  
          * using PROPAGATION_SUPPORTS in the transaction definitions. The
 518  
          * PROPAGATION_SUPPORTS propagation type does not work well with JTA.
 519  
          */
 520  
         @Override
 521  
         protected ActionForward processActionPerform(final HttpServletRequest request, final HttpServletResponse response, final Action action, final ActionForm form, final ActionMapping mapping) throws IOException, ServletException {
 522  
                 try {
 523  
                         
 524  0
                         ActionForward forward = action.execute(mapping, form, request, response);
 525  
 
 526  0
                         publishMessages(request);
 527  0
                         saveMessages(request);
 528  0
                         saveAuditErrors(request);
 529  
                         
 530  0
                         if (form instanceof PojoForm) {
 531  0
                                 if (((PojoForm)form).getEditableProperties() == null 
 532  
                                                 || ((PojoForm)form).getEditableProperties().isEmpty()) {
 533  0
                                         EditablePropertiesHistoryHolder holder = (EditablePropertiesHistoryHolder) GlobalVariables.getUserSession().getObjectMap().get(
 534  
                             KRADConstants.EDITABLE_PROPERTIES_HISTORY_HOLDER_ATTR_NAME);
 535  0
                                     if (holder == null) {
 536  0
                                             holder = new EditablePropertiesHistoryHolder();
 537  
                                     }
 538  
                                         
 539  0
                                         final String guid = holder.addEditablePropertiesToHistory(((PojoForm)form).getEditableProperties());
 540  0
                                     ((PojoForm)form).setActionEditablePropertiesGuid(guid);
 541  0
                                     GlobalVariables.getUserSession().addObject(KRADConstants.EDITABLE_PROPERTIES_HISTORY_HOLDER_ATTR_NAME, holder);
 542  
                                 }
 543  
                         }
 544  
                         
 545  0
                         return forward;
 546  
 
 547  0
                 } catch (Exception e) {
 548  0
                         if (e instanceof WrappedRuntimeException) {
 549  0
                                 e = (Exception) e.getCause();
 550  
                         }
 551  0
                         if (e instanceof ValidationException) {
 552  
                                 // add a generic error message if there are none
 553  0
                                 if (GlobalVariables.getMessageMap().hasNoErrors()) {
 554  
 
 555  0
                                         GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS, RiceKeyConstants.ERROR_CUSTOM, e.getMessage());
 556  
                                 }
 557  
 
 558  0
                                 if (form instanceof PojoForm) {
 559  0
                                         if (((PojoForm)form).getEditableProperties() == null 
 560  
                                                         || ((PojoForm)form).getEditableProperties().isEmpty()) {
 561  0
                                             EditablePropertiesHistoryHolder holder = (EditablePropertiesHistoryHolder) GlobalVariables.getUserSession().getObjectMap().get(
 562  
                                 KRADConstants.EDITABLE_PROPERTIES_HISTORY_HOLDER_ATTR_NAME);
 563  0
                                         if (holder == null) {
 564  0
                                                 holder = new EditablePropertiesHistoryHolder();
 565  
                                         }
 566  
 
 567  0
                                             final String guid = holder.addEditablePropertiesToHistory(((PojoForm)form).getEditableProperties());
 568  0
                                         ((PojoForm)form).setActionEditablePropertiesGuid(guid);
 569  0
                                         GlobalVariables.getUserSession().addObject(KRADConstants.EDITABLE_PROPERTIES_HISTORY_HOLDER_ATTR_NAME, holder);
 570  
                                         }
 571  
                                 }                        
 572  
                                 // display error messages and return to originating page
 573  0
                                 publishMessages(request);
 574  0
                                 return mapping.findForward(RiceConstants.MAPPING_BASIC);
 575  
                         }
 576  
 
 577  0
                         publishMessages(request);
 578  
 
 579  0
                         return (processException(request, response, e, form, mapping));
 580  
                 }
 581  
         }
 582  
 
 583  
         /**
 584  
          * Adds more detailed logging for unhandled exceptions
 585  
          * 
 586  
          * @see org.apache.struts.action.RequestProcessor#processException(HttpServletRequest,
 587  
          *      HttpServletResponse, Exception, ActionForm, ActionMapping)
 588  
          */
 589  
         @Override
 590  
         protected ActionForward processException(HttpServletRequest request, HttpServletResponse response, Exception exception, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
 591  0
                 ActionForward actionForward = null;
 592  
 
 593  
                 try {
 594  0
                         actionForward = super.processException(request, response, exception, form, mapping);
 595  0
                 } catch (IOException e) {
 596  0
                         logException(e);
 597  0
                         throw e;
 598  0
                 } catch (ServletException e) {
 599  
                         // special case, to make OptimisticLockExceptions easier to read
 600  0
                         Throwable rootCause = e.getRootCause();
 601  0
                         if (rootCause instanceof OjbOperationException) {
 602  0
                                 OjbOperationException ooe = (OjbOperationException) rootCause;
 603  
 
 604  0
                                 Throwable subcause = ooe.getCause();
 605  0
                                 if (subcause instanceof OptimisticLockException) {
 606  0
                                         OptimisticLockException ole = (OptimisticLockException) subcause;
 607  
 
 608  0
                                         StringBuffer message = new StringBuffer(e.getMessage());
 609  
 
 610  0
                                         Object sourceObject = ole.getSourceObject();
 611  0
                                         if (sourceObject != null) {
 612  0
                                                 message.append(" (sourceObject is ");
 613  0
                                                 message.append(sourceObject.getClass().getName());
 614  0
                                                 message.append(")");
 615  
                                         }
 616  
 
 617  0
                                         e = new ServletException(message.toString(), rootCause);
 618  
                                 }
 619  
                         }
 620  
 
 621  0
                         logException(e);
 622  0
                         throw e;
 623  0
                 }
 624  0
                 return actionForward;
 625  
         }
 626  
 
 627  
         private void logException(Exception e) {
 628  0
                 LOG.error("unhandled exception thrown by KualiRequestProcessor.processActionPerform", e);
 629  0
         }
 630  
 
 631  
         /**
 632  
          * Checks for errors in the error map and transforms them to struts action
 633  
          * messages then stores in the request.
 634  
          */
 635  
         private void publishMessages(HttpServletRequest request) {
 636  0
                 MessageMap errorMap = GlobalVariables.getMessageMap();
 637  0
                 if (!errorMap.hasNoErrors()) {
 638  0
                         ErrorContainer errorContainer = new ErrorContainer(errorMap);
 639  
 
 640  0
                         request.setAttribute("ErrorContainer", errorContainer);
 641  0
                         request.setAttribute(Globals.ERROR_KEY, errorContainer.getRequestErrors());
 642  0
                         request.setAttribute("ErrorPropertyList", errorContainer.getErrorPropertyList());
 643  
                 }
 644  
                 
 645  0
                 if (errorMap.hasWarnings()) {
 646  0
                         WarningContainer warningsContainer = new WarningContainer(errorMap);
 647  
                         
 648  0
                         request.setAttribute("WarningContainer", warningsContainer);
 649  0
                         request.setAttribute("WarningActionMessages", warningsContainer.getRequestMessages());
 650  0
                         request.setAttribute("WarningPropertyList", warningsContainer.getMessagePropertyList());
 651  
                 }
 652  
                 
 653  0
                 if (errorMap.hasInfo()) {
 654  0
                         InfoContainer infoContainer = new InfoContainer(errorMap);
 655  
                         
 656  0
                         request.setAttribute("InfoContainer", infoContainer);
 657  0
                         request.setAttribute("InfoActionMessages", infoContainer.getRequestMessages());
 658  0
                         request.setAttribute("InfoPropertyList", infoContainer.getMessagePropertyList());
 659  
                 }
 660  0
         }
 661  
 
 662  
         /**
 663  
          * Checks for messages in GlobalVariables and places list in request
 664  
          * attribute.
 665  
          */
 666  
         private void saveMessages(HttpServletRequest request) {
 667  0
                 if (!KNSGlobalVariables.getMessageList().isEmpty()) {
 668  0
                         request.setAttribute(KRADConstants.GLOBAL_MESSAGES, KNSGlobalVariables.getMessageList().toActionMessages());
 669  
                 }
 670  0
         }
 671  
 
 672  
         /**
 673  
          * Checks for messages in GlobalVariables and places list in request
 674  
          * attribute.
 675  
          */
 676  
         private void saveAuditErrors(HttpServletRequest request) {
 677  0
                 if (!KNSGlobalVariables.getAuditErrorMap().isEmpty()) {
 678  0
                         request.setAttribute(KNSConstants.AUDIT_ERRORS, KNSGlobalVariables.getAuditErrorMap());
 679  
                 }
 680  0
         }
 681  
 
 682  
         /**
 683  
          * A simple exception that allows us to wrap an exception that is thrown out
 684  
          * of a transaction template.
 685  
          */
 686  0
         @SuppressWarnings("serial")
 687  
         private static class WrappedRuntimeException extends RuntimeException {
 688  
                 public WrappedRuntimeException(Exception e) {
 689  0
                         super(e);
 690  0
                 }
 691  
         }
 692  
 
 693  
         /**
 694  
          * @return the sessionDocumentService
 695  
          */
 696  
         public SessionDocumentService getSessionDocumentService() {
 697  0
                 if ( sessionDocumentService == null ) {
 698  0
                         sessionDocumentService = KNSServiceLocator.getSessionDocumentService();
 699  
                 }
 700  0
                 return this.sessionDocumentService;
 701  
         }
 702  
 
 703  
         /**
 704  
          * @return the transactionManager
 705  
          */
 706  
         public PlatformTransactionManager getTransactionManager() {
 707  0
                 if ( transactionManager == null ) {
 708  0
                         transactionManager = KRADServiceLocatorInternal.getTransactionManager();
 709  
                 }
 710  0
                 return this.transactionManager;
 711  
         }
 712  
         
 713  
         private ActionForm createNewActionForm(ActionMapping mapping, HttpServletRequest request) {
 714  0
         String name = mapping.getName();
 715  0
         FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
 716  0
         if (config == null) {
 717  0
             log.warn("No FormBeanConfig found under '" + name + "'");
 718  0
             return (null);
 719  
         }
 720  0
         ActionForm instance = RequestUtils.createActionForm(config, servlet);
 721  0
         if ("request".equals(mapping.getScope())) {
 722  0
             request.setAttribute(mapping.getAttribute(), instance);
 723  
         } else {
 724  0
             HttpSession session = request.getSession();
 725  0
             session.setAttribute(mapping.getAttribute(), instance);
 726  
         }
 727  0
         return instance;
 728  
         }
 729  
 }