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