Sun Java System Application Server |
The Stateless Session bean has a Remote business interface with a single business method.
import javax.ejb.Remote; @Remote public interface StatelessSession { public String initUpperCase(String val) throws BadArgumentException; }
Note that unlike prior versions of EJB, the Remote interface is not required to extend java.rmi.Remote and its business methods are not required to throw java.rmi.RemoteException. Here, BadArgumentException is an application exception.
The business interface is designated as a remote business interface via the @javax.ejb.Remote annotation.
Here's the bean implementation:
@Stateless @Interceptors({ NullChecker.class, ArgumentsChecker.class }) public class StatelessSessionBean implements StatelessSession { public String initUpperCase(String val) { String first = val.substring(0, 1); return first.toUpperCase() + val.substring(1); } }
The annotation @javax.ejb.Stateless
defines the component and designates
this class as the bean class for a stateless session bean.
The business method converts the first character in the parameter to upper case. Note that the business method does not check if the argument is null OR if the parameter starts with a alphabet. It could have been done in the business method itself, but we use the EJB 3.0 interceptor facility to do the parameter validation checks.
Interceptors are used to interpose on business method invocations and life cycle events that occur on an enterprise bean instance. An interceptor class is just like any other java class. It need not extend any special class nor does it need to implement any well known interface. An interceptor class defines (exactly) one business method interceptor method by annotating a method with @AroundInvoke annotation. The method must take javax.interceptor.InvocationContext as argument and must return java.lang.Object. (Note:- It is possible to declare interceptors and interceptor methods using .xml file, but for this sample we will use only annotations).
More than one interceptor can be chained to interpose a single business method. @Interceptors is an annotation that can be used to indicate the list of interceptors to be invoked before any business methods are invoked on this bean. Note that since this annotation is defined at the type level, the interceptors are fired before every business method is invoked. The @Interceptors annotation is defined in javax.interceptor package.
The bean lists (using @Interceptor annotation) the list of interceptors to be fired before its business methods are called. Here the bean list two interceptors: NullChecker and ArgumentsChecker. The name of these classes can be anything. The exact method to be invoked on these interceptors is designated using the @AroundInvoke annotation. The @AroundInvoke annotation is defined in javax.interceptor package.
In our sample, the two interceptors are defined as follows:
package enterprise.interceptor_stateless_ejb; import java.lang.reflect.Method; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class NullChecker { @AroundInvoke public Object checkIfNull(InvocationContext ctx) throws Exception { Method method = ctx.getMethod(); if (method.getName().equals("initUpperCase")) { String param = (String) (ctx.getParameters()[0]); if (param == null) { throw new BadArgumentException("Illegal argument: null"); } } // An interceptor can throw any runtime exception or // application exceptions that are allowed in the // throws clause of the business method return ctx.proceed(); // Proceed to the next interceptor } } package enterprise.interceptor_stateless_ejb; import java.lang.reflect.Method; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class ArgumentsChecker { @AroundInvoke public Object checkArgument(InvocationContext ctx) throws Exception { Method method = ctx.getMethod(); if (method.getName().equals("initUpperCase")) { String param = (String) (ctx.getParameters()[0]); //Note that param cannot be null because //it has been validated by the previous interceptor char c = param.charAt(0); if (!Character.isLetter(c)) { throw new BadArgumentException("Illegal argument: " + param); } } // An interceptor can throw any runtime exception or // application exceptions that are allowed in the // throws clause of the business method return ctx.proceed(); // Proceed to call the business method } }
Before a business method is invoked, the container invokes the interceptor method (annotated with @AroundInvoke) of each interceptor. In our sample, before the bean's initUpperCase() method is invoked, the checkIfNull() and checkArgument() methods are invoked,in that order.
AroundInvoke methods run in the same Java call stack as the bean business method. For a single business method invocation, the container passes (the same) instance of InvocationContext to all the interceptor methods. The InvocationContext (defined in javax.interceptor package) provides various methods to examine as well as modify the parameter values passed to the business method.
The proceed() method in InvocationContext causes the next interceptor method in the chain to be invoked or, when called from the last AroundInvoke interceptor method, the bean's business method. Interceptor methods must always call InvocationContext.proceed() or no subsequent interceptor methods or bean business method or life cycle callback methods will be invoked.
In our sample, the interceptor methods use the InvocationContext.getMethod() and InvocationContext.getParameters() method to examine the parameter passed to the initUpperCase() business method. The NullChecker throws BadArgumentException if the parameter is null whereas the ArgumentChecker throws BadArgumentException if the first character in the string is not a letter. Note that An interceptor can throw any runtime exception or application exceptions that are allowed in the throws clause of the business method. If the interceptors find the parameter value to be valid, they call InvocationContext.proceed()
The good news is the deployment descriptor is no longer required! The two Java files above are sufficient to completely describe this stateless session bean.
You do not need to define any Sun-Specific deployment
descriptors (for example sun-ejb-jar.xml
and sun-application-client.xml
) for this
example. The JNDI name for the Remote Stateless Session bean will default to:
enterprise.interceptor_stateless_ejb.StatelessSession#enterprise.interceptor_stateless_ejb.StatelessSession
Follow these instructions to build, deploy, and run this sample application.
app_dir
is the sample application base
directory: samples_install_dir/javaee5/enterprise/interceptor-stateless-ear
app_dir.
app_dir>
ant all
app_dir> ant
default
compiles and packages the application
app_dir> ant
deploy
deploys it to application server
app_dir> ant
run
runs the test application client
app_dir> ant
clean
Follow these instructions to build, deploy, and run this sample application using NetBeans IDE.
samples_install_dir/javaee5/enterprise/interceptor-stateless-ear
as the project.interceptor-stateless-ear
and select Run Project
which will build, deploy and run the project. Sample output is given below. Copying 1 file to /home/sreeni/IAS/SAMPLES/WS/glassfish-samples/ws/javaee5/enterprise/interceptor-stateless-ear/dist Converted duke to Duke Cannot convert (BadArgument) duke Cannot convert (BadArgument)null Cannot convert (BadArgument) duke Cannot convert (BadArgument)4duke Converted Duke to Duke run-interceptor-stateless-appclient: BUILD SUCCESSFUL (total time: 17 seconds)
If you have problems when running the application, refer to troubleshooting document.
Copyright © 2006 Sun Microsystems, Inc. All rights reserved.