1 25 26 package org.objectweb.jonas_ejb.container; 27 28 import java.io.File ; 29 import java.io.IOException ; 30 import java.lang.reflect.Field ; 31 import java.net.URLClassLoader ; 32 import java.rmi.RemoteException ; 33 import java.util.Enumeration ; 34 import java.util.Hashtable ; 35 import java.util.Properties ; 36 37 import javax.ejb.EJBException ; 38 import javax.ejb.TimerService ; 39 import javax.ejb.TransactionRequiredLocalException ; 40 import javax.ejb.TransactionRolledbackLocalException ; 41 import javax.naming.Context ; 42 import javax.naming.InitialContext ; 43 import javax.naming.NamingException ; 44 import javax.resource.spi.work.WorkManager ; 45 import javax.transaction.NotSupportedException ; 46 import javax.transaction.RollbackException ; 47 import javax.transaction.Status ; 48 import javax.transaction.SystemException ; 49 import javax.transaction.Transaction ; 50 import javax.transaction.TransactionRequiredException ; 51 import javax.transaction.TransactionRolledbackException ; 52 53 import org.objectweb.jotm.TransactionContext; 54 import org.objectweb.transaction.jta.TransactionManager; 55 56 import org.objectweb.carol.rmi.exception.NoSuchObjectExceptionHelper; 57 import org.objectweb.carol.util.configuration.ConfigurationRepository; 58 59 import org.objectweb.jonas_ejb.deployment.api.BeanDesc; 60 import org.objectweb.jonas_ejb.deployment.api.MethodDesc; 61 import org.objectweb.jonas_ejb.lib.EJBInvocation; 62 63 import org.objectweb.jonas_lib.naming.ContainerNaming; 64 import org.objectweb.jonas_lib.version.Version; 65 66 import org.objectweb.security.context.SecurityContext; 67 import org.objectweb.security.context.SecurityCurrent; 68 69 import org.objectweb.util.monolog.api.BasicLevel; 70 71 76 public abstract class JFactory implements BeanFactory { 77 78 protected JContainer cont; 79 80 protected ContainerNaming naming = null; 81 82 protected TransactionManager tm = null; 83 84 protected WorkManager wm = null; 85 86 protected Context JNDICtx = null; 88 protected String ejbname = null; 89 90 protected BeanDesc dd; 91 92 protected Properties ejb10Env = null; 93 94 protected TimerService myTimerService = null; 95 96 protected boolean txbeanmanaged = false; 98 protected Class beanclass = null; 100 protected File passivationDir; 101 102 105 protected int minPoolSize; 106 107 protected int maxCacheSize; 108 109 113 private boolean iiopProtocolAvailable = false; 114 115 119 protected int timerTxAttr; 120 121 124 protected String ejbTimeoutSignature; 125 126 129 public JFactory() { 130 if (TraceEjb.isDebugIc()) { 131 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname); 132 } 133 } 134 135 140 public JFactory(BeanDesc dd, JContainer cont) { 141 if (TraceEjb.isDebugIc()) { 142 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 143 } 144 init(dd, cont); 145 } 146 147 152 public void init(BeanDesc dd, JContainer cont) { 153 this.cont = cont; 154 this.dd = dd; 155 naming = cont.getContainerNaming(); 156 tm = cont.getTransactionManager(); 157 wm = cont.getWorkManager(); 158 ejbname = dd.getEjbName(); 159 ejb10Env = dd.getEjb10Environment(); 160 maxCacheSize = dd.getCacheMax(); 161 minPoolSize = dd.getPoolMin(); 162 163 String cln = dd.getFullWrpHomeName() != null ? dd.getFullWrpHomeName() : dd.getFullWrpLocalHomeName(); 166 if (cln != null) { 167 checkJonasVersion(cln); 168 } 169 170 try { 172 JNDICtx = naming.createEnvironmentContext(ejbname); 173 cont.setBeanEnvironment(JNDICtx, dd); 174 } catch (NamingException e) { 175 TraceEjb.logger.log(BasicLevel.ERROR, "cannot build naming for this component", e); 176 throw new EJBException ("Cannot build naming for this component", e); 177 } 178 179 String cn = null; 181 try { 182 cn = dd.getFullDerivedBeanName(); 183 beanclass = cont.getClassLoader().loadClass(cn); 184 194 } catch (ClassNotFoundException e) { 195 TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + cn + e); 196 throw new EJBException ("Container failed to find class " + cn, e); 197 } 198 199 timerTxAttr = dd.getTimerTxAttribute(); 200 ejbTimeoutSignature = dd.getEjbTimeoutSignature(); 201 202 String protocol = ConfigurationRepository.getCurrentConfiguration().getProtocol().getName(); 204 if (protocol.equals("iiop")) { 205 iiopProtocolAvailable = true; 206 } 207 208 String pds = cont.getTmpDirName() + File.separator + dd.getIdentifier(); 210 passivationDir = new File (pds); 211 passivationDir.mkdir(); 212 if (TraceEjb.isDebugFactory()) { 213 TraceEjb.factory.log(BasicLevel.DEBUG, pds); 214 } 215 } 216 217 220 public WorkManager getWorkManager() { 221 return wm; 222 } 223 224 227 public abstract void initInstancePool(); 228 229 236 protected boolean isClassAvailable(String className, boolean unique) { 237 className = className.replace('.', '/') + ".class"; 238 Enumeration e = null; 239 try { 240 e = ((URLClassLoader ) cont.getClassLoader()).findResources(className); 241 } catch (IOException e1) { 242 return false; 243 } 244 if (e.hasMoreElements()) { 245 e.nextElement(); 246 return unique ? !e.hasMoreElements() : true; 247 } else { 248 return false; 249 } 250 } 251 252 256 259 public String getEJBName() { 260 return ejbname; 261 } 262 263 266 public abstract int getPoolSize(); 267 268 272 public BeanDesc getDeploymentDescriptor() { 273 return dd; 274 } 275 276 279 public TransactionManager getTransactionManager() { 280 return tm; 281 } 282 283 286 public JContainer getContainer() { 287 return cont; 288 } 289 290 293 public Hashtable getEnv() { 294 return naming.getEnv(); 295 } 296 297 300 public InitialContext getInitialContext() { 301 return naming.getInitialContext(); 302 } 303 304 308 312 public abstract TimerService getTimerService(); 313 314 317 public Properties getEjb10Environment() { 318 return ejb10Env; 319 } 320 321 325 public boolean isTxBeanManaged() { 326 return txbeanmanaged; 327 } 328 329 333 public Context setComponentContext() { 334 Context oldctx = naming.setComponentContext(JNDICtx); 335 if (TraceEjb.isDebugLoaderLog() && oldctx == null) { 336 TraceEjb.loaderlog.log(BasicLevel.DEBUG, "previous ctx was null"); 337 } 338 return oldctx; 339 } 340 341 345 public void resetComponentContext(Context oldctx) { 346 if (TraceEjb.isDebugLoaderLog() && oldctx == null) { 347 TraceEjb.loaderlog.log(BasicLevel.DEBUG, "to null"); 348 } 349 naming.resetComponentContext(oldctx); 350 } 351 352 355 public int getTimerTxAttribute() { 356 return timerTxAttr; 357 } 358 359 362 public String getEjbTimeoutSignature() { 363 return ejbTimeoutSignature; 364 } 365 366 369 public int getMinPoolSize() { 370 return minPoolSize; 371 } 372 373 376 public int getMaxCacheSize() { 377 return maxCacheSize; 378 } 379 380 385 public void checkSecurity(EJBInvocation ejbInv) { 386 387 String runAsRoleDD = null; 388 389 try { 390 if (ejbInv != null && ejbInv.methodPermissionSignature != null) { 392 if (ejbInv.methodPermissionSignature.length() != 0) { 403 cont.checkSecurity(ejbname, ejbInv, (dd.getRunAsRole() != null)); 404 } 405 } 406 407 runAsRoleDD = dd.getRunAsRole(); 408 if (runAsRoleDD != null) { 411 SecurityCurrent current = SecurityCurrent.getCurrent(); 412 if (current != null) { 413 SecurityContext sctx = current.getSecurityContext(); 414 if (sctx == null) { 415 if (TraceEjb.isDebugSecurity()) { 416 TraceEjb.security.log(BasicLevel.DEBUG, "runas : Security context is null, create a new one" 417 + " in ejb " + ejbname); 418 } 419 sctx = new SecurityContext(); 420 current.setSecurityContext(sctx); 421 } 422 String principalName = dd.getRunAsPrincipalName(); 423 String [] runAsRoles = dd.getDeploymentDesc().getRolesForRunAsPrincipal(principalName); 424 if (runAsRoles == null) { 425 runAsRoles = new String [] {runAsRoleDD}; 426 } 427 if (TraceEjb.isDebugSecurity()) { 428 TraceEjb.security.log(BasicLevel.DEBUG, "runAs roles are "); 429 for (int r = 0; r < runAsRoles.length; r++) { 430 TraceEjb.security.log(BasicLevel.DEBUG, "Role[" + r + "] = " + runAsRoles[r]); 431 } 432 TraceEjb.security.log(BasicLevel.DEBUG, "RunAs principal name = " + principalName); 433 } 434 sctx.pushRunAsPrincipal(principalName, runAsRoles); 435 sctx.pushRunAsRole(runAsRoleDD); 436 } else { 437 TraceEjb.security.log(BasicLevel.ERROR, "Can't push runas role as security current is null" 438 + " in ejb " + ejbname); 439 } 440 } 441 } catch (RuntimeException re) { 442 if (runAsRoleDD != null) { 444 SecurityCurrent current = SecurityCurrent.getCurrent(); 445 if (current != null) { 446 SecurityContext sctx = current.getSecurityContext(); 447 if (sctx == null) { 448 if (TraceEjb.isDebugSecurity()) { 449 TraceEjb.security.log(BasicLevel.DEBUG, "runas : Security context is null " + " in ejb " 450 + ejbname); 451 } 452 } else { 453 sctx.popRunAs(); 454 } 455 } else { 456 if (TraceEjb.isDebugSecurity()) { 457 TraceEjb.security.log(BasicLevel.DEBUG, "Can't pop runas role as security current is null" 458 + " in ejb " + ejbname); 459 } 460 } 461 } 462 if (TraceEjb.isDebugSecurity()) { 463 TraceEjb.logger.log(BasicLevel.DEBUG, "Security Runtime Exception", re); 464 } 465 throw re; 466 } 467 468 469 } 470 471 477 public RequestCtx preInvoke(int txa) { 478 479 if (TraceEjb.isDebugIc()) { 480 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 481 } 482 RequestCtx rctx = null; 483 484 485 try { 486 rctx = new RequestCtx(txa); 489 490 rctx.cloader = Thread.currentThread().getContextClassLoader(); 493 Thread.currentThread().setContextClassLoader(myClassLoader()); 494 495 rctx.jndiCtx = setComponentContext(); 498 499 checkTransaction(rctx); 501 502 } catch (RuntimeException e) { 503 TraceEjb.logger.log(BasicLevel.ERROR, "unexpected Runtime Exception", e); 506 throw e; 507 } 508 return rctx; 509 } 510 511 516 public void postInvoke(RequestCtx rctx) { 517 518 if (TraceEjb.isDebugIc()) { 519 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 520 } 521 522 try { 525 String runAsRoleDD = dd.getRunAsRole(); 526 if (runAsRoleDD != null) { 528 SecurityCurrent current = SecurityCurrent.getCurrent(); 530 if (current != null) { 531 SecurityContext sctx = current.getSecurityContext(); 532 if (sctx == null) { 533 TraceEjb.security.log(BasicLevel.ERROR, "runas: Security context is null " + " in ejb " 534 + ejbname); 535 } else { 536 sctx.popRunAs(); 537 } 538 } else { 539 TraceEjb.security.log(BasicLevel.ERROR, "Can't pop runas role as security current is null" 540 + " in ejb " + ejbname); 541 } 542 } 543 544 if (rctx.mustCommit) { 546 try { 548 Transaction t = tm.getTransaction(); 549 if (t == null) { 550 TraceEjb.logger.log(BasicLevel.ERROR, "Transaction disappeared: " + rctx.currTx); 551 Thread.dumpStack(); 552 throw new EJBException ("null transaction"); 553 } 554 if (rctx.currTx != t) { 555 TraceEjb.logger.log(BasicLevel.ERROR, "Transaction changed: " + rctx.currTx); 556 Thread.dumpStack(); 557 throw new EJBException ("bad transaction :" + t); 558 } 559 } catch (Exception e) { 560 throw new EJBException ("Cannot get current transaction:", e); 561 } 562 563 if (rctx.sysExc != null) { 564 TraceEjb.logger.log(BasicLevel.ERROR, "system exception raised by request:", rctx.sysExc); 565 try { 567 tm.rollback(); 568 } catch (Exception e) { 569 TraceEjb.logger.log(BasicLevel.ERROR, "exception during rollback:", e); 570 } 571 } else { 572 try { 573 switch (tm.getStatus()) { 577 case Status.STATUS_ACTIVE: 578 if (TraceEjb.isDebugTx()) { 579 TraceEjb.tx.log(BasicLevel.DEBUG, "committing transaction: " + rctx.currTx); 580 } 581 tm.commit(); 582 break; 583 case Status.STATUS_MARKED_ROLLBACK: 584 if (TraceEjb.isDebugTx()) { 585 TraceEjb.tx.log(BasicLevel.DEBUG, "rolling back transaction: " + rctx.currTx); 586 } 587 tm.rollback(); 588 break; 589 default: 590 TraceEjb.logger.log(BasicLevel.ERROR, "unexpected transaction status " + tm.getStatus()); 591 TraceEjb.logger.log(BasicLevel.ERROR, "transaction: " + rctx.currTx); 592 Thread.dumpStack(); 593 throw new EJBException ("unexpected transaction status :" + tm.getStatus()); 594 } 595 } catch (RollbackException e) { 596 TraceEjb.logger.log(BasicLevel.WARN, "Could not commit transaction (rolled back)"); 597 throw new TransactionRolledbackLocalException ("Could not commit transaction", e); 598 } catch (Exception e) { 599 TraceEjb.logger.log(BasicLevel.WARN, "Could not commit transaction:" + e); 600 throw new EJBException ("Container exception", e); 601 } 602 } 603 } 604 605 Thread.currentThread().setContextClassLoader(rctx.cloader); 607 608 Transaction tx = rctx.clientTx; 610 if (tx != null) { 611 try { 612 if (TraceEjb.isDebugTx()) { 613 TraceEjb.tx.log(BasicLevel.DEBUG, "resuming transaction"); 614 } 615 tm.resume(tx); 616 } catch (Exception e) { 617 TraceEjb.logger.log(BasicLevel.ERROR, "cannot resume transaction", e); 618 } 619 } 620 621 if (rctx.sysExc != null) { 627 TraceEjb.logger.log(BasicLevel.ERROR, "system exception in business method:", rctx.sysExc); 629 630 Transaction currentTx = null; 633 try { 634 currentTx = tm.getTransaction(); 635 if (currentTx != null) { 636 TraceEjb.logger.log(BasicLevel.WARN, "Client transaction will rollback"); 637 currentTx.setRollbackOnly(); 638 if (rctx.bmcalled) { 640 throw new TransactionRolledbackLocalException (rctx.sysExc.getMessage()); 641 } 642 } 643 } catch (SystemException e) { 644 TraceEjb.logger.log(BasicLevel.ERROR, "cannot set rollback only current tx:", e); 645 } 646 return; 647 } 648 649 resetComponentContext(rctx.jndiCtx); 651 652 653 } catch (TransactionRolledbackLocalException e) { 654 throw e; 655 } catch (EJBException e) { 656 TraceEjb.logger.log(BasicLevel.ERROR, "ejbexception: ", e); 657 throw e; 658 } catch (RuntimeException e) { 659 TraceEjb.logger.log(BasicLevel.ERROR, "unexpected runtime exception: ", e); 662 throw e; 663 } 664 } 665 666 675 public RequestCtx preInvokeRemote(int txa) throws RemoteException { 676 if (TraceEjb.isDebugIc()) { 677 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 678 } 679 try { 680 return preInvoke(txa); 681 } catch (javax.ejb.TransactionRequiredLocalException e) { 682 TransactionRequiredException tr = new TransactionRequiredException (e.getMessage()); 683 tr.detail = e; 684 throw tr; 685 } catch (javax.ejb.TransactionRolledbackLocalException e) { 686 TransactionRolledbackException tr = new TransactionRolledbackException (e.getMessage()); 687 tr.detail = e; 688 throw tr; 689 } catch (javax.ejb.NoSuchObjectLocalException e) { 690 throw NoSuchObjectExceptionHelper.create(e); 691 } catch (javax.ejb.EJBException e) { 692 RemoteException re = new RemoteException (e.getMessage()); 693 re.detail = e; 694 throw re; 695 } 696 } 697 698 706 public void postInvokeRemote(RequestCtx rctx) throws RemoteException { 707 if (TraceEjb.isDebugIc()) { 708 TraceEjb.interp.log(BasicLevel.DEBUG, ""); 709 } 710 try { 711 postInvoke(rctx); 712 } catch (javax.ejb.TransactionRequiredLocalException e) { 713 throw new javax.transaction.TransactionRequiredException (e.getMessage()); 714 } catch (javax.ejb.TransactionRolledbackLocalException e) { 715 throw new javax.transaction.TransactionRolledbackException (e.getMessage()); 716 } catch (javax.ejb.NoSuchObjectLocalException e) { 717 throw new java.rmi.NoSuchObjectException (e.getMessage()); 718 } catch (javax.ejb.EJBException e) { 719 throw new java.rmi.RemoteException (e.getMessage(), e); 720 } 721 } 722 723 727 abstract void checkTransaction(RequestCtx rctx); 728 729 741 private void checkTransactionInteroperability(int txa) { 742 743 TransactionContext transContext = ((org.objectweb.jotm.Current) tm).getPropagationContext(false); 745 if (transContext == null) { 746 return; 747 } 748 749 boolean isNullTxCtx = !transContext.isJotmCtx(); 750 751 if (isNullTxCtx) { 752 switch(txa) { 753 case MethodDesc.TX_MANDATORY: 756 TraceEjb.logger.log(BasicLevel.WARN, "mandatory and tx from another vendor"); 757 throw new EJBException ("Doesn't support transaction interoperability"); 758 759 case MethodDesc.TX_REQUIRED: 760 TraceEjb.logger.log(BasicLevel.WARN, "required and tx from another vendor"); 761 throw new EJBException ("Doesn't support transaction interoperability"); 762 763 case MethodDesc.TX_SUPPORTS: 764 TraceEjb.logger.log(BasicLevel.WARN, "supports and tx from another vendor"); 765 throw new EJBException ("Doesn't support transaction interoperability"); 766 default: 767 break; 769 } 770 } 771 } 772 773 779 protected void checkTransactionContainer(RequestCtx rctx) { 780 781 int txa = rctx.txAttr; 782 if (TraceEjb.isDebugTx()) { 783 TraceEjb.tx.log(BasicLevel.DEBUG, "transaction attribute = " + MethodDesc.getTxAttributeName(txa)); 784 } 785 786 if (txa == MethodDesc.TX_NOT_SET) { 787 return; 789 } 790 791 rctx.mustCommit = false; 792 Transaction cltx = null; 793 794 Transaction currtx = null; 796 try { 797 currtx = tm.getTransaction(); 798 if (TraceEjb.isDebugTx()) { 799 TraceEjb.tx.log(BasicLevel.DEBUG, "currtx=" + currtx); 800 } 801 } catch (SystemException e) { 802 TraceEjb.logger.log(BasicLevel.ERROR, "system exception while getting transaction:", e); 803 } 804 805 if (iiopProtocolAvailable) { 807 checkTransactionInteroperability(txa); 808 } 809 810 if (txa == MethodDesc.TX_NEVER && currtx != null) { 812 TraceEjb.logger.log(BasicLevel.WARN, "never and transaction not null"); 813 throw new EJBException ("Never attribute = caller must not be in a transaction"); 814 } 815 816 if (txa == MethodDesc.TX_MANDATORY && currtx == null) { 818 TraceEjb.logger.log(BasicLevel.WARN, "mandatory and not in transaction"); 819 throw new TransactionRequiredLocalException ("Mandatory attribute = caller must be in a transaction"); 820 } 821 822 if (currtx != null && (txa == MethodDesc.TX_REQUIRES_NEW || txa == MethodDesc.TX_NOT_SUPPORTED)) { 824 try { 825 cltx = tm.suspend(); 826 if (cltx != null && TraceEjb.isDebugTx()) { 827 TraceEjb.tx.log(BasicLevel.DEBUG, "Suspending client tx:" + cltx); 828 } 829 currtx = null; 830 } catch (SystemException e) { 831 TraceEjb.logger.log(BasicLevel.ERROR, "cannot suspend transaction:\n", e); 832 throw new EJBException ("Cannot suspend transaction", e); 833 } 834 } 835 836 if (txa == MethodDesc.TX_REQUIRES_NEW || (txa == MethodDesc.TX_REQUIRED && currtx == null)) { 841 try { 842 tm.begin(); 843 rctx.mustCommit = true; 844 currtx = tm.getTransaction(); 845 } catch (NotSupportedException e) { 846 TraceEjb.logger.log(BasicLevel.ERROR, "cannot start a transaction: NotSupportedException"); 847 throw new EJBException ("Nested Transactions Not Supported", e); 848 } catch (SystemException e) { 849 TraceEjb.logger.log(BasicLevel.ERROR, "cannot start a transaction:\n", e); 850 throw new EJBException ("Cannot start a transaction: SystemException", e); 851 } 852 } 853 854 rctx.currTx = currtx; 856 rctx.clientTx = cltx; 857 } 858 859 864 protected void checkJonasVersion(String clName) { 865 870 String fdName = "JONAS_VERSION"; 871 String gVersion = null; 872 try { 873 String resourceName = clName.replace('.', '/') + ".class"; 876 877 Enumeration e = null; 879 try { 880 e = cont.getClassLoader().getResources(resourceName); 881 } catch (IOException ioe) { 882 TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + clName + ioe); 883 throw new EJBException ("Container failed to find class " + clName, ioe); 884 } 885 886 int nbCls = 0; 888 String urls = ""; 889 while (e.hasMoreElements()) { 890 nbCls++; 891 urls += e.nextElement() + "\n"; 892 } 893 894 if (nbCls > 1) { 896 TraceEjb.logger 897 .log( 898 BasicLevel.WARN, 899 "there are " 900 + nbCls 901 + " resources for the class " 902 + clName 903 + ". Some problems can occur because it's the first resource which will be loaded. The list of resources is : \n" 904 + urls); 905 } 906 907 Class cl = cont.getClassLoader().loadClass(clName); 910 Field fd = cl.getDeclaredField("JONAS_VERSION"); 911 gVersion = (String ) fd.get(null); 912 } catch (ClassNotFoundException e) { 913 TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + clName, e); 914 return; 915 } catch (NoSuchFieldException e) { 916 TraceEjb.logger.log(BasicLevel.ERROR, "failed to find field " + fdName + " of class " + clName, e); 917 return; 918 } catch (IllegalAccessException e) { 919 TraceEjb.logger.log(BasicLevel.ERROR, "failed to get the value of the field " + fdName + " of class " 920 + clName, e); 921 return; 922 } 923 if (!Version.NUMBER.equals(gVersion)) { 926 TraceEjb.logger.log(BasicLevel.WARN, ejbname + "(Ver. " + gVersion 927 + ") bean not deployed with the same JOnAS version(" + Version.NUMBER + "). You have to redeploy " 928 + cont.getFileName() + "."); 929 } 930 } 931 932 935 public ClassLoader myClassLoader() { 936 return cont.getClassLoader(); 937 } 938 } 939 | Popular Tags |