The simplest answer is to use EJB3 and its Interceptor functionality in the guise of an @AroundInvoke method which gets called on every method invocation of the bean class.
Now this sounds OK if you are already using EJB3 and have access to the bean source code to modify it and add the interceptor method and the annotation.
If you don't have access to the original bean source code, you can still do it by using an external interceptor class. In this technique, you create an class external which contains interceptor method(s) and use the ejb-jar.xml file to declare the external interceptor class and bind it to the bean(s) and methods you want to apply it to.
By way of example, here's an external interceptor class:
package sab.demo.interceptors;To apply this to an existing bean class, create a partial ejb-jar.xml file with the entries pertinent to the interceptor class:
import javax.interceptor.InvocationContext;
public class AuditInterceptor {
public AuditInterceptor() {
}
/**
* Interceptor method which prints method call
*/
public Object logMethodCall(InvocationContext ic) throws Exception {
// The InvocationContext contains the context of the intercepted call
System.out.printf("ExternalInterceptor\n\tMethod: %s\n",
ic.getMethod().getName());
// Print out the parameter values if they exist
if(ic.getParameters().length!=0) {
System.out.printf("\tParameters: ");
boolean first = true;
String sep = ", ";
for(Object o : ic.getParameters()) {
System.out.printf(" %s", o.toString());
if(!first) {
System.out.printf("%c", sep);
} else {
first = false;
}
}
}
System.out.println();
// Carry on
return ic.proceed();
}
}
<?xml version="1.0" encoding="windows-1252" ?>When the bean is called from a client, the external interceptor is invoked and the method calls are printed to stdout:
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
xmlns="http://java.sun.com/xml/ns/javaee" version="3.0">
<interceptors>
<interceptor>
<interceptor-class>sab.demo.interceptors.AuditInterceptor</interceptor-class>
<around-invoke>
<method-name>logMethodCall</method-name>
</around-invoke>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>SomeBusiness</ejb-name>
<interceptor-class>sab.demo.interceptors.AuditInterceptor</interceptor-class>
<method>
<method-name>*</method-name>
</method>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>
ExternalInterceptorThe external interceptor class can be packaged within the EJB-JAR file, or alternatively, it can be packaged in a separate JAR file and included in the EAR file as a library. Using JEE5, the library can be referenced using the new <libraries ... > tag and putting the JAR file into the specified directory in the EAR file.
Method: someBusinessMethod
Parameters: 1188441131015
<application version="5">What about EJB 2.1?
<library-directory>libraries</library-directory>
<module>
<ejb>ejb.modulejar</ejb>
</module>
</application>
Turns out this works for EJB 2.1 applications as well with some minor tweaks to the existing descriptor file.
In this case, you only really need to alter the existing ejb-jar.xml so the version is specified as "3.0" and add the interceptors tags. Whereupon OC4J (10.1.3.x) will run the bean as EJB 3.0, and apply the interceptors as specified.
Here's an example of an EJB 2.1 being converted to EJB 3.0 and the interceptors added.
<?xml version = '1.0' encoding = 'windows-1252'?>
<!--
<ejb-jar
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
xmlns="http://java.sun.com/xml/ns/j2ee"
version="2.1" >
-->
<ejb-jar version="3.0">
<interceptors>
<interceptor>
<interceptor-class>sab.demo.interceptors.AuditInterceptor</interceptor-class>
<around-invoke>
<method-name>logMethodCall</method-name>
</around-invoke>
</interceptor>
</interceptors>
<enterprise-beans>
<session>
<description>Session Bean ( Stateless )</description>
<display-name>SomeBusiness</display-name>
<ejb-name>SomeBusiness</ejb-name>
<home>sab.demo.ejb21.SomeBusinessHome</home>
<remote>sab.demo.ejb21.SomeBusiness</remote>
<local-home>sab.demo.ejb21.SomeBusinessLocalHome</local-home>
<local>sab.demo.ejb21.SomeBusinessLocal</local>
<ejb-class>sab.demo.ejb21.SomeBusinessBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>SomeBusiness</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<interceptor-binding>
<ejb-name>SomeBusiness</ejb-name>
<interceptor-class>sab.demo.interceptors.AuditInterceptor</interceptor-class>
<method>
<method-name>*</method-name>
</method>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>
In this case, if you don't want to change the application.xml file to be versioned at JEE 5.0 and use its libraries inclusion facility, then to include the library containing the external interceptor class you can use the <library> element of the orion-application.xml file to specify the library to load:
<orion-application xsi="http://www.w3.org/2001/XMLSchema-instance" nonamespaceschemalocation="http://xmlns.oracle.com/oracleas/schema/orion-application-10_0.xsd">
<library path="InterceptorLibrary.jar"/>
</orion-application>
1 comment:
Hi,
I also want to intercept all ejb2.x invocations from J2ee client application(websphere and weblogic). will this technique work for me as well?
Post a Comment