1 29 30 package com.caucho.ejb.cfg; 31 32 import com.caucho.bytecode.JClass; 33 import com.caucho.bytecode.JClassDependency; 34 import com.caucho.bytecode.JClassLoader; 35 import com.caucho.bytecode.JClassLoaderWrapper; 36 import com.caucho.bytecode.JClassWrapper; 37 import com.caucho.bytecode.JMethod; 38 import com.caucho.config.BuilderProgram; 39 import com.caucho.config.BuilderProgramContainer; 40 import com.caucho.config.ConfigException; 41 import com.caucho.config.DependencyBean; 42 import com.caucho.config.LineConfigException; 43 import com.caucho.config.types.Period; 44 import com.caucho.ejb.AbstractServer; 45 import com.caucho.ejb.EjbServerManager; 46 import com.caucho.ejb.amber.AmberConfig; 47 import com.caucho.ejb.gen.BeanAssembler; 48 import com.caucho.ejb.gen.TransactionChain; 49 import com.caucho.ejb.gen.UserInRoleChain; 50 import com.caucho.ejb.gen.ViewClass; 51 import com.caucho.java.gen.BaseClass; 52 import com.caucho.java.gen.BaseMethod; 53 import com.caucho.java.gen.CallChain; 54 import com.caucho.java.gen.GenClass; 55 import com.caucho.java.gen.JavaClassGenerator; 56 import com.caucho.java.gen.MethodCallChain; 57 import com.caucho.loader.EnvironmentBean; 58 import com.caucho.loader.EnvironmentLocal; 59 import com.caucho.log.Log; 60 import com.caucho.make.ClassDependency; 61 import com.caucho.util.L10N; 62 import com.caucho.vfs.Depend; 63 import com.caucho.vfs.Path; 64 import com.caucho.vfs.PersistentDependency; 65 66 import javax.annotation.PostConstruct; 67 import javax.ejb.EJBHome ; 68 import javax.ejb.EJBLocalHome ; 69 import javax.ejb.EJBLocalObject ; 70 import javax.ejb.EJBObject ; 71 import java.lang.ref.SoftReference ; 72 import java.util.ArrayList ; 73 import java.util.HashMap ; 74 import java.util.Map ; 75 import java.util.WeakHashMap ; 76 import java.util.logging.Level ; 77 import java.util.logging.Logger ; 78 79 82 public class EjbBean implements EnvironmentBean, DependencyBean { 83 private static Logger log = Log.open(EjbBean.class); 84 private static L10N L = new L10N(EjbBean.class); 85 86 private static EnvironmentLocal<Map <JClass,SoftReference <JMethod[]>>> _methodCache 87 = new EnvironmentLocal<Map <JClass,SoftReference <JMethod[]>>>(); 88 89 private final EjbConfig _ejbConfig; 90 private final String _ejbModuleName; 91 92 private ClassLoader _loader; 93 94 protected JClassLoader _jClassLoader; 95 96 private String _ejbName; 97 private String _jndiName; 98 99 private String _location = ""; 100 101 private JClass _ejbClass; 104 105 protected JClass _remoteHome; 106 protected JClass _remote; 107 protected JClass _localHome; 108 protected JClass _local; 109 110 protected EjbView _remoteHomeView; 111 protected EjbView _remoteView; 112 protected EjbView _localHomeView; 113 protected EjbView _localView; 114 115 private boolean _isAllowPOJO; 116 117 private boolean _isContainerTransaction = true; 118 119 ArrayList <PersistentDependency> _dependList = 120 new ArrayList <PersistentDependency>(); 121 122 ArrayList <PersistentDependency> _configDependList = 123 new ArrayList <PersistentDependency>(); 124 125 ArrayList <String > _beanDependList = new ArrayList <String >(); 126 127 ArrayList <EjbMethodPattern> _methodList = new ArrayList <EjbMethodPattern>(); 128 129 private HashMap <String ,EjbBaseMethod> _methodMap = 130 new HashMap <String ,EjbBaseMethod>(); 131 132 private BuilderProgramContainer _initProgram; 133 private BuilderProgramContainer _serverProgram; 134 135 private long _transactionTimeout; 136 137 140 public EjbBean(EjbConfig ejbConfig, String ejbModuleName) 141 { 142 _ejbConfig = ejbConfig; 143 _ejbModuleName = ejbModuleName; 144 145 _loader = Thread.currentThread().getContextClassLoader(); 146 147 _jClassLoader = JClassLoaderWrapper.create(_loader); 148 } 149 150 153 public EjbConfig getConfig() 154 { 155 return _ejbConfig; 156 } 157 158 public String getEJBModuleName() 159 { 160 return _ejbModuleName; 161 } 162 163 166 public ClassLoader getClassLoader() 167 { 168 return _loader; 169 } 170 171 174 public void setConfigLocation(String filename, int line) 175 { 176 _location = filename + ":" + line + ": "; 177 } 178 179 182 public void setLocation(String location) 183 { 184 _location = location; 185 } 186 187 190 public String getLocation() 191 { 192 return _location; 193 } 194 195 198 public void setAllowPOJO(boolean allowPOJO) 199 { 200 _isAllowPOJO = allowPOJO; 201 } 202 203 206 public boolean isAllowPOJO() 207 { 208 return _isAllowPOJO; 209 } 210 211 214 public void addDescription(String description) 215 { 216 } 217 218 221 public void addDisplayName(String displayName) 222 { 223 } 224 225 228 public void addIcon(String icon) 229 { 230 } 231 232 235 public void setEJBName(String ejbName) 236 { 237 _ejbName = ejbName; 238 } 239 240 243 public String getEJBName() 244 { 245 return _ejbName; 246 } 247 248 251 public void setJndiName(String jndiName) 252 { 253 _jndiName = jndiName; 254 } 255 256 259 public String getJndiName() 260 { 261 return _jndiName; 262 } 263 264 267 public String getEJBKind() 268 { 269 return "unknown"; 270 } 271 272 275 public void setEJBClass(Class ejbClass) 276 throws ConfigException 277 { 278 setEJBClassWrapper(new JClassWrapper(ejbClass, _jClassLoader)); 279 } 280 281 284 public void setEJBClassWrapper(JClass ejbClass) 285 throws ConfigException 286 { 287 if (_ejbClass != null && ! _ejbClass.getName().equals(ejbClass.getName())) 288 throw error(L.l("ejb-class '{0}' cannot be redefined. Old value is '{1}'.", 289 _ejbClass.getName(), ejbClass.getName())); 290 291 292 _ejbClass = ejbClass; 293 294 if (! _ejbClass.isPublic()) 295 throw error(L.l("`{0}' must be public. Bean implementations must be public.", ejbClass.getName())); 296 297 if (_ejbClass.isFinal()) 298 throw error(L.l("`{0}' must not be final. Bean implementations must not be final.", ejbClass.getName())); 299 300 if (_ejbClass.isInterface()) 301 throw error(L.l("`{0}' must not be an interface. Bean implementations must be classes.", ejbClass.getName())); 302 303 JMethod constructor = null; 305 try { 306 constructor = ejbClass.getConstructor(new JClass[0]); 307 } catch (Throwable e) { 308 log.log(Level.FINE, e.toString(), e); 309 } 310 311 if (constructor == null) 312 throw error(L.l("`{0}' needs a public zero-arg constructor. Bean implementations need a public zero-argument constructor.", ejbClass.getName())); 313 314 JClass []exn = constructor.getExceptionTypes(); 315 for (int i = 0; i < exn.length; i++) { 316 if (! exn[i].isAssignableTo(RuntimeException .class)) { 317 throw error(L.l("{0}: constructor must not throw `{1}'. Bean constructors must not throw checked exceptions.", ejbClass.getName(), exn[i].getName())); 318 } 319 } 320 321 JMethod method = ejbClass.getMethod("finalize", new JClass[0]); 322 323 if (method != null && ! method.getDeclaringClass().equals(JClass.OBJECT)) 324 throw error(L.l("`{0}' may not implement finalize(). Bean implementations may not implement finalize().", ejbClass.getName())); 325 } 326 327 330 public Class getEJBClass() 331 { 332 try { 333 if (_ejbClass == null) 334 return null; 335 336 return Class.forName(_ejbClass.getName(), false, getClassLoader()); 337 } catch (RuntimeException e) { 338 throw e; 339 } catch (Exception e) { 340 throw new ConfigException(e); 341 } 342 } 343 344 347 public JClass getEJBClassWrapper() 348 { 349 return _ejbClass; 350 } 351 352 355 public String getEJBFullClassName() 356 { 357 return _ejbClass.getName(); 358 } 359 360 363 public String getEJBClassName() 364 { 365 String s = _ejbClass.getName(); 366 int p = s.lastIndexOf('.'); 367 368 if (p > 0) 369 return s.substring(p + 1); 370 else 371 return s; 372 } 373 374 377 public String getFullImplName() 378 { 379 return getEJBFullClassName(); 380 } 381 382 385 public void setHome(Class home) 386 throws ConfigException 387 { 388 setHomeWrapper(new JClassWrapper(home, _jClassLoader)); 389 } 390 391 394 public void setHomeWrapper(JClass remoteHome) 395 throws ConfigException 396 { 397 _remoteHome = remoteHome; 398 399 if (! remoteHome.isPublic()) 400 throw error(L.l("`{0}' must be public. <home> interfaces must be public.", remoteHome.getName())); 401 402 if (! remoteHome.isInterface()) 403 throw error(L.l("`{0}' must be an interface. <home> interfaces must be interfaces.", remoteHome.getName())); 404 405 if (! remoteHome.isAssignableTo(EJBHome .class) && ! isAllowPOJO()) 406 throw new ConfigException(L.l("`{0}' must extend EJBHome. <home> interfaces must extend javax.ejb.EJBHome.", remoteHome.getName())); 407 408 } 409 412 public JClass getRemoteHome() 413 { 414 return _remoteHome; 415 } 416 417 420 public Class getRemoteHomeClass() 421 { 422 if (_remoteHome == null) 423 return null; 424 425 try { 426 return Class.forName(_remoteHome.getName(), false, getClassLoader()); 427 } catch (Exception e) { 428 throw new RuntimeException (e); 429 } 430 } 431 432 435 public void setRemote(Class remote) 436 throws ConfigException 437 { 438 setRemoteWrapper(new JClassWrapper(remote, _jClassLoader)); 439 } 440 441 444 public void setRemoteWrapper(JClass remote) 445 throws ConfigException 446 { 447 _remote = remote; 448 449 if (! _remote.isPublic()) 450 throw error(L.l("`{0}' must be public. <remote> interfaces must be public.", remote.getName())); 451 452 if (! _remote.isInterface()) 453 throw error(L.l("`{0}' must be an interface. <remote> interfaces must be interfaces.", remote.getName())); 454 455 if (! remote.isAssignableTo(EJBObject .class) && ! isAllowPOJO()) 456 throw new ConfigException(L.l("`{0}' must extend EJBObject. <remote> interfaces must extend javax.ejb.EJBObject.", remote.getName())); 457 458 } 459 460 463 public JClass getRemote() 464 { 465 return _remote; 466 } 467 468 471 public Class getRemoteClass() 472 { 473 if (_remote == null) 474 return null; 475 476 try { 477 return Class.forName(_remote.getName(), false, getClassLoader()); 478 } catch (Exception e) { 479 throw new RuntimeException (e); 480 } 481 } 482 483 486 public void setLocalHome(Class localHome) 487 throws ConfigException 488 { 489 setLocalHomeWrapper(new JClassWrapper(localHome, _jClassLoader)); 490 } 491 492 495 public void setLocalHomeWrapper(JClass localHome) 496 throws ConfigException 497 { 498 _localHome = localHome; 499 500 if (! localHome.isPublic()) 501 throw error(L.l("`{0}' must be public. <local-home> interfaces must be public.", localHome.getName())); 502 503 if (! localHome.isInterface()) 504 throw error(L.l("`{0}' must be an interface. <local-home> interfaces must be interfaces.", localHome.getName())); 505 506 if (! localHome.isAssignableTo(EJBLocalHome .class) && ! isAllowPOJO()) 507 throw new ConfigException(L.l("`{0}' must extend EJBLocalHome. <local-home> interfaces must extend javax.ejb.EJBLocalHome.", localHome.getName())); 508 509 } 510 511 514 public JClass getLocalHome() 515 { 516 return _localHome; 517 } 518 519 522 public void setLocal(Class local) 523 throws ConfigException 524 { 525 setLocalWrapper(new JClassWrapper(local, _jClassLoader)); 526 } 527 528 531 public void setLocalWrapper(JClass local) 532 throws ConfigException 533 { 534 _local = local; 535 536 if (! local.isPublic()) 537 throw error(L.l("`{0}' must be public. <local> interfaces must be public.", local.getName())); 538 539 if (! local.isInterface()) 540 throw error(L.l("`{0}' must be an interface. <local> interfaces must be interfaces.", local.getName())); 541 542 if (! local.isAssignableTo(EJBLocalObject .class) && ! isAllowPOJO()) 543 throw new ConfigException(L.l("`{0}' must extend EJBLocalObject. <local> interfaces must extend javax.ejb.EJBLocalObject.", local.getName())); 544 } 545 546 549 public JClass getLocal() 550 { 551 return _local; 552 } 553 554 557 public boolean isContainerTransaction() 558 { 559 return _isContainerTransaction; 560 } 561 562 565 public EjbMethodPattern createMethod(MethodSignature sig) 566 { 567 for (int i = 0; i < _methodList.size(); i++) { 568 EjbMethodPattern method = _methodList.get(i); 569 570 if (method.getSignature().equals(sig)) 571 return method; 572 } 573 574 EjbMethodPattern method = new EjbMethodPattern(this, sig); 575 576 _methodList.add(method); 577 578 return method; 579 } 580 581 584 public void addMethod(EjbMethodPattern method) 585 { 586 _methodList.add(method); 587 } 588 589 592 public EjbMethodPattern getMethodPattern(JMethod method, String intf) 593 { 594 EjbMethodPattern bestMethod = null; 595 int bestCost = -1; 596 597 for (int i = 0; i < _methodList.size(); i++) { 598 EjbMethodPattern ejbMethod = _methodList.get(i); 599 MethodSignature sig = ejbMethod.getSignature(); 600 601 if (sig.isMatch(method, intf) && bestCost < sig.getCost()) { 602 bestMethod = ejbMethod; 603 bestCost = sig.getCost(); 604 } 605 } 606 607 return bestMethod; 608 } 609 610 613 public ArrayList <EjbMethodPattern> getMethodList() 614 { 615 return _methodList; 616 } 617 618 621 public void setTransactionTimeout(Period timeout) 622 { 623 _transactionTimeout = timeout.getPeriod(); 624 } 625 626 629 public long getTransactionTimeout() 630 { 631 return _transactionTimeout; 632 } 633 634 637 public void setSecurityIdentity(EjbSecurityIdentity securityIdentity) 638 { 639 } 640 641 644 public void addDependencyList(ArrayList <PersistentDependency> dependList) 645 { 646 for (int i = 0; dependList != null && i < dependList.size(); i++) { 647 addDependency(dependList.get(i)); 648 } 649 } 650 651 654 public void addDepend(Path path) 655 { 656 addDependency(new Depend(path)); 657 } 658 659 662 public void addDependency(PersistentDependency depend) 663 { 664 if (! _dependList.contains(depend)) 665 _dependList.add(depend); 666 } 667 668 671 public void addDependency(Class cl) 672 { 673 addDependency(new ClassDependency(cl)); 674 } 675 676 679 public ArrayList <PersistentDependency> getDependList() 680 { 681 return _dependList; 682 } 683 684 687 public void addBeanDependency(String ejbName) 688 { 689 if (! _beanDependList.contains(ejbName)) 690 _beanDependList.add(ejbName); 691 } 692 693 696 public ArrayList <String > getBeanDependList() 697 { 698 return _beanDependList; 699 } 700 701 704 public void addInitProgram(BuilderProgram init) 705 { 706 if (_initProgram == null) 707 _initProgram = new BuilderProgramContainer(); 708 709 _initProgram.addProgram(init); 710 } 711 712 715 public void addBuilderProgram(BuilderProgram init) 716 { 717 if (_serverProgram == null) 718 _serverProgram = new BuilderProgramContainer(); 719 720 _serverProgram.addProgram(init); 721 } 722 723 726 public BuilderProgramContainer getInitProgram() 727 { 728 return _initProgram; 729 } 730 731 734 public BuilderProgramContainer getServerProgram() 735 { 736 return _serverProgram; 737 } 738 739 742 @PostConstruct 743 public void init() 744 throws ConfigException 745 { 746 try { 747 introspect(); 748 749 assembleBeanMethods(); 750 751 createViews(); 752 753 761 } catch (LineConfigException e) { 762 throw e; 763 } catch (ConfigException e) { 764 throw new LineConfigException(_location + e.getMessage(), e); 765 } 766 } 767 768 771 public void introspect() 772 throws ConfigException 773 { 774 } 775 776 779 public void configureAmber(AmberConfig config) 780 throws ConfigException 781 { 782 } 783 784 787 protected void createViews() 788 throws ConfigException 789 { 790 if (_remoteHome != null) { 791 _remoteHomeView = createHomeView(_remoteHome, "RemoteHome"); 792 _remoteHomeView.introspect(); 793 } 794 795 if (_remote != null) { 796 _remoteView = createObjectView(_remote, "Remote"); 797 _remoteView.introspect(); 798 } 799 800 if (_localHome != null) { 801 _localHomeView = createHomeView(_localHome, "LocalHome"); 802 _localHomeView.introspect(); 803 } 804 805 if (_local != null) { 806 _localView = createObjectView(_local, "Local"); 807 _localView.introspect(); 808 } 809 } 810 811 814 protected EjbHomeView createHomeView(JClass homeClass, String prefix) 815 throws ConfigException 816 { 817 return new EjbHomeView(this, homeClass, prefix); 818 } 819 820 823 protected EjbObjectView createObjectView(JClass apiClass, String prefix) 824 throws ConfigException 825 { 826 return new EjbObjectView(this, apiClass, prefix); 827 } 828 829 832 public void generate(JavaClassGenerator javaGen, boolean isAutoCompile) 833 throws Exception 834 { 835 String fullClassName = getSkeletonName(); 836 837 if (javaGen.preload(fullClassName) != null) { 838 } 839 else if (isAutoCompile) { 840 GenClass genClass = assembleGenerator(fullClassName); 841 842 if (genClass != null) 843 javaGen.generate(genClass); 844 } 845 } 846 847 850 public AbstractServer deployServer(EjbServerManager ejbManager, 851 JavaClassGenerator javaGen) 852 throws ClassNotFoundException , ConfigException 853 { 854 throw new UnsupportedOperationException (); 855 } 856 857 860 protected void validateRemote(JClass objectClass) 861 throws ConfigException 862 { 863 JClass beanClass = getEJBClassWrapper(); 864 String beanName = beanClass.getName(); 865 866 String objectName = objectClass.getName(); 867 868 if (! objectClass.isPublic()) 869 throw error(L.l("`{0}' must be public", objectName)); 870 871 if (! objectClass.isInterface()) 872 throw error(L.l("`{0}' must be an interface", objectName)); 873 874 JMethod []methods = getMethods(objectClass); 875 for (int i = 0; i < methods.length; i++) { 876 JMethod method = methods[i]; 877 String name = method.getName(); 878 JClass []param = method.getParameterTypes(); 879 JClass retType = method.getReturnType(); 880 881 if (method.getDeclaringClass().isAssignableFrom(EJBObject .class)) 882 continue; 883 if (method.getDeclaringClass().isAssignableFrom(EJBLocalObject .class)) 884 continue; 885 886 if (objectClass.isAssignableTo(EJBObject .class)) 887 validateException(method, java.rmi.RemoteException .class); 888 889 if (name.startsWith("ejb")) { 890 throw error(L.l("`{0}' forbidden in {1}. Local or remote interfaces may not define ejbXXX methods.", 891 getFullMethodName(method), 892 objectName)); 893 } 894 895 JClass returnType = method.getReturnType(); 896 897 if (objectClass.isAssignableTo(EJBObject .class) && 898 (returnType.isAssignableTo(EJBLocalObject .class) || 899 returnType.isAssignableTo(EJBLocalHome .class))) 900 throw error(L.l("`{0}' must not return `{1}' in {2}. Remote methods must not return local interfaces.", 901 getFullMethodName(method), 902 getShortClassName(returnType), 903 objectClass.getName())); 904 905 JMethod implMethod = 906 validateRemoteImplMethod(method.getName(), param, 907 method, objectClass); 908 909 if (! returnType.equals(implMethod.getReturnType())) { 910 throw error(L.l("{0}: `{1}' must return {2} to match {3}.{4}. Business methods must return the same type as the interface.", 911 method.getDeclaringClass().getName(), 912 getFullMethodName(method), 913 implMethod.getReturnType().getName(), 914 getShortClassName(implMethod.getDeclaringClass()), 915 getFullMethodName(implMethod))); 916 } 917 918 validateExceptions(method, implMethod.getExceptionTypes()); 919 } 920 } 921 922 930 private JMethod validateRemoteImplMethod(String methodName, 931 JClass []param, 932 JMethod sourceMethod, 933 JClass sourceClass) 934 throws ConfigException 935 { 936 JMethod method = null; 937 JClass beanClass = getEJBClassWrapper(); 938 939 method = getMethod(beanClass, methodName, param); 940 941 if (method == null && sourceMethod != null) { 942 throw error(L.l("{0}: `{1}' expected to match {2}.{3}", 943 beanClass.getName(), 944 getFullMethodName(methodName, param), 945 getShortClassName(sourceMethod.getDeclaringClass()), 946 getFullMethodName(sourceMethod))); 947 } 948 else if (method == null) { 949 throw error(L.l("{0}: `{1}' expected", 950 beanClass.getName(), 951 getFullMethodName(methodName, param))); 952 } 953 961 else if (! method.isPublic()) { 962 throw error(L.l("{0}: `{1}' must be public", 963 beanClass.getName(), 964 getFullMethodName(methodName, param))); 965 } 966 967 if (method.isStatic()) { 968 throw error(L.l("{0}: `{1}' must not be static", 969 beanClass.getName(), 970 getFullMethodName(methodName, param))); 971 } 972 973 if (method.isFinal()) { 974 throw error(L.l("{0}: `{1}' must not be final.", 975 beanClass.getName(), 976 getFullMethodName(methodName, param), 977 beanClass.getName())); 978 } 979 980 return method; 981 } 982 983 JMethod validateNonFinalMethod(String methodName, JClass []param, 984 boolean isOptional) 985 throws ConfigException 986 { 987 if (isOptional && getMethod(_ejbClass, methodName, param) == null) 988 return null; 989 else 990 return validateNonFinalMethod(methodName, param); 991 } 992 993 JMethod validateNonFinalMethod(String methodName, JClass []param) 994 throws ConfigException 995 { 996 return validateNonFinalMethod(methodName, param, null, null); 997 } 998 999 JMethod validateNonFinalMethod(String methodName, JClass []param, 1000 JMethod sourceMethod, JClass sourceClass) 1001 throws ConfigException 1002 { 1003 return validateNonFinalMethod(methodName, param, 1004 sourceMethod, sourceClass, false); 1005 } 1006 1007 1015 JMethod validateNonFinalMethod(String methodName, JClass []param, 1016 JMethod sourceMethod, JClass sourceClass, 1017 boolean isOptional) 1018 throws ConfigException 1019 { 1020 JMethod method = validateMethod(methodName, param, 1021 sourceMethod, sourceClass, 1022 isOptional); 1023 1024 if (method == null && isOptional) 1025 return null; 1026 1027 if (method.isFinal()) 1028 throw error(L.l("{0}: `{1}' must not be final", 1029 _ejbClass.getName(), 1030 getFullMethodName(method))); 1031 1032 1033 if (method.isStatic()) 1034 throw error(L.l("{0}: `{1}' must not be static", 1035 _ejbClass.getName(), 1036 getFullMethodName(method))); 1037 1038 return method; 1039 } 1040 1041 JMethod validateMethod(String methodName, JClass []param) 1042 throws ConfigException 1043 { 1044 return validateMethod(methodName, param, null, null); 1045 } 1046 1047 1055 JMethod validateMethod(String methodName, JClass []param, 1056 JMethod sourceMethod, JClass sourceClass) 1057 throws ConfigException 1058 { 1059 return validateMethod(methodName, param, sourceMethod, sourceClass, false); 1060 } 1061 1062 1070 JMethod validateMethod(String methodName, JClass []param, 1071 JMethod sourceMethod, JClass sourceClass, 1072 boolean isOptional) 1073 throws ConfigException 1074 { 1075 JMethod method = null; 1076 1077 method = getMethod(_ejbClass, methodName, param); 1078 1079 if (method == null && isOptional) 1080 return null; 1081 1082 if (method == null && sourceMethod != null) { 1083 throw error(L.l("{0}: missing `{1}' needed to match {2}.{3}", 1084 _ejbClass.getName(), 1085 getFullMethodName(methodName, param), 1086 getShortClassName(sourceClass), 1087 getFullMethodName(sourceMethod))); 1088 } 1089 else if (method == null) { 1090 throw error(L.l("{0}: expected `{1}'", 1091 _ejbClass.getName(), 1092 getFullMethodName(methodName, param))); 1093 } 1094 1095 JClass declaringClass = method.getDeclaringClass(); 1096 1097 if (method.isAbstract()) { 1098 if (method.getDeclaringClass().getName().equals("javax.ejb.EntityBean")) 1099 throw error(L.l("{0}: `{1}' must not be abstract. Entity beans must implement the methods in EntityBean.", 1100 _ejbClass.getName(), 1101 getFullMethodName(methodName, param))); 1102 else if (method.getDeclaringClass().getName().equals("javax.ejb.SessionBean")) 1103 throw error(L.l("{0}: `{1}' must not be abstract. Session beans must implement the methods in SessionBean.", 1104 _ejbClass.getName(), 1105 getFullMethodName(methodName, param))); 1106 else if (sourceMethod != null) 1107 throw error(L.l("{0}: `{1}' must not be abstract. All methods from `{2}' must be implemented in the bean.", 1108 _ejbClass.getName(), 1109 getFullMethodName(methodName, param), 1110 sourceClass.getName())); 1111 else 1112 throw error(L.l("{0}: `{1}' must not be abstract. Business methods must be implemented.", 1113 _ejbClass.getName(), 1114 getFullMethodName(methodName, param))); 1115 } else if (! method.isPublic()) { 1116 throw error(L.l("{0}: `{1}' must be public. Business method implementations must be public.", 1117 _ejbClass.getName(), 1118 getFullMethodName(methodName, param))); 1119 } 1120 if (method.isStatic()) { 1121 throw error(L.l("{0}: `{1}' must not be static. Business method implementations must not be static.", 1122 _ejbClass.getName(), 1123 getFullMethodName(method))); 1124 } 1125 1126 return method; 1127 } 1128 1129 protected String getSkeletonName() 1130 { 1131 String className = getEJBClass().getName(); 1132 int p = className.lastIndexOf('.'); 1133 1134 if (p > 0) 1135 className = className.substring(p + 1); 1136 1137 String ejbName = getEJBName(); 1138 1139 String fullClassName = "_ejb." + ejbName + "." + className + "__EJB"; 1140 1141 return JavaClassGenerator.cleanClassName(fullClassName); 1142 } 1143 1144 1147 protected GenClass assembleGenerator(String fullClassName) 1148 throws NoSuchMethodException , ConfigException 1149 { 1150 int p = fullClassName.lastIndexOf('.'); 1151 String className = fullClassName; 1152 if (p > 0) 1153 className = fullClassName.substring(p + 1); 1154 1155 BeanAssembler assembler = createAssembler(fullClassName); 1156 1157 if (assembler == null) 1158 return null; 1159 1160 addImports(assembler); 1161 1162 assembler.addHeaderComponent(getEJBClassWrapper(), 1163 fullClassName, 1164 getFullImplName()); 1165 1166 assembleMethods(assembler, fullClassName); 1167 1168 1170 if (_remoteHomeView != null) 1171 _remoteHomeView.assembleView(assembler, fullClassName); 1172 1173 if (_remoteView != null) 1174 _remoteView.assembleView(assembler, fullClassName); 1175 1176 if (_localHomeView != null) 1177 _localHomeView.assembleView(assembler, fullClassName); 1178 1179 if (_localView != null) 1180 _localView.assembleView(assembler, fullClassName); 1181 1182 for (PersistentDependency depend : _dependList) { 1183 assembler.addDependency(depend); 1184 } 1185 1186 assembler.addDependency(new JClassDependency(_ejbClass)); 1187 1188 if (_remoteHome != null) 1189 assembler.addDependency(new JClassDependency(_remoteHome)); 1190 1191 if (_remote != null) 1192 assembler.addDependency(new JClassDependency(_remote)); 1193 1194 if (_localHome != null) 1195 assembler.addDependency(new JClassDependency(_localHome)); 1196 1197 if (_local != null) 1198 assembler.addDependency(new JClassDependency(_local)); 1199 1200 return assembler.getAssembledGenerator(); 1201 } 1202 1203 1206 protected void addImports(BeanAssembler assembler) 1207 { 1208 assembler.addImport("javax.ejb.*"); 1209 assembler.addImport("com.caucho.vfs.*"); 1210 1211 assembler.addImport("com.caucho.ejb.xa.EjbTransactionManager"); 1212 assembler.addImport("com.caucho.ejb.xa.TransactionContext"); 1213 1214 assembler.addImport("com.caucho.ejb.AbstractContext"); 1215 } 1216 1217 1220 protected BeanAssembler createAssembler(String fullClassName) 1221 { 1222 return null; 1223 } 1224 1225 1228 protected void assembleBeanMethods() 1229 throws ConfigException 1230 { 1231 JMethod []implMethods = getMethods(getEJBClassWrapper()); 1233 1234 for (int i = 0; i < implMethods.length; i++) { 1235 JMethod method = implMethods[i]; 1236 1237 EjbBaseMethod ejbMethod = null; 1238 1239 String name = method.getName(); 1240 1241 if (name.startsWith("ejb")) { 1242 ejbMethod = introspectEJBMethod(method); 1243 1244 if (ejbMethod != null) 1245 _methodMap.put(ejbMethod.getMethod().getFullName(), ejbMethod); 1246 } 1247 else 1248 validateImplMethod(method); 1249 } 1250 } 1251 1252 1255 protected void assembleMethods(BeanAssembler assembler, 1256 String fullClassName) 1257 throws ConfigException 1258 { 1259 for (EjbBaseMethod method : _methodMap.values()) { 1260 assembler.addMethod(method.assemble(assembler, fullClassName)); 1261 } 1262 } 1263 1264 1267 protected EjbBaseMethod introspectEJBMethod(JMethod method) 1268 throws ConfigException 1269 { 1270 return null; 1271 } 1272 1273 1276 protected void validateImplMethod(JMethod method) 1277 throws ConfigException 1278 { 1279 } 1280 1281 1284 protected void assembleMethods(BeanAssembler assembler, 1285 ViewClass view, 1286 String contextClassName, 1287 JMethod []methods, 1288 String prefix) 1289 throws NoSuchMethodException 1290 { 1291 for (int i = 0; i < methods.length; i++) { 1292 String className = methods[i].getDeclaringClass().getName(); 1293 String methodName = methods[i].getName(); 1294 JClass []args = methods[i].getParameterTypes(); 1295 1296 if (className.startsWith("javax.ejb.")) { 1297 } 1298 else if (isOld(methods, methods[i], i)) { 1299 } 1300 else if (methodName.equals("equals") && args.length == 1 && 1301 args[0].equals(JClass.OBJECT)) { 1302 } 1303 else if (methodName.equals("hashCode") && args.length == 0) { 1304 } 1305 else { 1306 JMethod beanMethod = null; 1307 1308 JClass ejbClass = getEJBClassWrapper(); 1309 1310 beanMethod = ejbClass.getMethod(methods[i].getName(), 1311 methods[i].getParameterTypes()); 1312 1313 if (beanMethod == null) 1314 throw new NoSuchMethodException ("Can't find public method " + 1315 methods[i].getFullName()); 1316 1317 CallChain call = new MethodCallChain(beanMethod); 1318 call = view.createPoolChain(call); 1319 call = getTransactionChain(call, beanMethod, prefix); 1320 call = getSecurityChain(call, beanMethod, prefix); 1321 1322 view.addMethod(new BaseMethod(methods[i], call)); 1323 } 1324 } 1325 } 1326 1327 protected void assembleHomeMethods(BeanAssembler assembler, 1328 BaseClass baseClass, 1329 String contextClassName, 1330 JClass homeClass, 1331 String prefix) 1332 throws NoSuchMethodException 1333 { 1334 JMethod []methods = getMethods(homeClass); 1335 1336 for (int i = 0; i < methods.length; i++) { 1337 String className = methods[i].getDeclaringClass().getName(); 1338 String methodName = methods[i].getName(); 1339 1340 if (className.startsWith("javax.ejb.")) { 1341 } 1342 else if (isOld(methods, methods[i], i)) { 1343 } 1344 else if (methodName.startsWith("create")) { 1345 JMethod beanMethod = null; 1346 1347 String name = ("ejbCreate" + Character.toUpperCase(methodName.charAt(0)) 1348 + methodName.substring(1)); 1349 1350 try { 1351 beanMethod = getEJBClassWrapper().getMethod(name, 1352 methods[i].getParameterTypes()); 1353 } catch (Throwable e) { 1354 } 1355 1356 1361 1362 1372 1373 } 1375 else if (methodName.startsWith("find")) { 1376 } 1378 else { 1379 JMethod beanMethod = null; 1380 1381 String name = ("ejbHome" + Character.toUpperCase(methodName.charAt(0)) 1382 + methodName.substring(1)); 1383 1384 try { 1385 beanMethod = getEJBClassWrapper().getMethod(name, 1386 methods[i].getParameterTypes()); 1387 } catch (Exception e) { 1388 throw new NoSuchMethodException ("can't find method " + name); 1389 } 1390 1391 CallChain call = new MethodCallChain(beanMethod); 1392 call = getTransactionChain(call, beanMethod, prefix); 1393 call = getSecurityChain(call, beanMethod, prefix); 1394 1395 baseClass.addMethod(new BaseMethod(methods[i], call)); 1396 } 1397 } 1398 } 1399 1400 protected CallChain getTransactionChain(CallChain next, 1401 JMethod method, 1402 String prefix) 1403 { 1404 return TransactionChain.create(next, getTransactionAttribute(method, prefix)); 1405 } 1406 1407 protected CallChain getSecurityChain(CallChain next, 1408 JMethod method, 1409 String prefix) 1410 { 1411 EjbMethodPattern ejbMethod = getMethodPattern(method, prefix); 1412 1413 ArrayList <String > roles = null; 1414 1415 if (ejbMethod != null) 1416 roles = ejbMethod.getRoles(); 1417 1418 if (roles == null) { 1419 ejbMethod = getMethodPattern(null, prefix); 1420 if (ejbMethod != null) 1421 roles = ejbMethod.getRoles(); 1422 } 1423 1424 if (roles == null) { 1425 ejbMethod = getMethodPattern(method, null); 1426 if (ejbMethod != null) 1427 roles = ejbMethod.getRoles(); 1428 } 1429 1430 if (roles == null) { 1431 ejbMethod = getMethodPattern(null, null); 1432 if (ejbMethod != null) 1433 roles = ejbMethod.getRoles(); 1434 } 1435 1436 if (roles != null) 1437 return new UserInRoleChain(next, roles); 1438 else 1439 return next; 1440 } 1441 1442 1447 protected void validatePublicMethod(JMethod method) 1448 throws ConfigException 1449 { 1450 if (! method.isPublic()) { 1451 throw error(L.l("{0}: '{1}' must be public.", 1452 _ejbClass.getName(), 1453 getFullMethodName(method))); 1454 } 1455 else if (method.isStatic()) { 1456 throw error(L.l("{0}: `{1}' must not be static.", 1457 _ejbClass.getName(), 1458 getFullMethodName(method))); 1459 } 1460 } 1461 1462 1465 static boolean isOld(JMethod []methods, JMethod method, int index) 1466 { 1467 for (int i = 0; i < index; i++) { 1468 if (isEquiv(methods[i], method)) 1469 return true; 1470 } 1471 1472 return false; 1473 } 1474 1475 static boolean isEquiv(JMethod oldMethod, JMethod method) 1476 { 1477 if (! oldMethod.getName().equals(method.getName())) 1478 return false; 1479 1480 JClass []oldParam = oldMethod.getParameterTypes(); 1481 JClass []param = method.getParameterTypes(); 1482 1483 if (oldParam.length != param.length) 1484 return false; 1485 1486 for (int j = 0; j < param.length; j++) { 1487 if (! param[j].equals(oldParam[j])) 1488 return false; 1489 } 1490 1491 return true; 1492 } 1493 1494 1497 public int getTransactionAttribute(JMethod method, String intf) 1498 { 1499 if (! isContainerTransaction()) 1500 return EjbMethod.TRANS_BEAN; 1501 1502 int transaction = EjbMethod.TRANS_REQUIRED; 1503 1504 EjbMethodPattern ejbMethod = getMethodPattern(null, null); 1505 1506 if (ejbMethod != null) 1507 transaction = ejbMethod.getTransactionType(); 1508 1509 ejbMethod = getMethodPattern(method, null); 1510 1511 if (ejbMethod != null) 1512 transaction = ejbMethod.getTransactionType(); 1513 1514 ejbMethod = getMethodPattern(method, intf); 1515 1516 if (ejbMethod != null) 1517 transaction = ejbMethod.getTransactionType(); 1518 1519 return transaction; 1520 } 1521 1522 1530 JMethod getMethod(String methodName, JClass []paramTypes) 1531 { 1532 return getMethod(getEJBClassWrapper(), methodName, paramTypes); 1533 } 1534 1535 1543 public static JMethod getMethod(JClass cl, JMethod sourceMethod) 1544 { 1545 return getMethod(cl, sourceMethod.getName(), 1546 sourceMethod.getParameterTypes()); 1547 } 1548 1549 1558 public static JMethod getMethod(JClass cl, String name, JClass []param) 1559 { 1560 if (cl == null) 1561 return null; 1562 1563 JMethod []methods = cl.getDeclaredMethods(); 1564 1565 for (int i = 0; i < methods.length; i++) { 1566 if (isMatch(methods[i], name, param)) 1567 return methods[i]; 1568 } 1569 1570 JMethod method = getMethod(cl.getSuperClass(), name, param); 1571 if (method != null) 1572 return method; 1573 1574 for (JClass iface : cl.getInterfaces()) { 1575 method = getMethod(iface, name, param); 1576 if (method != null) 1577 return method; 1578 } 1579 1580 return null; 1581 } 1582 1583 static boolean isMatch(JMethod methodA, JMethod methodB) 1584 { 1585 if (methodA == methodB) 1586 return true; 1587 else if (methodA == null || methodB == null) 1588 return false; 1589 else 1590 return isMatch(methodA, methodB.getName(), methodB.getParameterTypes()); 1591 } 1592 1593 static boolean isMatch(JMethod method, String name, JClass []param) 1594 { 1595 if (! method.getName().equals(name)) 1596 return false; 1597 1598 JClass []mparam = method.getParameterTypes(); 1599 1600 if (mparam.length != param.length) 1601 return false; 1602 1603 for (int j = 0; j < param.length; j++) { 1604 if (! mparam[j].equals(param[j])) 1605 return false; 1606 } 1607 1608 return true; 1609 } 1610 1611 1620 static JMethod findMethod(MethodSignature sig, JClass cl, String intf) 1621 { 1622 if (cl == null) 1623 return null; 1624 1625 JMethod []methods = getMethods(cl); 1626 1627 for (int i = 0; i < methods.length; i++) { 1628 if (sig.isMatch(methods[i], intf)) 1629 return methods[i]; 1630 } 1631 1632 return null; 1633 } 1634 1635 1638 static JMethod []getMethods(JClass cl) 1639 { 1640 Map <JClass,SoftReference <JMethod[]>> methodMap = _methodCache.get(); 1641 1642 if (methodMap == null) { 1643 methodMap = new WeakHashMap <JClass,SoftReference <JMethod[]>>(); 1644 _methodCache.set(methodMap); 1645 } 1646 1647 SoftReference <JMethod[]> methodArrayRef = methodMap.get(cl); 1648 JMethod []methodArray = null; 1649 1650 if (methodArrayRef != null) { 1651 methodArray = methodArrayRef.get(); 1652 1653 if (methodArray != null) 1654 return methodArray; 1655 } 1656 1657 ArrayList <JMethod> methods = new ArrayList <JMethod>(); 1658 1659 getMethods(methods, cl); 1660 1661 methodArray = methods.toArray(new JMethod[methods.size()]); 1662 1663 methodMap.put(cl, new SoftReference <JMethod[]>(methodArray)); 1664 1665 return methodArray; 1666 } 1667 1668 1671 static void getMethods(ArrayList <JMethod> methods, JClass cl) 1672 { 1673 if (cl == null) 1674 return; 1675 1676 JMethod []subMethods = cl.getDeclaredMethods(); 1677 1678 for (int i = 0; i < subMethods.length; i++) { 1679 if (findMethod(methods, subMethods[i]) == null) { 1680 methods.add(subMethods[i]); 1681 } 1682 } 1683 1684 getMethods(methods, cl.getSuperClass()); 1685 1686 JClass []interfaces = cl.getInterfaces(); 1687 for (int i = 0; interfaces != null && i < interfaces.length; i++) { 1688 getMethods(methods, interfaces[i]); 1689 } 1690 } 1691 1692 1700 static JMethod findMethod(ArrayList <JMethod> methods, JMethod method) 1701 { 1702 loop: 1703 for (int i = 0; i < methods.size(); i++) { 1704 JMethod oldMethod = methods.get(i); 1705 1706 if (! method.getName().equals(oldMethod.getName())) 1707 continue loop; 1708 1709 JClass []aParamTypes = oldMethod.getParameterTypes(); 1710 JClass []bParamTypes = method.getParameterTypes(); 1711 1712 if (aParamTypes.length != bParamTypes.length) 1713 continue loop; 1714 1715 for (int j = 0; j < aParamTypes.length; j++) { 1716 if (! aParamTypes[j].equals(bParamTypes[j])) 1717 continue loop; 1718 } 1719 1720 return oldMethod; 1721 } 1722 1723 return null; 1724 } 1725 1726 1729 static String getFullMethodName(JMethod method) 1730 { 1731 return getFullMethodName(method.getName(), method.getParameterTypes()); 1732 } 1733 1734 1737 static String getFullMethodName(String methodName, JClass []params) 1738 { 1739 String name = methodName + "("; 1740 1741 for (int i = 0; i < params.length; i++) { 1742 if (i != 0) 1743 name += ", "; 1744 1745 name += getShortClassName(params[i]); 1746 } 1747 1748 return name + ")"; 1749 } 1750 1751 1754 static String getClassName(JClass cl) 1755 { 1756 if (cl == null) 1757 return "null"; 1758 else if (cl.isArray()) 1759 return getClassName(cl.getComponentType()) + "[]"; 1760 else if (cl.getName().startsWith("java")) { 1761 int p = cl.getName().lastIndexOf('.'); 1762 1763 return cl.getName().substring(p + 1); 1764 } 1765 else 1766 return cl.getName(); 1767 } 1768 1769 1772 static String getShortClassName(JClass cl) 1773 { 1774 if (cl.isArray()) 1775 return getShortClassName(cl.getComponentType()) + "[]"; 1776 else { 1777 int p = cl.getName().lastIndexOf('.'); 1778 1779 return cl.getName().substring(p + 1); 1780 } 1781 } 1782 1783 1786 boolean classHasMethod(JMethod method, JClass cl) 1787 { 1788 try { 1789 JMethod match = cl.getMethod(method.getName(), 1790 method.getParameterTypes()); 1791 return match != null; 1792 } catch (Exception e) { 1793 return false; 1794 } 1795 } 1796 1797 void validateException(JMethod method, Class e) 1798 throws ConfigException 1799 { 1800 validateException(method, new JClassWrapper(e, _jClassLoader)); 1801 } 1802 1803 void validateException(JMethod method, JClass e) 1804 throws ConfigException 1805 { 1806 validateExceptions(method, new JClass[] { e }); 1807 } 1808 1809 1815 void validateExceptions(JMethod method, JClass []exn) 1816 throws ConfigException 1817 { 1818 JClass []methodExceptions = method.getExceptionTypes(); 1819 1820 loop: 1821 for (int i = 0; i < exn.length; i++) { 1822 if (exn[i].isAssignableTo(RuntimeException .class)) 1823 continue; 1824 1825 for (int j = 0; j < methodExceptions.length; j++) { 1826 if (methodExceptions[j].isAssignableFrom(exn[i])) 1827 continue loop; 1828 } 1829 1830 throw new ConfigException(L.l("{2}: `{0}' must throw {1}.", 1831 getFullMethodName(method), 1832 exn[i].getName(), 1833 method.getDeclaringClass().getName())); 1834 } 1835 } 1836 1837 void validateExceptions(JMethod caller, JMethod callee) 1838 throws ConfigException 1839 { 1840 JClass []exn = callee.getExceptionTypes(); 1841 JClass missing = findMissingException(caller, exn); 1842 1843 if (missing != null) { 1844 throw error(L.l("{0}: `{1}' must throw {2}.", 1845 caller.getDeclaringClass().getName(), 1846 getFullMethodName(caller), 1847 getShortClassName(missing), 1848 caller.getDeclaringClass().getName()) + 1849 L.l(" {0} must throw all {1}.{2} exceptions.", 1850 caller.getName(), 1851 getShortClassName(callee.getDeclaringClass()), 1852 callee.getName())); 1853 } 1854 } 1855 1856 1865 JClass findMissingException(JMethod method, JClass []exn) 1866 throws ConfigException 1867 { 1868 JClass []methodExceptions = method.getExceptionTypes(); 1869 1870 for (int i = 0; i < exn.length; i++) { 1871 if (! hasException(method, exn[i]) && 1872 ! exn[i].isAssignableTo(RuntimeException .class)) 1873 return exn[i]; 1874 } 1875 1876 return null; 1877 } 1878 1879 boolean hasException(JMethod method, JClass exn) 1880 throws ConfigException 1881 { 1882 JClass []methodExceptions = method.getExceptionTypes(); 1883 1884 for (int j = 0; j < methodExceptions.length; j++) { 1885 if (methodExceptions[j].isAssignableFrom(exn)) 1886 return true; 1887 } 1888 1889 return false; 1890 } 1891 1892 boolean hasException(JMethod method, Class exn) 1893 throws ConfigException 1894 { 1895 JClass []methodExceptions = method.getExceptionTypes(); 1896 1897 for (int j = 0; j < methodExceptions.length; j++) { 1898 if (methodExceptions[j].isAssignableFrom(exn)) 1899 return true; 1900 } 1901 1902 return false; 1903 } 1904 1905 1908 public ConfigException error(String msg) 1909 { 1910 return new ConfigException(msg); 1911 } 1912} 1913 | Popular Tags |