StatefulActionRequestProcessor.java :  » Web-Framework » Strecks » org » strecks » web » struts » Java Open Source

Java Open Source » Web Framework » Strecks 
Strecks » org » strecks » web » struts » StatefulActionRequestProcessor.java
/*
 * Copyright 2005-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package org.strecks.web.struts;

import org.apache.struts.action.RequestProcessor;

/**
 * Implements extension of <code>RequestProcessor</code> to allow for Strecks specific functionality - namely,
 * handling <code>ValidBindingForm</code>, and <code>StatefulAction</code>
 * @author Phil Zoio
 * @deprecated
 */
public class StatefulActionRequestProcessor extends RequestProcessor
{

  /*private static Log log = LogFactory.getLog(StatefulActionRequestProcessor.class);

  private Map<Class, Map<String, InjectionWrapper>> injectionMap = new HashMap<Class, Map<String, InjectionWrapper>>();

  private Map<Class, ValidationInfo> validatorMap = new HashMap<Class, ValidationInfo>();

  private Map<Class, BindConvertInfo> bindHandlerMap = new HashMap<Class, BindConvertInfo>();

  /**
   * Delegates to superclass to create instance of <code>ActionForm</code>. If this instance is not of type
   * <code>ValidBindingForm</code>, then proceeds as normal. <br>
   * <br>
   * If the form is a <code>ValidBindingForm</code> instance, then the form is inspected for validation and binding
   * annotations. The validation and binding metadata is then used to build the <code>Validator</code> and
   * <code>BindHandler</code> instances and associated contextual information necessary for performing
   * annotation-based binding and validation

  @Override
  protected ActionForm processActionForm(HttpServletRequest request, HttpServletResponse response,
      ActionMapping mapping)
  {

    ActionForm form = super.processActionForm(request, response, mapping);
    if (form instanceof ValidBindingForm)
    {

      Class formClass = form.getClass();

      BindConvertInfo bindMap = null;
      synchronized (bindHandlerMap)
      {
        bindMap = bindHandlerMap.get(formClass);
        if (bindMap == null)
        {
          BindAnnotationReader bindablesReader = new BindAnnotationReader();
          bindMap = bindablesReader.readBindables(form);
          bindHandlerMap.put(formClass, bindMap);
        }
      }

      ValidationInfo validMap = null;

      synchronized (validatorMap)
      {
        // possibly the java.util.concurrent library
        validMap = validatorMap.get(formClass);
        if (validMap == null)
        {
          ValidationAnnotationReader reader = new ValidationAnnotationReader();
          validMap = reader.readValidationHandlers(form, bindMap);
          validatorMap.put(formClass, validMap);
        }
      }

      ValidBindingForm validatorForm = (ValidBindingForm) form;
      validatorForm.setValidationInfo(validMap);
      validatorForm.setBindConvertInfo(bindMap);

      boolean isPosted = "POST".equalsIgnoreCase(request.getMethod());
      validatorForm.setPosted(isPosted);

      return validatorForm;
    }
    return form;

  }

  /**
   * Overrides default error storing mechanism so that errors stored under the key <code>Globals.ERROR_KEY</code>
   * are added to the session automatically. This allows the "Redirect After Post" pattern to be supported for forms
   * failing validation in addition to successful form submissions. Similarly, any errors previously in session are
   * added to request scope but removed from the session.

  @Override
  protected boolean processValidate(HttpServletRequest request, HttpServletResponse response, ActionForm form,
      ActionMapping mapping) throws IOException, ServletException
  {

    if (mapping.getValidate())
    {
      // clear out errors from any previous validation from session
      request.getSession().setAttribute(Globals.ERROR_KEY, null);
    }

    boolean validate = super.processValidate(request, response, form, mapping);

    if (validate == false)
    {
      // if validation failed, then add the errors to the session
      Object errors = request.getAttribute(Globals.ERROR_KEY);
      request.getSession().setAttribute(Globals.ERROR_KEY, errors);
    }
    return validate;
  }

  /**
   * Works in a similar way to the superclass, using the superclass (<code>RequestProcessor</code> to create
   * <code>Action</code> subclass instances. Adds additional logic to check if the returned action is a
   * <code>StatefulAction</code> implementation. If so, the <code>InjectionAnnotationReader</code> is used to load
   * all the <code>InjectionHandler</code>s and associated contextual information so for subsequent injection of
   * action class dependencies. In addition, the prototype instance of <code>StatefulAction</code> is cloned, so
   * that it can store request specific state in a threadsafe manner. Note that the <code>InjectionHandler</code>s
   * themselves do not store any thread-specific state

  @Override
  protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response,
      ActionMapping actionMapping) throws IOException
  {

    String type = actionMapping.getType();
    Action action = null;

    synchronized (actions)
    {
      action = (Action) actions.get(type);
      if (action == null)
      {
        action = super.processActionCreate(request, response, actionMapping);

        // don't need to synchronize on inputMap - same scope as actions
        if (action instanceof StatefulAction)
        {
          // now hold input parameter list to be extracted
          InjectionAnnotationReader injectionAnnotationReader = new InjectionAnnotationReader();
          injectionAnnotationReader.readAnnotations(action.getClass());

          Map<String, InjectionWrapper> inputInfos = injectionAnnotationReader.getInjectionMap();

          injectionMap.put(action.getClass(), inputInfos);
        }
      }
    }

    // clone to make this thread safe. When the request is finished it
    // should be garbage collected, because
    // there will be no other references to this action
    if (action instanceof StatefulAction)
    {
      action = ((StatefulAction) action).clone();
    }
    return action;
  }

  /**
   * Extensively re-implements <code>RequestProcessor.processActionPerform()</code> in the following ways:
   * <ul>
   * <li>adds <code>beforePeform()</code> and <code>afterPerform()</code> callbacks</li>
   * <li>checks to see if action class implements <code>StatefulAction</code>. If so, then
   * <ul>
   * <li>consumes any redirect parameters (by removing them from session scope and adding them to the request scope</li>
   * <li>sets the <code>cancelled</code> property of <code>StatefulAction</code></li>
   * <li>calls <code>StatefulAction.setEnvironment()</code>, so that this does not have to passed into
   * <code>execute()</code></li>
   * <li>calls <code>doInjection()</code> to inject any dependencies into the <code>StatefulAction</code>
   * implementation</li>
   * <li>calls <code>StatefulAction.preBind()</code>, so that any pre-binding initialization can occur (e.g.
   * reference data lookup, etc)</li>
   * <li>performs any inward binding of data, if necessary</li>
   * <li>calls <code>StatefulAction.execute()</code>, so that any pre-binding initialization can occur (e.g.
   * reference data lookup, etc)</li>
   * <li>performs any outward binding of domain model data to forms, if necessary</li>
   * ation can occur (e.g. reference data lookup, etc)</li>
   * <li>If the form has been cancelled, then the last four steps (from <code>preBind()</code> onwards, are
   * omitted. Instead, <code>statefulAction.cancel()</code> is called</li>
   * <li>If any exception is thrown, either by <code>cancel()</code>, <code>preBind()</code> or any of the
   * methods following it, <code>statefulAction.handleRuntimeException(e)</code> is called, giving the action class
   * an opportunity to handle the exception</li>
   * <li>the <code>StatefulAction</code> instance is then added to the request scope under the key
   * <code>InfrastructureKeys.ACTION_CLASS</code> </li>
   * </ul>
   * </li>
   * <li>if the request is using the GET method, the URL is added to the "history list", allowing for implementing
   * back operations and reverting control to previous screens</li>
   * <li>if the <code>ActionForward</code> is a <code>PageClassForward</code> instance, the
   * <code>PageClass</code> instance is attached to request scope using the key
   * <code>InfrastructureKeys.PAGE_CLASS</code>. If it is a <code>RedirectForward</code>, this object is added
   * to request scope using the key <code>InfrastructureKeys.REDIRECT</code>, and the redirect parameters are added
   * to session scope using the key <code>InfrastructureKeys.REDIRECT_PARAMETERS</code></li>
   * <li>if the request is using the GET method, the URL is added to the "history list", allowing for implementing
   * back operations and reverting control to previous screens</li>
   * 
   * </ul>
   * 
   * 

  @Override
  protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response,
      Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException
  {

    log.info("Starting process action perform " + request.getRequestURI());
    log.info("Using " + action.getClass().getName());
    ActionForward actionForward;

    try
    {
      actionForward = beforePerform(action, mapping, request, response);
      if (actionForward == null)
      {

        if (action instanceof StatefulAction)
        {

          // consume any redirect parameters
          Map redirectParams = (Map) request.getSession()
              .getAttribute(InfrastructureKeys.REDIRECT_PARAMETERS);
          if (redirectParams != null)
          {
            request.getSession().removeAttribute(InfrastructureKeys.REDIRECT_PARAMETERS);
            request.setAttribute(InfrastructureKeys.REDIRECT_PARAMETERS, redirectParams);
          }

          StatefulAction statefulAction = (StatefulAction) action;
          boolean cancelled = false;
          if (request.getAttribute(Globals.CANCEL_KEY) != null)
          {
            cancelled = true;
          }

          // set up request environment for stateful action
          statefulAction.setEnvironment(mapping, form, request, response);

          ActionContext context = new ActionContextImpl(request, response, getServletContext(), form, mapping);

          // inject action inputs
          doInjection(statefulAction, context);

          try
          {
            if (cancelled)
              actionForward = statefulAction.cancel();

            else
            {

              // notify action that binding is about to occur.
              // prior to domain object bound from form
              statefulAction.preBind();

              // do incoming bindings
              bindInwards(form, request);

              actionForward = statefulAction.execute();

              // do outgoing bindings
              bindOutwards(form, request);

            }

          }
          catch (RuntimeException e)
          {
            actionForward = statefulAction.handleRuntimeException(e);
          }

          request.setAttribute(InfrastructureKeys.ACTION_BEAN, statefulAction);

        }
        else
        {
          // execute regular Struts actions
          actionForward = action.execute(mapping, form, request, response);
        }

        if (request.getMethod().equalsIgnoreCase("GET"))
        {
          HttpSession session = request.getSession();

          @SuppressWarnings("unchecked")
          List<String> goodURLs = (List<String>) session.getAttribute(InfrastructureKeys.GOOD_URL_HISTORY);

          if (goodURLs == null)
          {
            goodURLs = new ArrayList<String>();
          }

          goodURLs.add(buildURL(request));
          session.setAttribute(InfrastructureKeys.GOOD_URL_HISTORY, goodURLs);
        }

      }
    }
    catch (Exception e)
    {
      log.error(e);
      request.setAttribute(InfrastructureKeys.APPLICATION_EXCEPTION, e);
      actionForward = super.processException(request, response, e, form, mapping);
    }

    if (actionForward instanceof PageForward)
    {
      // save the instance of the PageClass
      PageForward pageClassForward = (PageForward) actionForward;
      Page pageClass = pageClassForward.getPage();
      pageClass.setHttpServletResponse(response);
      request.setAttribute(InfrastructureKeys.PAGE_BEAN, pageClass);
    }
    else
    {
      if (actionForward instanceof RedirectForward)
      {
        RedirectForward r = (RedirectForward) actionForward;
        request.setAttribute(InfrastructureKeys.REDIRECT, actionForward);
        request.getSession().setAttribute(InfrastructureKeys.REDIRECT_PARAMETERS, r.getSessionParameters());
      }
    }

    log.info("Ended action perform of " + request.getRequestURI() + StringUtils.LINE_SEPARATOR);
    return actionForward;
  }

  /**
   * Binds outwards only for new forms. Once form is populated then no additional outward data binding should be
   * necessary

  protected void bindOutwards(ActionForm form, HttpServletRequest request)
  {
    if (form instanceof ValidBindingForm)
    {
      BindingForm v = (BindingForm) form;
      if (v.getBindOutwards())
      {
        v.bindOutwards();
      }
    }
  }

  /**
   * Bind inwards for posts which are not cancelled

  protected void bindInwards(ActionForm form, HttpServletRequest request)
  {
    if (form instanceof ValidBindingForm)
    {
      ValidBindingForm v = (ValidBindingForm) form;
      // if method is post and cancel key is not set then bind inwards
      if (v.isPosted() && request.getAttribute(Globals.CANCEL_KEY) == null)
      {
        v.bindInwards();
      }
    }
  }

  /**
   * Run check prior to invocation of access. Main purpose: user logon check. Only return ActionForward if state is
   * incorrect (eg logging on needs to occur)

  protected ActionForward beforePerform(Action action, ActionMapping mapping, HttpServletRequest request,
      HttpServletResponse response)
  {
    return null;
  }

  /**
   * Do any post action finalization. Guarranteed to run because this is in finally block

  protected void afterPerform(Action action, ActionMapping mapping, HttpServletRequest request,
      HttpServletResponse response)
  {
  }

  private void doInjection(StatefulAction action, ActionContext context)
  {
    Map<String, InjectionWrapper> inputHandlerMap = injectionMap.get(action.getClass());
    if (inputHandlerMap != null)
    {
      Set<String> keySet = inputHandlerMap.keySet();
      for (String propertyName : keySet)
      {
        InjectionWrapper wrapper = inputHandlerMap.get(propertyName);
        wrapper.inject(action, context);
      }
    }
  }

  private String buildURL(HttpServletRequest request)
  {
    String servletPath = request.getServletPath();

    String queryString = request.getQueryString();
    if (queryString != null)
    {
      servletPath += "?" + queryString;
    }
    return servletPath;
  }*/
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.