Announcement Announcement Module
Collapse
No announcement yet.
AOP working with struts action, but not working with DispatchAction Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AOP working with struts action, but not working with DispatchAction

    After many coffees, I think that Ive found what is happenning to Spring AOP when working with my struts actions classes.

    I have done a simple example that works nicely (thanks Mike), but it only works when the Actions are instances of classes Action or ActionSupport.
    However, when I try the same example with DispatchAction or DispatchActionSupport, the AOP aspects arent called.

    Here is my example:

    WEB.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Example1</display-name>
    <!-- Spring integration -->
    <listener>
    <display-name>spring-applicationContext</display-name>
    <listener-class>org.springframework.web.context.ContextLoade rListener</listener-class>
    </listener>
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext*.xml</param-value>
    </context-param>

    <!-- Spring integration end-->
    <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
    <param-name>debug</param-name>
    <param-value>2</param-value>
    </init-param>
    <init-param>
    <param-name>detail</param-name>
    <param-value>2</param-value>
    </init-param>
    <init-param>
    <param-name>validate</param-name>
    <param-value>true</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
    </servlet-mapping>


    <!-- The Usual Welcome File List -->
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    </web-app>
    applicationContext-web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schem...-beans-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <bean id="action1" name="/action1" scope="prototype" autowire="byName" class="example1.actions.Action1Action"></bean>

    <aop:config proxy-target-class="true">
    <aop:aspect ref="logging">
    <aopointcut id="test1"
    expression="execution(* example1.actions.*.*(..))" />
    <aop:before pointcut-ref="test1" method="logBefore" />
    <aop:after-returning pointcut-ref="test1" method="logAfter" />
    </aop:aspect>
    </aop:config>

    <bean id="logging" class="example1.logging.Logging" />

    <aop:aspectj-autoproxy />

    </beans>
    struts-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
    <struts-config>
    <!-- Action Mappings -->
    <action-mappings>
    <action path="/action1" parameter="cmd" type="org.springframework.web.struts.DelegatingAct ionProxy"></action>
    </action-mappings>


    <plug-in className="org.springframework.web.struts.ContextL oaderPlugIn"/>

    </struts-config>
    Logging.class

    public class Logging {

    public void logBefore() {
    System.out.println("before an action");
    }

    public void logAfter() {
    System.out.println("After an action");
    }
    }
    Action1Action.class

    public class Action1Action extends ActionSupport{

    public ActionForward execute(ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    return null;
    }
    }
    This works perfect, but when I change Action1Action to DispatchActionSupport it doesnt work:

    public class Action1Action extends DispatchActionSupport{

    public ActionForward entrance(ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    return null;
    }
    }
    Is there a reason for this? Is this a bug? How can I report it as a bug?
    Am I doing something wrong?
    Well, I hope this helps someone.

    P.D. By the way, Im moving to Dublin, is there anyone in Dublin working with this?
    Last edited by Javier Rivas; May 14th, 2007, 01:39 AM.

  • #2
    Eventually I get it working, although I dont think in the most elegant way.

    When I override the execute method in my DispatchAction class, it works. But the execute method is the only one which gets crosscut, the other methods dont.

    public class Action1Action extends DispatchActionSupport{

    public ActionForward execute(ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    return super.execute(mapping, form, request, response);
    }

    public ActionForward entrance(ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    return null;
    }


    }

    Im not a struts expert, but I dont think this is working well.

    Comment


    • #3
      I would assume this is due to the fact the other calls are internal calls and hence aren't proxied.
      http://www.springframework.org/docs/...ng-aop-proxies

      Comment


      • #4
        Originally posted by Javier Rivas View Post
        Eventually I get it working, although I dont think in the most elegant way.

        When I override the execute method in my DispatchAction class, it works. But the execute method is the only one which gets crosscut, the other methods dont.
        .
        Hello

        i have exactly the same problem. Did you found a solution?

        Regards
        Angela

        Comment


        • #5
          I don't remember quite well how I did it, since it was long time ago.

          However, I can tell you that spring was creating a proxy for my ActionClass extending DispatchActionSupport.

          The entry point to this proxy was the execute method, and that was the only one that was intercepted by spring AOP.

          That method dispatches calls to methods within the class, and because they are inner calls, then wont get intercepted.

          WORKAROUND: You can override the execute method in your action class, and set that as your pointcut. Then add whichever business logic you need there, and call the super to follow the flow.

          I hope it helps.

          Comment


          • #6
            Hi

            Thanks for the answer!

            I wanted to intercept all Exceptions with a Throws Advice. But most Exception are thrown form my inner calls (executeXYZ ), so unfortunately this wont work.

            Kind Regards
            Angela

            Comment


            • #7
              I found a rather-nice solution to this.

              Have your action class inherit from this convenience class of mine where the dispatchMethod is overriden by a copy of original struts code, modified to get around the local call:


              import java.lang.reflect.InvocationTargetException;
              import java.lang.reflect.Method;

              import javax.servlet.ServletException;
              import javax.servlet.http.HttpServletRequest;
              import javax.servlet.http.HttpServletResponse;

              import org.apache.struts.action.Action;
              import org.apache.struts.action.ActionForm;
              import org.apache.struts.action.ActionForward;
              import org.apache.struts.action.ActionMapping;
              import org.apache.struts.actions.EventDispatchAction;
              import org.springframework.beans.BeansException;
              import org.springframework.web.context.WebApplicationCont ext;
              import org.springframework.web.context.support.WebApplica tionContextUtils;
              import org.springframework.web.struts.DelegatingActionUti ls;


              /**
              * Convenience class for Spring-aware Struts 1.1+ EventDispatchActions with re-intrant local calls
              * to paramtrized methods
              * @author derf02a
              *
              */
              public class EventDispatchActionSupport extends EventDispatchAction {

              /**
              * Dispatch to the specified method.
              * @since Struts 1.1
              */
              @Override
              protected ActionForward dispatchMethod(ActionMapping mapping,
              ActionForm form,
              HttpServletRequest request,
              HttpServletResponse response,
              String name) throws Exception {

              // Make sure we have a valid method name to call.
              // This may be null if the user hacks the query string.
              if (name == null) {
              return this.unspecified(mapping, form, request, response);
              }

              // Identify the method object to be dispatched to
              Method method = null;
              try {
              method = getMethod(name);

              } catch(NoSuchMethodException e) {
              String message =
              messages.getMessage("dispatch.method", mapping.getPath(), name);
              log.error(message, e);

              String userMsg =
              messages.getMessage("dispatch.method.user", mapping.getPath());
              throw new NoSuchMethodException(userMsg);
              }

              ActionForward forward = null;
              try {



              Object args[] = {mapping, form, request, response};

              /*
              * Get access to actual bean that may be proxied for trace purposes.
              * Invoke method on it so that poincuts may apply to the action
              */
              // forward = (ActionForward) method.invoke(this, args);
              Action action = getDelegateAction(mapping, request);
              if (action == null) {
              action = this;
              }

              forward = (ActionForward) method.invoke(action, args);

              } catch(ClassCastException e) {
              String message =
              messages.getMessage("dispatch.return", mapping.getPath(), name);
              log.error(message, e);
              throw e;

              } catch(IllegalAccessException e) {
              String message =
              messages.getMessage("dispatch.error", mapping.getPath(), name);
              log.error(message, e);
              throw e;

              } catch(InvocationTargetException e) {
              // Rethrow the target exception if possible so that the
              // exception handling machinery can deal with it
              Throwable t = e.getTargetException();
              if (t instanceof Exception) {
              throw ((Exception) t);
              } else {
              String message =
              messages.getMessage("dispatch.error", mapping.getPath(), name);
              log.error(message, e);
              throw new ServletException(t);
              }
              }

              // Return the returned ActionForward instance
              return (forward);
              }

              /**
              * Return the delegate Action for the given mapping.
              * <p>The default implementation determines a bean name from the
              * given ActionMapping and looks up the corresponding bean in the
              * WebApplicationContext.
              * @param mapping the Struts ActionMapping
              * @return the delegate Action, or <code>null</code> if none found
              * @throws BeansException if thrown by WebApplicationContext methods
              * @see #determineActionBeanName
              */
              protected Action getDelegateAction(ActionMapping mapping, HttpServletRequest request) throws BeansException {
              String beanName = DelegatingActionUtils.determineActionBeanName(mapp ing);
              WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContex t(request.getSession().getServletContext());
              if (! ctx.containsBean(beanName)) {
              return null;
              }
              return (Action) ctx.getBean(beanName, Action.class);
              }

              }
              Last edited by Frederic Dernbach; Apr 16th, 2013, 05:20 AM. Reason: Show modified Java snippet

              Comment

              Working...
              X