Announcement Announcement Module
Collapse
No announcement yet.
Pointcut on handleRequest of a SimpleFormController Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Pointcut on handleRequest of a SimpleFormController

    Hi!

    I'm trying to have a pointcut on the method handleRequest of a controller which extends SimpleFormController. I try to do this using Schema-based AOP support.

    Here is my controller:
    Code:
    package testaop;
    
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.SimpleFormController;
    
    public class IndexController extends SimpleFormController {
    
    	protected ModelAndView onSubmit(Object arg0) throws Exception {
    		return new ModelAndView(getSuccessView(),null);
    	}
    
    	protected Object formBackingObject(HttpServletRequest arg0) throws Exception {
    		return new Object();
    	}
    }
    Here is the code of my aspect:
    Code:
    package testaop;
    
    public class OneAspect {
    	public void callMeBefore()
    	{
    		System.out.println("callMeBefore called");
    		throw new RuntimeException();
    	}
    }
    And finally my XML beans definition:
    Code:
    <?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/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    
    		
    	
    	 <!-- les mappings de l'application-->
    	<bean name="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    		<property name="mappings">
    			<props>
    				<!-- Permet d'ajouter un utilisateur -->
    				<prop key="/index.html">Index.Controller</prop>
    			</props>
    		</property>
    
    	<!-- l'intercepteur permet la gestion multilingue -->
    		<property name="interceptors">
    			<list>
    				<!-- Permet de changer la langue dans une session d'un utilisateur -->
    				<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    					<property name="paramName">
    						<value>lang</value>
    					</property>
    				</bean>
    			</list>
    		</property>
    		
    	</bean>
          
          <!-- ce controleur redirige vers une vue qui correspond à lurl de la requete, par exemple www..../index.html = vue index -->
    	<bean id="UrlFilenameViewController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
    	
    	<!-- Le résolveur de vues qui supporte l i18n -->
    	<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    		<property name="basename">
    			<value>vues</value>
    		</property>
    	</bean>
    		
    	<!-- le résolveur d i18n -->
    	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
    	 
    	<!-- upload de fichiers -->
    	<bean id="multipartResolver"
    	  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    	  <property name="maxUploadSize">
    	    <value>1000000</value>
    	  </property>
    	</bean>
    	
    	
    	<bean name="Index.Controller" class="testaop.IndexController">
    		<property name="bindOnNewForm">
    			<value>false</value>
    		</property>
    		
    		<property name="sessionForm">
    			<value>true</value>
    		</property>
    		
    		<property name="commandName">
    			<value>formulaire</value>
    		</property>
    		
    		<property name="formView">
    			<value>index</value>
    		</property>
    		
    		<property name="successView">
    			<value>index</value>
    		</property>
    	</bean>
    	
    	<aop:aspectj-autoproxy/>
    	<bean name="beanAspect" class="testaop.OneAspect"/>
    
    	
    	<aop:config>  	
           	<aop:aspect id="aspect_aBean" ref="beanAspect">
           		<aop:pointcut id="appelController" 
              expression="execution(* testaop.IndexController.handleRequest(..))"/>
              
           		<aop:before pointcut="execution(* testaop.IndexController.handleRequest(..))" 
    				method="callMeBefore"/>
    		</aop:aspect>   	
        </aop:config>
        
    </beans>
    You can see the expression of the pointcut:
    Code:
    execution(* testaop.IndexController.handleRequest(..))
    This pointcut is not suitable for my controller because I can read this in the log file:
    Code:
    21:59:07,108 DEBUG AopUtils:283 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* testaop.IndexController.handleRequest(..))]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] rejected for class [testaop.IndexController]
    21:59:07,412 DEBUG AopUtils:264 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* testaop.IndexController.handleRequest(..))]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] rejected for class [testaop.IndexController]
    I tried another expression which was:
    Code:
    execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..))
    This one matched my controller. The logs was:
    Code:
    22:03:12,361 DEBUG AopUtils:259 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..))]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] accepted for class [testaop.IndexController]
    Each time my controller was called, the advice was triggered. Perfect, except that this pointcut match any of my controller and it's not the behaviour that I want.

    So I tried another expression, in order to target the controller IndexController specifically:
    Code:
    execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..)) and target(testaop.IndexController)
    But my controller is not matched by the pointcut. Here the log:
    Code:
    22:12:28,419 DEBUG AopUtils:283 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..)) and target(testaop.IndexController)]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] rejected for class [testaop.IndexController]
    22:12:28,623 DEBUG AopUtils:264 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..)) and target(testaop.IndexController)]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] rejected for class [testaop.IndexController]
    Do you know how I can write an expression to match handleRequest of testaop.IndexController ?

    Thanks!

  • #2
    Try the following pointcut:

    Code:
    execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..))
    && this(testaop.IndexController)
    The reason the first pointcut didn't match is that the handlerRequest() method is in AbstractController, but not in your controller (you didn't override it).

    -Ramnivas

    Comment


    • #3
      Hi Ramnivas!
      Thank you for your answer but it's not working

      I can't use && so I use and. So, the expression was:
      Code:
      execution(* org.springframework.web.servlet.mvc.AbstractController.handleRequest(..)) and this(testaop.IndexController)
      And the log tell me thant the pointcut doesn't fit for my controller ...

      I tried other expressions. My conclusion is that there are things very weird with my program. I can only catch Abstract classes or Interfaces! For instance, expressions like this:
      Code:
      target(org.springframework.web.servlet.mvc.AbstractController)
      works great (matches all my controllers, testaop.IndexController too)
      or this:
      Code:
      target(org.springframework.web.servlet.mvc.Controller)
      works well too (matches all my controllers, testaop.IndexController too)
      But this one:
      Code:
      target(testaop.IndexController)
      doesn't match my controller (it should, doentn't it?).

      Is it normal that I can only refer to abstract classes or interfaces in joinpoint expressions (spring aop limitation?)?
      Maybe there are issues with using or not cglib?
      Have you ever successfully used AOP on your webapplication spring controllers?

      I don't give up
      Thanks!!

      Comment


      • #4
        Hi!
        Just a simple question:
        Is it possible to reference a class (and not an interface or abstract class) in pointcut expressions with spring aop?

        Documentation just says: Spring AOP only supports method execution join points for Spring beans.

        In advance, Thank you!
        Last edited by pacman2; Nov 3rd, 2006, 04:07 AM. Reason: incomplete

        Comment


        • #5
          Is it normal that I can only refer to abstract classes or interfaces in joinpoint expressions (spring aop limitation?)?
          No it isn't we use it on different concrete classes and interface implementations. I figure their is still something wrong with your pointcut. Although it might also have to do with some proxying magic which do not proxy classes automatically. Therefor the this(your.class) fails because it is not inside your class but inside a proxy enclosing your class, however it still extends AbstractController and the interface Controller. Hence the abstract/interface pointcuts still work.

          You might try to change your auto proxy config to the following.

          Code:
          <aop:aspectj-autoproxy proxy-target-class="true"/>

          Comment


          • #6
            Hi! Thank you very much mdeinum but
            still not working forcing the use of cglib (<aop:aspectj-autoproxy proxy-target-class="true"/>)

            I tried this pointcut:
            Code:
            execution(* testaop.IndexController.*(..))
            but my controller is not weaved (logs told me).
            Code:
            11:00:48,203 DEBUG AopUtils:264 - Candidate advisor [org.springframework.aop.aspectj.AspectJPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* testaop.IndexController.*(..))]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: adviceMethod=public void testaop.OneAspect.callMeBefore(); aspectName='beanAspect']] rejected for class [testaop.IndexController]
            I found in another post a dirty technique to do what I want (execute security check on call of handleRequest method of testaop.IndexController):
            This pointcut works well:
            Code:
            target(org.springframework.web.servlet.mvc.Controller)
            So with an around advice, I could get the HttpRequest arg and determine which controller fired handleRequest (thanks to the URL). But, it's so dirty!

            Thanks!

            Comment


            • #7
              Hi!

              I downgraded to Spring 1.2 programmatic AOP API and it does the job!

              Thank you ramnivas and mdeinum for the time you waste for me!
              A+

              Comment


              • #8
                I have a question related to the above.
                Having the following definition:
                Code:
                <aop:aspectj-autoproxy proxy-target-class="true"/>
                
                <bean name="changePwdChecker" class="no.infotorg.service.ChangePwdChecker"/>
                  
                <aop:config>  	
                  <aop:aspect id="changePwdAspect" ref="changePwdChecker">
                     <aop:before
                    pointcut="target(org.springframework.web.servlet.mvc.AbstractController)"
                           method="doCheckPwdChange"/>
                  </aop:aspect>   	
                </aop:config>
                I experience that some of my controllers are weaved, but not all.

                These controllers are weaved:
                - Controllers that extend AbstractCommandController
                - Controllers that extend a native class which extends AbstractWizardFormController

                These controllers are not weaved:
                - Controllers that extend MultiActionController
                - Controllers that extend AbstractWizardFormController

                Can anyone tell me why some, and not all, controllers that inherits AbstractController get weaved?

                The "<aop:aspectj-autoproxy proxy-target-class="true"/>" declaration has to be present for the first category of controllers to be weaved. Could it be that the latter category of controllers are not getting proxied for some reason or another, and thus not getting weaved?

                Comment


                • #9
                  First of all you are trying to use 2 mechanisms at once. The annotation based (aspectj-autoproxy) and the configuration based AOP (aop:config). Mixing them isn't a good idea, use one or the other.

                  Comment


                  • #10
                    Yeah, that is one of the things that really confuses me. I do not have any annotations in my code, but nothing gets weaved unless I include the <aop:aspectj-autoproxy proxy-target-class="true"/> declaration.

                    Comment


                    • #11
                      I guess because something isn't quite right (not sure what) no proxies are created. You aren't weaving anything here, that would require a real aspect and the use of some agent.

                      Have you tried to use the Controller interface as a target instead of the AbstractController?

                      Comment


                      • #12
                        Using the Controller interface didn't change anything.
                        Last edited by mortenhaugen; Dec 28th, 2006, 01:15 PM. Reason: Mistake

                        Comment


                        • #13
                          Finally solved!

                          The reason that the Controller interface target did not work, was that I had and'ed a statement into the pointcut:
                          Code:
                          <aop:before pointcut="target(org.springframework.web.servlet.mvc.Controller)
                                 		 and !this(web.AjaxAutocompleteController)"
                          This obviously caused the JDK dynamic proxy not to be used (because the pointcut then wasn't based on interfaces only, I believe).
                          Introducing <aop:config proxy-target-class="true"> solved the problem (which forces use of CGLIB proxy).
                          (I also tried to remove the "and !this(..." statement, which got the weaving to work without proxy-target-class="true" as well, because of interface based proxying).

                          Thank you, mdeinum!
                          Last edited by mortenhaugen; Dec 28th, 2006, 03:19 PM.

                          Comment


                          • #14
                            Would you mind posting your complete configuration for this ? I've been trying like mad to configure an aop:before on the Controller interface without success. I have aop:config working for other parts of my application (eg execution of service level transactions).

                            Here's how i thought it would work:

                            Code:
                            <aop:config>
                              <aop:aspect ref="auditWebRequest">
                                <aop:pointcut id="requestMethods" expression="target(org.springframework.web.servlet.mvc.Controller)"
                                <aop:before pointcut-ref="requestMethods" method="beforeWebRequest" />
                              </aop:aspect>
                            </aop:config>
                            
                            <bean id="auditWebRequest" class="..."/>
                            Others in this thread seem to have gotten this to work so i must be missing something obvious. (note i'm not using annotations, jdk 1.4.2)

                            Comment


                            • #15
                              It isn't nice to hijack a thread . However here goes. It seems your pointcut isn't right. Try org.springframework.web.servlet.mvc.Controller+ as your pointcut.

                              Also I'm not sure specifying just a target is going to intercept your calls.

                              You could try the following

                              Code:
                              execution(* org.springframework.web.servlet.mvc.Controller+.*(..))

                              Comment

                              Working...
                              X