JMessageEndpointProxy.java

00001 
00026 package org.objectweb.jonas_ejb.container;
00027 
00028 import java.lang.reflect.InvocationHandler;
00029 import java.lang.reflect.InvocationTargetException;
00030 import java.lang.reflect.Method;
00031 import java.lang.reflect.Proxy;
00032 
00033 import javax.ejb.MessageDrivenBean;
00034 import javax.ejb.EJBException;
00035 import javax.resource.ResourceException;
00036 import javax.resource.spi.IllegalStateException;
00037 import javax.transaction.xa.XAResource;
00038 
00039 import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
00040 
00041 import org.objectweb.transaction.jta.TransactionManager;
00042 import org.objectweb.util.monolog.api.BasicLevel;
00043 
00051 public class JMessageEndpointProxy implements InvocationHandler {
00052 
00053     protected JMdbEndpointFactory bf = null;
00054 
00055     protected JMessageEndpoint ep = null;
00056 
00057     protected MessageDrivenBean mdb = null;
00058 
00059     protected TransactionManager tm = null;
00060 
00061     boolean b4Delivery = false;
00062 
00063     int msgCount = 0;
00064 
00065     // RequestCtx associated to the thread
00066     // Thread specific data
00067     private transient static ThreadLocal requestCtx = new ThreadLocal();
00068     
00076     public JMessageEndpointProxy(JMdbEndpointFactory bf, MessageDrivenBean mdb, JMessageEndpoint ep) {
00077         this.bf = bf;
00078         this.mdb = mdb;
00079         this.ep = ep;
00080         // keep these locally for efficiency.
00081         tm = bf.getTransactionManager();
00082     }
00083 
00084     // ------------------------------------------------------------------
00085     // InvocationHandler implementation
00086     // ------------------------------------------------------------------
00087 
00088     public Object invoke(Object obj, Method method, Object[] aobj) throws Throwable, NoSuchMethodException,
00089             ResourceException, Exception {
00090         RequestCtx rctx = null;
00091         String methodName = method.getName();
00092         Object ret = null;
00093         Throwable invokeEx = null;
00094 
00095         TraceEjb.mdb.log(BasicLevel.DEBUG, "Calling " + methodName + " on " + this);
00096         if (ep.released) {
00097             throw new IllegalStateException("Endpoint is in a released state and must be reactivated before using");
00098         }
00099         // Object methods
00100         if ("equals".equals(methodName)) {
00101             Object obj1 = null;
00102             if (Proxy.isProxyClass(aobj[0].getClass())) {
00103                 obj1 = (Object) Proxy.getInvocationHandler(aobj[0]);
00104             } else {
00105                 obj1 = aobj[0];
00106             }
00107             ret = new Boolean(this.equals(obj1));
00108         } else if ("hashCode".equals(methodName)) {
00109             ret = new Integer(this.hashCode());
00110         } else if ("toString".equals(methodName)) {
00111             ret = this.toString();
00112         } else if ("afterDelivery".equals(methodName)) {
00113             if (!b4Delivery) {
00114                 throw new IllegalStateException(methodName + " called w/o call to beforeDelivery");
00115             }
00116             b4Delivery = false;
00117             msgCount = 0;
00118             rctx = (RequestCtx) requestCtx.get();
00119             try {
00120                 if (rctx.mustCommit && ep.getXAResource() != null) {
00121                     rctx.currTx.delistResource(ep.getXAResource(), XAResource.TMSUCCESS);
00122                 }
00123                 bf.postInvoke(rctx);
00124             } catch (Exception e) {
00125                 TraceEjb.logger.log(BasicLevel.ERROR, "exception on postInvoke: ", e);
00126                 throw new RuntimeException(e);
00127             }
00128         } else if ("beforeDelivery".equals(methodName)) {
00129             
00130             TraceEjb.mdb.log(BasicLevel.DEBUG, "beforeDelivery called");
00131             if (b4Delivery) {
00132                 throw new IllegalStateException(methodName + " called w/o call to afterDelivery");
00133             }
00134             if (bf.isTxBeanManaged()) {
00135                 throw new IllegalStateException(methodName + " cannot be called when using bean managed transactions");
00136             }
00137             if (tm.getTransaction() != null) {
00138                 throw new IllegalStateException(methodName + " cannot be called when using an imported transaction");
00139             }
00140             msgCount = 0;
00141             // retrieve intented method name passed in parameter
00142             Object obj1 = null;
00143             if (Proxy.isProxyClass(aobj[0].getClass())) {
00144                 obj1 = (Object) Proxy.getInvocationHandler(aobj[0]);
00145             } else {
00146                 obj1 = aobj[0];
00147             }
00148             Method intentedTargetMethod = (Method) obj1;
00149             String intentedTargetMethodName = intentedTargetMethod.getName();
00150 
00151             TraceEjb.mdb.log(BasicLevel.DEBUG, "intentedTargetMethodName=" + intentedTargetMethodName);
00152             try {
00153                 TraceEjb.mdb.log(BasicLevel.DEBUG, "before preInvoke");
00154                 rctx = bf.preInvoke(getTxAttr(intentedTargetMethod));
00155                 // JCA 1.5 ?12.5.6 mentions that beforeDelivery and afterDelivery
00156                 // must be called from a single thread of control.
00157                 // so the RequestCtx is stored in thread specific data for next
00158                 // use in afterDelivery call and intended method call.
00159                 requestCtx.set(rctx);
00160                 b4Delivery = true;
00161                 if (rctx.mustCommit && ep.getXAResource() != null) {
00162 
00163                     rctx.currTx.enlistResource(ep.getXAResource());
00164                     TraceEjb.mdb.log(BasicLevel.DEBUG, "enlistResource Ok");
00165                 }
00166             } catch (Exception e) {
00167                 TraceEjb.logger.log(BasicLevel.ERROR, "preInvoke failed: ", e);
00168                 throw new RuntimeException(e);
00169             }
00170             TraceEjb.mdb.log(BasicLevel.DEBUG, "beforeDelivery ended");
00171         } else if ("release".equals(methodName)) {
00172             bf.releaseEndpoint(ep);
00173         } else {
00174             msgCount++;
00175 
00176             if (!b4Delivery) {
00177                 boolean isImportedTx = tm.getTransaction() != null;
00178                 rctx = bf.preInvoke(getTxAttr(method));
00179                 // JCA 1.5 ?12.5.9
00180                 // if txRequired && imported tx, use the source managed Tx
00181                 // and ignore the XAResource
00182                 if (rctx.mustCommit) {
00183                     if (!isImportedTx) {
00184 
00185                         if (ep.getXAResource() != null) {
00186                             rctx.currTx.enlistResource(ep.getXAResource());
00187                         }
00188                     } else {
00189                         rctx.mustCommit = false;
00190                     }
00191                 }
00192                 bf.checkSecurity(null);
00193             } else if (msgCount > 1) {
00194                 throw new IllegalStateException("Unable to deliver multiple messages");
00195             } else {
00196                 rctx = (RequestCtx) requestCtx.get();
00197             }
00198             try {
00199                 TraceEjb.mdb.log(BasicLevel.DEBUG, "Before invoke");
00200                 ret = method.invoke(mdb, aobj);
00201                 TraceEjb.mdb.log(BasicLevel.DEBUG, "After invoke");
00202             } catch (InvocationTargetException ite) {
00203                 Throwable t = ite.getTargetException();
00204                 if (t instanceof RuntimeException) {
00205                     if (rctx != null) {
00206                         rctx.sysExc = new EJBException((RuntimeException) t);
00207                     }
00208                 } else {
00209                     if (rctx != null) {
00210                         rctx.sysExc = t;
00211                     }
00212                 }
00213                 invokeEx = rctx.sysExc;
00214                 TraceEjb.logger.log(BasicLevel.ERROR, "error thrown by an enterprise Bean", t);
00215             } catch (Throwable ex) {
00216                 //ex.printStackTrace();
00217                 if (rctx != null) {
00218                     rctx.sysExc = ex;
00219                 }
00220                 invokeEx = ex;
00221 
00222                 TraceEjb.logger.log(BasicLevel.ERROR, "error thrown by an enterprise Bean", ex);
00223             } finally {
00224                 if (!b4Delivery) {
00225                     try {
00226                         if (!bf.isTxBeanManaged() && rctx.mustCommit && ep.getXAResource() != null) {
00227                             rctx.currTx.delistResource(ep.getXAResource(), XAResource.TMSUCCESS);
00228                         }
00229                         bf.postInvoke(rctx);
00230                     } catch (Exception e) {
00231                         TraceEjb.logger.log(BasicLevel.ERROR, "exception on postInvoke: ", e);
00232                         if (invokeEx == null) {
00233                             invokeEx = e;
00234                         }
00235                     }
00236                 } else {
00237                     // Reset message count if not using after/before delivery
00238                     msgCount = 0;
00239                 }
00240             }
00241         }
00242         if (invokeEx != null) {
00243             TraceEjb.logger.log(BasicLevel.ERROR, "Exception raised: ", invokeEx);
00244             throw invokeEx;
00245         }
00246         TraceEjb.mdb.log(BasicLevel.DEBUG, "ret="+ret);
00247         return ret;
00248     }
00249 
00250     private int getTxAttr(Method m) {
00251         int ret = MethodDesc.TX_NOT_SUPPORTED;
00252         try {
00253             ret = bf.isDeliveryTransacted(m) ? MethodDesc.TX_REQUIRED : MethodDesc.TX_NOT_SUPPORTED;
00254         } catch (NoSuchMethodException nsme) {
00255         }
00256         return ret;
00257     }
00258 }
00259 

Generated on Tue Feb 15 15:05:39 2005 for JOnAS by  doxygen 1.3.9.1