1 25 26 package org.objectweb.jonas_ejb.container; 27 28 import java.rmi.NoSuchObjectException ; 29 import java.rmi.RemoteException ; 30 31 import javax.ejb.EJBException ; 32 import javax.ejb.EntityBean ; 33 import javax.ejb.NoSuchObjectLocalException ; 34 import javax.ejb.ObjectNotFoundException ; 35 import javax.ejb.TimedObject ; 36 import javax.ejb.Timer ; 37 import javax.ejb.TimerService ; 38 import javax.transaction.Status ; 39 import javax.transaction.SystemException ; 40 import javax.transaction.Transaction ; 41 42 import org.objectweb.jonas_ejb.deployment.api.EntityDesc; 43 import org.objectweb.jonas_ejb.deployment.api.MethodDesc; 44 import org.objectweb.jonas_timer.TraceTimer; 45 46 import org.objectweb.util.monolog.api.BasicLevel; 47 48 59 public abstract class JEntitySwitch { 60 61 64 protected JEntityFactory bf; 65 66 69 protected Object pk = null; 70 71 74 protected JEntityLocal local = null; 75 76 79 protected JEntityRemote remote = null; 80 81 84 protected long inactivityTimeout; 86 89 protected boolean shared; 90 91 101 protected int lockpolicy; 102 103 107 protected boolean txUpdates; 108 109 112 protected TimerService myTimerService = null; 113 114 117 protected int countIH = 0; 118 119 122 protected int countIT = 0; 123 124 127 protected int waiters = 0; 128 129 133 protected boolean inDirtyList = false; 134 135 140 protected boolean mustReload = false; 141 142 146 protected boolean mustStore = false; 147 148 152 protected boolean todiscard = false; 153 154 protected Transaction runningtx = null; 157 158 protected Transaction writingtx = null; 161 162 166 protected Transaction blockedtx = null; 167 168 protected boolean isremoved = false; 169 170 protected static int counter = 0; 172 173 protected String ident="0000 "; 174 175 178 protected long timestamp = System.currentTimeMillis(); 179 180 private final static long FEW_MINUTS = 180000; 181 182 private static final int MAX_NB_RETRY = 2; 183 184 187 protected boolean lazyregister = false; 188 189 193 protected boolean reentrant; 194 195 abstract JEntityContext getContext4Tx(Transaction tx); 196 197 abstract void setContext4Tx(Transaction tx, JEntityContext ctx); 198 199 abstract void removeContext4Tx(Transaction tx); 200 201 abstract protected void initpolicy(JEntityFactory bf); 202 203 abstract public boolean passivateIH(boolean passivation); 204 205 abstract public void endIH(); 206 207 abstract public void notifyWriting(Transaction tx, JEntityContext bctx); 208 209 213 public JEntitySwitch() { 214 } 215 216 223 public void init(JEntityFactory bf, Object pk) { 224 this.bf = bf; 225 this.pk = pk; 226 isremoved = false; 227 if (pk == null) { 228 TraceEjb.logger.log(BasicLevel.ERROR, "Init Entity Switch with a null PK!"); 229 throw new EJBException ("Init Entity Switch with a null PK!"); 230 } 231 232 shared = bf.isShared(); 233 reentrant = bf.isReentrant(); 234 inactivityTimeout = bf.getInactivityTimeout() * 1000; 235 initpolicy(bf); 236 if (TraceEjb.isDebugSynchro()) { 237 ident = "<" + counter + ":" + pk + ">"; 239 } 240 counter++; 241 242 countIH = 0; 243 countIT = 0; 244 waiters = 0; 245 246 if (bf.getHome() != null) { 248 try { 249 remote = ((JEntityHome) bf.getHome()).createRemoteObject(); 250 remote.setEntitySwitch(this); 251 } catch (RemoteException e) { 252 throw new EJBException ("cannot create Remote Object", e); 253 } 254 } 255 256 if (bf.getLocalHome() != null) { 258 local = ((JEntityLocalHome) bf.getLocalHome()).createLocalObject(); 259 local.setEntitySwitch(this); 260 } 261 if (inactivityTimeout > 0) { 265 timestamp = System.currentTimeMillis() + FEW_MINUTS; 266 if (TraceTimer.isDebug()) { 267 TraceTimer.logger.log(BasicLevel.DEBUG, ident + timestamp); 268 } 269 } 270 } 271 272 275 public JEntityLocal getLocal() { 276 return local; 277 } 278 279 282 public JEntityRemote getRemote() { 283 return remote; 284 } 285 286 290 public TimerService getEntityTimerService() { 291 if (pk == null) { 294 throw new java.lang.IllegalStateException (); 295 } 296 if (myTimerService == null) { 297 myTimerService = new JTimerService(this); 299 } 300 return myTimerService; 301 } 302 303 307 public void notifyTimeout(Timer timer) { 308 if (TraceTimer.isDebug()) { 309 TraceTimer.logger.log(BasicLevel.DEBUG, ident); 310 } 311 312 boolean committed = false; 313 for (int nbretry = 0; ! committed && nbretry < MAX_NB_RETRY; nbretry++) { 314 RequestCtx rctx = bf.preInvoke(bf.getTimerTxAttribute()); 315 try { 316 JEntityContext bctx = getICtx(rctx.currTx, false); 317 EntityBean eb = bctx.getInstance(); 318 bf.checkSecurity(null); 319 if (eb instanceof TimedObject ) { 320 TimedObject instance = (TimedObject ) eb; 321 instance.ejbTimeout(timer); 322 } else { 323 throw new EJBException ("The bean does not implement the `TimedObject` interface"); 324 } 325 committed = (rctx.currTx == null) || 326 (rctx.currTx.getStatus() != Status.STATUS_MARKED_ROLLBACK); 327 } catch (EJBException e) { 328 rctx.sysExc = e; 329 throw e; 330 } catch (RuntimeException e) { 331 rctx.sysExc = e; 332 throw new EJBException ("RuntimeException thrown by an enterprise Bean", e); 333 } catch (Error e) { 334 rctx.sysExc = e; 335 throw new EJBException ("Error thrown by an enterprise Bean" + e); 336 } catch (RemoteException e) { 337 rctx.sysExc = e; 338 throw new EJBException ("Remote Exception raised:", e); 339 } catch (SystemException e) { 340 rctx.sysExc = e; 341 throw new EJBException ("Cannot get transaction status:", e); 342 } finally { 343 try { 344 bf.postInvoke(rctx); 345 } finally { 346 if (rctx.sysExc != null) { 347 discardICtx(rctx.currTx); 348 } else { 349 releaseICtx(rctx.currTx); 350 } 351 } 352 } 353 } 354 } 355 356 359 public Object getPrimaryKey() { 360 if (pk == null) { 361 throw new java.lang.IllegalStateException (); 362 } 363 return pk; 364 } 365 366 371 public void bindICtx(Transaction tx, JEntityContext bctx) { 372 mapICtx(tx, bctx, true, false, false); 373 } 374 375 382 public synchronized boolean tryBindICtx(Transaction tx, JEntityContext bctx, boolean simple) throws ObjectNotFoundException { 383 384 if (getContext4Tx(tx) != null) { 386 if (TraceEjb.isDebugIc()) { 387 TraceEjb.context.log(BasicLevel.DEBUG, ident + "context already mapped!"); 388 } 389 if (getContext4Tx(tx).isMarkedRemoved()) { 390 if (TraceEjb.isDebugIc()) { 391 TraceEjb.context.log(BasicLevel.DEBUG, ident + " currently being removed"); 392 } 393 if (simple) { 394 throw new ObjectNotFoundException ("Instance is currently being removed"); 395 } else { 396 return false; 398 } 399 } 400 return false; 402 } 403 404 try { 406 bctx.initEntityContext(this); 407 bctx.activate(true); 408 } catch (Exception e) { 409 TraceEjb.synchro.log(BasicLevel.WARN, ident + "Cannot bind Ctx: " + e); 410 return false; 411 } 412 setContext4Tx(tx, bctx); if (!lazyregister) { 414 if (tx == null) { 415 if (TraceEjb.isDebugSynchro()) { 416 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "IH find"); 417 } 418 } else { 419 if (TraceEjb.isDebugSynchro()) { 420 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "IT find"); 421 } 422 registerCtx(tx, bctx); 423 } 424 } 425 return true; 426 } 427 428 435 public JEntityContext getICtx(Transaction tx, JEntityContext newctx) { 436 return mapICtx(tx, newctx, false, false, false); 437 } 438 439 445 public JEntityContext getICtx(Transaction tx, boolean checkr) { 446 return mapICtx(tx, null, false, true, checkr); 447 } 448 449 455 public synchronized boolean terminate(Transaction tx) { 456 if (TraceEjb.isDebugSwapper()) { 457 TraceEjb.swapper.log(BasicLevel.DEBUG, ident); 458 } 459 waitmyturn(tx); 460 JEntityContext jec = getContext4Tx(tx); 461 if (jec != null) { 462 if (todiscard || jec.isMarkedRemoved()) { 463 discardContext(tx, true, true); 464 } else { 465 try { 466 jec.storeIfModified(); 467 } catch (Exception e) { 468 TraceEjb.logger.log(BasicLevel.ERROR, ident, "error while storing bean state:", e); 469 } 470 jec.passivate(); 471 discardContext(tx, false, true); 472 } 473 if (waiters > 0) { 474 if (TraceEjb.isDebugSynchro()) { 475 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " notify"); 476 } 477 notifyAll(); 478 } 479 } 480 return true; 481 } 482 483 abstract void waitmyturn(Transaction tx); 484 485 494 public synchronized JEntityContext mapICtx(Transaction tx, JEntityContext bctx, boolean forced, boolean holdit, boolean checkreentrance) { 495 496 try { 497 if (bf == null) { 499 TraceEjb.synchro.log(BasicLevel.ERROR, "JEntitySwitch not initialized!"); 500 throw new EJBException ("JEntitySwitch not initialized"); 501 } 502 if (TraceEjb.isDebugSynchro()) { 503 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " tx=" + tx); 504 } 505 506 if (!reentrant && checkreentrance) { 508 if (runningtx != null && countIT > 0 && tx != null && tx.equals(runningtx)) { 509 throw new EJBException ("non-reentrant bean accessed twice in same transaction"); 510 } 511 if (tx == null && countIH > 0) { 512 throw new EJBException ("non-reentrant bean accessed twice outside transaction"); 513 } 514 } 515 waitmyturn(tx); 517 518 if (inactivityTimeout > 0) { 520 timestamp = System.currentTimeMillis() + FEW_MINUTS; 521 if (TraceTimer.isDebug()) { 522 TraceTimer.logger.log(BasicLevel.DEBUG, ident + timestamp); 523 } 524 } 525 526 boolean newtrans = false; 528 JEntityContext jec = getContext4Tx(tx); 529 if (forced) { 530 if (jec != null) { 532 if (TraceEjb.isDebugContext()) { 533 TraceEjb.context.log(BasicLevel.DEBUG, ident + "new context is enforced!"); 534 } 535 discardContext(tx, false, true); 536 } 537 jec = bctx; 538 setContext4Tx(tx, jec); 539 jec.initEntityContext(this); 540 newtrans = true; 541 isremoved = false; } else { 543 if (isremoved) { 545 TraceEjb.logger.log(BasicLevel.WARN, ident + " has been removed."); 546 throw new NoSuchObjectLocalException ("Try to access a bean previously removed"); 547 } 548 if (jec != null) { 549 if (todiscard) { 550 TraceEjb.logger.log(BasicLevel.WARN, ident + " has been discarded."); 551 throw new NoSuchObjectLocalException ("Try to access a bean previously discarded"); 552 } 553 if (bctx != null) { 556 if (TraceEjb.isDebugContext()) { 557 TraceEjb.context.log(BasicLevel.DEBUG, ident + "a context was supplied!"); 558 } 559 bf.releaseJContext(bctx); 560 } 561 if (runningtx == null && lockpolicy != EntityDesc.LOCK_DATABASE) { 564 newtrans = true; 565 } 566 jec.reuseEntityContext(newtrans); 567 } else { 568 if (bctx != null) { 569 jec = bctx; 570 } else { 571 jec = bf.getJContext(this); 573 } 574 jec.initEntityContext(this); 575 jec.activate(true); 576 setContext4Tx(tx, jec); newtrans = true; 578 } 579 } 580 581 if (tx != null) { 582 if (newtrans && !lazyregister) { 584 try { 585 registerCtx(tx, jec); 586 if (TraceEjb.isDebugSynchro()) { 587 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IT: new tx, registerSynchronization"); 588 } 589 } catch (IllegalStateException e) { 590 if (TraceEjb.synchro.isLoggable(BasicLevel.WARN)) { 591 TraceEjb.synchro.log(BasicLevel.WARN, ident + "mapICtx IT: not registered!", e); 592 } 593 } 594 } 595 } else { 596 if (holdit) { 597 if (TraceEjb.isDebugSynchro()) { 598 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IH count=" + countIH); 599 } 600 if ((shared || mustReload) && countIH == 0) { 601 jec.activate(false); 604 mustReload = false; 605 } 606 } 607 if (!inDirtyList && !txUpdates) { 608 inDirtyList = true; 609 bf.registerEJB(this); 610 } 611 } 612 613 return jec; 614 } finally { 615 if (holdit) { 616 if (tx == null) { 617 countIH++; 618 } else { 619 countIT++; 620 } 621 } 622 } 623 } 624 625 public Transaction getBlockedTx() { 626 Transaction tx = blockedtx; 627 if (tx != null && TraceEjb.isDebugSynchro()) { 628 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "tx " + runningtx + " is blocking " + blockedtx); 629 } 630 return tx; 631 } 632 633 public Transaction getBlockingTx() { 634 Transaction tx = ( blockedtx != null ? runningtx : null); 635 if (tx != null && TraceEjb.isDebugSynchro()) { 636 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "tx " + runningtx + " is blocking " + blockedtx); 637 } 638 return tx; 639 } 640 641 645 public synchronized void releaseICtx(Transaction tx) { 646 647 if (tx == null) { 648 countIH--; 650 if (TraceEjb.isDebugSynchro()) { 651 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "releaseICtx IH count=" + countIH); 652 } 653 if (countIH == 0) { 654 JEntityContext jec = getContext4Tx(tx); 655 if (jec == null) { 656 TraceEjb.context.log(BasicLevel.ERROR, ident + " No context!"); 657 Thread.dumpStack(); 658 return; 659 } 660 if (todiscard || jec.isMarkedRemoved()) { 661 discardContext(tx, true, true); 663 } else { 664 if (mustStore) { 665 try { 666 jec.storeIfModified(); 667 } catch (EJBException e) { 668 if (TraceEjb.isVerbose()) { 669 TraceEjb.logger.log(BasicLevel.WARN, ident + " ejbexception", e); 670 } 671 } 672 mustStore = false; 673 } 674 } 675 if (waiters > 0) { 676 if (TraceEjb.isDebugSynchro()) { 677 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " notify"); 678 } 679 notifyAll(); 680 } 681 } 682 } else { 683 if (TraceEjb.isDebugSynchro()) { 686 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "releaseICtx IT"); 687 } 688 countIT--; 689 } 690 } 691 692 697 public synchronized void discardICtx(Transaction tx) { 698 if (tx == null) { 699 countIH--; 700 if (countIH == 0) { 701 discardContext(tx, false, false); 702 return; 703 } 704 } else { 705 countIT--; 706 if (runningtx == null) { 707 return; 709 } 710 } 711 todiscard = true; 713 } 714 715 721 public synchronized void txCompleted(Transaction tx, boolean committed) { 722 JEntityContext jec = getContext4Tx(tx); 723 if (jec == null) { 724 TraceEjb.context.log(BasicLevel.ERROR, ident + " No context for this tx"); 725 return; 726 } 727 runningtx = null; 728 if (writingtx != null && tx.equals(writingtx)) { 729 writingtx = null; 730 } 731 732 if (TraceEjb.isDebugSynchro()) { 733 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " txCompleted " + committed); 734 } 735 736 if (todiscard || (jec.isNewInstance() && !committed)) { 739 discardContext(tx, !todiscard, false); 740 return; 741 } 742 743 if (jec.isMarkedRemoved()) { 744 if (TraceEjb.isDebugContext()) { 745 TraceEjb.context.log(BasicLevel.DEBUG, ident + "remove!"); 746 } 747 discardContext(tx, committed, true); 748 } else { 749 if (shared || !committed) { 750 if (TraceEjb.isDebugContext()) { 753 TraceEjb.context.log(BasicLevel.DEBUG, jec + " passivated!"); 754 } 755 jec.passivate(); 756 if (committed) { 757 bf.releaseJContext(jec); 759 } 760 removeContext4Tx(tx); 761 } else { 762 jec.detachTx(); 765 } 766 if (lockpolicy == EntityDesc.LOCK_CONTAINER_READ_COMMITTED || lockpolicy == EntityDesc.LOCK_DATABASE) { 769 mustReload = true; 770 } 771 } 772 if (waiters > 0) { 773 if (TraceEjb.isDebugSynchro()) { 774 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " notify"); 775 } 776 notifyAll(); 777 } 778 } 779 780 787 protected void registerCtx(Transaction tx, JEntityContext bctx) { 788 if (bf == null) { 790 TraceEjb.synchro.log(BasicLevel.ERROR, "JEntitySwitch not initialized!"); 791 throw new EJBException ("JEntitySwitch not initialized"); 792 } 793 try { 795 if (bf.registerContext(tx, bctx)) { 796 if (TraceEjb.isDebugContext()) { 797 TraceEjb.context.log(BasicLevel.DEBUG, bctx + "registered!"); 798 } 799 bctx.setRunningTx(tx); 800 runningtx = tx; 801 } else { 802 TraceEjb.context.log(BasicLevel.WARN, bctx + "could not be registered!"); 803 } 804 } catch (IllegalStateException e) { 805 TraceEjb.logger.log(BasicLevel.ERROR, ident + "Transaction is in an illegal state"); 806 throw e; 807 } 808 } 809 810 816 protected void discardContext(Transaction tx, boolean forgetpk, boolean pool) { 817 if (TraceEjb.isDebugContext()) { 818 TraceEjb.context.log(BasicLevel.DEBUG, ""); 819 } 820 JEntityContext jec = getContext4Tx(tx); 821 if (jec != null) { 822 if (pool) { 823 bf.releaseJContext(jec); 824 } 825 removeContext4Tx(tx); 826 } 827 if (forgetpk) { 828 if (remote != null) { 829 try { 830 remote.unexportObject(); 831 } catch (NoSuchObjectException e) { 832 TraceEjb.logger.log(BasicLevel.ERROR, ident + " unexport entity failed: ", e); 833 } 834 } 835 bf.removeEJB(getPrimaryKey()); 836 837 if (myTimerService != null) { 839 ((JTimerService) myTimerService).cancelAllTimers(); 840 myTimerService = null; 841 } 842 isremoved = true; 844 } 845 todiscard = false; } 847 848 851 public int getPolicy() { 852 return lockpolicy; 853 } 854 855 860 abstract public int getState(); 861 864 public JFactory getBeanFactory() { 865 return bf; 866 } 867 868 } 869 | Popular Tags |