Well, it looks like I found a solution to my problem.
Problem: I have a stateless session EJB that throws a CreateException in
ejbCreate(). In a clustered environment, I believe this should cause the client
proxy to fail-over to another node. The current behavior in JBoss 3.2.6 is to
throw the CreateException back to the client wrapped in an
UndeclaredThrowableException. The client proxy just propogates the
UndeclaredThrowableException all the way back up the call chain without failing
over.
Solution: I wrote my own interceptor that catches CreateExceptions and throws
back a GenericClusteringException. The client proxy will fail-over when it
receives a GenericClusteringException with status set to not completed.
Here is the code to my interceptor, in case anyone is interested.
| package com.itgssi.util.jboss.ejb;
|
| import javax.ejb.CreateException;
|
| import org.jboss.ejb.plugins.AbstractInterceptor;
| import org.jboss.ha.framework.interfaces.GenericClusteringException;
| import org.jboss.invocation.Invocation;
|
| /**
| * <p>
| * <code>CreateExceptionHandlerInterceptor</code> handles CreateExceptions
| * during invocations to an EJB. In order for these exceptions to cause the
| * client to fail-over in a clustered environment, they get converted to
| * <code>GenericClusteringException</code>s.
| * </p>
| * <p>
| * <em>NOTE:</em> for this interceptor to work propertly, it must come
BEFORE
| * <code>org.jboss.ejb.plugins.CleanShutdownInterceptor</code>.
| * <code>CleanShutdownInterceptor</code> will change the status on
| * <code>GenericClusteringException</code> s that pass through it to MAYBE,
| * which will not cause the client to fail-over. This is the behavior in
JBoss
| * 3.2.6; I'm not sure about other versions.
| * </p>
| *
| * @author anguyen
| */
| public class CreateExceptionHandlerInterceptor extends AbstractInterceptor {
|
| /**
| * This invocation handles <code>CreateException</code>s thrown by
| * other invokers further down the chain. The current behavior is
| * to log the <code>CreateException</code>'s message as a warning
| * and throw a <code>GenericClusteringException</code> with a
| * completed status of NO. Clients of a clustered EJB should
| * interpret this exception as an indication that the EJB
| * is unavailable on this node and fail-over to another node.
| */
| public Object invoke(Invocation mi) throws Exception {
| try {
| return getNext().invoke(mi);
| }
| catch (CreateException e) {
| handleCreateException(e);
| // if handle create exception doesn't throw an exception....
| throw e;
| }
| catch (Exception e) {
| Throwable rootCause = e;
| while ((rootCause = rootCause.getCause()) != null) {
| // loop until we get to the root cause
| }
| if (rootCause instanceof CreateException) {
| handleCreateException((CreateException) rootCause);
| }
| // if the root cause is not a CreateException, rethrow
| // the original exception
| throw e;
| }
| }
|
| void handleCreateException(CreateException e) throws Exception {
| String message = "EJB creation failed on node";
| log.warn(message);
| log.debug("Stack Trace", e);
| throw new
GenericClusteringException(GenericClusteringException.COMPLETED_NO, message);
| }
| }
|
To use this interceptor, I created a custom container for my EJB in jboss.xml.
| <?xml version="1.0" encoding="UTF-8"?>
| <!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 3.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss_3_0.dtd">
|
| <jboss>
|
| <enterprise-beans>
|
| <!--
| To add beans that you have deployment descriptor info for, add
| a file to your XDoclet merge directory called jboss-beans.xml that
contains
| the <session></session>, <entity></entity> and
<message-driven></message-driven>
| markup for those beans.
| -->
|
| <session>
| <ejb-name>MySLSB</ejb-name>
| <jndi-name>ejb/MySLSB</jndi-name>
| <configuration-name>My Clustered Stateless
SessionBean</configuration-name>
| <clustered>true</clustered>
| <cluster-config>
| <partition-name>DefaultPartition</partition-name>
|
<home-load-balance-policy>org.jboss.ha.framework.interfaces.RoundRobin</home-load-balance-policy>
|
<bean-load-balance-policy>org.jboss.ha.framework.interfaces.RoundRobin</bean-load-balance-policy>
| </cluster-config>
|
| </session>
|
| </enterprise-beans>
|
| <resource-managers>
| </resource-managers>
|
| <!--
| | for container settings, you can merge in jboss-container.xml
| | this can contain <invoker-proxy-bindings/> and
<container-configurations/>
| -->
| <container-configurations>
| <container-configuration>
| <container-name>My Clustered Stateless SessionBean</container-name>
| <call-logging>false</call-logging>
|
<invoker-proxy-binding-name>clustered-stateless-rmi-invoker</invoker-proxy-binding-name>
| <container-interceptors>
| <!-- This interceptor must come before CleanShutdownInterceptor
to work properly -->
|
<interceptor>com.itgssi.util.jboss.ejb.CreateExceptionHandlerInterceptor</interceptor>
|
<interceptor>org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor</interceptor>
|
<interceptor>org.jboss.ejb.plugins.CleanShutdownInterceptor</interceptor>
| <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
|
<interceptor>org.jboss.ejb.plugins.SecurityInterceptor</interceptor>
| <!-- CMT -->
| <interceptor
transaction="Container">org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>
| <interceptor transaction="Container"
metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
| <interceptor
transaction="Container">org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor</interceptor>
| <!-- BMT -->
| <interceptor
transaction="Bean">org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor</interceptor>
| <interceptor
transaction="Bean">org.jboss.ejb.plugins.TxInterceptorBMT</interceptor>
| <interceptor transaction="Bean"
metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
|
<interceptor>org.jboss.resource.connectionmanager.CachedConnectionInterceptor</interceptor>
| </container-interceptors>
|
<instance-pool>org.jboss.ejb.plugins.StatelessSessionInstancePool</instance-pool>
| <instance-cache></instance-cache>
| <persistence-manager></persistence-manager>
| <container-pool-conf>
| <MaximumSize>100</MaximumSize>
| </container-pool-conf>
| </container-configuration>
|
| </container-configurations>
| </jboss>
|
I used the standard Clustered Stateless SessionBean container as a template.
You could also modify the default Clustered Stateless SessionBean container and
just add the interceptor there.
Kudos to the JBoss developers for giving us the hooks necessary to come up with
these kinds of solutions.
View the original post :
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3872917#3872917
Reply to the post :
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=3872917
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user