org.apache.openejb.config.rules.CheckClasses Maven / Gradle / Ivy
The newest version!
/*
* 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.OpenEJBRuntimeException;
import org.apache.openejb.config.EjbModule;
import org.apache.openejb.dyni.DynamicSubclass;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.EntityBean;
import org.apache.openejb.jee.Interceptor;
import org.apache.openejb.jee.RemoteBean;
import org.apache.openejb.jee.SessionBean;
import org.apache.openejb.util.SafeToolkit;
import org.apache.openejb.util.Strings;
import org.apache.openejb.util.proxy.DynamicProxyImplFactory;
import org.apache.xbean.finder.ClassFinder;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.RunAs;
import javax.ejb.EJB;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.EJBs;
import javax.ejb.Init;
import javax.ejb.Local;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Remote;
import javax.ejb.Remove;
import javax.ejb.Timeout;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionManagement;
import javax.jws.WebService;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import static java.lang.reflect.Modifier.isAbstract;
/**
* @version $Rev$ $Date$
*/
public class CheckClasses extends ValidationBase {
private static final List> beanOnlyAnnotations = new ArrayList>();
static {
beanOnlyAnnotations.add(PostConstruct.class);
beanOnlyAnnotations.add(PreDestroy.class);
beanOnlyAnnotations.add(Resource.class);
beanOnlyAnnotations.add(Resources.class);
beanOnlyAnnotations.add(DeclareRoles.class);
beanOnlyAnnotations.add(DenyAll.class);
beanOnlyAnnotations.add(PermitAll.class);
beanOnlyAnnotations.add(RolesAllowed.class);
beanOnlyAnnotations.add(RunAs.class);
beanOnlyAnnotations.add(EJB.class);
beanOnlyAnnotations.add(EJBs.class);
beanOnlyAnnotations.add(Init.class);
beanOnlyAnnotations.add(PostActivate.class);
beanOnlyAnnotations.add(PrePassivate.class);
beanOnlyAnnotations.add(Remove.class);
beanOnlyAnnotations.add(Timeout.class);
beanOnlyAnnotations.add(TransactionAttribute.class);
beanOnlyAnnotations.add(TransactionManagement.class);
}
public void validate(final EjbModule ejbModule) {
for (final EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
try {
final Class> beanClass = check_hasEjbClass(bean);
// All the subsequent checks require the bean class
if (beanClass == null) {
continue;
}
if (!(bean instanceof RemoteBean)) {
continue;
}
if (bean instanceof SessionBean && ((SessionBean) bean).getProxy() != null) {
continue;
}
final RemoteBean b = (RemoteBean) bean;
check_isEjbClass(b);
check_hasDependentClasses(b, b.getEjbClass(), "ejb-class");
check_hasInterface(b);
if (b.getRemote() != null) {
checkInterface(b, beanClass, "remote", b.getRemote());
}
if (b.getHome() != null) {
checkInterface(b, beanClass, "home", b.getHome());
}
if (b.getLocal() != null) {
checkInterface(b, beanClass, "local", b.getLocal());
}
if (b.getLocalHome() != null) {
checkInterface(b, beanClass, "local-home", b.getLocalHome());
}
if (b instanceof SessionBean) {
final SessionBean sessionBean = (SessionBean) b;
for (final String interfce : sessionBean.getBusinessLocal()) {
checkInterface(b, beanClass, "business-local", interfce);
}
for (final String interfce : sessionBean.getBusinessRemote()) {
checkInterface(b, beanClass, "business-remote", interfce);
}
}
} catch (final RuntimeException e) {
throw new OpenEJBRuntimeException(bean.getEjbName(), e);
}
}
for (final Interceptor interceptor : ejbModule.getEjbJar().getInterceptors()) {
check_hasInterceptorClass(interceptor);
}
}
private void checkInterface(final RemoteBean b, final Class> beanClass, String tag, final String className) {
final Class> interfce = lookForClass(className, tag, b.getEjbName());
if (interfce == null) {
return;
}
check_hasDependentClasses(b, className, tag);
tag = Strings.lcfirst(Strings.camelCase(tag));
isValidInterface(b, interfce, beanClass, tag);
final ClassFinder finder = new ClassFinder(interfce);
for (final Class extends Annotation> annotation : beanOnlyAnnotations) {
if (interfce.isAnnotationPresent(annotation)) {
warn(b, "interface.beanOnlyAnnotation", annotation.getSimpleName(), interfce.getName(), b.getEjbClass());
}
for (final Method method : finder.findAnnotatedMethods(annotation)) {
warn(b, "interfaceMethod.beanOnlyAnnotation", annotation.getSimpleName(), interfce.getName(), method.getName(), b.getEjbClass());
}
}
}
private void check_hasInterface(final RemoteBean b) {
if (b.getRemote() != null) {
return;
}
if (b.getLocal() != null) {
return;
}
Class> beanClass = null;
try {
beanClass = loadClass(b.getEjbClass());
} catch (final OpenEJBException e) {
// no-op
}
if (b instanceof EntityBean) {
fail(b, "noInterfaceDeclared.entity", beanClass.getSimpleName());
return;
}
if (b.getBusinessLocal().size() > 0) {
return;
}
if (b.getBusinessRemote().size() > 0) {
return;
}
if (((SessionBean) b).getServiceEndpoint() != null) {
return;
}
if (beanClass.isAnnotationPresent(WebService.class)) {
return;
}
//fail(b, "noInterfaceDeclared.session");
}
private void check_hasDependentClasses(final RemoteBean b, final String className, final String type) {
try {
final ClassLoader cl = module.getClassLoader();
final Class> clazz = cl.loadClass(className);
for (final Object item : clazz.getFields()) {
item.toString();
}
for (final Object item : clazz.getMethods()) {
item.toString();
}
for (final Object item : clazz.getConstructors()) {
item.toString();
}
for (final Object item : clazz.getAnnotations()) {
item.toString();
}
// checking for any declared enum constants
for (final Class klass : clazz.getClasses()) {
if (klass.isEnum()) {
klass.toString();
}
}
} catch (final ClassNotFoundException e) {
/*
# 0 - Referring Class name
# 1 - Dependent Class name
# 2 - Element (home, ejb-class, remote)
# 3 - Bean name
*/
final String missingClass = e.getMessage();
fail(b, "missing.dependent.class", className, missingClass, type, b.getEjbName());
} catch (final NoClassDefFoundError e) {
/*
# 0 - Referring Class name
# 1 - Dependent Class name
# 2 - Element (home, ejb-class, remote)
# 3 - Bean name
*/
final String missingClass = e.getMessage();
fail(b, "missing.dependent.class", className, missingClass, type, b.getEjbName());
}
}
public Class> check_hasEjbClass(final EnterpriseBean b) {
final String ejbName = b.getEjbName();
final Class> beanClass = lookForClass(b.getEjbClass(), "ejb-class", ejbName);
final boolean isDynamicProxyImpl = DynamicProxyImplFactory.isKnownDynamicallyImplemented(beanClass);
if (beanClass == null) {
return null;
}
if (beanClass.isInterface() && !isDynamicProxyImpl) {
fail(ejbName, "interfaceDeclaredAsBean", beanClass.getName());
}
if (isCmp(b)) {
return beanClass;
}
if (isAbstract(beanClass.getModifiers()) && !isAbstractAllowed(beanClass)) {
fail(ejbName, "abstractDeclaredAsBean", beanClass.getName());
}
return beanClass;
}
public static boolean isAbstractAllowed(final Class clazz) {
if (DynamicProxyImplFactory.isKnownDynamicallyImplemented(clazz)) {
return true;
}
if (DynamicSubclass.isDynamic(clazz)) {
return true;
}
return false;
}
private void check_hasInterceptorClass(final Interceptor i) {
lookForClass(i.getInterceptorClass(), "interceptor-class", "Interceptor");
}
private void check_isEjbClass(final RemoteBean b) {
if (b instanceof SessionBean) { //NOPMD
// DMB: Beans in ejb 3 are not required to implement javax.ejb.SessionBean
// but it would still be nice to think of some sort of check to do here.
// compareTypes(b, b.getEjbClass(), javax.ejb.SessionBean.class);
} else if (b instanceof EntityBean) {
compareTypes(b, b.getEjbClass(), javax.ejb.EntityBean.class);
}
}
private Class> lookForClass(final String clazz, final String type, final String ejbName) {
try {
return loadClass(clazz);
} catch (final OpenEJBException e) {
/*
# 0 - Class name
# 1 - Element (home, ejb-class, remote)
# 2 - Bean name
*/
fail(ejbName, "missing.class", clazz, type, ejbName);
} catch (final NoClassDefFoundError e) {
/*
# 0 - Class name
# 1 - Element (home, ejb-class, remote)
# 2 - Bean name
# 3 - Misslocated Class name
*/
fail(ejbName, "misslocated.class", clazz, type, ejbName, e.getMessage());
throw e;
}
return null;
}
private boolean isValidInterface(final RemoteBean b, final Class clazz, final Class beanClass, final String tag) {
if (clazz.equals(beanClass)) {
fail(b, "xml." + tag + ".beanClass", clazz.getName());
} else if (!clazz.isInterface()) {
fail(b, "xml." + tag + ".notInterface", clazz.getName());
} else if (EJBHome.class.isAssignableFrom(clazz)) {
if (tag.equals("home")) {
return true;
}
fail(b, "xml." + tag + ".ejbHome", clazz.getName());
} else if (EJBLocalHome.class.isAssignableFrom(clazz)) {
if (tag.equals("localHome")) {
return true;
}
fail(b, "xml." + tag + ".ejbLocalHome", clazz.getName());
} else if (EJBObject.class.isAssignableFrom(clazz)) {
if (tag.equals("remote")) {
return true;
}
fail(b, "xml." + tag + ".ejbObject", clazz.getName());
} else if (EJBLocalObject.class.isAssignableFrom(clazz)) {
if (tag.equals("local")) {
return true;
}
fail(b, "xml." + tag + ".ejbLocalObject", clazz.getName());
} else {
if (tag.equals("businessLocal") || tag.equals("businessRemote")) {
return true;
} else if (clazz.isAnnotationPresent(Local.class)) {
fail(b, "xml." + tag + ".businessLocal", clazz.getName());
} else if (clazz.isAnnotationPresent(Remote.class)) {
fail(b, "xml." + tag + ".businessRemote", clazz.getName());
} else {
fail(b, "xml." + tag + ".unknown", clazz.getName());
}
}
// must be tagged as , , , or
return false;
}
private void compareTypes(final RemoteBean b, final String clazz1, final Class> class2) {
Class> class1 = null;
try {
class1 = loadClass(clazz1);
} catch (final OpenEJBException e) {
return;
}
if (class1 != null && !class2.isAssignableFrom(class1)) {
fail(b, "wrong.class.type", clazz1, class2.getName());
}
}
protected Class> loadClass(final String clazz) throws OpenEJBException {
final ClassLoader cl = module.getClassLoader();
try {
return Class.forName(clazz, false, cl);
} catch (final ClassNotFoundException cnfe) {
throw new OpenEJBException(SafeToolkit.messages.format("cl0007", clazz, module.getJarLocation()), cnfe);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy