1 22 package org.jboss.ejb.plugins; 23 24 import java.lang.reflect.Method ; 25 import java.rmi.RemoteException ; 26 import javax.ejb.EJBObject ; 27 import javax.ejb.EJBException ; 28 import javax.transaction.Transaction ; 29 import javax.transaction.Status ; 30 31 import org.jboss.invocation.Invocation; 32 import org.jboss.invocation.InvocationType; 33 import org.jboss.ejb.Container; 34 import org.jboss.ejb.EntityEnterpriseContext; 35 import org.jboss.metadata.EntityMetaData; 36 import org.jboss.ejb.plugins.lock.Entrancy; 37 import org.jboss.ejb.plugins.lock.NonReentrantLock; 38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.CMRInvocation; 39 40 53 public class EntityReentranceInterceptor 54 extends AbstractInterceptor 55 { 56 protected boolean reentrant = false; 57 58 60 public void setContainer(Container container) 61 { 62 super.setContainer(container); 63 if (container != null) 64 { 65 EntityMetaData meta = (EntityMetaData) container.getBeanMetaData(); 66 reentrant = meta.isReentrant(); 67 } 68 } 69 70 protected boolean isTxExpired(Transaction miTx) throws Exception 71 { 72 if (miTx != null && miTx.getStatus() == Status.STATUS_MARKED_ROLLBACK) 73 { 74 return true; 75 } 76 return false; 77 } 78 79 public Object invoke(Invocation mi) 80 throws Exception 81 { 82 EntityEnterpriseContext ctx = (EntityEnterpriseContext) mi.getEnterpriseContext(); 84 boolean nonReentrant = !(reentrant || isReentrantMethod(mi)); 85 86 NonReentrantLock methodLock = ctx.getMethodLock(); 88 Transaction miTx = ctx.getTransaction(); 89 boolean locked = false; 90 try 91 { 92 while (!locked) 93 { 94 if (methodLock.attempt(5000, miTx, nonReentrant)) 95 { 96 locked = true; 97 } 98 else 99 { 100 if (isTxExpired(miTx)) 101 { 102 log.error("Saw rolled back tx=" + miTx); 103 throw new RuntimeException ("Transaction marked for rollback, possibly a timeout"); 104 } 105 } 106 } 107 } 108 catch (NonReentrantLock.ReentranceException re) 109 { 110 if (mi.getType() == InvocationType.REMOTE) 111 { 112 throw new RemoteException ("Reentrant method call detected: " 113 + container.getBeanMetaData().getEjbName() + " " 114 + ctx.getId().toString()); 115 } 116 else 117 { 118 throw new EJBException ("Reentrant method call detected: " 119 + container.getBeanMetaData().getEjbName() + " " 120 + ctx.getId().toString()); 121 } 122 } 123 try 124 { 125 ctx.lock(); 126 return getNext().invoke(mi); 127 } 128 finally 129 { 130 ctx.unlock(); 131 methodLock.release(nonReentrant); 132 } 133 } 134 135 137 private static final Method getEJBHome; 138 private static final Method getHandle; 139 private static final Method getPrimaryKey; 140 private static final Method isIdentical; 141 private static final Method remove; 142 143 static 144 { 145 try 146 { 147 Class [] noArg = new Class [0]; 148 getEJBHome = EJBObject .class.getMethod("getEJBHome", noArg); 149 getHandle = EJBObject .class.getMethod("getHandle", noArg); 150 getPrimaryKey = EJBObject .class.getMethod("getPrimaryKey", noArg); 151 isIdentical = EJBObject .class.getMethod("isIdentical", new Class []{EJBObject .class}); 152 remove = EJBObject .class.getMethod("remove", noArg); 153 } 154 catch (Exception e) 155 { 156 e.printStackTrace(); 157 throw new ExceptionInInitializerError (e); 158 } 159 } 160 161 protected boolean isReentrantMethod(Invocation mi) 162 { 163 Method m = mi.getMethod(); 165 if (m != null && ( 166 m.equals(getEJBHome) || 167 m.equals(getHandle) || 168 m.equals(getPrimaryKey) || 169 m.equals(isIdentical) || 170 m.equals(remove))) 171 { 172 return true; 173 } 174 175 if (mi instanceof CMRInvocation) 177 { 178 Entrancy entrancy = ((CMRInvocation) mi).getEntrancy(); 179 if (entrancy == Entrancy.NON_ENTRANT) 180 { 181 log.trace("NON_ENTRANT invocation"); 182 return true; 183 } 184 } 185 186 return false; 187 } 188 189 } 190 | Popular Tags |