Coverage Report - org.kuali.rice.kns.web.struts.action.KualiAction
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiAction
0%
0/388
0%
0/218
4.243
 
 1  
 /*
 2  
  * Copyright 2006-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  
 
 17  
 package org.kuali.rice.kns.web.struts.action;
 18  
 
 19  
 import org.apache.commons.lang.ObjectUtils;
 20  
 import org.apache.commons.lang.StringUtils;
 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.actions.DispatchAction;
 25  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 26  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 27  
 import org.kuali.rice.core.api.util.RiceConstants;
 28  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 29  
 import org.kuali.rice.kim.util.KimConstants;
 30  
 import org.kuali.rice.kns.lookup.LookupUtils;
 31  
 import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
 32  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 33  
 import org.kuali.rice.kns.util.KNSGlobalVariables;
 34  
 import org.kuali.rice.kns.util.WebUtils;
 35  
 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
 36  
 import org.kuali.rice.kns.web.struts.form.KualiForm;
 37  
 import org.kuali.rice.kns.web.struts.form.LookupForm;
 38  
 import org.kuali.rice.kns.web.struts.form.pojo.PojoForm;
 39  
 import org.kuali.rice.kns.web.struts.form.pojo.PojoFormBase;
 40  
 import org.kuali.rice.krad.bo.BusinessObject;
 41  
 import org.kuali.rice.krad.document.authorization.DocumentAuthorizerBase;
 42  
 import org.kuali.rice.krad.exception.AuthorizationException;
 43  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 44  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 45  
 import org.kuali.rice.krad.service.KualiModuleService;
 46  
 import org.kuali.rice.krad.service.ModuleService;
 47  
 import org.kuali.rice.krad.util.GlobalVariables;
 48  
 import org.kuali.rice.krad.util.KRADConstants;
 49  
 import org.kuali.rice.krad.util.KRADUtils;
 50  
 import org.kuali.rice.krad.util.UrlFactory;
 51  
 
 52  
 import javax.servlet.http.HttpServletRequest;
 53  
 import javax.servlet.http.HttpServletResponse;
 54  
 import java.util.Arrays;
 55  
 import java.util.Enumeration;
 56  
 import java.util.HashMap;
 57  
 import java.util.HashSet;
 58  
 import java.util.Map;
 59  
 import java.util.Properties;
 60  
 import java.util.Set;
 61  
 
 62  
 /**
 63  
  * <p>The base {@link org.apache.struts.action.Action} class for all KNS-based Actions. Extends from the standard 
 64  
  * {@link org.apache.struts.actions.DispatchAction} which allows for a <i>methodToCall</i> request parameter to
 65  
  * be used to indicate which method to invoke.</p>
 66  
  * 
 67  
  * <p>This Action overrides #execute to set methodToCall for image submits.  Also performs other setup
 68  
  * required for KNS framework calls.</p>
 69  
  *
 70  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 71  
  */
 72  0
 public abstract class KualiAction extends DispatchAction {
 73  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiAction.class);
 74  
 
 75  0
     private static KualiModuleService kualiModuleService = null;
 76  0
     private static BusinessObjectAuthorizationService businessObjectAuthorizationService = null;
 77  0
     private static EncryptionService encryptionService = null;
 78  0
     private static Boolean OUTPUT_ENCRYPTION_WARNING = null;
 79  0
     private static String applicationBaseUrl = null;
 80  
     
 81  0
     private Set<String> methodToCallsToNotCheckAuthorization = new HashSet<String>();
 82  
     
 83  
     {
 84  0
             methodToCallsToNotCheckAuthorization.add( "performLookup" );
 85  0
             methodToCallsToNotCheckAuthorization.add( "performQuestion" );
 86  0
             methodToCallsToNotCheckAuthorization.add( "performQuestionWithInput" );
 87  0
             methodToCallsToNotCheckAuthorization.add( "performQuestionWithInputAgainBecauseOfErrors" );
 88  0
             methodToCallsToNotCheckAuthorization.add( "performQuestionWithoutInput" );
 89  0
             methodToCallsToNotCheckAuthorization.add( "performWorkgroupLookup" );
 90  0
     }
 91  
     
 92  
     /**
 93  
      * Entry point to all actions.
 94  
      *
 95  
      * NOTE: No need to hook into execute for handling framwork setup anymore. Just implement the methodToCall for the framework
 96  
      * setup, Constants.METHOD_REQUEST_PARAMETER will contain the full parameter, which can be sub stringed for getting framework
 97  
      * parameters.
 98  
      *
 99  
      * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
 100  
      *      javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 101  
      */
 102  
     public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 103  0
         ActionForward returnForward = null;
 104  
 
 105  0
         String methodToCall = findMethodToCall(form, request);
 106  0
         if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getMethodToCall())) {
 107  0
             if (StringUtils.isNotBlank(getImageContext(request, KRADConstants.ANCHOR))) {
 108  0
                 ((KualiForm) form).setAnchor(getImageContext(request, KRADConstants.ANCHOR));
 109  
             }
 110  0
             else if (StringUtils.isNotBlank(request.getParameter(KRADConstants.ANCHOR))) {
 111  0
                 ((KualiForm) form).setAnchor(request.getParameter(KRADConstants.ANCHOR));
 112  
             }
 113  
             else {
 114  0
                 ((KualiForm) form).setAnchor(KRADConstants.ANCHOR_TOP_OF_FORM);
 115  
             }
 116  
         }
 117  
         // if found methodToCall, pass control to that method, else return the basic forward
 118  0
         if (StringUtils.isNotBlank(methodToCall)) {
 119  0
                 if ( LOG.isDebugEnabled() ) {
 120  0
                         LOG.debug("methodToCall: '" + methodToCall+"'");
 121  
                 }
 122  0
             returnForward = dispatchMethod(mapping, form, request, response, methodToCall);
 123  
         }
 124  
         else {
 125  0
             returnForward = defaultDispatch(mapping, form, request, response);
 126  
         }
 127  
 
 128  
         // make sure the user can do what they're trying to according to the module that owns the functionality
 129  0
         if ( !methodToCallsToNotCheckAuthorization.contains(methodToCall) ) {
 130  0
                 if ( LOG.isDebugEnabled() ) {
 131  0
                         LOG.debug( "'" + methodToCall + "' not in set of excempt methods: " + methodToCallsToNotCheckAuthorization);
 132  
                 }
 133  0
                 checkAuthorization(form, methodToCall);
 134  
         } else {
 135  0
                 if ( LOG.isDebugEnabled() ) {
 136  0
                         LOG.debug("'" + methodToCall + "' is exempt from auth checks." );
 137  
                 }
 138  
         }
 139  
 
 140  
         // Add the ActionForm to GlobalVariables
 141  
         // This will allow developers to retrieve both the Document and any request parameters that are not
 142  
         // part of the Form and make them available in ValueFinder classes and other places where they are needed.
 143  0
         if(KNSGlobalVariables.getKualiForm() == null) {
 144  0
                 KNSGlobalVariables.setKualiForm((KualiForm)form);
 145  
         }
 146  
 
 147  0
         return returnForward;
 148  
     }
 149  
     
 150  
     /**
 151  
      * When no methodToCall is specified, the defaultDispatch method is invoked.  Default implementation
 152  
      * returns the "basic" ActionForward.
 153  
      */
 154  
     protected ActionForward defaultDispatch(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 155  0
             return mapping.findForward(RiceConstants.MAPPING_BASIC);
 156  
     }
 157  
 
 158  
     @Override
 159  
     protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String methodToCall) throws Exception {
 160  0
         GlobalVariables.getUserSession().addObject(DocumentAuthorizerBase.USER_SESSION_METHOD_TO_CALL_OBJECT_KEY, methodToCall);
 161  0
         return super.dispatchMethod(mapping, form, request, response, methodToCall);
 162  
     }
 163  
     
 164  
     protected String findMethodToCall(ActionForm form, HttpServletRequest request) throws Exception {
 165  
         String methodToCall;
 166  0
         if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getMethodToCall())) {
 167  0
             methodToCall = ((KualiForm) form).getMethodToCall();
 168  
         }
 169  
         else {
 170  
             // call utility method to parse the methodToCall from the request.
 171  0
             methodToCall = WebUtils.parseMethodToCall(form, request);
 172  
         }
 173  0
         return methodToCall;
 174  
     }
 175  
 
 176  
     /**
 177  
      * Toggles the tab state in the ui
 178  
      *
 179  
      * @param mapping
 180  
      * @param form
 181  
      * @param request
 182  
      * @param response
 183  
      * @return
 184  
      * @throws Exception
 185  
      */
 186  
     public ActionForward toggleTab(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 187  0
         KualiForm kualiForm = (KualiForm) form;
 188  0
         String tabToToggle = getTabToToggle(request);
 189  0
         if (StringUtils.isNotBlank(tabToToggle)) {
 190  0
             if (kualiForm.getTabState(tabToToggle).equals("OPEN")) {
 191  0
                     kualiForm.getTabStates().remove(tabToToggle);
 192  0
                     kualiForm.getTabStates().put(tabToToggle, "CLOSE");
 193  
             }
 194  
             else {
 195  0
                     kualiForm.getTabStates().remove(tabToToggle);
 196  0
                     kualiForm.getTabStates().put(tabToToggle, "OPEN");
 197  
             }
 198  
         }
 199  
 
 200  0
         doProcessingAfterPost( kualiForm, request );
 201  0
         return mapping.findForward(RiceConstants.MAPPING_BASIC);
 202  
     }
 203  
 
 204  
     /**
 205  
      * Toggles all tabs to open
 206  
      *
 207  
      * @param mapping
 208  
      * @param form
 209  
      * @param request
 210  
      * @param response
 211  
      * @return
 212  
      * @throws Exception
 213  
      */
 214  
     public ActionForward showAllTabs(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 215  0
             return this.doTabOpenOrClose(mapping, form, request, response, true);
 216  
     }
 217  
 
 218  
     /**
 219  
      * Toggles all tabs to closed
 220  
      *
 221  
      * @param mapping
 222  
      * @param form
 223  
      * @param request
 224  
      * @param response
 225  
      * @return
 226  
      * @throws Exception
 227  
      */
 228  
     public ActionForward hideAllTabs(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 229  0
         return this.doTabOpenOrClose(mapping, form, request, response, false);
 230  
     }
 231  
     
 232  
     /**
 233  
      * 
 234  
      * Toggles all tabs to open of closed depending on the boolean flag.
 235  
      * 
 236  
      * @param mapping the mapping
 237  
      * @param form the form
 238  
      * @param request the request
 239  
      * @param response the response
 240  
      * @param open whether to open of close the tabs
 241  
      * @return the action forward
 242  
      */
 243  
     private ActionForward doTabOpenOrClose(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, boolean open) {
 244  0
         KualiForm kualiForm = (KualiForm) form;
 245  
 
 246  0
         Map<String, String> tabStates = kualiForm.getTabStates();
 247  0
         Map<String, String> newTabStates = new HashMap<String, String>();
 248  0
         for (String tabKey: tabStates.keySet()) {
 249  0
                 newTabStates.put(tabKey, open ? "OPEN" : "CLOSE");
 250  
         }
 251  0
         kualiForm.setTabStates(newTabStates);
 252  0
         doProcessingAfterPost( kualiForm, request );
 253  0
         return mapping.findForward(RiceConstants.MAPPING_BASIC);
 254  
     }
 255  
 
 256  
     /**
 257  
      * Default refresh method. Called from returning frameworks.
 258  
      *
 259  
      * @param mapping
 260  
      * @param form
 261  
      * @param request
 262  
      * @param response
 263  
      * @return
 264  
      * @throws Exception
 265  
      */
 266  
     public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 267  0
         return mapping.findForward(RiceConstants.MAPPING_BASIC);
 268  
     }
 269  
 
 270  
 
 271  
     /**
 272  
      * Parses the method to call attribute to pick off the line number which should be deleted.
 273  
      *
 274  
      * @param request
 275  
      * @return
 276  
      */
 277  
     protected int getLineToDelete(HttpServletRequest request) {
 278  0
         return getSelectedLine(request);
 279  
     }
 280  
 
 281  
     /**
 282  
      * Parses the method to call attribute to pick off the line number which should have an action performed on it.
 283  
      *
 284  
      * @param request
 285  
      * @return
 286  
      */
 287  
     protected int getSelectedLine(HttpServletRequest request) {
 288  0
         int selectedLine = -1;
 289  0
         String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 290  0
         if (StringUtils.isNotBlank(parameterName)) {
 291  0
             String lineNumber = StringUtils.substringBetween(parameterName, ".line", ".");
 292  0
             selectedLine = Integer.parseInt(lineNumber);
 293  
         }
 294  
 
 295  0
         return selectedLine;
 296  
     }
 297  
 
 298  
     /**
 299  
      * Determines which tab was requested to be toggled
 300  
      *
 301  
      * @param request
 302  
      * @return
 303  
      */
 304  
     protected String getTabToToggle(HttpServletRequest request) {
 305  0
         String tabToToggle = "";
 306  0
         String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 307  0
         if (StringUtils.isNotBlank(parameterName)) {
 308  0
             tabToToggle = StringUtils.substringBetween(parameterName, ".tab", ".");
 309  
         }
 310  
 
 311  0
         return tabToToggle;
 312  
     }
 313  
 
 314  
     /**
 315  
      * Retrieves the header tab to navigate to.
 316  
      *
 317  
      * @param request
 318  
      * @return
 319  
      */
 320  
     protected String getHeaderTabNavigateTo(HttpServletRequest request) {
 321  0
         String headerTabNavigateTo = RiceConstants.MAPPING_BASIC;
 322  0
         String imageContext = getImageContext(request, KRADConstants.NAVIGATE_TO);
 323  0
         if (StringUtils.isNotBlank(imageContext)) {
 324  0
             headerTabNavigateTo = imageContext;
 325  
         }
 326  0
         return headerTabNavigateTo;
 327  
     }
 328  
 
 329  
     /**
 330  
      * Retrieves the header tab dispatch.
 331  
      *
 332  
      * @param request
 333  
      * @return
 334  
      */
 335  
     protected String getHeaderTabDispatch(HttpServletRequest request) {
 336  0
         String headerTabDispatch = null;
 337  0
         String imageContext = getImageContext(request, KRADConstants.HEADER_DISPATCH);
 338  0
         if (StringUtils.isNotBlank(imageContext)) {
 339  0
             headerTabDispatch = imageContext;
 340  
         }
 341  
         else {
 342  
             // In some cases it might be in request params instead
 343  0
             headerTabDispatch = request.getParameter(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 344  
         }
 345  0
         return headerTabDispatch;
 346  
     }
 347  
 
 348  
     /**
 349  
      * Retrieves the image context
 350  
      *
 351  
      * @param request
 352  
      * @param contextKey
 353  
      * @return
 354  
      */
 355  
     protected String getImageContext(HttpServletRequest request, String contextKey) {
 356  0
         String imageContext = "";
 357  0
         String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 358  0
         if (StringUtils.isBlank(parameterName)) {
 359  0
             parameterName = request.getParameter("methodToCallPath");
 360  
         }
 361  0
         if (StringUtils.isNotBlank(parameterName)) {
 362  0
             imageContext = StringUtils.substringBetween(parameterName, contextKey, ".");
 363  
         }
 364  0
         return imageContext;
 365  
     }
 366  
 
 367  
     protected String getReturnLocation(HttpServletRequest request, ActionMapping mapping) {
 368  0
             String mappingPath = mapping.getPath();
 369  0
             String basePath = getApplicationBaseUrl();
 370  0
         return basePath + ("/lookup".equals(mappingPath) || "/maintenance".equals(mappingPath) || "/multipleValueLookup".equals(mappingPath) ? "/kr" : "") + mappingPath + ".do";
 371  
     }
 372  
 
 373  
     /**
 374  
      * Retrieves the value of a parameter to be passed into the lookup or inquiry frameworks.  The default implementation of this method will attempt to look
 375  
      * in the request to determine wheter the appropriate value exists as a request parameter.  If not, it will attempt to look through the form object to find
 376  
      * the property.
 377  
      * 
 378  
      * @param boClass a class implementing boClass, representing the BO that will be looked up
 379  
      * @param parameterName the name of the parameter
 380  
      * @param parameterValuePropertyName the property (relative to the form object) where the value to be passed into the lookup/inquiry may be found
 381  
      * @param form
 382  
      * @param request
 383  
      * @return
 384  
      */
 385  
     protected String retrieveLookupParameterValue(Class<? extends BusinessObject> boClass, String parameterName, String parameterValuePropertyName, ActionForm form, HttpServletRequest request) throws Exception {
 386  
             String value;
 387  0
             if (StringUtils.contains(parameterValuePropertyName, "'")) {
 388  0
                     value = StringUtils.replace(parameterValuePropertyName, "'", "");
 389  
             }
 390  0
             else if (request.getParameterMap().containsKey(parameterValuePropertyName)) {
 391  0
                     value = request.getParameter(parameterValuePropertyName);
 392  
             }
 393  
             else {
 394  0
                     if (form instanceof KualiForm) {
 395  0
                             value = ((KualiForm) form).retrieveFormValueForLookupInquiryParameters(parameterName, parameterValuePropertyName);
 396  
                     } else {
 397  0
                             if (LOG.isDebugEnabled()) {
 398  0
                                     LOG.debug("Unable to retrieve lookup/inquiry parameter value for parameter name " + parameterName + " parameter value property " + parameterValuePropertyName);
 399  
                             }
 400  0
                             value = null;
 401  
                     }
 402  
             }
 403  
             
 404  0
             if (value != null && boClass != null && getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(boClass, parameterName)) {
 405  0
                     value = getEncryptionService().encrypt(value) + EncryptionService.ENCRYPTION_POST_PREFIX;
 406  
             }
 407  0
             return value;
 408  
     }
 409  
     
 410  
     /**
 411  
      * Takes care of storing the action form in the User session and forwarding to the lookup action.
 412  
      *
 413  
      * @param mapping
 414  
      * @param form
 415  
      * @param request
 416  
      * @param response
 417  
      * @return
 418  
      * @throws Exception
 419  
      */
 420  
     @SuppressWarnings("unchecked")
 421  
         public ActionForward performLookup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 422  
         // parse out the important strings from our methodToCall parameter
 423  0
         String fullParameter = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 424  0
         validateLookupInquiryFullParameter(request, form, fullParameter);
 425  
         
 426  0
         KualiForm kualiForm = (KualiForm) form;
 427  
         
 428  
         // when we return from the lookup, our next request's method to call is going to be refresh
 429  0
         kualiForm.registerEditableProperty(KRADConstants.DISPATCH_REQUEST_PARAMETER);
 430  
         
 431  
         // parse out the baseLookupUrl if there is one
 432  0
         String baseLookupUrl = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM14_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM14_RIGHT_DEL);
 433  
         
 434  
         // parse out business object class name for lookup
 435  0
         String boClassName = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL, KRADConstants.METHOD_TO_CALL_BOPARM_RIGHT_DEL);
 436  0
         if (StringUtils.isBlank(boClassName)) {
 437  0
             throw new RuntimeException("Illegal call to perform lookup, no business object class name specified.");
 438  
         }
 439  0
         Class boClass = null;
 440  
                 try{
 441  0
                         boClass = Class.forName(boClassName);
 442  0
                 } catch(ClassNotFoundException cnfex){
 443  
                         // we must have a valid boClass that can be loaded unless baseLookupUrl is defined
 444  0
                         if (StringUtils.isBlank(baseLookupUrl)) {
 445  0
                                 if ( LOG.isDebugEnabled() ) {
 446  0
                                         LOG.debug( "BO Class " + boClassName + " not found in the current context, checking the RiceApplicationConfigurationService." );
 447  
                                 }
 448  0
                                 baseLookupUrl = KRADServiceLocatorWeb.getRiceApplicationConfigurationMediationService().getBaseLookupUrl(boClassName);
 449  0
                                 if ( LOG.isDebugEnabled() ) {
 450  0
                                         LOG.debug( "URL Returned from KSB: " + baseLookupUrl );
 451  
                                 }
 452  0
                                 if ( StringUtils.isBlank(baseLookupUrl)) {
 453  0
                                         throw new IllegalArgumentException("The classname (" + boClassName + ") does not represent a valid class and no base URL could be found on the bus.");
 454  
                                 }
 455  
                         }
 456  0
                 }
 457  
                 
 458  
         // build the parameters for the lookup url
 459  0
         Properties parameters = new Properties();
 460  0
         String conversionFields = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL);
 461  0
         if (StringUtils.isNotBlank(conversionFields)) {
 462  0
             parameters.put(KRADConstants.CONVERSION_FIELDS_PARAMETER, conversionFields);
 463  
             
 464  
             // register each of the destination parameters of the field conversion string as editable
 465  0
             String[] fieldConversions = conversionFields.split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 466  0
             for (String fieldConversion : fieldConversions) {
 467  0
                     String destination = fieldConversion.split(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR)[1];
 468  0
                     kualiForm.registerEditableProperty(destination);
 469  
             }
 470  
         }
 471  
 
 472  
         // pass values from form that should be pre-populated on lookup search
 473  0
         String parameterFields = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM2_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM2_RIGHT_DEL);
 474  0
         if ( LOG.isDebugEnabled() ) {
 475  0
             LOG.debug( "fullParameter: " + fullParameter );
 476  0
             LOG.debug( "parameterFields: " + parameterFields );
 477  
         }
 478  0
         if (StringUtils.isNotBlank(parameterFields)) {
 479  0
             String[] lookupParams = parameterFields.split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 480  0
             if ( LOG.isDebugEnabled() ) {
 481  0
                      LOG.debug( "lookupParams: " + Arrays.toString(lookupParams) ); 
 482  
             }
 483  0
             for (String lookupParam : lookupParams) {
 484  0
                     String[] keyValue = lookupParam.split(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 485  0
                 if (keyValue.length != 2) {
 486  0
                                         throw new RuntimeException("malformed field conversion pair: " + Arrays.toString(keyValue));
 487  
                                 } 
 488  
 
 489  0
                 String lookupParameterValue = retrieveLookupParameterValue(boClass, keyValue[1], keyValue[0], form, request);
 490  0
                 if (StringUtils.isNotBlank(lookupParameterValue)) {
 491  0
                         parameters.put(keyValue[1], lookupParameterValue);
 492  
                 }
 493  
 
 494  0
                 if ( LOG.isDebugEnabled() ) {
 495  0
                     LOG.debug( "keyValue[0]: " + keyValue[0] );
 496  0
                     LOG.debug( "keyValue[1]: " + keyValue[1] );
 497  
                 }
 498  
             }
 499  
         }
 500  
 
 501  
         // pass values from form that should be read-Only on lookup search
 502  0
         String readOnlyFields = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM8_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM8_RIGHT_DEL);
 503  0
         if (StringUtils.isNotBlank(readOnlyFields)) {
 504  0
             parameters.put(KRADConstants.LOOKUP_READ_ONLY_FIELDS, readOnlyFields);
 505  
         }
 506  
 
 507  0
         if ( LOG.isDebugEnabled() ) {
 508  0
             LOG.debug( "fullParameter: " + fullParameter );
 509  0
             LOG.debug( "readOnlyFields: " + readOnlyFields );
 510  
         }
 511  
 
 512  
         // grab whether or not the "return value" link should be hidden or not
 513  0
         String hideReturnLink = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM3_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM3_RIGHT_DEL);
 514  0
         if (StringUtils.isNotBlank(hideReturnLink)) {
 515  0
             parameters.put(KRADConstants.HIDE_LOOKUP_RETURN_LINK, hideReturnLink);
 516  
         }
 517  
 
 518  
         // add the optional extra button source and parameters string
 519  0
         String extraButtonSource = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM4_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM4_RIGHT_DEL);
 520  0
         if (StringUtils.isNotBlank(extraButtonSource)) {
 521  0
             parameters.put(KRADConstants.EXTRA_BUTTON_SOURCE, extraButtonSource);
 522  
         }
 523  0
         String extraButtonParams = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM5_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM5_RIGHT_DEL);
 524  0
         if (StringUtils.isNotBlank(extraButtonParams)) {
 525  0
             parameters.put(KRADConstants.EXTRA_BUTTON_PARAMS, extraButtonParams);
 526  
         }
 527  
 
 528  0
         String lookupAction = KRADConstants.LOOKUP_ACTION;
 529  
 
 530  
         // is this a multi-value return?
 531  0
         boolean isMultipleValue = false;
 532  0
         String multipleValues = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM6_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM6_RIGHT_DEL);
 533  0
         if ((new Boolean(multipleValues).booleanValue())) {
 534  0
             parameters.put(KRADConstants.MULTIPLE_VALUE, multipleValues);
 535  0
             lookupAction = KRADConstants.MULTIPLE_VALUE_LOOKUP_ACTION;
 536  0
             isMultipleValue = true;
 537  
         }
 538  
 
 539  
         // the name of the collection being looked up (primarily for multivalue lookups
 540  0
         String lookedUpCollectionName = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM11_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM11_RIGHT_DEL);
 541  0
         if (StringUtils.isNotBlank(lookedUpCollectionName)) {
 542  0
             parameters.put(KRADConstants.LOOKED_UP_COLLECTION_NAME, lookedUpCollectionName);
 543  
         }
 544  
 
 545  
         // grab whether or not the "supress actions" column should be hidden or not
 546  0
         String supressActions = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM7_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM7_RIGHT_DEL);
 547  0
         if (StringUtils.isNotBlank(supressActions)) {
 548  0
             parameters.put(KRADConstants.SUPPRESS_ACTIONS, supressActions);
 549  
         }
 550  
 
 551  
         // grab the references that should be refreshed upon returning from the lookup
 552  0
         String referencesToRefresh = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM10_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM10_RIGHT_DEL);
 553  0
         if (StringUtils.isNotBlank(referencesToRefresh)) {
 554  0
             parameters.put(KRADConstants.REFERENCES_TO_REFRESH, referencesToRefresh);
 555  
         }
 556  
 
 557  
         // anchor, if it exists
 558  0
         if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
 559  0
             parameters.put(KRADConstants.LOOKUP_ANCHOR, ((KualiForm) form).getAnchor());
 560  
         }
 561  
 
 562  
         // now add required parameters
 563  0
         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "start");
 564  
 
 565  
         // pass value from form that shows if autoSearch is desired for lookup search
 566  0
         String autoSearch = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM9_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM9_RIGHT_DEL);
 567  
 
 568  0
         if (StringUtils.isNotBlank(autoSearch)) {
 569  0
             parameters.put(KRADConstants.LOOKUP_AUTO_SEARCH, autoSearch);
 570  0
             if ("YES".equalsIgnoreCase(autoSearch)){
 571  0
                 parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "search");
 572  
             }
 573  
         }
 574  
 
 575  0
         parameters.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(form));
 576  0
         parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, boClassName);
 577  
 
 578  0
         parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation(request, mapping));
 579  
         
 580  0
             if (form instanceof KualiDocumentFormBase) {
 581  0
                     String docNum = ((KualiDocumentFormBase) form).getDocument().getDocumentNumber();
 582  0
                         if(docNum != null){
 583  0
                                 parameters.put(KRADConstants.DOC_NUM, docNum);
 584  
                         }
 585  0
                 }else if(form instanceof LookupForm){
 586  0
                         String docNum = ((LookupForm) form).getDocNum();
 587  0
                         if(docNum != null){
 588  0
                                 parameters.put(KRADConstants.DOC_NUM, ((LookupForm) form).getDocNum());
 589  
                         }
 590  
             }
 591  
 
 592  0
             if (boClass != null) {
 593  0
                     ModuleService responsibleModuleService = getKualiModuleService().getResponsibleModuleService(boClass);
 594  0
                     if(responsibleModuleService!=null && responsibleModuleService.isExternalizable(boClass)){
 595  0
                             Map<String, String> parameterMap = new HashMap<String, String>();
 596  0
                             Enumeration<Object> e = parameters.keys();
 597  0
                             while (e.hasMoreElements()) {
 598  0
                                     String paramName = (String) e.nextElement();
 599  0
                                     parameterMap.put(paramName, parameters.getProperty(paramName));
 600  0
                             }
 601  0
                             return new ActionForward(responsibleModuleService.getExternalizableBusinessObjectLookupUrl(boClass, parameterMap), true);
 602  
                     }
 603  
             }
 604  
                 
 605  0
             if (StringUtils.isBlank(baseLookupUrl)) {
 606  0
                     baseLookupUrl = getApplicationBaseUrl() + "/kr/" + lookupAction;
 607  
             } else {
 608  0
                     if (isMultipleValue) {
 609  0
                             LookupUtils.transformLookupUrlToMultiple(baseLookupUrl);
 610  
                     }
 611  
             }
 612  0
             String lookupUrl = UrlFactory.parameterizeUrl(baseLookupUrl, parameters);
 613  0
         return new ActionForward(lookupUrl, true);
 614  
     }
 615  
 
 616  
     protected void validateLookupInquiryFullParameter(HttpServletRequest request, ActionForm form, String fullParameter){
 617  0
             PojoFormBase pojoFormBase = (PojoFormBase) form;
 618  0
         if(WebUtils.isFormSessionDocument((PojoFormBase) form)){
 619  0
                 if(!pojoFormBase.isPropertyEditable(fullParameter)) {
 620  0
                         throw new RuntimeException("The methodToCallAttribute is not registered as an editable property.");
 621  
                 }
 622  
         }
 623  0
     }
 624  
     
 625  
     @SuppressWarnings("unchecked")
 626  
         public ActionForward performInquiry(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 627  
         // parse out the important strings from our methodToCall parameter
 628  0
         String fullParameter = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 629  0
         validateLookupInquiryFullParameter(request, form, fullParameter);
 630  
         
 631  
         // when javascript is disabled, the inquiry will appear in the same window as the document.  when we close the inquiry, 
 632  
         // our next request's method to call is going to be refresh
 633  0
         KualiForm kualiForm = (KualiForm) form;
 634  0
         kualiForm.registerEditableProperty(KRADConstants.DISPATCH_REQUEST_PARAMETER);
 635  
         
 636  
         // parse out business object class name for lookup
 637  0
         String boClassName = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL, KRADConstants.METHOD_TO_CALL_BOPARM_RIGHT_DEL);
 638  0
         if (StringUtils.isBlank(boClassName)) {
 639  0
             throw new RuntimeException("Illegal call to perform inquiry, no business object class name specified.");
 640  
         }
 641  
 
 642  
         // build the parameters for the inquiry url
 643  0
         Properties parameters = new Properties();
 644  0
         parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, boClassName);
 645  
 
 646  0
         parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation(request, mapping));
 647  
 
 648  
         // pass values from form that should be pre-populated on inquiry
 649  0
         String parameterFields = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM2_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM2_RIGHT_DEL);
 650  0
         if ( LOG.isDebugEnabled() ) {
 651  0
             LOG.debug( "fullParameter: " + fullParameter );
 652  0
             LOG.debug( "parameterFields: " + parameterFields );
 653  
         }
 654  0
         if (StringUtils.isNotBlank(parameterFields)) {
 655  
             // TODO : create a method for this to be used by both lookup & inquiry ?
 656  0
             String[] inquiryParams = parameterFields.split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 657  0
             if ( LOG.isDebugEnabled() ) {
 658  0
                 LOG.debug( "inquiryParams: " + inquiryParams );
 659  
             }
 660  0
             Class<? extends BusinessObject> boClass = (Class<? extends BusinessObject>) Class.forName(boClassName);
 661  0
             for (String inquiryParam : inquiryParams) {
 662  0
                 String[] keyValue = inquiryParam.split(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 663  
 
 664  0
                 String inquiryParameterValue = retrieveLookupParameterValue(boClass, keyValue[1], keyValue[0], form, request);
 665  0
                 if (inquiryParameterValue == null) {
 666  0
                         parameters.put(keyValue[1], "directInquiryKeyNotSpecified");
 667  
                 }
 668  
                 else {
 669  0
                         parameters.put(keyValue[1], inquiryParameterValue);
 670  
                 }
 671  
 
 672  0
                 if ( LOG.isDebugEnabled() ) {
 673  0
                     LOG.debug( "keyValue[0]: " + keyValue[0] );
 674  0
                     LOG.debug( "keyValue[1]: " + keyValue[1] );
 675  
                 }
 676  
             }
 677  
         }
 678  0
         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "start");
 679  0
         parameters.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(form));
 680  0
         String inquiryUrl = null;
 681  
         try {
 682  0
                 Class.forName(boClassName);
 683  0
                 inquiryUrl = getApplicationBaseUrl() + "/kr/" + KRADConstants.DIRECT_INQUIRY_ACTION;
 684  0
         } catch ( ClassNotFoundException ex ) {
 685  0
                 inquiryUrl = KRADServiceLocatorWeb.getRiceApplicationConfigurationMediationService().getBaseInquiryUrl(boClassName);
 686  0
         }
 687  0
         inquiryUrl = UrlFactory.parameterizeUrl(inquiryUrl, parameters);
 688  0
         return new ActionForward(inquiryUrl, true);
 689  
 
 690  
     }
 691  
 
 692  
     /**
 693  
      * This method handles rendering the question component, but without any of the extra error fields
 694  
      *
 695  
      * @param mapping
 696  
      * @param form
 697  
      * @param request
 698  
      * @param response
 699  
      * @param questionId
 700  
      * @param questionText
 701  
      * @param questionType
 702  
      * @param caller
 703  
      * @param context
 704  
      * @return ActionForward
 705  
      * @throws Exception
 706  
      */
 707  
     protected ActionForward performQuestionWithoutInput(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionId, String questionText, String questionType, String caller, String context) throws Exception {
 708  0
         return performQuestion(mapping, form, request, response, questionId, questionText, questionType, caller, context, false, "", "", "", "");
 709  
     }
 710  
 
 711  
     /**
 712  
      * Handles rendering a question prompt - without a specified context.
 713  
      *
 714  
      * @param mapping
 715  
      * @param form
 716  
      * @param request
 717  
      * @param response
 718  
      * @param questionId
 719  
      * @param questionText
 720  
      * @param questionType
 721  
      * @param caller
 722  
      * @param context
 723  
      * @return ActionForward
 724  
      * @throws Exception
 725  
      */
 726  
     protected ActionForward performQuestionWithInput(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionId, String questionText, String questionType, String caller, String context) throws Exception {
 727  0
         return performQuestion(mapping, form, request, response, questionId, questionText, questionType, caller, context, true, "", "", "", "");
 728  
     }
 729  
 
 730  
     /**
 731  
      * Handles re-rendering a question prompt because of an error on what was submitted.
 732  
      *
 733  
      * @param mapping
 734  
      * @param form
 735  
      * @param request
 736  
      * @param response
 737  
      * @param questionId
 738  
      * @param questionText
 739  
      * @param questionType
 740  
      * @param caller
 741  
      * @param context
 742  
      * @param reason
 743  
      * @param errorKey
 744  
      * @param errorPropertyName
 745  
      * @param errorParameter
 746  
      * @return ActionForward
 747  
      * @throws Exception
 748  
      */
 749  
     protected ActionForward performQuestionWithInputAgainBecauseOfErrors(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionId, String questionText, String questionType, String caller, String context, String reason, String errorKey, String errorPropertyName, String errorParameter) throws Exception {
 750  0
         return performQuestion(mapping, form, request, response, questionId, questionText, questionType, caller, context, true, reason, errorKey, errorPropertyName, errorParameter);
 751  
     }
 752  
 
 753  
     /**
 754  
      * Handles rendering a question prompt - with a specified context.
 755  
      *
 756  
      * @param mapping
 757  
      * @param form
 758  
      * @param request
 759  
      * @param response
 760  
      * @param questionId
 761  
      * @param questionText
 762  
      * @param questionType
 763  
      * @param caller
 764  
      * @param context
 765  
      * @param showReasonField
 766  
      * @param reason
 767  
      * @param errorKey
 768  
      * @param errorPropertyName
 769  
      * @param errorParameter
 770  
      * @return ActionForward
 771  
      * @throws Exception
 772  
      */
 773  
     private ActionForward performQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionId, String questionText, String questionType, String caller, String context, boolean showReasonField, String reason, String errorKey, String errorPropertyName, String errorParameter) throws Exception {
 774  0
         Properties parameters = new Properties();
 775  
 
 776  0
         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "start");
 777  0
         parameters.put(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(form));
 778  0
         parameters.put(KRADConstants.CALLING_METHOD, caller);
 779  0
         parameters.put(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME, questionId);
 780  0
         parameters.put(KRADConstants.QUESTION_IMPL_ATTRIBUTE_NAME, questionType);
 781  0
         parameters.put(KRADConstants.QUESTION_TEXT_ATTRIBUTE_NAME, questionText);
 782  0
         parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation(request, mapping));
 783  0
         parameters.put(KRADConstants.QUESTION_CONTEXT, context);
 784  0
         parameters.put(KRADConstants.QUESTION_SHOW_REASON_FIELD, Boolean.toString(showReasonField));
 785  0
         parameters.put(KRADConstants.QUESTION_REASON_ATTRIBUTE_NAME, reason);
 786  0
         parameters.put(KRADConstants.QUESTION_ERROR_KEY, errorKey);
 787  0
         parameters.put(KRADConstants.QUESTION_ERROR_PROPERTY_NAME, errorPropertyName);
 788  0
         parameters.put(KRADConstants.QUESTION_ERROR_PARAMETER, errorParameter);
 789  0
         parameters.put(KRADConstants.QUESTION_ANCHOR, form instanceof KualiForm ? ObjectUtils.toString(((KualiForm) form).getAnchor()) : "");
 790  0
         Object methodToCallAttribute = request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 791  0
         if (methodToCallAttribute != null) {
 792  0
             parameters.put(KRADConstants.METHOD_TO_CALL_PATH, methodToCallAttribute);
 793  0
             ((PojoForm) form).registerEditableProperty(String.valueOf(methodToCallAttribute));
 794  
         }
 795  
         
 796  0
             if (form instanceof KualiDocumentFormBase) {
 797  0
                     String docNum = ((KualiDocumentFormBase) form).getDocument().getDocumentNumber();
 798  0
                     if(docNum != null){
 799  0
                             parameters.put(KRADConstants.DOC_NUM, ((KualiDocumentFormBase) form)
 800  
                                         .getDocument().getDocumentNumber());
 801  
                     }
 802  
                 }
 803  
 
 804  0
         String questionUrl = UrlFactory.parameterizeUrl(getApplicationBaseUrl() + "/kr/" + KRADConstants.QUESTION_ACTION, parameters);
 805  0
         return new ActionForward(questionUrl, true);
 806  
     }
 807  
 
 808  
 
 809  
     /**
 810  
      * Takes care of storing the action form in the User session and forwarding to the workflow workgroup lookup action.
 811  
      *
 812  
      * @param mapping
 813  
      * @param form
 814  
      * @param request
 815  
      * @param response
 816  
      * @return
 817  
      * @throws Exception
 818  
      */
 819  
     public ActionForward performWorkgroupLookup(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 820  0
             String returnUrl = null;
 821  0
             if ("/kr".equals(mapping.getModuleConfig().getPrefix())) {
 822  0
                     returnUrl = getApplicationBaseUrl() + mapping.getModuleConfig().getPrefix() + mapping.getPath() + ".do";
 823  
             } else {
 824  0
                     returnUrl = getApplicationBaseUrl() + mapping.getPath() + ".do";
 825  
             }
 826  
 
 827  
 
 828  0
         String fullParameter = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 829  0
         String conversionFields = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL);
 830  
 
 831  0
         String deploymentBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
 832  
                 KRADConstants.WORKFLOW_URL_KEY);
 833  0
         String workgroupLookupUrl = deploymentBaseUrl + "/Lookup.do?lookupableImplServiceName=WorkGroupLookupableImplService&methodToCall=start&docFormKey=" + GlobalVariables.getUserSession().addObjectWithGeneratedKey(form);
 834  
 
 835  0
         if (conversionFields != null) {
 836  0
             workgroupLookupUrl += "&conversionFields=" + conversionFields;
 837  
         }
 838  0
             if (form instanceof KualiDocumentFormBase) {
 839  0
                         workgroupLookupUrl +="&docNum="+ ((KualiDocumentFormBase) form).getDocument().getDocumentNumber();
 840  
                 }
 841  
             
 842  0
         workgroupLookupUrl += "&returnLocation=" + returnUrl;
 843  
 
 844  0
         return new ActionForward(workgroupLookupUrl, true);
 845  
     }
 846  
 
 847  
     /**
 848  
      * Handles requests that originate via Header Tabs.
 849  
      *
 850  
      * @param mapping
 851  
      * @param form
 852  
      * @param request
 853  
      * @param response
 854  
      * @return
 855  
      * @throws Exception
 856  
      */
 857  
     public ActionForward headerTab(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 858  
         // header tab actions can do two things - 1, call into an action and perform what needs to happen in there and 2, forward to
 859  
         // a new location.
 860  0
         String headerTabDispatch = getHeaderTabDispatch(request);
 861  0
         if (StringUtils.isNotEmpty(headerTabDispatch)) {
 862  0
             ActionForward forward = dispatchMethod(mapping, form, request, response, headerTabDispatch);
 863  0
             if (GlobalVariables.getMessageMap().getNumberOfPropertiesWithErrors() > 0) {
 864  0
                 return mapping.findForward(RiceConstants.MAPPING_BASIC);
 865  
             }
 866  0
             this.doTabOpenOrClose(mapping, form, request, response, false);
 867  0
             if (forward.getRedirect()) {
 868  0
                 return forward;
 869  
             }
 870  
         }
 871  0
         return dispatchMethod(mapping, form, request, response, getHeaderTabNavigateTo(request));
 872  
     }
 873  
 
 874  
     /**
 875  
      * Override this method to provide action-level access controls to the application.
 876  
      *
 877  
      * @param form
 878  
      * @throws AuthorizationException
 879  
      */
 880  
     protected void checkAuthorization( ActionForm form, String methodToCall) throws AuthorizationException 
 881  
     {
 882  0
             String principalId = GlobalVariables.getUserSession().getPrincipalId();
 883  0
             Map<String, String> roleQualifier = new HashMap<String, String>(getRoleQualification(form, methodToCall));
 884  0
             Map<String, String> permissionDetails = KRADUtils.getNamespaceAndActionClass(this.getClass());
 885  
             
 886  0
         if (!KimApiServiceLocator.getPermissionService().isAuthorizedByTemplateName(principalId, KRADConstants.KRAD_NAMESPACE,
 887  
                         KimConstants.PermissionTemplateNames.USE_SCREEN, permissionDetails, roleQualifier ))
 888  
         {
 889  0
             throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(), 
 890  
                             methodToCall,
 891  
                             this.getClass().getSimpleName());
 892  
         }
 893  0
     }
 894  
     
 895  
     /** 
 896  
      * override this method to add data from the form for role qualification in the authorization check
 897  
      */
 898  
     protected Map<String,String> getRoleQualification(ActionForm form, String methodToCall) {
 899  0
             return new HashMap<String,String>();
 900  
     }
 901  
 
 902  
     protected static KualiModuleService getKualiModuleService() {
 903  0
         if ( kualiModuleService == null ) {
 904  0
             kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
 905  
         }
 906  0
         return kualiModuleService;
 907  
     }
 908  
 
 909  
     /**
 910  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 911  
      * <p>Value is textAreaFieldName
 912  
      */
 913  
     public static final String TEXT_AREA_FIELD_NAME="textAreaFieldName";
 914  
     /**
 915  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 916  
      * <p>Value is textAreaFieldLabel
 917  
     */
 918  
     public static final String TEXT_AREA_FIELD_LABEL="textAreaFieldLabel";
 919  
     /**
 920  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 921  
      * <p>Value is textAreaReadOnly
 922  
     */
 923  
     public static final String TEXT_AREA_READ_ONLY="textAreaReadOnly";
 924  
     /**
 925  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 926  
      * <p>Value is textAreaFieldAnchor
 927  
     */
 928  
     public static final String TEXT_AREA_FIELD_ANCHOR="textAreaFieldAnchor";
 929  
     /**
 930  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 931  
      * <p>Value is textAreaFieldAnchor
 932  
     */
 933  
     public static final String TEXT_AREA_MAX_LENGTH="textAreaMaxLength";
 934  
     /**
 935  
      * Constant defined to match with TextArea.jsp and updateTextArea function in core.js
 936  
      * <p>Value is htmlFormAction
 937  
     */
 938  
     public static final String FORM_ACTION="htmlFormAction";
 939  
     /**
 940  
      * Constant defined to match input parameter from URL and from TextArea.jsp.
 941  
      * <p>Value is methodToCall
 942  
     */
 943  
     public static final String METHOD_TO_CALL="methodToCall";
 944  
     /**
 945  
      * Constant defined to match with global forwarding in struts-config.xml
 946  
      * for Text Area Update.
 947  
      * <p>Value is updateTextArea
 948  
     */
 949  
     public static final String FORWARD_TEXT_AREA_UPDATE="updateTextArea";
 950  
     /**
 951  
      * Constant defined to match with method to call in TextArea.jsp.
 952  
      * <p>Value is postTextAreaToParent
 953  
     */
 954  
     public static final String POST_TEXT_AREA_TO_PARENT="postTextAreaToParent";
 955  
     /**
 956  
      * Constant defined to match with local forwarding in struts-config.xml
 957  
      * for the parent of the Updated Text Area.
 958  
      * <p>Value is forwardNext
 959  
     */
 960  
     public static final String FORWARD_NEXT="forwardNext";
 961  
 
 962  
     /**
 963  
      * This method is invoked when Java Script is turned off from the web browser. It
 964  
      * setup the information that the update text area requires for copying current text
 965  
      * in the calling page text area and returning to the calling page. The information
 966  
      * is passed to the JSP through Http Request attributes. All other parameters are
 967  
      * forwarded 
 968  
      *  
 969  
      * @param mapping
 970  
      * @param form
 971  
      * @param request
 972  
      * @param response
 973  
      * @return
 974  
      */
 975  
     public ActionForward updateTextArea(ActionMapping mapping,
 976  
             ActionForm form,
 977  
             HttpServletRequest request,
 978  
             HttpServletResponse response)  {
 979  0
         if (LOG.isTraceEnabled()) {
 980  0
             String lm=String.format("ENTRY %s%n%s", form.getClass().getSimpleName(),
 981  
                     request.getRequestURI());
 982  0
             LOG.trace(lm);
 983  
         }
 984  
                                 
 985  0
         final String[] keyValue = getTextAreaParams(request);
 986  
         
 987  0
         request.setAttribute(TEXT_AREA_FIELD_NAME, keyValue[0]);
 988  0
         request.setAttribute(FORM_ACTION,keyValue[1]);
 989  0
         request.setAttribute(TEXT_AREA_FIELD_LABEL,keyValue[2]);
 990  0
         request.setAttribute(TEXT_AREA_READ_ONLY,keyValue[3]);
 991  0
         request.setAttribute(TEXT_AREA_MAX_LENGTH,keyValue[4]);
 992  0
         if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
 993  0
             request.setAttribute(TEXT_AREA_FIELD_ANCHOR,((KualiForm) form).getAnchor());
 994  
         }
 995  
         
 996  
         // Set document related parameter
 997  0
         String docWebScope=(String)request.getAttribute(KRADConstants.DOCUMENT_WEB_SCOPE);
 998  0
         if (docWebScope != null && docWebScope.trim().length() >= 0) {
 999  0
             request.setAttribute(KRADConstants.DOCUMENT_WEB_SCOPE, docWebScope);
 1000  
         }
 1001  
 
 1002  0
         request.setAttribute(KRADConstants.DOC_FORM_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(form));
 1003  
         
 1004  0
         ActionForward forward=mapping.findForward(FORWARD_TEXT_AREA_UPDATE);
 1005  
 
 1006  0
         if (LOG.isTraceEnabled()) {
 1007  0
             String lm=String.format("EXIT %s", (forward==null)?"null":forward.getPath());
 1008  0
             LOG.trace(lm);
 1009  
         }
 1010  
                         
 1011  0
         return forward;
 1012  
     }
 1013  
     
 1014  
     /**
 1015  
      * This method takes the {@link org.kuali.rice.krad.util.KRADConstants.METHOD_TO_CALL_ATTRIBUTE} out of the request
 1016  
      * and parses it returning the required fields needed for a text area. The fields returned
 1017  
      * are the following in this order.
 1018  
      * <ol>
 1019  
      * <li>{@link #TEXT_AREA_FIELD_NAME}</li>
 1020  
      * <li>{@link #FORM_ACTION}</li>
 1021  
      * <li>{@link #TEXT_AREA_FIELD_LABEL}</li>
 1022  
      * <li>{@link #TEXT_AREA_READ_ONLY}</li>
 1023  
      * <li>{@link #TEXT_AREA_MAX_LENGTH}</li>
 1024  
      * </ol>
 1025  
      * 
 1026  
      * @param request the request to retrieve the textarea parameters
 1027  
      * @return a string array holding the parsed fields
 1028  
      */
 1029  
     private String[] getTextAreaParams(HttpServletRequest request) {
 1030  
         // parse out the important strings from our methodToCall parameter
 1031  0
         String fullParameter = (String) request.getAttribute(
 1032  
                 KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
 1033  
 
 1034  
         // parse textfieldname:htmlformaction
 1035  0
         String parameterFields = StringUtils.substringBetween(fullParameter,
 1036  
                 KRADConstants.METHOD_TO_CALL_PARM2_LEFT_DEL,
 1037  
                 KRADConstants.METHOD_TO_CALL_PARM2_RIGHT_DEL);
 1038  0
         if ( LOG.isDebugEnabled() ) {
 1039  0
             LOG.debug( "fullParameter: " + fullParameter );
 1040  0
             LOG.debug( "parameterFields: " + parameterFields );
 1041  
         }
 1042  0
         String[] keyValue = null;
 1043  0
         if (StringUtils.isNotBlank(parameterFields)) {
 1044  0
             String[] textAreaParams = parameterFields.split(
 1045  
                     KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 1046  0
             if ( LOG.isDebugEnabled() ) {
 1047  0
                 LOG.debug( "lookupParams: " + textAreaParams );
 1048  
             }
 1049  0
             for (final String textAreaParam : textAreaParams) {
 1050  0
                 keyValue = textAreaParam.split(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 1051  
 
 1052  0
                 if ( LOG.isDebugEnabled() ) {
 1053  0
                     LOG.debug( "keyValue[0]: " + keyValue[0] );
 1054  0
                     LOG.debug( "keyValue[1]: " + keyValue[1] );
 1055  0
                     LOG.debug( "keyValue[2]: " + keyValue[2] );
 1056  0
                     LOG.debug( "keyValue[3]: " + keyValue[3] );
 1057  0
                     LOG.debug( "keyValue[4]: " + keyValue[4] );
 1058  
                 }
 1059  
             }
 1060  
         }
 1061  
         
 1062  0
         return keyValue;
 1063  
     }
 1064  
     
 1065  
     /**
 1066  
      * This method is invoked from the TextArea.jsp for posting its value to the parent
 1067  
      * page that called the extended text area page. The invocation is done through
 1068  
      * Struts action. The default forwarding id is RiceContants.MAPPING_BASIC. This
 1069  
      * can be overridden using the parameter key FORWARD_NEXT.
 1070  
      * 
 1071  
      * @param mapping
 1072  
      * @param form
 1073  
      * @param request
 1074  
      * @param response
 1075  
      * @return
 1076  
      */
 1077  
     public ActionForward postTextAreaToParent(ActionMapping mapping,
 1078  
             ActionForm form,
 1079  
             HttpServletRequest request,
 1080  
             HttpServletResponse response) {
 1081  
         
 1082  0
         if (LOG.isTraceEnabled()) {
 1083  0
             String lm=String.format("ENTRY %s%n%s", form.getClass().getSimpleName(),
 1084  
                     request.getRequestURI());
 1085  0
             LOG.trace(lm);
 1086  
         }
 1087  
                         
 1088  0
         String forwardingId=request.getParameter(FORWARD_NEXT);
 1089  0
         if (forwardingId == null) {
 1090  0
             forwardingId=RiceConstants.MAPPING_BASIC;
 1091  
         }
 1092  0
         ActionForward forward=mapping.findForward(forwardingId);
 1093  
              
 1094  0
         if (LOG.isTraceEnabled()) {
 1095  0
             String lm=String.format("EXIT %s", (forward==null)?"null":forward.getPath());
 1096  0
             LOG.trace(lm);
 1097  
         }
 1098  
                         
 1099  0
         return forward;
 1100  
     }
 1101  
     
 1102  
     /**
 1103  
      * Use to add a methodToCall to the a list which will not have authorization checks.
 1104  
      * This assumes that the call will be redirected (as in the case of a lookup) that will perform
 1105  
      * the authorization.
 1106  
      */
 1107  
     protected final void addMethodToCallToUncheckedList( String methodToCall ) {
 1108  0
             methodToCallsToNotCheckAuthorization.add(methodToCall);
 1109  0
     }
 1110  
     
 1111  
     /**
 1112  
      * This method does all special processing on a document that should happen on each HTTP post (ie, save, route, approve, etc).
 1113  
      */
 1114  
     protected void doProcessingAfterPost( KualiForm form, HttpServletRequest request ) {
 1115  
             
 1116  0
     }
 1117  
     
 1118  
     protected BusinessObjectAuthorizationService getBusinessObjectAuthorizationService() {
 1119  0
             if (businessObjectAuthorizationService == null) {
 1120  0
                     businessObjectAuthorizationService = KNSServiceLocator.getBusinessObjectAuthorizationService();
 1121  
             }
 1122  0
             return businessObjectAuthorizationService;
 1123  
     }
 1124  
     
 1125  
     protected EncryptionService getEncryptionService() {
 1126  0
             if (encryptionService == null) {
 1127  0
                     encryptionService = CoreApiServiceLocator.getEncryptionService();
 1128  
             }
 1129  0
             return encryptionService;
 1130  
     }
 1131  
 
 1132  
         public static String getApplicationBaseUrl() {
 1133  0
                 if ( applicationBaseUrl == null ) {
 1134  0
                         applicationBaseUrl = KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
 1135  
                     KRADConstants.APPLICATION_URL_KEY);
 1136  
                 }
 1137  0
                 return applicationBaseUrl;
 1138  
         }
 1139  
 }