0001: /*
0002: * JBoss, Home of Professional Open Source.
0003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004: * as indicated by the @author tags. See the copyright.txt file in the
0005: * distribution for a full listing of individual contributors.
0006: *
0007: * This is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU Lesser General Public License as
0009: * published by the Free Software Foundation; either version 2.1 of
0010: * the License, or (at your option) any later version.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this software; if not, write to the Free
0019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021: */
0022: package org.jboss.ejb3.interceptor;
0023:
0024: import org.jboss.ejb3.EJBContainer;
0025: import org.jboss.ejb3.metamodel.EjbJarDD;
0026: import org.jboss.ejb3.metamodel.Interceptor;
0027: import org.jboss.ejb3.metamodel.InterceptorBinding;
0028: import org.jboss.ejb3.metamodel.Interceptors;
0029: import org.jboss.logging.Logger;
0030:
0031: import javax.annotation.PostConstruct;
0032: import javax.annotation.PreDestroy;
0033: import javax.ejb.CreateException;
0034: import javax.ejb.PostActivate;
0035: import javax.ejb.PrePassivate;
0036: import javax.interceptor.AroundInvoke;
0037: import javax.interceptor.ExcludeClassInterceptors;
0038: import javax.interceptor.ExcludeDefaultInterceptors;
0039: import javax.interceptor.InvocationContext;
0040: import java.lang.annotation.Annotation;
0041: import java.lang.reflect.Method;
0042: import java.lang.reflect.Modifier;
0043: import java.rmi.RemoteException;
0044: import java.util.*;
0045: import java.util.concurrent.ConcurrentHashMap;
0046: import java.util.concurrent.ConcurrentMap;
0047:
0048: /**
0049: * A repository of interceptor details shared amongst all containers in this deployment.
0050: * Interceptors differ from other ejb 3 artifacts in that we can have annotations on the
0051: * interceptor classes which are not the ejb container, so we cannot use annotation overrides
0052: * on the interceptors themselves.<BR/>
0053: * <BR/>
0054: * The xml structures get added on deployment.<BR/>
0055: * Interceptors only declared by using @Interceptors on the bean class get added on demand.<BR/>
0056: *
0057: * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
0058: * @version $Revision: 63298 $
0059: */
0060: public class InterceptorInfoRepository {
0061: private static Logger log = Logger
0062: .getLogger(InterceptorInfoRepository.class);
0063:
0064: private Set<String> beanClasses = new HashSet<String>();
0065:
0066: private Interceptors interceptorsXml;
0067:
0068: private List<InterceptorBinding> bindingsXml;
0069:
0070: private ConcurrentMap<Class, InterceptorInfo> infos = new ConcurrentHashMap<Class, InterceptorInfo>();
0071:
0072: private ConcurrentMap<String, InterceptorInfo> ejbInfos = new ConcurrentHashMap<String, InterceptorInfo>();
0073:
0074: private LinkedHashSet<InterceptorInfo> defaultInterceptors = null;
0075:
0076: private InterceptorSorter sorter = new InterceptorSorter();
0077:
0078: public InterceptorInfoRepository() {
0079: }
0080:
0081: public void initialise(EjbJarDD dd) {
0082: this .interceptorsXml = dd.getInterceptors();
0083:
0084: if (dd.getAssemblyDescriptor() != null) {
0085: this .bindingsXml = dd.getAssemblyDescriptor()
0086: .getInterceptorBindings();
0087: }
0088:
0089: initialiseInfosFromXml();
0090: initialiseDefaultInterceptors();
0091: }
0092:
0093: public void addBeanClass(String classname) {
0094: beanClasses.add(classname);
0095: }
0096:
0097: public InterceptorInfo getInterceptorInfo(Class clazz) {
0098: initialiseInfosFromXml();
0099: return infos.get(clazz);
0100: }
0101:
0102: public HashSet<InterceptorInfo> getDefaultInterceptors() {
0103: return defaultInterceptors;
0104: }
0105:
0106: public boolean hasDefaultInterceptors() {
0107: return defaultInterceptors.size() > 0;
0108: }
0109:
0110: public ArrayList<InterceptorInfo> getClassInterceptors(
0111: EJBContainer container) {
0112: javax.interceptor.Interceptors interceptors = (javax.interceptor.Interceptors) container
0113: .resolveAnnotation(javax.interceptor.Interceptors.class);
0114: ArrayList<InterceptorInfo> infos = getInterceptorsFromAnnotation(
0115: container, interceptors);
0116:
0117: return infos;
0118: }
0119:
0120: public ArrayList<InterceptorInfo> getMethodInterceptors(
0121: EJBContainer container, Method m) {
0122: javax.interceptor.Interceptors interceptors = (javax.interceptor.Interceptors) container
0123: .resolveAnnotation(m,
0124: javax.interceptor.Interceptors.class);
0125: ArrayList<InterceptorInfo> infos = getInterceptorsFromAnnotation(
0126: container, interceptors);
0127:
0128: return infos;
0129: }
0130:
0131: public Method[] getBeanClassAroundInvokes(EJBContainer container) {
0132: return getBeanClassInterceptors(container, AroundInvoke.class);
0133: }
0134:
0135: public Method[] getBeanClassPostConstructs(EJBContainer container) {
0136: return getBeanClassInterceptors(container, PostConstruct.class);
0137: }
0138:
0139: public Method[] getBeanClassPostActivates(EJBContainer container) {
0140: return getBeanClassInterceptors(container, PostActivate.class);
0141: }
0142:
0143: public Method[] getBeanClassPrePassivates(EJBContainer container) {
0144: return getBeanClassInterceptors(container, PrePassivate.class);
0145: }
0146:
0147: public Method[] getBeanClassPreDestroys(EJBContainer container) {
0148: return getBeanClassInterceptors(container, PreDestroy.class);
0149: }
0150:
0151: private Method[] getBeanClassInterceptors(EJBContainer container,
0152: Class type) {
0153: InterceptorInfo info = getOrInitialiseFromAnnotations(container);
0154: return getMethodsForEvent(info, type);
0155: }
0156:
0157: public InterceptorInfo[] getBusinessInterceptors(
0158: EJBContainer container, Method method) {
0159: return getInterceptors(container, AroundInvoke.class, method);
0160: }
0161:
0162: public InterceptorInfo[] getPostConstructInterceptors(
0163: EJBContainer container) {
0164: return getInterceptors(container, PostConstruct.class, null);
0165: }
0166:
0167: public InterceptorInfo[] getPostActivateInterceptors(
0168: EJBContainer container) {
0169: return getInterceptors(container, PostActivate.class, null);
0170: }
0171:
0172: public InterceptorInfo[] getPrePassivateInterceptors(
0173: EJBContainer container) {
0174: return getInterceptors(container, PrePassivate.class, null);
0175: }
0176:
0177: public InterceptorInfo[] getPreDestroyInterceptors(
0178: EJBContainer container) {
0179: return getInterceptors(container, PreDestroy.class, null);
0180: }
0181:
0182: private InterceptorInfo[] getInterceptors(EJBContainer container,
0183: Class type, Method method) {
0184: ArrayList<InterceptorInfo> interceptors = new ArrayList<InterceptorInfo>();
0185:
0186: if (!hasAnnotation(container, ExcludeDefaultInterceptors.class,
0187: method)) {
0188: HashSet<InterceptorInfo> infos = getDefaultInterceptors();
0189: if (infos != null) {
0190: interceptors.addAll(trimUnwanted(infos, type));
0191: }
0192: sorter.sortDefaultInterceptors(container, interceptors);
0193: }
0194:
0195: if (!hasAnnotation(container, ExcludeClassInterceptors.class,
0196: method)) {
0197: List<InterceptorInfo> infos = container
0198: .getClassInterceptors();
0199: if (infos != null) {
0200: interceptors.addAll(trimUnwanted(infos, type));
0201: }
0202:
0203: if (type != AroundInvoke.class) {
0204: List<InterceptorInfo> methodOnlyInterceptors = getMethodOnlyInterceptorsForLifecycle(
0205: container, type, interceptors);
0206: if (infos != null)
0207: interceptors.addAll(methodOnlyInterceptors);
0208: }
0209: sorter.sortClassInterceptors(container, interceptors);
0210: }
0211:
0212: if (type == AroundInvoke.class) {
0213: List<InterceptorInfo> infos = getMethodInterceptors(
0214: container, method);
0215: if (infos != null)
0216: interceptors.addAll(trimUnwanted(infos, type));
0217: sorter.sortMethodInterceptors(container, method,
0218: interceptors);
0219: }
0220:
0221: InterceptorInfo[] ints = interceptors
0222: .toArray(new InterceptorInfo[interceptors.size()]);
0223: return ints;
0224: }
0225:
0226: private List<InterceptorInfo> getMethodOnlyInterceptorsForLifecycle(
0227: EJBContainer container, Class type,
0228: List<InterceptorInfo> infos) {
0229: HashSet<InterceptorInfo> methodLevelInterceptors = (HashSet<InterceptorInfo>) container
0230: .getApplicableInterceptors().clone();
0231:
0232: for (InterceptorInfo info : infos) {
0233: if (methodLevelInterceptors.contains(info)) {
0234: methodLevelInterceptors.remove(info);
0235: }
0236: }
0237:
0238: if (defaultInterceptors != null) {
0239: for (InterceptorInfo info : defaultInterceptors) {
0240: if (methodLevelInterceptors.contains(info)) {
0241: methodLevelInterceptors.remove(info);
0242: }
0243: }
0244: }
0245:
0246: List<InterceptorInfo> trimmedInfos = trimUnwanted(
0247: methodLevelInterceptors, type);
0248: return trimmedInfos;
0249: }
0250:
0251: private boolean hasAnnotation(EJBContainer container,
0252: Class annotation, Method method) {
0253: if (container.resolveAnnotation(annotation) != null) {
0254: return true;
0255: }
0256:
0257: if (method != null) {
0258: return container.resolveAnnotation(method, annotation) != null;
0259: }
0260:
0261: return false;
0262: }
0263:
0264: private List<InterceptorInfo> trimUnwanted(
0265: Collection<InterceptorInfo> interceptors, Class type) {
0266: ArrayList<InterceptorInfo> ints = new ArrayList<InterceptorInfo>(
0267: interceptors.size());
0268: ints.addAll(interceptors);
0269:
0270: for (Iterator<InterceptorInfo> it = ints.iterator(); it
0271: .hasNext();) {
0272: InterceptorInfo info = it.next();
0273: if (!hasMethodsForEvent(info, type)) {
0274: it.remove();
0275: }
0276: }
0277:
0278: return ints;
0279: }
0280:
0281: private boolean hasMethodsForEvent(InterceptorInfo info, Class type) {
0282: return getMethodsForEvent(info, type) != null;
0283: }
0284:
0285: private Method[] getMethodsForEvent(InterceptorInfo info, Class type) {
0286: if (type == AroundInvoke.class)
0287: return info.getAroundInvokes();
0288: else if (type == PostConstruct.class)
0289: return info.getPostConstructs();
0290: else if (type == PostActivate.class)
0291: return info.getPostActivates();
0292: else if (type == PrePassivate.class)
0293: return info.getPrePassivates();
0294: else if (type == PreDestroy.class)
0295: return info.getPreDestroys();
0296: return null;
0297: }
0298:
0299: private ArrayList<InterceptorInfo> getInterceptorsFromAnnotation(
0300: EJBContainer container,
0301: javax.interceptor.Interceptors interceptors) {
0302: ArrayList<InterceptorInfo> inters = new ArrayList<InterceptorInfo>();
0303: if (interceptors == null)
0304: return inters;
0305:
0306: for (Class clazz : interceptors.value()) {
0307: InterceptorInfo info = getOrInitialiseFromAnnotations(clazz);
0308: validateInterceptorForContainer(container, info.getClazz());
0309: inters.add(info);
0310: }
0311:
0312: return inters;
0313: }
0314:
0315: private void validateInterceptorForContainer(
0316: EJBContainer container, Class interceptor) {
0317: if (beanClasses.contains(interceptor.getName())) {
0318: if (!interceptor.equals(container.getClazz())) {
0319: throw new RuntimeException("Bean class "
0320: + interceptor.getName()
0321: + " cannot be used as an interceptor for "
0322: + container.getEjbName());
0323: }
0324: }
0325: }
0326:
0327: private void initialiseInfosFromXml() {
0328: if (interceptorsXml != null) {
0329: //Initialise all interceptor entries so we know which classes we have xml for
0330: HashMap<String, AnnotationInitialiser> initialisers = new HashMap<String, AnnotationInitialiser>();
0331: for (Interceptor xml : interceptorsXml.getInterceptors()) {
0332: XmlInitialiser init = new XmlInitialiser(xml);
0333: initialisers.put(xml.getInterceptorClass(), init);
0334: }
0335:
0336: //Create entries recursively, top classes first so we get the method hierarchies
0337: for (Interceptor xml : interceptorsXml.getInterceptors()) {
0338: String clazz = xml.getInterceptorClass();
0339: initialiseSuperClassesFirstFromXmlOrAnnotations(
0340: initialisers, clazz);
0341: }
0342:
0343: }
0344: }
0345:
0346: private InterceptorInfo initialiseSuperClassesFirstFromXmlOrAnnotations(
0347: HashMap<String, AnnotationInitialiser> initialisers,
0348: String super ClassName) {
0349: if ("java.lang.Object".equals(super ClassName)) {
0350: return null;
0351: }
0352:
0353: AnnotationInitialiser initialiser = initialisers
0354: .get(super ClassName);
0355: if (initialiser == null) {
0356: initialiser = new AnnotationInitialiser(super ClassName,
0357: InterceptorSignatureValidator.instance);
0358: initialisers.put(initialiser.getClazz().getName(),
0359: initialiser);
0360: }
0361: InterceptorInfo super Info = initialiseSuperClassesFirstFromXmlOrAnnotations(
0362: initialisers, initialiser.getClazz().getSuperclass()
0363: .getName());
0364:
0365: InterceptorInfo info = initialiser.getInfo();
0366: info.calculateHierarchy(super Info);
0367: infos.put(info.getClazz(), info);
0368: return info;
0369: }
0370:
0371: /*
0372: * Default interceptors are defined using xml only
0373: */
0374: private void initialiseDefaultInterceptors() {
0375: defaultInterceptors = new LinkedHashSet<InterceptorInfo>();
0376:
0377: if (bindingsXml != null) {
0378: for (InterceptorBinding bindingXml : bindingsXml) {
0379: if (bindingXml.getEjbName().equals("*")
0380: && (bindingXml.getMethodName() == null || bindingXml
0381: .getMethodName().length() == 0)) {
0382: for (String classname : bindingXml
0383: .getInterceptorClasses()) {
0384: if (beanClasses.contains(classname)) {
0385: throw new RuntimeException(
0386: "Bean class defined in default binding "
0387: + classname);
0388: }
0389: InterceptorInfo info = getOrInitialiseFromAnnotations(classname);
0390: defaultInterceptors.add(info);
0391: }
0392: }
0393: }
0394: }
0395: }
0396:
0397: private InterceptorInfo getOrInitialiseFromAnnotations(
0398: String classname) {
0399: Class clazz = loadClass(classname);
0400: return getOrInitialiseFromAnnotations(clazz);
0401: }
0402:
0403: private InterceptorInfo getOrInitialiseFromAnnotations(Class clazz) {
0404: InterceptorInfo info = infos.get(clazz);
0405:
0406: if (info == null) {
0407: synchronized (this ) {
0408: info = infos.get(clazz);
0409: if (info == null) {
0410: info = initialiseFromAnnotations(clazz);
0411: infos.put(clazz, info);
0412: }
0413: }
0414: }
0415:
0416: return info;
0417: }
0418:
0419: private InterceptorInfo initialiseFromAnnotations(Class clazz) {
0420: InterceptorInfo super Info = null;
0421: if (clazz.getSuperclass() != Object.class) {
0422: super Info = getOrInitialiseFromAnnotations(clazz
0423: .getSuperclass());
0424: }
0425:
0426: AnnotationInitialiser init = new AnnotationInitialiser(clazz,
0427: InterceptorSignatureValidator.instance);
0428: InterceptorInfo info = init.getInfo();
0429: info.calculateHierarchy(super Info);
0430: return info;
0431: }
0432:
0433: private InterceptorInfo getOrInitialiseFromAnnotations(
0434: EJBContainer container) {
0435: InterceptorInfo info = ejbInfos.get(container.getEjbName());
0436:
0437: if (info == null) {
0438: synchronized (this ) {
0439: info = ejbInfos.get(container.getEjbName());
0440: if (info == null) {
0441: info = initialiseFromAnnotations(container);
0442: ejbInfos.put(container.getEjbName(), info);
0443: }
0444: }
0445: }
0446:
0447: return info;
0448: }
0449:
0450: private InterceptorInfo initialiseFromAnnotations(
0451: EJBContainer container) {
0452: //Currently I see no way in spec for specifying interceptors of an ejb super class using xml,
0453: //use annotations only to initialise super classes, and don't store these
0454: InterceptorInfo super Info = initialiseContainerSuperClassFromAnnotationsOnly(container
0455: .getClazz().getSuperclass());
0456: AnnotationInitialiser init = new ContainerInitialiser(container);
0457: InterceptorInfo info = init.getInfo();
0458: info.calculateHierarchy(super Info);
0459: return info;
0460: }
0461:
0462: private InterceptorInfo initialiseContainerSuperClassFromAnnotationsOnly(
0463: Class clazz) {
0464: InterceptorInfo super Info = null;
0465: if (clazz != Object.class) {
0466: super Info = initialiseContainerSuperClassFromAnnotationsOnly(clazz
0467: .getSuperclass());
0468: }
0469:
0470: AnnotationInitialiser init = new AnnotationInitialiser(clazz,
0471: BeanSignatureValidator.instance);
0472: InterceptorInfo info = init.getInfo();
0473: info.calculateHierarchy(super Info);
0474: return info;
0475: }
0476:
0477: private Class loadClass(String name) {
0478: try {
0479: return Thread.currentThread().getContextClassLoader()
0480: .loadClass(name);
0481: } catch (Exception e) {
0482: throw new RuntimeException("Interceptor class not found: "
0483: + name);
0484: }
0485: }
0486:
0487: private static boolean checkExceptions(
0488: Class<?> allowedExceptions[], Method method) {
0489: for (Class<?> exception : method.getExceptionTypes()) {
0490: boolean isAllowed = false;
0491: for (Class<?> allowed : allowedExceptions) {
0492: if (allowed.isAssignableFrom(exception))
0493: isAllowed = true;
0494: }
0495: if (!isAllowed) {
0496: log.warn("Illegal exception '" + exception.getName()
0497: + "' in lifecycle signature (EJB3 12.4.2): "
0498: + method);
0499: return false;
0500: }
0501: }
0502: return true;
0503: }
0504:
0505: public static boolean checkValidBusinessSignature(Method method) {
0506: int modifiers = method.getModifiers();
0507:
0508: if (!Modifier.isStatic(modifiers)) {
0509: if (method.getReturnType().equals(Object.class)) {
0510: Class[] params = method.getParameterTypes();
0511: if (params.length == 1
0512: && params[0].equals(InvocationContext.class)) {
0513: Class[] exceptions = method.getExceptionTypes();
0514: if (exceptions.length == 1
0515: && exceptions[0].equals(Exception.class)) {
0516: return true;
0517: }
0518: }
0519: }
0520: }
0521: return false;
0522: }
0523:
0524: public static boolean checkValidLifecycleSignature(Method method) {
0525: int modifiers = method.getModifiers();
0526:
0527: if (!Modifier.isStatic(modifiers)) {
0528: if (method.getReturnType().equals(Void.TYPE)) {
0529: Class[] params = method.getParameterTypes();
0530: if (params.length == 1
0531: && params[0].equals(InvocationContext.class)) {
0532: return true;
0533: }
0534: }
0535: }
0536: return false;
0537: }
0538:
0539: /**
0540: * EJB3 12.4
0541: * Lifecycle methods may throw runtime exceptions, but not application exceptions.
0542: * Note that for 2.1 beans CreateException (on ejbCreate) and RemoteException should pass.
0543: *
0544: * @param method
0545: * @return
0546: */
0547: public static boolean checkValidBeanLifecycleSignature(Method method) {
0548: int modifiers = method.getModifiers();
0549: if (method.getName().equals("ejbCreate")) {
0550: // for public void ejbCreate(...) throws javax.ejb.CreateException
0551: if (!Modifier.isStatic(modifiers)
0552: && method.getReturnType().equals(Void.TYPE)
0553: && method.getExceptionTypes().length <= 1) {
0554: if (!checkExceptions(new Class<?>[] {
0555: RuntimeException.class, CreateException.class,
0556: RemoteException.class }, method))
0557: return false;
0558: return true;
0559: }
0560: } else if (!Modifier.isStatic(modifiers)
0561: && method.getReturnType().equals(Void.TYPE)
0562: && method.getParameterTypes().length == 0) {
0563: if (!checkExceptions(new Class<?>[] {
0564: RuntimeException.class, RemoteException.class },
0565: method))
0566: return false;
0567: return true;
0568: }
0569: return false;
0570: }
0571:
0572: public static String simpleType(Class type) {
0573: Class ret = type;
0574: if (ret.isArray()) {
0575: Class arr = ret;
0576: String array = "";
0577: while (arr.isArray()) {
0578: array += "[]";
0579: arr = arr.getComponentType();
0580: }
0581: return arr.getName() + array;
0582: }
0583: return ret.getName();
0584: }
0585:
0586: private interface SignatureValidator {
0587: boolean checkValidLifecycle(Method m);
0588:
0589: boolean checkValidAround(Method m);
0590: }
0591:
0592: private static class InterceptorSignatureValidator implements
0593: SignatureValidator {
0594: static SignatureValidator instance = new InterceptorSignatureValidator();
0595:
0596: public boolean checkValidAround(Method m) {
0597: return checkValidBusinessSignature(m);
0598: }
0599:
0600: public boolean checkValidLifecycle(Method m) {
0601: return checkValidLifecycleSignature(m);
0602: }
0603: }
0604:
0605: private static class BeanSignatureValidator implements
0606: SignatureValidator {
0607: static SignatureValidator instance = new BeanSignatureValidator();
0608:
0609: public boolean checkValidAround(Method m) {
0610: return checkValidBusinessSignature(m);
0611: }
0612:
0613: public boolean checkValidLifecycle(Method m) {
0614: return checkValidBeanLifecycleSignature(m);
0615: }
0616: }
0617:
0618: private class AnnotationInitialiser {
0619: SignatureValidator signatureValidator;
0620: Class clazz;
0621:
0622: InterceptorInfo info;
0623:
0624: AnnotationInitialiser(String classname,
0625: SignatureValidator signatureValidator) {
0626: clazz = loadClass(classname);
0627: this .signatureValidator = signatureValidator;
0628: info = new InterceptorInfo(clazz);
0629: }
0630:
0631: AnnotationInitialiser(Class clazz,
0632: SignatureValidator signatureValidator) {
0633: this .clazz = clazz;
0634: this .signatureValidator = signatureValidator;
0635: info = new InterceptorInfo(clazz);
0636: }
0637:
0638: public Class getClazz() {
0639: return clazz;
0640: }
0641:
0642: InterceptorInfo getInfo() {
0643: for (Method method : clazz.getDeclaredMethods()) {
0644: info.setAroundInvoke(resolveAroundInvoke(method));
0645: info.setPostConstruct(resolvePostConstruct(method));
0646: info.setPostActivate(resolvePostActivate(method));
0647: info.setPreDestroy(resolvePreDestroy(method));
0648: info.setPrePassivate(resolvePrePassivate(method));
0649: }
0650: return info;
0651: }
0652:
0653: Method resolveAroundInvoke(Method method) {
0654: AroundInvoke ann = (AroundInvoke) getAnnotation(method,
0655: AroundInvoke.class);
0656: if (ann != null) {
0657: if (!signatureValidator.checkValidAround(method)) {
0658: throw new RuntimeException(
0659: "@"
0660: + ((Annotation) ann)
0661: .annotationType().getName()
0662: + " annotated method in has the wrong signature - "
0663: + method);
0664: }
0665: return method;
0666: }
0667: return null;
0668: }
0669:
0670: Method resolvePostConstruct(Method method) {
0671: PostConstruct ann = (PostConstruct) getAnnotation(method,
0672: PostConstruct.class);
0673: return resolveLifecycleMethod(method, ann);
0674: }
0675:
0676: Method resolvePostActivate(Method method) {
0677: PostActivate ann = (PostActivate) getAnnotation(method,
0678: PostActivate.class);
0679: return resolveLifecycleMethod(method, ann);
0680: }
0681:
0682: Method resolvePreDestroy(Method method) {
0683: PreDestroy ann = (PreDestroy) getAnnotation(method,
0684: PreDestroy.class);
0685: return resolveLifecycleMethod(method, ann);
0686: }
0687:
0688: Method resolvePrePassivate(Method method) {
0689: PrePassivate ann = (PrePassivate) getAnnotation(method,
0690: PrePassivate.class);
0691: return resolveLifecycleMethod(method, ann);
0692: }
0693:
0694: Method resolveLifecycleMethod(Method method, Annotation ann) {
0695: if (ann != null) {
0696: if (!signatureValidator.checkValidLifecycle(method)) {
0697: throw new RuntimeException(
0698: "@"
0699: + ((Annotation) ann)
0700: .annotationType().getName()
0701: + " annotated method has the wrong signature - "
0702: + method);
0703: }
0704: return method;
0705: }
0706: return null;
0707: }
0708:
0709: Object getAnnotation(Method method, Class annotation) {
0710: return method.getAnnotation(annotation);
0711: }
0712:
0713: }
0714:
0715: private class ContainerInitialiser extends AnnotationInitialiser {
0716: EJBContainer container;
0717:
0718: public ContainerInitialiser(EJBContainer container) {
0719: // FIXME ContainerInitialiser constructor
0720: super (container.getBeanClass(),
0721: BeanSignatureValidator.instance);
0722: this .container = container;
0723: }
0724:
0725: Object getAnnotation(Method method, Class annotation) {
0726: return container.resolveAnnotation(method, annotation);
0727: }
0728:
0729: /*
0730: * Lifecycle methods on bean class have a different signature from those defined on
0731: *
0732: */
0733: Method resolveLifecycleMethod(Method method, Annotation ann) {
0734: if (ann != null) {
0735: if (!signatureValidator.checkValidLifecycle(method)) {
0736: throw new RuntimeException(
0737: "@"
0738: + ann.annotationType().getName()
0739: + " annotated method has the wrong signature - "
0740: + method);
0741: }
0742: return method;
0743: }
0744: return null;
0745: }
0746: }
0747:
0748: private class XmlInitialiser extends AnnotationInitialiser {
0749: Interceptor xml;
0750:
0751: XmlInitialiser(Interceptor xml) {
0752: super (xml.getInterceptorClass(),
0753: InterceptorSignatureValidator.instance);
0754: this .xml = xml;
0755: }
0756:
0757: InterceptorInfo getInfo() {
0758: info.setAroundInvoke(findInterceptorMethodFromXml(clazz,
0759: "around-invoke-method", xml.getAroundInvoke()));
0760: info.setPostConstruct(findInterceptorMethodFromXml(clazz,
0761: "post-construct-method", xml.getPostConstruct()));
0762: info.setPostActivate(findInterceptorMethodFromXml(clazz,
0763: "post-activate-method", xml.getPostActivate()));
0764: info.setPreDestroy(findInterceptorMethodFromXml(clazz,
0765: "pre-destroy-method", xml.getPreDestroy()));
0766: info.setPrePassivate(findInterceptorMethodFromXml(clazz,
0767: "pre-passivate-method", xml.getPrePassivate()));
0768: super .getInfo();
0769: info.setXml(xml);
0770: return info;
0771: }
0772:
0773: java.lang.reflect.Method findInterceptorMethodFromXml(
0774: Class clazz, String lookingFor,
0775: org.jboss.ejb3.metamodel.Method xml) {
0776: if (xml == null)
0777: return null;
0778: if (xml.getMethodName() == null
0779: || xml.getMethodName().trim().equals("")) {
0780: throw new RuntimeException(
0781: lookingFor
0782: + " must contain a valid method name for interceptor "
0783: + clazz.getName());
0784: }
0785: if (xml.getMethodParams() != null) {
0786: log.debug("Ignoring method parameters for "
0787: + lookingFor + " in interceptor "
0788: + clazz.getName());
0789: }
0790:
0791: ArrayList<Method> possible = new ArrayList<Method>();
0792: for (java.lang.reflect.Method method : clazz
0793: .getDeclaredMethods()) {
0794: if (xml.getMethodName().equals(method.getName())) {
0795: possible.add(method);
0796: }
0797: }
0798:
0799: if (possible.size() == 0) {
0800: throw new RuntimeException(
0801: lookingFor
0802: + " must contain a valid method name for interceptor "
0803: + clazz.getName());
0804: }
0805:
0806: Method found = null;
0807:
0808: for (Method method : possible) {
0809: if (lookingFor.equals("around-invoke-method")) {
0810: if (signatureValidator.checkValidAround(method)) {
0811: found = method;
0812: }
0813: } else {
0814: if (signatureValidator.checkValidLifecycle(method)) {
0815: found = method;
0816: }
0817: }
0818: }
0819:
0820: if (found == null) {
0821: throw new RuntimeException(
0822: lookingFor
0823: + " has the wrong method signature for interceptor "
0824: + clazz.getName());
0825: }
0826:
0827: return found;
0828: }
0829: }
0830:
0831: private class InterceptorSorter {
0832: boolean initialised;
0833: List<InterceptorBinding> orderedBindings;
0834:
0835: private void initialise() {
0836: if (!initialised) {
0837: synchronized (this ) {
0838: if (bindingsXml != null) {
0839: for (InterceptorBinding binding : bindingsXml) {
0840: if (binding.isOrdered()) {
0841: //Validate each interceptor only occurs once
0842: HashSet<String> names = new HashSet<String>();
0843: for (Iterator it = binding
0844: .getInterceptorClasses()
0845: .iterator(); it.hasNext();) {
0846: String className = (String) it
0847: .next();
0848: if (names.contains(className)) {
0849: throw new RuntimeException(
0850: className
0851: + " occurs more than once in ordered binding "
0852: + getInterceptorBindingString(binding));
0853: }
0854: names.add(className);
0855: }
0856:
0857: if (orderedBindings == null) {
0858: orderedBindings = new ArrayList<InterceptorBinding>();
0859: }
0860: orderedBindings.add(binding);
0861: }
0862: }
0863: }
0864: }
0865: log.trace("orderedBindings = " + orderedBindings);
0866: initialised = true;
0867: }
0868: }
0869:
0870: void sortDefaultInterceptors(EJBContainer container,
0871: ArrayList<InterceptorInfo> infos) {
0872: initialise();
0873: if (orderedBindings == null)
0874: return;
0875: ArrayList<String> bindingOrder = null;
0876: for (InterceptorBinding binding : orderedBindings) {
0877: if (binding.getEjbName().equals("*")) {
0878: if (bindingOrder != null) {
0879: throw new RuntimeException(
0880: "There should only be one interceptor-binding specifying "
0881: + "the order of default interceptors "
0882: + getInterceptorBindingString(binding));
0883: }
0884: bindingOrder = binding.getInterceptorClasses();
0885: }
0886: }
0887: sortInterceptors(infos, bindingOrder);
0888: }
0889:
0890: void sortClassInterceptors(EJBContainer container,
0891: ArrayList<InterceptorInfo> infos) {
0892: initialise();
0893: if (orderedBindings == null)
0894: return;
0895: ArrayList<String> bindingOrder = null;
0896: for (InterceptorBinding binding : orderedBindings) {
0897: if (binding.getMethodName() != null
0898: && binding.getMethodName().trim().length() > 0) {
0899: continue;
0900: }
0901: if (binding.getEjbName().equals(container.getEjbName())) {
0902: if (bindingOrder != null) {
0903: throw new RuntimeException(
0904: "There should only be one interceptor-binding specifying "
0905: + "the order of class interceptors: "
0906: + getInterceptorBindingString(binding));
0907: }
0908: bindingOrder = binding.getInterceptorClasses();
0909: }
0910: }
0911: sortInterceptors(infos, bindingOrder);
0912: }
0913:
0914: void sortMethodInterceptors(EJBContainer container,
0915: Method method, ArrayList<InterceptorInfo> infos) {
0916: initialise();
0917: if (orderedBindings == null)
0918: return;
0919: ArrayList<String> methodNoParamsOrder = null;
0920: ArrayList<String> methodParamsOrder = null;
0921: for (InterceptorBinding binding : orderedBindings) {
0922: if (binding.getEjbName().equals(container.getEjbName())) {
0923: if (binding.getMethodName() != null
0924: && binding.getMethodName().equals(
0925: method.getName())) {
0926: if (binding.getMethodParams() == null) {
0927: if (methodNoParamsOrder != null) {
0928: throw new RuntimeException(
0929: "There should only be one interceptor-binding specifying "
0930: + "the order of method interceptors: "
0931: + getInterceptorBindingString(binding));
0932: }
0933: methodNoParamsOrder = binding
0934: .getInterceptorClasses();
0935: } else {
0936: Class[] params = method.getParameterTypes();
0937: List<String> methodParams = binding
0938: .getMethodParams();
0939: if (methodParams.size() == params.length) {
0940: boolean matches = true;
0941: for (int i = 0; i < params.length; i++) {
0942: if (!simpleType(params[i]).equals(
0943: methodParams.get(i))) {
0944: matches = false;
0945: break;
0946: }
0947: }
0948:
0949: if (matches) {
0950: if (methodParamsOrder != null) {
0951: boolean first = false;
0952: StringBuffer paramBuf = new StringBuffer();
0953: paramBuf.append("(");
0954: for (String par : methodParams) {
0955: if (!first)
0956: paramBuf.append(",");
0957: paramBuf.append(par);
0958: }
0959: paramBuf.append(")");
0960: throw new RuntimeException(
0961: "There should only be one interceptor-binding specifying "
0962: + "the order of method interceptors: "
0963: + getInterceptorBindingString(binding));
0964: }
0965:
0966: methodParamsOrder = binding
0967: .getInterceptorClasses();
0968: }
0969: }
0970: }
0971: }
0972: }
0973: }
0974:
0975: if (methodParamsOrder != null) {
0976: sortInterceptors(infos, methodParamsOrder);
0977:
0978: } else {
0979: sortInterceptors(infos, methodNoParamsOrder);
0980: }
0981: }
0982:
0983: void sortInterceptors(ArrayList<InterceptorInfo> infos,
0984: ArrayList<String> interceptorOrder) {
0985: if (interceptorOrder == null)
0986: return;
0987: Collections.sort(infos, new InterceptorComparator(
0988: interceptorOrder));
0989: }
0990:
0991: String getInterceptorBindingString(InterceptorBinding binding) {
0992: StringBuffer buf = new StringBuffer();
0993: List methodParams = binding.getMethodParams();
0994:
0995: buf.append(binding.getEjbName());
0996: if (binding.getMethodName() != null) {
0997: buf.append("." + binding.getMethodName());
0998: if (methodParams != null) {
0999: buf.append("(");
1000: for (int i = 0; i < methodParams.size();) {
1001: if (i == 0)
1002: buf.append(",");
1003: buf.append((String) methodParams.get(i));
1004: }
1005: buf.append(")");
1006: }
1007: }
1008:
1009: return buf.toString();
1010: }
1011: }
1012:
1013: private class InterceptorComparator implements
1014: Comparator<InterceptorInfo> {
1015: ArrayList<String> ordered;
1016:
1017: InterceptorComparator(ArrayList<String> ordered) {
1018: this .ordered = ordered;
1019: }
1020:
1021: public int compare(InterceptorInfo o1, InterceptorInfo o2) {
1022: int pos1 = ordered.indexOf(o1.getClazz().getName());
1023: int pos2 = ordered.indexOf(o2.getClazz().getName());
1024:
1025: //Make anything not specified in the order come last
1026: if (pos1 < 0)
1027: pos1 = Integer.MAX_VALUE;
1028: if (pos2 < 0)
1029: pos2 = Integer.MAX_VALUE;
1030:
1031: if (pos1 < pos2) {
1032: return -1;
1033: } else if (pos1 > pos2) {
1034: return 1;
1035: } else {
1036: return 0;
1037: }
1038: }
1039:
1040: }
1041:
1042: }
|