How to register aspect in spring application on non-spring-managed object - spring

I have a spring mvc application running in JBoss. I am using Spring AOP all over the place (using Annotations); they are working perfectly. I want, however, to also create an aspect for a couple of JBoss classes (specifically their login JaaS stuff).
I have created a POJO within my application that looks like the following:
package com.mycompany.aspect
(all imports here)
#Aspect
public class MyAspect{
#Pointcut("execution(* org.jboss.plugins.*.login(..))"
private void myPointCut();
#Around("myPointCut()")
public Object doSomething(){....}
}
I have also created an aop.xml file in my META-INF directory that looks like the following:
<aspectj>
<aspects>
<aspect name="com.mycompany.aspect.MyAspect"/>
</aspects>
<weaver>
<include within="org.jboss.plugins.*"/>
</weaver>
</aspectj>
I have also added the following jvm option:
-javaagent:pathto/aspectjweaver.jar (pathto is the right path to my aspectjweaver.jar file)
When my application deploys I get the following RuntimeException:
..... cannot register non aspect com$mycompany$aspect$MyAspect, com.mycompany.aspect.MyAspect
What could I possibly be doing wrong???
EDIT: I should mention I am using JBoss AS (4.2)... This I cannot change :(

Related

How to create AOP interceptors for Mule classes?

This is what I've tried so far and my interceptor is not triggered (no "TATATA" in my logs) :
My interceptor AopLoggingInterceptor.java :
package fr.mycompany.bus.flow.reco.ani.custom.interceptor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AopLoggingInterceptor {
#Around("execution(* org.mule.api.transport.MessageReceiver.routeMessage(org.mule.api.MuleMessage))")
public Object addMonitor(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("TATATA Before");
Object object = pjp.proceed();
System.out.println("TATATA After");
return object;
}
}
META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</aspects>
<weaver options="-verbose">
<!-- Weave types that are within the org.mule.* packages. -->
<include within="org.mule.*" />
</weaver>
</aspectj>
My Mule/Spring config file :
<?xml version="1.0" encoding="UTF-8"?>
<mule >
<spring:beans>
<context:component-scan base-package="fr.mycompany.bus" />
<context:annotation-config />
<aop:aspectj-autoproxy />
<!-- Aspect -->
<spring:bean name="aopLoggingInterceptor" class="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</spring:beans>
</mule>
My Mule file config consists of one flow with one inbound endpoint, 2 outbound endpoints, loggers and transformers (valid flow widely tested).
VM args :
-XX:PermSize=128M -XX:MaxPermSize=256M -javaagent:D:\path\to\mule\opt\aspectjweaver-1.6.11.jar
Extract from mule file starting in Eclipse which shows weaving is created :
[MuleApplicationClassLoader#2934847] info AspectJ Weaver Version 1.6.11 built on Tuesday Mar 15, 2011 at 15:31:04 GMT
[MuleApplicationClassLoader#2934847] info register classloader org.mule.module.launcher.MuleApplicationClassLoader#2934847
[MuleApplicationClassLoader#2934847] info using configuration /D:/BusToolBox/workspaces/dev/.mule/apps/bus-esb-mrc-reco-ani/classes/META-INF/aop.xml
[MuleApplicationClassLoader#2934847] info register aspect fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor
EDIT
It works nicely with a class included in my project, but not with mule classes :
[MuleApplicationClassLoader#6ad5934d] debug generating class 'fr.mycompany.bus.flow.reco.ani.custom.transformer.CustomerDetailToSiebelRecoAniOutputTransformer$AjcClosure1'
EDIT 2
Here is the best result I can get (by using <context:load-time-weaver />), the loading process tries to look for more classes loaded by difference classloaders is , but it results in :
ERROR 2014-08-08 16:00:46,802 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalStateException: ClassLoader [org.mule.module.launcher.MuleApplicationClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
If I try to use spring-instrument-3.2.1.RELEASE.jar, I get same result as before (only main classloader is seen). Does it mean there is no hope with Mule ?
Have a look at this example for using Mule and Spring AOP. The example shows how to invoke Around advice for a component, but should be similar for the interceptor.
There is something very important when working with Spring AOP. In spring aop documentation is stated:
Use the simplest thing that can work. Spring AOP is simpler than using
full AspectJ as there is no requirement to introduce the AspectJ
compiler / weaver into your development and build processes. If you
only need to advise the execution of operations on Spring beans, then
Spring AOP is the right choice. If you need to advise objects not
managed by the Spring container (such as domain objects typically),
then you will need to use AspectJ. You will also need to use AspectJ
if you wish to advise join points other than simple method executions
(for example, field get or set join points, and so on).
So if you want that your AopLoggingInterceptor is invoked for MessageReceiver method calls, that is not going to work because the MessageReceiver object is not managed by the Spring container. The Spring container doesn't "see" this objects.
In other words Spring-AOP cannot add an aspect to anything that is not created by the Spring factory. I found that statement here.

Spring EJB remote interface call

I need help in making a call to EJB remote interface from Spring.
I have a legacy EJB deployed in my JBoss.
Ejb-jar.xml islisted below.
<session>
<display-name>ServiceBean</display-name>
<ejb-name>ServiceBean</ejb-name>
<home>com.ejbproject.ejb.ServiceHome</home>
<remote>com.ejbproject.ejb.Service</remote>
<ejb-class>com.ejbproject.ejb.impl.ServiceBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
I have a web application which uses Spring.The spring application context contains the following entry:
<jee:remote-slsb id="myServiceBean"
jndi-name="ejb/ServiceBean"
business-interface="com.myproject.account.ejb.ServiceBean"
resource-ref='true'></jee:remote-slsb>
I created the business interface ServiceBean in web project and added all methods defined in remote interface define in ejb-jar.xml.
The web application is deployed in the same JBoss server.
But when I try to deploy I am getting a naming exception 'ServiceBean' not bound. Do I have to add environment entries in web.xml to access the EJB (even if both the EJB and web application are deployed in same JBoss)?
First of all, check real jndi-name of your ejb component, usually application server print some information about it in the log files.
Then try to define slsb like this
<jee:remote-slsb
id="taskStarter"
jndi-name="ejb/TaskStarterBean#ru.TaskStarterRemote"
business-interface="ru.TaskStarter"
lookup-home-on-startup="false"
/>
I show my realization of this structure:
#Remote(TaskStarterRemote.class)
#Local(TaskStarterLocal.class)
#Stateless
public class TaskStarterBean implements TaskStarter
#Remote
public interface TaskStarterRemote extends TaskStarter
public interface TaskStarter

#Autowired in bean not in spring context

I am new to springs. Is there an alternative for autowired to be used in a ordinary java bean which is not present in spring context.
You can do so by using Spring #Configurable with some AspectJ magic.
If you need a detailed explanation, here is the link.
And here is a brief overview of how it can be achieved.
First you have some bean that you want injected somewhere:
#Component
public class InjectedClass {
// ...
}
Then, you have a class that is not spring-container managed, that you want to instantiate. You want autowiring to work with this class. You mark it as a #Configurable.
#Configurable
public class NonContainerManagedClass {
#Autowired
private InjectedClass injected;
// ...
}
Now you need to tell spring that you want this non-container managed autowiring to work. So you put the following in your spring configuration.
<context:load-time-weaver />
<context:spring-configured />
Now, since this kind of thing requires modification of the bytecodes of your #Configurable class. So you tell Tomcat to use a different classloader. You can do so by creating a context.xml in your application's META-INF diretory and putting the following in there.
<Context path="/youWebAppName">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/>
</Context>
Now, Tomcat needs to find that classloader. You can ensure that by putting Spring's spring-tomcat-weaver.jar (probably named org.springframework.instrument.tomcat-<version>.jar) in your tomcat installation's lib directory, and voila, the aspectj magic starts working. For classes that are annotated with #Configurable annotation, the #Autowired dependencies are resolved automatically; even if the instances are created outside of the spring-container.
This is probably the only way to make that work with Spring, in a clean manner. Make sure that you have appropriate dependencies in your classpath.
Another way would be to use the full AspectJ functionality and providing custom aspects around all your constructors and handling the dependency-injection yourself.

SpringAOP, load-time-weaver, strange behavior

in this moment i am facing one problem and really dont know what i am doing wrong. I am coding logging for my webservice using Spring framework and AOP in #AspectJ style. I got two bundles - background and frontend. In background bundle I have LogAspect, which look like this:
#Aspect
public class LogAspect {
#Pointcut("#annotation(logMethod)")
public void logMethodAnnotated(LogMethod logMethod){}
#Before("logMethodAnnotated(logMethod)")
public void beforeLogMethodAnnotated(JoinPoint jp){
//actions
}
#After("logMethodAnnotated(logMethod)")
public void afterLogMethodAnnotated(JoinPoint jp){
//actions
}
}
and META-INF/spring/background-osgi.xml:
<context:annotation-config />
<context:component-scan base-package="simon.background"/>
<context:load-time-weaver />
and also META-INF/aop.xml:
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="simon.background.*"/>
<include within="simon.frontend.controller.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="simon.background.log.LogAspect"/>
</aspects>
</aspectj>
In frontend bundle I've just put into aplicationContext.xml <context:load-time-weaver aspectj-weaving="on" />. But the code is acting very strange. I found out, that there is some problem, when I put into my advice methods JoinPoint as argument. (I mean, when I got advice methods without arguments, so there were no JoinPoin in method header, everything has been working fine and advices has been running before and after #LogMethod (my annotation, which I use to say, that i want to log this method) annotated methods). But now it is working like this:
- when I start server and so that the bundles are deployed for the first time, then the advices are run just for methods, they are #LogMethod annotated and belongs to background bundle, but not for annotated methods in frontend.controller.
- and in addition, when I have done some changes in one of my controllers, saved it and deployed just frontend bundle, then when I run #LogMethod annotated method, I got this error:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.LinkageError: loader constraint violation: when resolving method "simon.background.log.LogAspect.afterLogMethodAnnotated(Lorg/aspectj/lang/JoinPoint;)V" the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) of the current class, simon/frontend/controller/HuhController, and the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) for resolved class, simon/background/log/LogAspect, have different Class objects for the type /aspectj/lang/JoinPoint;)V used in the signature
Any ideas what is going on and how can i fix it, so my program will be able to run advices correctly?
One additional note, it could maybe help: When I run this in Debug mode with advices without JoinPoint argument, I realized, that both advices were running twice for one method.
On running twice, could it be because you are using both and
at the same time? Difference between <context:annotation-config> vs <context:component-scan>
Your pointcut has been triggered twice because your expression only constraints annotation type. When a method is called, call() and execution() are both match this expression so.
You can use #annotation(xxx) && execution(* *(..)) on your point cut to restrict the condition on execution only.

how to define contextParameter in Spring

I am working on a web project and I defined some properties in the context.xml of my Tomcat, like path, properties value for the configuration of the application.
My problem arrives when I want to write some JUnit tests, which are launched outside my web container, how can I define these parameters?
To be clear, in my context.xml (in Tomcat configuration directory), I have:
<Parameter name="myProperty" value="myValue" override="false"/>
And with Spring, I access it with:
<property name="property" value="#{myProperty}" />
But when I launch a junit test, the context.xml is not loaded, I need another way to define the property.
How can I do that?
To be more precise, the context.xml file which we are talking about is a file used by my Tomcat server, it does not follow the Spring schema and I think that I can't "import" it into Spring.
I already use the SpringJUnit4ClassRunner and the ContextConfiguration tag, it works fine, but now, I need to emulate/replace the Tomcat's behaviour to define this ContextParameters and retrieve my parameter...
I hope I am clearer :)
Try using something like this :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:context.xml")
public class MyTestClass {
//put tests here
}
EDIT:
You can also specify a path to the context file :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:src/main/resources/spring/config.xml")
public class MyTestClass {
//put tests here
}
For the suggestion above to work, you need to depend on the spring-test module.
You can also load your context file the good old fashion way.
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml")
And then grab your bean by name.

Resources