org.apache.openejb.config.rules.CheckCallbacks Maven / Gradle / Ivy
/*
* 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 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.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.xbean.finder.ClassFinder;
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.interceptor.InvocationContext;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* @version $Rev$ $Date$
*/
public class CheckCallbacks extends ValidationBase {
@Override
public void validate(final EjbModule module) {
for (final EnterpriseBean bean : module.getEjbJar().getEnterpriseBeans()) {
final Class ejbClass;
try {
ejbClass = loadClass(bean.getEjbClass());
} catch (final OpenEJBException e) {
continue;
}
if (bean instanceof Invokable) {
final Invokable invokable = (Invokable) bean;
for (final AroundInvoke aroundInvoke : invokable.getAroundInvoke()) {
checkAroundInvoke(ejbClass, aroundInvoke, bean.getEjbName());
}
for (final AroundTimeout aroundTimeout : invokable.getAroundTimeout()) {
checkAroundTimeout(ejbClass, aroundTimeout, bean.getEjbName());
}
}
for (final LifecycleCallback callback : bean.getPostConstruct()) {
checkCallback(ejbClass, "PostConstruct", callback, bean);
}
for (final LifecycleCallback callback : bean.getPreDestroy()) {
checkCallback(ejbClass, "PreDestroy", callback, bean);
}
final ClassFinder finder = new ClassFinder(ejbClass);
if (bean instanceof Session) {
final SessionBean session = (SessionBean) bean;
if (session.getSessionType() == SessionType.STATEFUL) {
for (final LifecycleCallback callback : session.getPrePassivate()) {
checkCallback(ejbClass, "PrePassivate", callback, bean);
}
for (final LifecycleCallback callback : session.getPostActivate()) {
checkCallback(ejbClass, "PostActivate", callback, bean);
}
checkSessionSynchronization(ejbClass, session);
for (final LifecycleCallback callback : session.getAfterBegin()) {
checkCallback(ejbClass, "AfterBegin", callback, bean);
}
for (final LifecycleCallback callback : session.getBeforeCompletion()) {
checkCallback(ejbClass, "BeforeCompletion", callback, bean);
}
for (final LifecycleCallback callback : session.getAfterCompletion()) {
checkCallback(ejbClass, "AfterCompletion", callback, bean, boolean.class);
}
// for (LifecycleCallback callback : session.getAfterCompletion()) {
// checkCallback(ejbClass, "Init", callback, bean, boolean.class);
// }
for (final AroundTimeout aroundTimeout : session.getAroundTimeout()) {
ignoredMethodAnnotation("AroundTimeout", bean, bean.getEjbClass(), aroundTimeout.getMethodName(), SessionType.STATEFUL.getName());
}
for (final Timer timer : session.getTimer()) {
ignoredMethodAnnotation("Schedule/Schedules", bean, bean.getEjbClass(), timer.getTimeoutMethod().getMethodName(), SessionType.STATEFUL.getName());
}
} else {
for (final LifecycleCallback callback : session.getAfterBegin()) {
ignoredMethodAnnotation("AfterBegin", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
}
for (final LifecycleCallback callback : session.getBeforeCompletion()) {
ignoredMethodAnnotation("BeforeCompletion", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
}
for (final LifecycleCallback callback : session.getAfterCompletion()) {
ignoredMethodAnnotation("AfterCompletion", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
}
for (final LifecycleCallback callback : session.getPrePassivate()) {
ignoredMethodAnnotation("PrePassivate", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
}
for (final LifecycleCallback callback : session.getPostActivate()) {
ignoredMethodAnnotation("PostActivate", bean, bean.getEjbClass(), callback.getMethodName(), session.getSessionType().getName());
}
for (final RemoveMethod method : session.getRemoveMethod()) {
ignoredMethodAnnotation("Remove", bean, bean.getEjbClass(), method.getBeanMethod().getMethodName(), session.getSessionType().getName());
}
for (final InitMethod method : session.getInitMethod()) {
ignoredMethodAnnotation("Init", bean, bean.getEjbClass(), method.getBeanMethod().getMethodName(), session.getSessionType().getName());
}
}
} else {
for (final Method method : finder.findAnnotatedMethods(PrePassivate.class)) {
ignoredMethodAnnotation("PrePassivate", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final Method method : finder.findAnnotatedMethods(PostActivate.class)) {
ignoredMethodAnnotation("PostActivate", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final Method method : finder.findAnnotatedMethods(Remove.class)) {
ignoredMethodAnnotation("Remove", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final Method method : finder.findAnnotatedMethods(Init.class)) {
ignoredMethodAnnotation("Init", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final Method method : finder.findAnnotatedMethods(AfterBegin.class)) {
ignoredMethodAnnotation("AfterBegin", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final Method method : finder.findAnnotatedMethods(BeforeCompletion.class)) {
ignoredMethodAnnotation("BeforeCompletion", bean, bean.getEjbClass(), method.getName(), bean.getClass().getSimpleName());
}
for (final 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 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 (final Interceptor interceptor : module.getEjbJar().getInterceptors()) {
final Class interceptorClass;
try {
interceptorClass = loadClass(interceptor.getInterceptorClass());
} catch (final OpenEJBException e) {
continue;
}
for (final AroundInvoke aroundInvoke : interceptor.getAroundInvoke()) {
checkAroundInvoke(interceptorClass, aroundInvoke, "Interceptor");
}
for (final AroundTimeout aroundTimeout : interceptor.getAroundTimeout()) {
checkAroundTimeout(interceptorClass, aroundTimeout, "Interceptor");
}
for (final LifecycleCallback callback : interceptor.getPostConstruct()) {
checkCallback(interceptorClass, "PostConstruct", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getPreDestroy()) {
checkCallback(interceptorClass, "PreDestroy", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getPrePassivate()) {
checkCallback(interceptorClass, "PrePassivate", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getPostActivate()) {
checkCallback(interceptorClass, "PostActivate", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getAfterBegin()) {
checkCallback(interceptorClass, "AfterBegin", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getBeforeCompletion()) {
checkCallback(interceptorClass, "BeforeCompletion", callback, interceptor);
}
for (final LifecycleCallback callback : interceptor.getAfterCompletion()) {
checkCallback(interceptorClass, "AfterCompletion", callback, interceptor);
}
}
}
private void checkAroundTypeInvoke(final String aroundType, final Class ejbClass, final String declaringClassName, final String declaringMethodName, final String componentName) {
try {
final Class> declaringClass;
try {
declaringClass = declaringClassName == null ? ejbClass : loadClass(declaringClassName);
} catch (final OpenEJBException e) {
fail(componentName, "missing.class", declaringClassName, aroundType, ejbClass.getName());
return;
}
final Method method = getMethod(declaringClass, declaringMethodName, InvocationContext.class);
final Class> returnType = method.getReturnType();
if (!returnType.equals(Object.class)) {
fail(componentName, "aroundInvoke.badReturnType", aroundType, declaringMethodName, returnType.getName(), declaringClassName);
}
boolean throwsException = false;
for (final Class> exceptionType : method.getExceptionTypes()) {
if (exceptionType.getName().equals(Exception.class.getName())) {
throwsException = true;
}
}
if (!throwsException) {
fail(componentName, "aroundInvoke.mustThrowException", aroundType, declaringMethodName, declaringClassName);
}
} catch (final NoSuchMethodException e) {
final List 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);
final 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(final Class> ejbClass, final AroundInvoke aroundInvoke, final String componentName) {
checkAroundTypeInvoke("AroundInvoke", ejbClass, aroundInvoke.getClassName(), aroundInvoke.getMethodName(), componentName);
}
private void checkAroundTimeout(final Class> ejbClass, final AroundTimeout aroundTimeout, final String componentName) {
checkAroundTypeInvoke("AroundTimeout", ejbClass, aroundTimeout.getClassName(), aroundTimeout.getMethodName(), componentName);
}
private void checkCallback(final Class> ejbClass, final String type, final CallbackMethod callback, final EnterpriseBean bean, final Class... parameterTypes) {
try {
final Class> delcaringClass;
try {
delcaringClass = callback.getClassName() == null ? ejbClass : loadClass(callback.getClassName());
} catch (final OpenEJBException e) {
fail(type, "missing.class", callback.getClassName(), type, bean.getEjbName());
return;
}
final Method method = getMethod(delcaringClass, callback.getMethodName(), parameterTypes);
if (implementsSessionBean(delcaringClass)) {
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
}
final Class> returnType = method.getReturnType();
if (!returnType.equals(Void.TYPE)) {
fail(bean, "callback.badReturnType", type, callback.getMethodName(), returnType.getName(), callback.getClassName());
}
final int methodModifiers = method.getModifiers();
if (Modifier.isFinal(methodModifiers) || Modifier.isStatic(methodModifiers)) {
fail(bean, "callback.badModifier", type, callback.getMethodName(), callback.getClassName());
}
} catch (final NoSuchMethodException e) {
final List possibleMethods = getMethods(ejbClass, callback.getMethodName());
if (possibleMethods.size() == 0) {
fail(bean, "callback.missing", type, callback.getMethodName(), callback.getClassName());
} else if (possibleMethods.size() == 1) {
final Class>[] parameters = possibleMethods.get(0).getParameterTypes();
if (parameters.length == 1 && parameters[0].equals(InvocationContext.class)) {
fail(bean.getEjbName(), "callback.invocationcontext.notallowed", type,
callback.getMethodName());
} else {
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(final Class> ejbClass) {
final Class>[] interfaces = ejbClass.getInterfaces();
for (final Class> interfce : interfaces) {
if (interfce.equals(javax.ejb.SessionBean.class)) {
return true;
}
}
return false;
}
private void checkCallback(final Class interceptorClass, final String type, final CallbackMethod callback, final Interceptor interceptor) {
try {
final Class> delcaringClass;
try {
delcaringClass = callback.getClassName() == null ? interceptorClass : loadClass(callback.getClassName());
} catch (final OpenEJBException e) {
fail(type, "missing.class", callback.getClassName(), type, interceptor.getInterceptorClass());
return;
}
final Method method = getMethod(delcaringClass, callback.getMethodName(), InvocationContext.class);
final Class> returnType = method.getReturnType();
if (!returnType.equals(Void.TYPE)) {
fail("Interceptor", "interceptor.callback.badReturnType", interceptorClass, type, callback.getMethodName(), returnType.getName());
}
} catch (final NoSuchMethodException e) {
final List 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());
final 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(final Class ejbClass, final 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 {
final 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 Method getMethod(Class clazz, final String methodName, final Class... parameterTypes) throws NoSuchMethodException {
NoSuchMethodException original = null;
while (clazz != null) {
try {
return clazz.getDeclaredMethod(methodName, parameterTypes);
} catch (final NoSuchMethodException e) {
if (original == null) {
original = e;
}
}
clazz = clazz.getSuperclass();
}
throw original;
}
private List getMethods(Class clazz, final String methodName) {
final List methods = new ArrayList();
while (clazz != null) {
for (final Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
methods.add(method);
}
}
clazz = clazz.getSuperclass();
}
return methods;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy