1 25 26 package org.objectweb.jonas_ejb.container; 27 28 import java.io.Serializable ; 29 import java.util.ArrayList ; 30 import java.util.Collection ; 31 import java.util.Collections ; 32 import java.util.Date ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.LinkedList ; 36 import java.util.List ; 37 import java.util.ListIterator ; 38 39 import javax.ejb.EJBException ; 40 import javax.ejb.EntityBean ; 41 import javax.ejb.FinderException ; 42 import javax.ejb.Timer ; 43 import javax.ejb.TimerService ; 44 import javax.naming.Context ; 45 import javax.naming.NamingException ; 46 import javax.transaction.RollbackException ; 47 import javax.transaction.SystemException ; 48 import javax.transaction.Transaction ; 49 50 import org.objectweb.jonas_ejb.deployment.api.EntityDesc; 51 import org.objectweb.jonas_ejb.deployment.api.EntityJdbcCmp1Desc; 52 import org.objectweb.jonas_ejb.deployment.api.EntityJdbcCmp2Desc; 53 import org.objectweb.jorm.naming.api.PExceptionNaming; 54 import org.objectweb.jorm.naming.api.PName; 55 56 import org.objectweb.util.monolog.api.BasicLevel; 57 58 66 public class JEntityFactory extends JFactory implements TimerService { 67 68 71 protected JEntityHome home = null; 72 73 76 protected JEntityLocalHome localhome = null; 77 78 81 protected boolean reentrant; 82 83 88 protected boolean shared = false; 89 90 93 protected int lockPolicy; 94 95 98 protected boolean prefetch = false; 99 100 103 protected List bctxlist = new ArrayList (); 104 105 protected int instanceCount = 0; 106 107 108 protected int inactivityTimeout; 110 114 protected HashMap pklist = new HashMap (); 115 116 120 protected HashMap txlist = new HashMap (); 121 122 125 private LinkedList dirtyList = new LinkedList (); 126 127 private boolean mustSyncDirtyEntities = false; 128 129 protected Object datasource = null; 131 132 135 private static int ucount = 1; 136 137 140 String dsname = null; 141 142 145 public JEntityFactory() { 146 if (TraceEjb.isDebugIc()) { 147 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 148 } 149 } 150 151 156 public void init(EntityDesc dd, JContainer cont) { 157 super.init(dd, cont); 158 reentrant = dd.isReentrant(); 159 shared = dd.isShared(); 160 lockPolicy = dd.getLockPolicy(); 161 prefetch = dd.isPrefetch(); 162 if (lockPolicy == EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED && prefetch) { 163 throw new EJBException ("Cannot set READ_UNCOMMITTED and prefetch for a bean"); 164 } 165 inactivityTimeout = dd.getInactivityTimeout(); 166 167 if (dd instanceof EntityJdbcCmp1Desc) { 170 dsname = ((EntityJdbcCmp1Desc) dd).getDatasourceJndiName(); 171 if (dsname != null) { 172 try { 173 datasource = getInitialContext().lookup(dsname); 174 } catch (NamingException e) { 175 String err = dsname + " is not known by the EJB server."; 176 TraceEjb.logger.log(BasicLevel.ERROR, err, e); 177 throw new EJBException (err, e); 178 } 179 } 180 } 181 182 if (dd instanceof EntityJdbcCmp2Desc) { 183 dsname = ((EntityJdbcCmp2Desc) dd).getDatasourceJndiName(); 184 if (dsname != null) { 185 try { 186 datasource = getInitialContext().lookup(dsname); 187 } catch (NamingException e) { 188 String err = dsname + " is not known by the EJB server."; 189 TraceEjb.logger.log(BasicLevel.ERROR, err); 190 throw new EJBException (err, e); 191 } 192 } 193 } 194 195 Class homeclass = null; 197 String clname = dd.getFullWrpHomeName(); 198 if (clname != null) { 199 try { 200 homeclass = cont.getClassLoader().loadClass(clname); 201 } catch (ClassNotFoundException e) { 202 throw new EJBException (ejbname + "Cannot load " + clname, e); 203 } 204 if (TraceEjb.isDebugIc()) { 205 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": " + clname + " loaded"); 206 } 207 try { 208 int nbp = 2; 210 Class [] ptype = new Class [nbp]; 211 Object [] pobj = new Object [nbp]; 212 ptype[0] = org.objectweb.jonas_ejb.deployment.api.EntityDesc.class; 213 pobj[0] = (Object ) dd; 214 ptype[1] = org.objectweb.jonas_ejb.container.JEntityFactory.class; 215 pobj[1] = (Object ) this; 216 home = (JEntityHome) homeclass.getConstructor(ptype).newInstance(pobj); 217 } catch (Exception e) { 218 throw new EJBException (ejbname + " Cannot create home ", e); 219 } 220 221 try { 223 home.register(); 224 } catch (Exception e) { 225 throw new EJBException (ejbname + " Cannot register home ", e); 226 } 227 } 228 229 clname = dd.getFullWrpLocalHomeName(); 231 if (clname != null) { 232 try { 233 homeclass = cont.getClassLoader().loadClass(clname); 234 } catch (ClassNotFoundException e) { 235 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot load " + clname); 236 throw new EJBException ("Cannot load " + clname, e); 237 } 238 if (TraceEjb.isDebugIc()) { 239 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": " + clname + " loaded"); 240 } 241 try { 242 int nbp = 2; 244 Class [] ptype = new Class [nbp]; 245 Object [] pobj = new Object [nbp]; 246 ptype[0] = org.objectweb.jonas_ejb.deployment.api.EntityDesc.class; 247 pobj[0] = (Object ) dd; 248 ptype[1] = org.objectweb.jonas_ejb.container.JEntityFactory.class; 249 pobj[1] = (Object ) this; 250 localhome = (JEntityLocalHome) homeclass.getConstructor(ptype).newInstance(pobj); 251 } catch (Exception e) { 252 throw new EJBException (ejbname + " Cannot create localhome ", e); 253 } 254 try { 256 localhome.register(); 257 } catch (Exception e) { 258 throw new EJBException (ejbname + " Cannot register localhome ", e); 259 } 260 } 261 } 262 263 266 public void initInstancePool() { 267 Context bnctx = setComponentContext(); for (int i = 0; i < minPoolSize; i++) { 270 JEntityContext ctx = null; 271 try { 272 ctx = createNewInstance(null); 273 synchronized(bctxlist) { 274 bctxlist.add(ctx); 275 } 276 } catch (Exception e) { 277 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot create new instance", e); 278 throw new EJBException (ejbname + " Cannot init pool of instances ", e); 279 } 280 } 281 resetComponentContext(bnctx); 282 } 283 284 290 public synchronized JEntitySwitch getEJB(Object pk) { 291 292 if (TraceEjb.isDebugIc()) { 293 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 294 } 295 296 if (pk == null) { 297 TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???"); 298 return null; 299 } 300 JEntitySwitch bs = (JEntitySwitch) pklist.get(pk); 301 if (bs == null) { 302 bs = getJEntitySwitch(); 303 bs.init(this, pk); 304 if (TraceEjb.isDebugIc()) { 305 TraceEjb.interp.log(BasicLevel.DEBUG, "Adding PK to pklist:" + pk); 306 } 307 pklist.put(pk, bs); 308 } 309 return bs; 310 } 311 312 318 public synchronized JEntitySwitch existEJB(Object pk, JEntitySwitch bs) { 319 if (pk == null) { 320 TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???"); 321 return null; 322 } 323 JEntitySwitch ret = (JEntitySwitch) pklist.get(pk); 324 if (TraceEjb.isDebugIc()) { 325 TraceEjb.interp.log(BasicLevel.DEBUG, "Looking for PK in pklist:" + pk); 326 TraceEjb.interp.log(BasicLevel.DEBUG, ret == null ? "no" : "yes"); 327 } 328 if (ret == null && bs != null) { 329 bs.init(this, pk); 331 pklist.put(pk, bs); 332 } 333 return ret; 334 } 335 336 343 public boolean rebindEJB(Transaction tx, JEntityContext bctx, Object pk) { 344 if (TraceEjb.isDebugIc()) { 345 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 346 } 347 348 if (pk == null) { 349 TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???"); 350 return false; 351 } 352 JEntitySwitch bs = bctx.getEntitySwitch(); 353 JEntitySwitch old = null; 354 synchronized (this) { 355 old = (JEntitySwitch) pklist.get(pk); 356 } 357 boolean ret = true; 358 if (old != null) { 359 364 ret = old.terminate(tx); 367 } 368 synchronized (this) { 369 bs.init(this, pk); 370 if (TraceEjb.isDebugIc()) { 371 TraceEjb.interp.log(BasicLevel.DEBUG, "Adding PK to pklist:" + pk); 372 } 373 pklist.put(pk, bs); 374 } 375 return ret; 376 } 377 378 383 public synchronized void bindEJB(Object pk, JEntitySwitch bs) { 384 if (TraceEjb.isDebugIc()) { 385 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 386 } 387 if (pk == null) { 388 TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???"); 389 return; 390 } 391 bs.init(this, pk); 392 pklist.put(pk, bs); 393 } 394 395 401 public JEntitySwitch getJEntitySwitch() { 402 switch (lockPolicy) { 403 case EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED: 404 return new JEntitySwitchCRU(); 405 case EntityDesc.LOCK_CONTAINER_READ_COMMITTED: 406 return new JEntitySwitchCRC(); 407 case EntityDesc.LOCK_DATABASE: 408 return new JEntitySwitchDB(); 409 case EntityDesc.LOCK_READ_ONLY: 410 return new JEntitySwitchRO(); 411 default: 412 return new JEntitySwitchCS(); 413 } 414 } 415 416 420 public synchronized void removeEJB(Object pk) { 421 if (TraceEjb.isDebugIc()) { 422 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 423 } 424 if (pk == null) { 425 TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???"); 426 return; 427 } 428 pklist.remove(pk); 429 } 430 431 436 public synchronized void registerEJB(JEntitySwitch ejb) { 437 if (TraceEjb.isDebugSwapper()) { 438 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname); 439 } 440 if (dirtyList.contains(ejb)) { 441 TraceEjb.swapper.log(BasicLevel.ERROR, ejbname + " Elt already in the dirty list"); 442 return; 443 } 444 dirtyList.addLast(ejb); 445 mustSyncDirtyEntities = true; 446 } 447 448 451 public void synchronizeEntities() { 452 if (TraceEjb.isDebugSwapper()) { 453 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname); 454 } 455 cont.registerBFS(this); 456 } 457 458 461 public boolean dirtyInstances() { 462 return mustSyncDirtyEntities; 463 } 464 465 468 public int getInactivityTimeout() { 469 return inactivityTimeout; 470 } 471 472 476 479 public int getPoolSize() { 480 return bctxlist.size(); 481 } 482 483 487 public void stop() { 488 if (TraceEjb.isDebugIc()) { 489 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 490 } 491 try { 492 if (home != null) { 493 home.unregister(); 494 } 495 if (localhome != null) { 496 localhome.unregister(); 497 } 498 } catch (NamingException e) { 499 } 500 } 501 502 505 public void sync() { 506 507 if (!mustSyncDirtyEntities) { 508 if (TraceEjb.isDebugSwapper()) { 509 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " cacheSize = " + getCacheSize()); 510 } 511 return; 513 } 514 515 if (TraceEjb.isDebugSwapper()) { 516 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " dirtyList size = " + dirtyList.size()); 517 } 518 519 Context bnctx = setComponentContext(); 521 522 LinkedList wsdone = new LinkedList (); 524 synchronized (this) { 525 for (ListIterator i = dirtyList.listIterator(0); i.hasNext();) { 526 JEntitySwitch es = (JEntitySwitch) i.next(); 527 if (es.passivateIH(false)) { 528 i.remove(); 530 wsdone.addLast(es); 531 } else { 532 if (TraceEjb.isDebugSwapper()) { 533 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " swapper could not passivate an instance"); 534 } 535 } 536 } 537 } 538 539 mustSyncDirtyEntities = false; for (ListIterator i = wsdone.listIterator(0); i.hasNext();) { 543 JEntitySwitch es = (JEntitySwitch) i.next(); 544 es.endIH(); 545 } 546 547 resetComponentContext(bnctx); 549 } 550 551 554 public void reduceCache() { 555 if (TraceEjb.isDebugSwapper()) { 556 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + pklist.size()); 557 } 558 560 int count = 0; 564 565 ClassLoader old = Thread.currentThread().getContextClassLoader(); 567 Thread.currentThread().setContextClassLoader(myClassLoader()); 568 569 Context bnctx = setComponentContext(); 571 572 Collection coll = null; 573 HashMap clone = null; 574 synchronized (this) { 575 clone = (HashMap ) pklist.clone(); 576 } 577 JEntitySwitch bs = null; 578 for (Iterator i = clone.values().iterator(); i.hasNext();) { 579 bs = (JEntitySwitch) i.next(); 580 if (!bs.passivateIH(true)) { 581 count++; 582 } 583 } 584 resetComponentContext(bnctx); 586 Thread.currentThread().setContextClassLoader(old); 587 588 int poolsz = minPoolSize - count; 591 if (poolsz < 0) { 592 poolsz = 0; 593 } 594 595 synchronized (bctxlist) { 597 if (TraceEjb.isDebugSwapper()) { 598 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + ": try to reduce " + bctxlist.size() + " to " + poolsz); 599 } 600 while (bctxlist.size() > poolsz) { 601 ListIterator i = bctxlist.listIterator(); 602 if (i.hasNext()) { 603 i.next(); 604 i.remove(); 605 instanceCount--; 606 } 607 } 608 } 609 if (TraceEjb.isDebugSwapper()) { 610 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " cacheSize= " + getCacheSize()); 611 } 612 printMemoryUsage(); 613 } 614 615 618 public JHome getHome() { 619 return home; 620 } 621 622 625 public JLocalHome getLocalHome() { 626 return localhome; 627 } 628 629 633 639 public JEntityContext getJContext(JEntitySwitch es) { 640 if (TraceEjb.isDebugIc()) { 641 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 642 } 643 JEntityContext bctx = null; 644 645 synchronized (bctxlist) { 647 try { 648 bctx = (JEntityContext) bctxlist.remove(0); 649 } catch (IndexOutOfBoundsException ex) { 651 } 653 } 654 655 if (bctx == null) { 656 try { 658 bctx = createNewInstance(es); 659 } catch (Exception e) { 660 throw new EJBException ("Cannot create a new instance ", e); 661 } 662 } 663 664 if (bctx.getEntitySwitch() != null) { 666 TraceEjb.context.log(BasicLevel.ERROR, ejbname + "Context already initialized!"); 667 } 668 669 return bctx; 670 } 671 672 676 public void releaseJContext(JContext ctx) { 677 JEntityContext bctx = (JEntityContext) ctx; 678 if (TraceEjb.isDebugContext()) { 679 TraceEjb.context.log(BasicLevel.DEBUG, ejbname); 680 } 681 bctx.razEntityContext(); 682 synchronized(bctxlist) { 683 690 bctxlist.add(bctx); 691 } 692 } 693 694 698 702 public TimerService getTimerService() { 703 return this; 704 } 705 706 709 public int getCacheSize() { 710 return instanceCount; 711 } 712 713 716 public boolean isReentrant() { 717 return reentrant; 718 } 719 720 723 public boolean isShared() { 724 return shared; 725 } 726 727 730 public int lockPolicy() { 731 return lockPolicy; 732 } 733 734 737 public boolean isPrefetch() { 738 return prefetch; 739 } 740 741 744 public Object getDataSource() { 745 if (datasource == null) { 746 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + ": datasource not defined in JEntityFactory"); 747 } 748 return datasource; 749 } 750 751 756 public void checkTransaction(RequestCtx rctx) { 757 checkTransactionContainer(rctx); 758 } 759 760 766 public void syncForFind(Transaction tx) { 767 if (TraceEjb.isDebugIc()) { 768 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 769 } 770 if (tx == null) { 771 if (lockPolicy == EntityDesc.LOCK_CONTAINER_SERIALIZED) { 772 sync(); 773 } 774 } else { 775 TxListener txl = (TxListener) txlist.get(tx); 776 if (txl != null) { 777 txl.storeInstances(); 778 } 779 } 780 } 781 782 785 public boolean isBlocking(Transaction tx) { 786 HashMap clone = null; 787 synchronized (this) { 788 clone = (HashMap ) pklist.clone(); 789 } 790 JEntitySwitch bs = null; 791 for (Iterator i = clone.values().iterator(); i.hasNext();) { 792 bs = (JEntitySwitch) i.next(); 793 Transaction tb = bs.getBlockingTx(); 794 if (tb != null && tb.equals(tx)) { 795 return true; 796 } 797 } 798 return false; 799 } 800 801 804 public boolean isBlocked(Transaction tx) { 805 HashMap clone = null; 806 synchronized (this) { 807 clone = (HashMap ) pklist.clone(); 808 } 809 JEntitySwitch bs = null; 810 for (Iterator i = clone.values().iterator(); i.hasNext();) { 811 bs = (JEntitySwitch) i.next(); 812 Transaction tb = bs.getBlockedTx(); 813 if (tb != null && tb.equals(tx)) { 814 return true; 815 } 816 } 817 return false; 818 } 819 820 824 public void removeTxListener(Transaction tx) { 825 if (TraceEjb.isDebugIc()) { 826 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 827 } 828 txlist.remove(tx); 829 } 830 831 837 public boolean registerContext(Transaction tx, JEntityContext ec) throws IllegalStateException { 838 if (TraceEjb.isDebugIc()) { 839 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 840 } 841 842 TxListener txl = (TxListener) txlist.get(tx); 844 if (txl == null) { 845 txl = new TxListener(this, tx); 846 try { 848 tx.registerSynchronization(txl); 849 } catch (RollbackException e) { 850 if (TraceEjb. isVerbose()) { 851 TraceEjb.logger.log(BasicLevel.WARN, ejbname + " transaction has been marked rollbackOnly", e); 852 } 853 } catch (SystemException e) { 854 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot register synchro ", e); 855 throw new IllegalStateException ("cannot register synchro"); 857 } 858 txlist.put(tx, txl); 859 } 860 861 txl.addInstance(ec); 863 return true; 864 } 865 866 870 public synchronized EntityCounters getEntityCounters() { 871 EntityCounters ec = new EntityCounters(); 872 Collection coll = pklist.values(); 873 for (Iterator i = coll.iterator(); i.hasNext();) { 874 JEntitySwitch es = (JEntitySwitch) i.next(); 875 switch (es.getState()) { 876 case 0: 877 ec.inTx++; 878 break; 879 case 1: 880 ec.outTx++; 881 break; 882 case 2: 883 ec.idle++; 884 break; 885 case 3: 886 ec.passive++; 887 break; 888 case 4: 889 ec.removed++; 890 break; 891 } 892 } 893 return ec; 894 } 895 896 900 public int calculateAutomaticPk() { 901 if (TraceEjb.isDebugIc()) { 902 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 903 } 904 int uid; 905 synchronized (getClass()) { 906 uid = (int) (System.currentTimeMillis() % (java.lang.Integer.MAX_VALUE / 10)); 907 uid = uid * 10 + ucount++; 908 } 909 return uid; 910 } 911 912 918 public void dummyFinderException(boolean dummy) throws FinderException { 919 if (!dummy) { 920 throw new FinderException ("dummy exception !!!"); 921 } 922 } 923 924 928 public void printAllPks() { 929 if (TraceEjb.isDebugSwapper()) { 930 HashMap clone = null; 931 synchronized (this) { 932 clone = (HashMap ) pklist.clone(); 933 } 934 JEntitySwitch bs = null; 935 for (Iterator i = clone.values().iterator(); i.hasNext();) { 936 bs = (JEntitySwitch) i.next(); 937 TraceEjb.swapper.log(BasicLevel.DEBUG, "PK=" + bs.getPrimaryKey()); 938 } 939 } 940 } 941 942 946 private void printMemoryUsage() { 947 if (TraceEjb.isDebugSwapper()) { 948 System.gc(); 949 TraceEjb.swapper.log(BasicLevel.DEBUG, 950 " total = " + Runtime.getRuntime().totalMemory() / 1024 + 951 " free = " + Runtime.getRuntime().freeMemory() / 1024); 952 } 953 } 954 955 959 965 protected JEntityContext createNewInstance(JEntitySwitch es) throws Exception { 966 if (TraceEjb.isDebugIc()) { 967 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 968 } 969 970 EntityBean bean = null; 972 try { 973 bean = (EntityBean ) beanclass.newInstance(); 974 } catch (InstantiationException e) { 975 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot instantiate bean"); 976 throw e; 977 } catch (IllegalAccessException e) { 978 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot instantiate bean"); 979 throw e; 980 } 981 982 JEntityContext ec = createNewContext(bean); 984 bean.setEntityContext(ec); 985 ec.setState(1); 986 987 synchronized (this) { 989 instanceCount++; 990 } 991 if (maxCacheSize != 0 && instanceCount > maxCacheSize) { 992 if (TraceEjb.isDebugSwapper()) { 994 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + ": Too many instances :" + instanceCount + ", max=" 995 + maxCacheSize); 996 } 997 cont.registerBF(this); 998 } 999 1000 return ec; 1001 } 1002 1003 protected JEntityContext createNewContext(EntityBean bean) { 1004 return new JEntityContext(this, bean); 1005 } 1006 1007 1011 public Serializable encodePK(Serializable pk) { 1012 return pk; 1013 } 1014 1015 1019 public Serializable decodePK(Serializable strpk) { 1020 return strpk; 1021 } 1022 1023 1027 public Timer createTimer(long arg0, Serializable arg1) throws IllegalArgumentException , IllegalStateException , EJBException { 1028 throw new IllegalStateException ("timer are associated with a PK"); 1029 } 1030 1031 1034 public Timer createTimer(long arg0, long arg1, Serializable arg2) throws IllegalArgumentException , IllegalStateException , EJBException { 1035 throw new IllegalStateException ("timer are associated with a PK"); 1036 } 1037 1038 1041 public Timer createTimer(Date arg0, Serializable arg1) throws IllegalArgumentException , IllegalStateException , EJBException { 1042 throw new IllegalStateException ("timer are associated with a PK"); 1043 } 1044 1045 1048 public Timer createTimer(Date arg0, long arg1, Serializable arg2) throws IllegalArgumentException , IllegalStateException , EJBException { 1049 throw new IllegalStateException ("timer are associated with a PK"); 1050 } 1051 1052 1055 public Collection getTimers() throws IllegalStateException , EJBException { 1056 throw new IllegalStateException ("timer are associated with a PK"); 1057 } 1058 1059} 1060 | Popular Tags |