cancel
Showing results for 
Search instead for 
Did you mean: 

Webscripts and spring aop

modestas
Champ in-the-making
Champ in-the-making
Is it possible to use Aspects for logging performance?

If i try to add:

<bean id="aspectLogger" class="com.kaunas.PerformanceAspect"/>

    <aop:config>
        <aop:pointcut id="pointcutLog" expression="@annotation(com.kaunas.AspectAdvice)"/>
        <aop:aspect id="aopAspect" ref="aspectLogger" order="1">
            <aop:around pointcut-ref="pointcutLog" method="logPerformance"/>
        </aop:aspect>
    </aop:config>

to module-context.xml file I am not able to start alfresco anymore. I get problems with "BeanCreation"

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationEventMulticaster' defined in class path resource [alfresco/core-services-context.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crossRepositoryCopyServiceWriteTxnAdvisor' defined in class path resource [alfresco/public-services-context.xml]: Cannot resolve reference to bean 'retryingWriteTxnAdvice' while setting bean property 'advice'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'retryingWriteTxnAdvice' defined in class path resource [alfresco/core-services-context.xml]: Cannot resolve reference to bean 'retryingTransactionHelper' while setting bean property 'txnHelper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'retryingTransactionHelper' defined in class path resource [alfresco/core-services-context.xml]: Cannot resolve reference to bean 'transactionService' while setting bean property 'transactionService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionService' defined in class path resource [alfresco/core-services-context.xml]: Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [alfresco/hibernate-context.xml]: Initialization of bean failed; nested exception is org.alfresco.error.AlfrescoRuntimeException: 09300000 A transaction has not be started for method 'isSingleton' on org.springframework.beans.factory.FactoryBean

So my initial question would be is it possible to use spring aop with alfresco? And if it is possible example or a guide how to do it would be very helpful.

respectfully,
Modestas
6 REPLIES 6

mrogers
Star Contributor
Star Contributor
I'd think so.   However you need to understand how alfresco uses spring interceptors (instead of aspects)  and cut the correct class.

Also why do it that way?

modestas
Champ in-the-making
Champ in-the-making
I want to check performance. for example how much time it takes to execute code in my custom WebScript. I want to do it in debug mode only and i want to keep my code clean. The easiest way is to add annotation on top of the method i want to check performance.

Maybe fast guide for integration of interceptors in alfresco is available?

kw_ecm
Champ in-the-making
Champ in-the-making
Modestas, have you figure out how to get spring aop working with alfresco yet?

I am having the same question, once I added the aop config like below, I got the same error.
<bean id="customizableTraceInterceptor" class="org.springframework.aop.interceptor.CustomizableTraceInterceptor">
        <property name="enterMessage" value="$[invocationTime] Entering $[methodName]($[arguments])"/>
        <property name="exitMessage" value="$[invocationTime] Leaving $[methodName](): $[returnValue]"/>
    </bean>
    <aop:config>
        <aop:advisor advice-ref="customizableTraceInterceptor" pointcut="within(org.mycompany.dept.*)"/>
    </aop:config>

Thanks
KW

fungi
Champ in-the-making
Champ in-the-making
I recently ran into this same issue trying to profile code in Alfresco. I looked around a bit a found a couple things.
It seems that alfresco does not play nicely with AOP auto-proxy mechanism. I believe this is due using the ProxyFacotryBean in alfresco.

You could do something like the following to target a specific service. This will essentially add advice to a specific service. You should be able to find suitable example in Alfresco source.
You MUST override the service in your custom context config.
Add your custom interceptor to the list of interceptors.
Also note that the idrefs will be "local" you will need to change these to "bean"

 
    <bean id="timingLogger" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>

     <bean id="timingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
         <property name="advice" ref="timingLogger"/>
         <property name="patterns">
           <list>
             <value>.*</value>
           </list>
         </property>
     </bean>

     </bean>

    <bean id="WorkflowService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>org.alfresco.service.cmr.workflow.WorkflowService</value>
        </property>
        <property name="target">
            <ref bean="workflowServiceImpl"/>
        </property>
        <property name="interceptorNames">
            <list>
                <idref bean="WorkflowService_transaction"/>
                <idref bean="AuditMethodInterceptor"/>
                <idref bean="exceptionTranslator"/>
                <idref bean="WorkflowService_security"/>
                <idref bean="timingAdvisor"/>
            </list>
        </property>
    </bean>


Another option is to use the MethodInterceptor and BeanFactoryAware interfaces cooked into your class
 
package foo.tools.monitor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.StopWatch;

public class CaptureExecutionTime implements MethodInterceptor, BeanFactoryAware{
   private static final Logger log = Logger.getLogger(CaptureExecutionTime.class);
   private static final String WORKFLOW_SERVICE = "WorkflowService";
   @Override
   public void setBeanFactory(BeanFactory beanFactory) throws BeansException
   {
      if(beanFactory.containsBean(WORKFLOW_SERVICE))
      {
         Advised proxy =  (Advised) beanFactory.getBean(WORKFLOW_SERVICE);
         proxy.addAdvice(this);
      }
   }

   @Override
   public Object invoke(MethodInvocation i) throws Throwable {
      final StopWatch stopWatch = new StopWatch();
      stopWatch.start("Method: "+i.getMethod().getName() +" :: Is called on: "+ i.getThis());
      try{
         return i.proceed();
      }finally {
         stopWatch.stop();
         System.out.println(stopWatch.prettyPrint());
      }
   }
}


Then define your bean in a custom-context.xml
 
<bean id="profile_monitor" class="us.co.denver.tools.monitor.CaptureExecutionTime" >
</bean>


mrogers mentiones
<blockquote>However you need to understand how alfresco uses spring interceptors (instead of aspects) and cut the correct class.</blockquote>

According to spring doc this is a valid AOP mechanism.
http://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/apbs05.html

I am not really sure why auto-proxy does not work in Alfresco. It would be nice to undertand if that is a bug in alfresco or spring or just to be expected when using ProxyFactoryBean???
Here is another post that kinda goes a bit deeper into the issue.
http://forum.spring.io/forum/spring-projects/aop/32157-mixing-proxyfactorybean-and-aspectj

fungi
Champ in-the-making
Champ in-the-making
In my first example I use ProxyFactoryBean to proxy the WorkflowService. This does not work due to the WorkflowService already has a proxy def in Alfresco. Apparently another proxy cannot be created.

The solution was to override the existing bean def and add the advice to existing list. Bean sure to use "bean" instead of "local" on your idref.

  <bean id="WorkflowService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>org.alfresco.service.cmr.workflow.WorkflowService</value>
        </property>
        <property name="target">
            <ref bean="workflowServiceImpl"/>
        </property>
        <property name="interceptorNames">
            <list>
                <idref bean="WorkflowService_transaction"/>
                <idref bean="AuditMethodInterceptor"/>
                <idref bean="exceptionTranslator"/>
                <idref bean="WorkflowService_security"/>
                <idref bean="timingAdvisor"/>
            </list>
        </property>
    </bean>

fungi
Champ in-the-making
Champ in-the-making
I found another approach using CGLib to Proxy classes with no Interfaces
Prerequisite: you will need cglib-2.2.2.jar on the classpath. Spring will use cglib when no interface is available.

I use the ProxyFactoryBean to declare a proxy in Spring Context. Notice in this config I comment out the proxyInterfaces property. Also I set the proxyTargetClass to true. This forces spring to use cglib proxies on the non-interface target.

NOTE: I override the spring bean jbpm_template now all the beans using jbpm_template will use the proxy instead.

     <bean id="jbpm_template" class="org.springframework.aop.framework.ProxyFactoryBean">
<!–          <property name="proxyInterfaces"> –>
<!–                    <value>org.springmodules.workflow.jbpm31.JbpmTemplate</value> –>
<!–          </property> –>
         <property name="proxyTargetClass">
                   <value>true</value>
         </property>
         <property name="target"><ref bean="jbpm_template_Trans_Target"/></property>
         <property name="interceptorNames">
             <list>
                 <value>profile_monitor</value>
             </list>
         </property>
     </bean>


Next the old jbpm_template bean becomes the target of our proxy. This I copied from the alfresco source and changed the bean id.

    <bean id="jbpm_template_Trans_Target"
        class="org.alfresco.repo.workflow.jbpm.JBPMTransactionTemplate">
        <constructor-arg index="0" ref="jbpm_configuration" />
    </bean>