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