1 22 package org.jboss.ejb.plugins; 23 24 import org.jboss.ejb.BeanLock; 25 import org.jboss.ejb.Container; 26 import org.jboss.ejb.EnterpriseContext; 27 import org.jboss.ejb.InstanceCache; 28 import org.jboss.ejb.InstancePool; 29 import org.jboss.ejb.StatefulSessionContainer; 30 import org.jboss.ejb.AllowedOperationsAssociation; 31 import org.jboss.invocation.Invocation; 32 import org.jboss.invocation.InvocationType; 33 import org.jboss.logging.Logger; 34 import org.jboss.metadata.SessionMetaData; 35 36 import javax.ejb.EJBException ; 37 import javax.ejb.EJBObject ; 38 import javax.ejb.Handle ; 39 import javax.ejb.NoSuchObjectLocalException ; 40 import javax.ejb.TimedObject ; 41 import javax.ejb.Timer ; 42 import javax.transaction.RollbackException ; 43 import javax.transaction.Status ; 44 import javax.transaction.Synchronization ; 45 import javax.transaction.Transaction ; 46 import java.lang.reflect.Method ; 47 import java.rmi.NoSuchObjectException ; 48 import java.rmi.RemoteException ; 49 50 60 public class StatefulSessionInstanceInterceptor 61 extends AbstractInterceptor 62 { 63 65 67 68 protected Logger log = Logger.getLogger(this.getClass()); 69 70 protected StatefulSessionContainer container; 71 72 74 private static final Method getEJBHome; 75 private static final Method getHandle; 76 private static final Method getPrimaryKey; 77 private static final Method isIdentical; 78 private static final Method remove; 79 private static final Method getEJBObject; 80 private static final Method ejbTimeout; 81 82 static 83 { 84 try 85 { 86 Class [] noArg = new Class [0]; 87 getEJBHome = EJBObject .class.getMethod("getEJBHome", noArg); 88 getHandle = EJBObject .class.getMethod("getHandle", noArg); 89 getPrimaryKey = EJBObject .class.getMethod("getPrimaryKey", noArg); 90 isIdentical = EJBObject .class.getMethod("isIdentical", new Class []{EJBObject .class}); 91 remove = EJBObject .class.getMethod("remove", noArg); 92 getEJBObject = Handle .class.getMethod("getEJBObject", noArg); 93 ejbTimeout = TimedObject .class.getMethod("ejbTimeout", new Class []{Timer .class}); 94 } 95 catch (Exception e) 96 { 97 e.printStackTrace(); 98 throw new ExceptionInInitializerError (e); 99 } 100 } 101 102 104 106 public void setContainer(Container container) 107 { 108 this.container = (StatefulSessionContainer)container; 109 } 110 111 public Container getContainer() 112 { 113 return container; 114 } 115 116 118 public Object invokeHome(Invocation mi) 119 throws Exception 120 { 121 if (getEJBObject.equals(mi.getMethod())) 123 return getNext().invokeHome(mi); 124 125 InstancePool pool = container.getInstancePool(); 127 EnterpriseContext ctx = pool.get(); 128 129 mi.setEnterpriseContext(ctx); 131 132 ctx.lock(); 134 135 ctx.setPrincipal(mi.getPrincipal()); 137 138 AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_HOME); 139 140 try 141 { 142 return getNext().invokeHome(mi); 144 } 145 finally 146 { 147 synchronized (ctx) 148 { 149 AllowedOperationsAssociation.popInMethodFlag(); 150 151 ctx.unlock(); 153 154 if (ctx.getId() == null) 156 { 157 pool.free(ctx); 158 } 159 } 160 } 161 } 162 163 protected void register(EnterpriseContext ctx, Transaction tx, BeanLock lock) 164 { 165 InstanceSynchronization synch = new InstanceSynchronization(ctx, lock); 167 168 try 169 { 170 if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) 174 { 175 176 return; 177 } 178 179 try 181 { 182 tx.registerSynchronization(synch); 183 } 184 catch (Exception ex) 185 { 186 getContainer().getLockManager().removeLockRef(lock.getId()); 189 throw ex; 190 } 191 192 synch.afterBegin(); 194 195 } catch (RollbackException e) 196 { 197 198 } catch (Exception e) 199 { 200 201 throw new EJBException (e); 202 203 } 204 } 205 206 public Object invoke(Invocation mi) 207 throws Exception 208 { 209 InstanceCache cache = container.getInstanceCache(); 210 InstancePool pool = container.getInstancePool(); 211 Object methodID = mi.getId(); 212 EnterpriseContext ctx = null; 213 214 BeanLock lock = container.getLockManager().getLock(methodID); 215 try 216 { 217 228 if(SecurityActions.peekRunAsIdentity() == null) 229 SecurityActions.pushSubjectContext(mi.getPrincipal(), mi.getCredential(), null); 230 231 lock.sync(); 232 try 233 { 234 try 236 { 237 ctx = cache.get(methodID); 238 } 239 catch (NoSuchObjectException e) 240 { 241 if (mi.isLocal()) 242 throw new NoSuchObjectLocalException (e.getMessage()); 243 else 244 throw e; 245 } 246 catch (EJBException e) 247 { 248 throw e; 249 } 250 catch (RemoteException e) 251 { 252 throw e; 253 } 254 catch (Exception e) 255 { 256 InvocationType type = mi.getType(); 257 boolean isLocal = (type == InvocationType.LOCAL || type == InvocationType.LOCALHOME); 258 if (isLocal) 259 throw new EJBException ("Unable to get an instance from the pool/cache", e); 260 else 261 throw new RemoteException ("Unable to get an intance from the pool/cache", e); 262 } 263 264 mi.setEnterpriseContext(ctx); 266 EnterpriseBeanPolicyContextHandler.setEnterpriseBean(ctx.getInstance()); 268 269 boolean isBMT = ((SessionMetaData)container.getBeanMetaData()).isBeanManagedTx(); 271 if (isBMT == false) 272 { 273 274 if (ctx.getTransaction() != null && 276 !ctx.getTransaction().equals(mi.getTransaction())) 278 { 279 StringBuffer msg = new StringBuffer ("Application Error: " + 281 "tried to enter Stateful bean with different tx context"); 282 msg.append(", contextTx: " + ctx.getTransaction()); 283 msg.append(", methodTx: " + mi.getTransaction()); 284 throw new EJBException (msg.toString()); 285 } 286 287 if (ctx.getTransaction() == null && mi.getTransaction() != null) 289 { 290 register(ctx, mi.getTransaction(), lock); 291 } 292 } 293 294 if (!ctx.isLocked()) 295 { 296 297 ctx.lock(); 299 } 300 else 301 { 302 if (!isCallAllowed(mi)) 303 { 304 throw new EJBException ("Application Error: no concurrent " + 306 "calls on stateful beans"); 307 } 308 else 309 { 310 ctx.lock(); 311 } 312 } 313 } 314 finally 315 { 316 lock.releaseSync(); 317 } 318 319 ctx.setPrincipal(mi.getPrincipal()); 321 322 if (ejbTimeout.equals(mi.getMethod())) 323 AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_TIMEOUT); 324 else 325 AllowedOperationsAssociation.pushInMethodFlag(IN_BUSINESS_METHOD); 326 327 boolean validContext = true; 328 try 329 { 330 Object ret = getNext().invoke(mi); 332 return ret; 333 } 334 catch (RemoteException e) 335 { 336 cache.remove(methodID); 338 pool.discard(ctx); 339 validContext = false; 340 341 throw e; 342 } 343 catch (RuntimeException e) 344 { 345 cache.remove(methodID); 347 pool.discard(ctx); 348 validContext = false; 349 350 throw e; 351 } 352 catch (Error e) 353 { 354 cache.remove(methodID); 356 pool.discard(ctx); 357 validContext = false; 358 359 throw e; 360 } 361 finally 362 { 363 AllowedOperationsAssociation.popInMethodFlag(); 364 365 if (validContext) 366 { 367 lock.sync(); 369 try 370 { 371 372 ctx.unlock(); 374 375 if (ctx.getId() == null) 377 { 378 cache.remove(methodID); 380 pool.free(ctx); 381 } 382 } 383 finally 384 { 385 lock.releaseSync(); 386 } 387 } 388 } 389 } 390 finally 391 { 392 container.getLockManager().removeLockRef(lock.getId()); 393 SecurityActions.popSubjectContext(); 394 } 395 } 396 397 protected boolean isCallAllowed(Invocation mi) 398 { 399 Method m = mi.getMethod(); 400 if (m.equals(getEJBHome) || 401 m.equals(getHandle) || 402 m.equals(getPrimaryKey) || 403 m.equals(isIdentical) || 404 m.equals(remove)) 405 { 406 return true; 407 } 408 return false; 409 } 410 411 413 private class InstanceSynchronization 414 implements Synchronization 415 { 416 419 private EnterpriseContext ctx; 420 421 private boolean notifySession = false; 423 424 private Method afterBegin; 426 private Method beforeCompletion; 427 private Method afterCompletion; 428 private BeanLock lock; 429 private boolean beforeCompletionInvoked = false; 430 431 434 InstanceSynchronization(EnterpriseContext ctx, BeanLock lock) 435 { 436 this.ctx = ctx; 437 this.lock = lock; 438 this.lock.addRef(); 439 440 notifySession = (ctx.getInstance() instanceof javax.ejb.SessionSynchronization ); 442 443 if (notifySession) 444 { 445 try 446 { 447 Class sync = Class.forName("javax.ejb.SessionSynchronization"); 449 450 afterBegin = sync.getMethod("afterBegin", new Class [0]); 452 beforeCompletion = sync.getMethod("beforeCompletion", new Class [0]); 453 afterCompletion = sync.getMethod("afterCompletion", new Class [] 454 {boolean.class}); 455 } 456 catch (Exception e) 457 { 458 log.error("failed to setup InstanceSynchronization", e); 459 } 460 } 461 } 462 463 465 public void afterBegin() 466 { 467 if (notifySession) 468 { 469 try 470 { 471 AllowedOperationsAssociation.pushInMethodFlag(IN_AFTER_BEGIN); 472 afterBegin.invoke(ctx.getInstance(), new Object [0]); 473 } 474 catch (Exception e) 475 { 476 log.error("failed to invoke afterBegin", e); 477 } 478 finally{ 479 AllowedOperationsAssociation.popInMethodFlag(); 480 } 481 } 482 } 483 484 public void beforeCompletion() 485 { 486 if( log.isTraceEnabled() ) 487 log.trace("beforeCompletion called"); 488 489 ctx.lock(); 491 beforeCompletionInvoked = true; 492 493 if (notifySession) 494 { 495 try 496 { 497 AllowedOperationsAssociation.pushInMethodFlag(IN_BEFORE_COMPLETION); 498 beforeCompletion.invoke(ctx.getInstance(), new Object [0]); 499 } 500 catch (Exception e) 501 { 502 log.error("failed to invoke beforeCompletion", e); 503 } 504 finally{ 505 AllowedOperationsAssociation.popInMethodFlag(); 506 } 507 } 508 } 509 510 public void afterCompletion(int status) 511 { 512 if( log.isTraceEnabled() ) 513 log.trace("afterCompletion called"); 514 515 lock.sync(); 516 try 517 { 518 ctx.setTransaction(null); 520 521 if (beforeCompletionInvoked) 522 ctx.unlock(); 523 524 if (notifySession) 525 { 526 527 try 528 { 529 AllowedOperationsAssociation.pushInMethodFlag(IN_AFTER_COMPLETION); 530 if (status == Status.STATUS_COMMITTED) 531 { 532 afterCompletion.invoke(ctx.getInstance(), new Object []{Boolean.TRUE}); 533 } 534 else 535 { 536 afterCompletion.invoke(ctx.getInstance(), new Object []{Boolean.FALSE}); 537 } 538 } 539 catch (Exception e) 540 { 541 log.error("failed to invoke afterCompletion", e); 542 } 543 finally{ 544 AllowedOperationsAssociation.popInMethodFlag(); 545 } 546 } 547 } 548 finally 549 { 550 lock.releaseSync(); 551 container.getLockManager().removeLockRef(lock.getId()); 552 } 553 } 554 } 555 } 556 557 | Popular Tags |