Package org.apache.openejb.config.rules

Source Code of org.apache.openejb.config.rules.CheckCallbacks

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.config.rules;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import javax.ejb.AfterBegin;
import javax.ejb.AfterCompletion;
import javax.ejb.BeforeCompletion;
import javax.ejb.Init;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Remove;
import javax.ejb.SessionSynchronization;
import javax.ejb.Timeout;
import javax.interceptor.InvocationContext;

import org.apache.openejb.OpenEJBException;
import org.apache.openejb.config.EjbModule;
import org.apache.openejb.jee.AroundInvoke;
import org.apache.openejb.jee.AroundTimeout;
import org.apache.openejb.jee.CallbackMethod;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.InitMethod;
import org.apache.openejb.jee.Interceptor;
import org.apache.openejb.jee.Invokable;
import org.apache.openejb.jee.LifecycleCallback;
import org.apache.openejb.jee.NamedMethod;
import org.apache.openejb.jee.RemoveMethod;
import org.apache.openejb.jee.Session;
import org.apache.openejb.jee.SessionBean;
import org.apache.openejb.jee.SessionType;
import org.apache.openejb.jee.Timer;
import org.apache.openejb.jee.TimerConsumer;
import org.apache.openejb.util.Join;
import org.apache.xbean.finder.ClassFinder;

/**
* @version $Rev: 1153797 $ $Date: 2011-08-04 02:09:44 -0700 (Thu, 04 Aug 2011) $
*/
public class CheckCallbacks extends ValidationBase {

    public void validate(EjbModule module) {
        for (EnterpriseBean bean : module.getEjbJar().getEnterpriseBeans()) {
            Class ejbClass = null;
            try {
                ejbClass = loadClass(bean.getEjbClass());
            } catch (OpenEJBException e) {
                continue;
            }

            if (bean instanceof Invokable) {
                Invokable invokable = (Invokable) bean;
               
                for (AroundInvoke aroundInvoke : invokable.getAroundInvoke()) {
                    checkAroundInvoke(ejbClass, aroundInvoke, bean.getEjbName());
                }
               
                for (AroundTimeout aroundTimeout : invokable.getAroundTimeout()) {
                    checkAroundTimeout(ejbClass, aroundTimeout, bean.getEjbName());
                }
            }

            for (LifecycleCallback callback : bean.getPostConstruct()) {
                checkCallback(ejbClass, "PostConstruct", callback, bean);
            }

            for (LifecycleCallback callback : bean.getPreDestroy()) {
                checkCallback(ejbClass, "PreDestroy", callback, bean);
            }

            ClassFinder finder = new ClassFinder(ejbClass);

            if (bean instanceof Session ) {
                SessionBean session = (SessionBean) bean;

                if (session.getSessionType() == SessionType.STATEFUL ) {

                    for (LifecycleCallback callback : session.getPrePassivate()) {
                        checkCallback(ejbClass, "PrePassivate", callback, bean);
                    }

                    for (LifecycleCallback callback : session.getPostActivate()) {
                        checkCallback(ejbClass, "PostActivate", callback, bean);
                    }

                    checkSessionSynchronization(ejbClass, session);

                    for (LifecycleCallback callback : session.getAfterBegin()) {
                        checkCallback(ejbClass, "AfterBegin", callback, bean);
                    }

                    for (LifecycleCallback callback : session.getBeforeCompletion()) {
                        checkCallback(ejbClass, "BeforeCompletion", callback, bean);
                    }

                    for (LifecycleCallback callback : session.getAfterCompletion()) {
                        checkCallback(ejbClass, "AfterCompletion", callback, bean, boolean.class);
                    }
//                    for (LifecycleCallback callback : session.getAfterCompletion()) {
//                        checkCallback(ejbClass, "Init", callback, bean, boolean.class);
//                    }

                    for (AroundTimeout aroundTimeout : session.getAroundTimeout()) {
                        ignoredMethodAnnotation("AroundTimeout", bean, bean.getEjbClass(), aroundTimeout.getMethodName(), SessionType.STATEFUL.getName());
                    }

                    for (Timer timer : session.getTimer()) {
                        ignoredMethodAnnotation("Schedule/Schedules", bean, bean.getEjbClass(), timer.getTimeoutMethod().getMethodName(), SessionType.STATEFUL.getName());
                    }

                } else {

                    for (LifecycleCallback callback : session.getAfterBegin()) {
                        ignoredMethodAnnotation("AfterBegin", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
                    }

                    for (LifecycleCallback callback : session.getBeforeCompletion()) {
                        ignoredMethodAnnotation("BeforeCompletion", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
                    }

                    for (LifecycleCallback callback : session.getAfterCompletion()) {
                        ignoredMethodAnnotation("AfterCompletion", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
                    }

                    for (LifecycleCallback callback : session.getPrePassivate()) {
                        ignoredMethodAnnotation("PrePassivate", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
                    }

                    for (LifecycleCallback callback : session.getPostActivate()) {
                        ignoredMethodAnnotation("PostActivate", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
                    }

                    for (RemoveMethod method : session.getRemoveMethod()) {
                        ignoredMethodAnnotation("Remove", bean, bean.getEjbClass(), method.getBeanMethod().getMethodName(), session.getSessionType().getName());
                    }

                    for (InitMethod method : session.getInitMethod()) {
                        ignoredMethodAnnotation("Init", bean, bean.getEjbClass(), method.getBeanMethod().getMethodName(), session.getSessionType().getName());
                    }
                }
            } else {

                for (Method method : finder.findAnnotatedMethods(PrePassivate.class)) {
                    ignoredMethodAnnotation("PrePassivate", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(PostActivate.class)) {
                    ignoredMethodAnnotation("PostActivate", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(Remove.class)) {
                    ignoredMethodAnnotation("Remove", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(Init.class)) {
                    ignoredMethodAnnotation("Init", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(AfterBegin.class)) {
                    ignoredMethodAnnotation("AfterBegin", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(BeforeCompletion.class)) {
                    ignoredMethodAnnotation("BeforeCompletion", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }

                for (Method method : finder.findAnnotatedMethods(AfterCompletion.class)) {
                    ignoredMethodAnnotation("AfterCompletion", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
                }
            }

//            if (bean instanceof TimerConsumer) {
//                TimerConsumer timerConsumer = (TimerConsumer) bean;
//                checkTimeOut(ejbClass, timerConsumer.getTimeoutMethod(), bean);
//
//                List<Method> timeoutMethods = finder.findAnnotatedMethods(Timeout.class);
//                if (timeoutMethods.size() > 1) {
//                    fail(timerConsumer.getTimerConsumerName(), "timeout.tooManyMethods", timeoutMethods.size(), Join.join(",", timeoutMethods));
//                }
//
//                for(Timer timer : ((TimerConsumer) bean).getTimer()) {
//                    checkTimeOut(ejbClass, timer.getTimeoutMethod(), bean);
//                }
//            }
        }

        for (Interceptor interceptor : module.getEjbJar().getInterceptors()) {
            Class interceptorClass = null;
            try {
                interceptorClass = loadClass(interceptor.getInterceptorClass());
            } catch (OpenEJBException e) {
                continue;
            }

            for (AroundInvoke aroundInvoke : interceptor.getAroundInvoke()) {
                checkAroundInvoke(interceptorClass, aroundInvoke, "Interceptor");
            }

            for (AroundTimeout aroundTimeout : interceptor.getAroundTimeout()) {
                checkAroundTimeout(interceptorClass, aroundTimeout, "Interceptor");
            }

            for (LifecycleCallback callback : interceptor.getPostConstruct()) {
                checkCallback(interceptorClass, "PostConstruct", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getPreDestroy()) {
                checkCallback(interceptorClass, "PreDestroy", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getPrePassivate()) {
                checkCallback(interceptorClass, "PrePassivate", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getPostActivate()) {
                checkCallback(interceptorClass, "PostActivate", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getAfterBegin()) {
                checkCallback(interceptorClass, "AfterBegin", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getBeforeCompletion()) {
                checkCallback(interceptorClass, "BeforeCompletion", callback, interceptor);
            }

            for (LifecycleCallback callback : interceptor.getAfterCompletion()) {
                checkCallback(interceptorClass, "AfterCompletion", callback, interceptor);
            }
        }
    }

    private void checkAroundTypeInvoke(String aroundType, Class ejbClass, String declaringClassName, String declaringMethodName, String componentName) {
        try {
            Class<?> declaringClass = null;
            try {
                declaringClass = declaringClassName == null ? ejbClass : loadClass(declaringClassName);
            } catch (OpenEJBException e) {
                fail(componentName, "missing.class", declaringClassName, aroundType, ejbClass.getName());
                return;
            }
            Method method = getMethod(declaringClass, declaringMethodName, InvocationContext.class);

            Class<?> returnType = method.getReturnType();

            if (!returnType.equals(Object.class)) {
                fail(componentName, "aroundInvoke.badReturnType", aroundType, declaringMethodName, returnType.getName(), declaringClassName);
            }

            boolean throwsException = false;
            for (Class<?> exceptionType : method.getExceptionTypes()) {
                if (exceptionType.getName().equals(Exception.class.getName())) {
                    throwsException = true;
                }
            }

            if (!throwsException) {
                fail(componentName, "aroundInvoke.mustThrowException", aroundType, declaringMethodName, declaringClassName);
            }

        } catch (NoSuchMethodException e) {
            List<Method> possibleMethods = getMethods(ejbClass, declaringMethodName);

            if (possibleMethods.size() == 0) {
                fail(componentName, "aroundInvoke.missing", aroundType, declaringMethodName, declaringClassName);
            } else if (possibleMethods.size() == 1) {
                fail(componentName, "aroundInvoke.invalidArguments", aroundType, declaringMethodName, getParameters(possibleMethods.get(0)), declaringClassName);
                Class<?> returnType = possibleMethods.get(0).getReturnType();
                if (!returnType.equals(Object.class)) {
                    fail(componentName, "aroundInvoke.badReturnType", aroundType, declaringMethodName, returnType.getName(), declaringClassName);
                }
            } else {
                fail(componentName, "aroundInvoke.missing.possibleTypo", aroundType, declaringMethodName, possibleMethods.size(), declaringClassName);
            }
        }
    }

    private void checkAroundInvoke(Class<?> ejbClass, AroundInvoke aroundInvoke, String componentName) {
        checkAroundTypeInvoke("AroundInvoke", ejbClass, aroundInvoke.getClassName(), aroundInvoke.getMethodName(), componentName);
    }

    private void checkAroundTimeout(Class<?> ejbClass, AroundTimeout aroundTimeout, String componentName) {
        checkAroundTypeInvoke("AroundTimeout", ejbClass, aroundTimeout.getClassName(), aroundTimeout.getMethodName(), componentName);
    }

    private void checkCallback(Class<?> ejbClass, String type, CallbackMethod callback, EnterpriseBean bean, Class... parameterTypes) {
        try {
            Class<?> delcaringClass = null;
            try {
                delcaringClass = callback.getClassName() == null ? ejbClass : loadClass(callback.getClassName());
            } catch (OpenEJBException e) {
                fail(type, "missing.class", callback.getClassName(), type, bean.getEjbName());
                return;
            }
            Method method = getMethod(delcaringClass, callback.getMethodName(), parameterTypes);
            if (implementsSessionBean(delcaringClass)) {
                SessionBean sb = (SessionBean) bean;
                if ("PreDestroy".equals(type)) {
                    if (!callback.getMethodName().equals("ejbRemove"))
                        fail(bean.getEjbName(), "callback.sessionbean.invalidusage", type, callback.getMethodName(), ejbClass);
                } else if ("PostActivate".equals(type)) {
                    if (!callback.getMethodName().equals("ejbActivate"))
                        fail(bean.getEjbName(), "callback.sessionbean.invalidusage", type, callback.getMethodName(), ejbClass);
                } else if ("PrePassivate".equals(type)) {
                    if (!callback.getMethodName().equals("ejbPassivate"))
                        fail(bean.getEjbName(), "callback.sessionbean.invalidusage", type, callback.getMethodName(), ejbClass);
                } else if ("PostConstruct".equals(type)) {

                    if (!callback.getMethodName().equals("ejbCreate")) {
                        fail(bean.getEjbName(), "callback.sessionbean.invalidusage", type, callback.getMethodName(), ejbClass);
                    }

                }
                // @AfterCompletion, @BeforeCompletion and @AfterBegin are assumed to be allowed to be used on Stateful bean implementing javax.ejb.SessionBean
            }
            Class<?> returnType = method.getReturnType();

            if (!returnType.equals(Void.TYPE)) {
                fail(bean, "callback.badReturnType", type, callback.getMethodName(), returnType.getName(), callback.getClassName());
            }

            int methodModifiers = method.getModifiers();
            if (Modifier.isFinal(methodModifiers) || Modifier.isStatic(methodModifiers)) {
                fail(bean, "callback.badModifier", type, callback.getMethodName(), callback.getClassName());
            }
        } catch (NoSuchMethodException e) {
            List<Method> possibleMethods = getMethods(ejbClass, callback.getMethodName());

            if (possibleMethods.size() == 0) {
                fail(bean, "callback.missing", type, callback.getMethodName(), callback.getClassName());
            } else if (possibleMethods.size() == 1) {
                fail(bean, "callback.invalidArguments", type, callback.getMethodName(), getParameters(possibleMethods.get(0)), callback.getClassName(), getParameters(parameterTypes));
            } else {
                fail(bean, "callback.missing.possibleTypo", type, callback.getMethodName(), possibleMethods.size(), callback.getClassName(), getParameters(parameterTypes));
            }
        }
    }

    private boolean implementsSessionBean(Class<?> ejbClass) {
        Class<?>[] interfaces = ejbClass.getInterfaces();
        for (Class<?> interfce : interfaces) {
            if(interfce.equals(javax.ejb.SessionBean.class))
                return true;
        }
        return false;
    }

    private void checkCallback(Class interceptorClass, String type, CallbackMethod callback, Interceptor interceptor) {
        try {
            Class<?> delcaringClass = null;
            try {
                delcaringClass = callback.getClassName() == null ? interceptorClass : loadClass(callback.getClassName());
            } catch (OpenEJBException e) {
                fail(type, "missing.class", callback.getClassName(), type, interceptor.getInterceptorClass());
                return;
            }
            Method method = getMethod(delcaringClass, callback.getMethodName(), InvocationContext.class);

            Class<?> returnType = method.getReturnType();

            if (!returnType.equals(Void.TYPE)) {
                fail("Interceptor", "interceptor.callback.badReturnType", interceptorClass, type, callback.getMethodName(), returnType.getName());
            }
        } catch (NoSuchMethodException e) {
            List<Method> possibleMethods = getMethods(interceptorClass, callback.getMethodName());

            if (possibleMethods.size() == 0) {
                fail("Interceptor", "interceptor.callback.missing", type, callback.getMethodName(), interceptorClass.getName());
            } else if (possibleMethods.size() == 1) {
                fail("Interceptor", "interceptor.callback.invalidArguments", type, callback.getMethodName(), getParameters(possibleMethods.get(0)), interceptorClass.getName());
                Class<?> returnType = possibleMethods.get(0).getReturnType();

                if (!returnType.equals(Void.TYPE)) {
                    fail("Interceptor", "interceptor.callback.badReturnType", interceptorClass, type, callback.getMethodName(), returnType.getName());
                }
            } else {
                fail("Interceptor", "interceptor.callback.missing.possibleTypo", type, callback.getMethodName(), possibleMethods.size(), interceptorClass.getName());
            }
        }
    }

    private void checkSessionSynchronization(Class ejbClass, SessionBean bean) {
        if (SessionSynchronization.class.isAssignableFrom(ejbClass)) {
            if (bean.getAfterBeginMethod() != null || bean.getBeforeCompletionMethod() != null || bean.getAfterCompletionMethod() != null) {
                fail(bean, "callback.sessionSynchronization.invalidUse", ejbClass.getName());
            } else {
                ClassFinder classFinder = new ClassFinder(ejbClass);
                if (classFinder.findAnnotatedMethods(AfterBegin.class).size() > 0 || classFinder.findAnnotatedMethods(BeforeCompletion.class).size() > 0
                        || classFinder.findAnnotatedMethods(AfterCompletion.class).size() > 0) {
                    fail(bean, "callback.sessionSynchronization.invalidUse", ejbClass.getName());
                }
            }
        }
    }

    private void checkTimeOut(Class<?> ejbClass, NamedMethod timeout, EnterpriseBean bean) {
        if (timeout == null) return;
        try {
            Class<?>[] parameterClasses;
            if (timeout.getMethodParams() == null) {
                parameterClasses = new Class[0];
            } else {
                List<String> methodParams = timeout.getMethodParams().getMethodParam();
                parameterClasses = new Class[methodParams.size()];
                for (int i = 0; i < methodParams.size(); i++) {
                    parameterClasses[i] = loadClass(methodParams.get(i));
                }
            }
            Method method = getMethod(ejbClass, timeout.getMethodName(), parameterClasses);
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 0 && (parameterTypes.length != 1 || parameterTypes[0] != javax.ejb.Timer.class)) {
                fail(bean, "timeout.invalidArguments", timeout.getMethodName(), Join.join(",", Join.CLASS_CALLBACK, parameterClasses));
            }
            Class<?> returnType = method.getReturnType();
            if (!returnType.equals(Void.TYPE)) {
                fail(bean, "timeout.badReturnType", timeout.getMethodName(), returnType.getName());
            }
        } catch (NoSuchMethodException e) {
            List<Method> possibleMethods = getMethods(ejbClass, timeout.getMethodName());

            if (possibleMethods.size() == 0) {
                fail(bean, "timeout.missing", timeout.getMethodName());
            } else {
                fail(bean, "timeout.missing.possibleTypo", timeout.getMethodName(), possibleMethods.size());
            }
        } catch(OpenEJBException e){
            //ignore ? Could not load the class of the parameter
        }
    }

    private Method getMethod(Class clazz, String methodName, Class... parameterTypes) throws NoSuchMethodException {
        NoSuchMethodException original = null;
        while (clazz != null){
            try {
                return clazz.getDeclaredMethod(methodName, parameterTypes);
            } catch (NoSuchMethodException e) {
                if (original == null) original = e;
            }
            clazz = clazz.getSuperclass();
        }
        throw original;
    }

    private List<Method> getMethods(Class clazz, String methodName) {
        List<Method> methods = new ArrayList<Method>();
        while (clazz != null){
            for (Method method : clazz.getDeclaredMethods()) {
                if (method.getName().equals(methodName)){
                    methods.add(method);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return methods;
    }

}
TOP

Related Classes of org.apache.openejb.config.rules.CheckCallbacks

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.