package org.jboss.verifier.strategy;
import org.gjt.lindfors.pattern.StrategyContext;
import org.jboss.logging.Logger;
import org.jboss.metadata.BeanMetaData;
import org.jboss.metadata.EntityMetaData;
import org.jboss.metadata.MessageDrivenMetaData;
import org.jboss.util.NestedRuntimeException;
import org.jboss.verifier.Section;
import org.jboss.verifier.event.VerificationEvent;
import org.jboss.verifier.factory.DefaultEventFactory;
import org.jboss.verifier.factory.VerificationEventFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.jms.Message;
public abstract class AbstractVerifier
implements VerificationStrategy
{
static final Logger log = Logger.getLogger(AbstractVerifier.class);
protected final static String EJB_OBJECT_INTERFACE =
"javax.ejb.EJBObject";
protected final static String EJB_HOME_INTERFACE =
"javax.ejb.EJBHome";
protected final static String EJB_LOCAL_OBJECT_INTERFACE =
"javax.ejb.EJBLocalObject";
protected final static String EJB_LOCAL_HOME_INTERFACE =
"javax.ejb.EJBLocalHome";
protected ClassLoader classloader = null;
private VerificationEventFactory factory = null;
private VerificationContext context = null;
public AbstractVerifier(VerificationContext context)
{
this.context = context;
this.classloader = context.getClassLoader();
this.factory = new DefaultEventFactory(getMessageBundle());
if (this.classloader == null)
{
URL[] list = {context.getJarLocation()};
ClassLoader parent = Thread.currentThread().getContextClassLoader();
this.classloader = new URLClassLoader(list, parent);
}
}
public boolean isAssignableFrom(String className, Class assignableFromClass)
{
try
{
Class clazz = this.classloader.loadClass(className);
return clazz.isAssignableFrom(assignableFromClass);
}
catch (ClassNotFoundException e)
{
log.warn("Failed to find class: " + className, e);
}
return false;
}
public boolean isAssignableFrom(Class clazz, String assignableFromClassName)
{
try
{
Class assignableFromClass = this.classloader.loadClass(assignableFromClassName);
return clazz.isAssignableFrom(assignableFromClass);
}
catch (ClassNotFoundException e)
{
log.warn("Failed to find class: " + assignableFromClassName, e);
}
return false;
}
public abstract String getMessageBundle();
public abstract boolean isCreateMethod(Method m);
public abstract boolean isEjbCreateMethod(Method m);
public boolean hasLegalRMIIIOPArguments(Method method)
{
Class[] params = method.getParameterTypes();
for (int i = 0; i < params.length; ++i)
{
if (!isRMIIIOPType(params[i]))
return false;
}
return true;
}
public boolean hasLegalRMIIIOPReturnType(Method method)
{
return isRMIIIOPType(method.getReturnType());
}
public boolean hasLegalRMIIIOPExceptionTypes(Method method)
{
Iterator it = Arrays.asList(method.getExceptionTypes()).iterator();
while (it.hasNext())
{
Class exception = (Class)it.next();
if (!isRMIIDLExceptionType(exception))
return false;
}
return true;
}
public boolean throwsRemoteException(Method method)
{
Class[] exception = method.getExceptionTypes();
for (int i = 0; i < exception.length; ++i)
{
if (exception[i].equals(java.io.IOException.class)
|| exception[i].equals(java.lang.Exception.class))
{
continue;
}
if (isAssignableFrom(exception[i], "java.rmi.RemoteException"))
{
return true;
}
}
return false;
}
public boolean hasSingleArgument(Method method, Class argClass)
{
Class[] params = method.getParameterTypes();
if (params.length == 1)
{
if (params[0].equals(argClass))
return true;
}
return false;
}
public boolean hasNoArguments(Method method)
{
Class[] params = method.getParameterTypes();
return (params.length == 0) ? true : false;
}
public boolean throwsNoException(Method method)
{
boolean hasCheckedException = false;
Class[] exceptions = method.getExceptionTypes();
for (int e = 0; e < exceptions.length; e++)
{
Class ex = exceptions[e];
boolean isError = Error.class.isAssignableFrom(ex);
boolean isRuntimeException = RuntimeException.class.isAssignableFrom(ex);
boolean isRemoteException = RemoteException.class.isAssignableFrom(ex);
if (isError == false && isRuntimeException == false && isRemoteException == false)
hasCheckedException = true;
}
return hasCheckedException == false;
}
public boolean throwsCreateException(Method method)
{
Class[] exception = method.getExceptionTypes();
for (int i = 0; i < exception.length; ++i)
{
if (isAssignableFrom("javax.ejb.CreateException", exception[i]))
return true;
}
return false;
}
public boolean throwsFinderException(Method method)
{
Class[] exception = method.getExceptionTypes();
for (int i = 0; i < exception.length; ++i)
{
if (isAssignableFrom("javax.ejb.FinderException", exception[i]))
return true;
}
return false;
}
public boolean isStatic(Member member)
{
return (Modifier.isStatic(member.getModifiers()));
}
public boolean isStatic(Class c)
{
return (Modifier.isStatic(c.getModifiers()));
}
public boolean isFinal(Member member)
{
return (Modifier.isFinal(member.getModifiers()));
}
public boolean isFinal(Class c)
{
return (Modifier.isFinal(c.getModifiers()));
}
public boolean isPublic(Member member)
{
return (Modifier.isPublic(member.getModifiers()));
}
public boolean isPublic(Class c)
{
return (Modifier.isPublic(c.getModifiers()));
}
public boolean isAllFieldsPublic(Class c)
{
try
{
Field list[] = c.getFields();
for (int i = 0; i < list.length; i++)
{
if (!Modifier.isPublic(list[i].getModifiers()))
return false;
}
}
catch (Exception e)
{
return false;
}
return true;
}
public boolean isAbstract(Class c)
{
return (Modifier.isAbstract(c.getModifiers()));
}
public boolean isAbstract(Method m)
{
return (Modifier.isAbstract(m.getModifiers()));
}
public boolean isSingleObjectFinder(EntityMetaData entity,
Method finder)
{
return hasPrimaryKeyReturnType(entity, finder);
}
public boolean isMultiObjectFinder(Method f)
{
return (java.util.Collection.class.isAssignableFrom(f.getReturnType())
|| java.util.Enumeration.class.isAssignableFrom(f.getReturnType()));
}
public boolean hasRemoteReturnType(BeanMetaData bean, Method m)
{
try
{
Class clazz = classloader.loadClass(bean.getRemote());
return m.getReturnType().isAssignableFrom(clazz);
}
catch (Exception e)
{
return false;
}
}
public boolean hasLocalReturnType(BeanMetaData bean, Method m)
{
try
{
Class clazz = classloader.loadClass(bean.getLocal());
return m.getReturnType().isAssignableFrom(clazz);
}
catch (Exception e)
{
return false;
}
}
public boolean hasVoidReturnType(Method method)
{
return (method.getReturnType() == Void.TYPE);
}
public boolean hasMessageDrivenBeanInterface(Class c)
{
return isAssignableFrom("javax.ejb.MessageDrivenBean", c);
}
public boolean hasMessageListenerInterface(Class c)
{
return isAssignableFrom("javax.jms.MessageListener", c);
}
public boolean hasSessionBeanInterface(Class c)
{
return isAssignableFrom("javax.ejb.SessionBean", c);
}
public boolean hasEntityBeanInterface(Class c)
{
return isAssignableFrom("javax.ejb.EntityBean", c);
}
public boolean hasEJBObjectInterface(Class c)
{
return isAssignableFrom("javax.ejb.EJBObject", c);
}
public boolean hasEJBLocalObjectInterface(Class c)
{
return isAssignableFrom("javax.ejb.EJBLocalObject", c);
}
public boolean hasEJBHomeInterface(Class c)
{
return isAssignableFrom("javax.ejb.EJBHome", c);
}
public boolean hasEJBLocalHomeInterface(Class c)
{
return isAssignableFrom("javax.ejb.EJBLocalHome", c);
}
public boolean hasSessionSynchronizationInterface(Class c)
{
return isAssignableFrom("javax.ejb.SessionSynchronization", c);
}
public boolean hasDefaultConstructor(Class c)
{
try
{
Constructor ctr = c.getConstructor(new Class[0]);
}
catch (NoSuchMethodException e)
{
return false;
}
return true;
}
public boolean hasFinalizer(Class c)
{
try
{
Method finalizer = c.getDeclaredMethod(FINALIZE_METHOD, new Class[0]);
}
catch (NoSuchMethodException e)
{
return false;
}
return true;
}
public boolean hasFinderMethod(Class c)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (method[i].getName().startsWith("ejbFind"))
return true;
}
return false;
}
public boolean isFinderMethod(Method m)
{
return (m.getName().startsWith("find"));
}
public boolean isOnMessageMethod(Method m)
{
if ("onMessage".equals(m.getName()))
{
Class[] paramTypes = m.getParameterTypes();
if (paramTypes.length == 1)
{
if (Message.class.equals(paramTypes[0]))
return true;
}
}
return false;
}
public boolean hasANonStaticField(Class c)
{
try
{
Field list[] = c.getFields();
for (int i = 0; i < list.length; i++)
{
if (!Modifier.isStatic(list[i].getModifiers()))
return true;
}
}
catch (Exception ignored)
{
}
return false;
}
public boolean hasOnMessageMethod(Class c)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isOnMessageMethod(method[i]))
return true;
}
return false;
}
public boolean hasCreateMethod(Class c)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isCreateMethod(method[i]))
return true;
}
return false;
}
public boolean hasEJBCreateMethod(Class c, boolean isSession)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isEjbCreateMethod(method[i]))
{
if (!isStatic(method[i]) && !isFinal(method[i])
&& ((isSession && hasVoidReturnType(method[i]))
|| (!isSession))
)
{
return true;
}
}
}
return false;
}
public boolean hasDefaultCreateMethod(Class home)
{
Method[] method = home.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isCreateMethod(method[i]))
{
Class[] params = method[i].getParameterTypes();
if (params.length == 0)
return true;
}
}
return false;
}
public boolean hasEJBFindByPrimaryKey(Class c)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
return true;
}
return false;
}
public boolean hasPrimaryKeyReturnType(EntityMetaData entity, Method m)
{
try
{
return
m.getReturnType().isAssignableFrom(classloader.loadClass(entity.getPrimaryKeyClass()));
}
catch (ClassNotFoundException cnfe)
{
return
m.getReturnType().getName().equals(entity.getPrimaryKeyClass());
}
}
public Method getDefaultCreateMethod(Class c)
{
Method method = null;
try
{
method = c.getMethod(CREATE_METHOD, null);
}
catch (NoSuchMethodException ignored)
{
}
return method;
}
public Method getEJBFindByPrimaryKey(Class c)
{
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
return method[i];
}
return null;
}
public Iterator getEJBFindMethods(Class c)
{
List finders = new LinkedList();
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (method[i].getName().startsWith("ejbFind"))
finders.add(method[i]);
}
return finders.iterator();
}
public Iterator getFinderMethods(Class home)
{
List finders = new LinkedList();
Method[] method = home.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (method[i].getName().startsWith("find"))
finders.add(method[i]);
}
return finders.iterator();
}
public Iterator getOnMessageMethods(Class c)
{
List onMessages = new LinkedList();
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isOnMessageMethod(method[i]))
onMessages.add(method[i]);
}
return onMessages.iterator();
}
public Iterator getEJBCreateMethods(Class c)
{
List ejbCreates = new LinkedList();
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isEjbCreateMethod(method[i]))
ejbCreates.add(method[i]);
}
return ejbCreates.iterator();
}
public Iterator getCreateMethods(Class c)
{
List creates = new LinkedList();
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isCreateMethod(method[i]))
creates.add(method[i]);
}
return creates.iterator();
}
public boolean hasMoreThanOneCreateMethods(Class c)
{
int count = 0;
Method[] method = c.getMethods();
for (int i = 0; i < method.length; ++i)
{
if (isCreateMethod(method[i]))
{
++count;
}
}
return (count > 1);
}
public boolean hasMatchingExceptions(Method source, Method target)
{
Class[] a = source.getExceptionTypes();
Class[] b = target.getExceptionTypes();
Class rteClass = null;
Class errorClass = null;
try
{
rteClass = classloader.loadClass("java.lang.RuntimeException");
errorClass = classloader.loadClass("java.lang.Error");
}
catch (ClassNotFoundException cnfe)
{
}
for (int i = 0; i < a.length; ++i)
{
if (rteClass.isAssignableFrom(a[i])
|| errorClass.isAssignableFrom(a[i]))
{
continue;
}
boolean found = false;
for (int j = 0; j < b.length; ++j)
{
if (b[j].isAssignableFrom(a[i]))
{
found = true;
break;
}
}
if (!found)
{
return false;
}
}
return true;
}
public boolean hasMatchingMethod(Class bean, Method method)
{
try
{
bean.getMethod(method.getName(), method.getParameterTypes());
return true;
}
catch (NoSuchMethodException e)
{
return false;
}
}
public boolean hasMatchingReturnType(Method a, Method b)
{
return (a.getReturnType() == b.getReturnType());
}
public boolean hasMatchingEJBPostCreate(Class bean, Method create)
{
try
{
return (bean.getMethod(getMatchingEJBPostCreateName(create.getName()),
create.getParameterTypes()) != null);
}
catch (NoSuchMethodException e)
{
return false;
}
}
public boolean hasMatchingEJBCreate(Class bean, Method create)
{
try
{
return (bean.getMethod(getMatchingEJBCreateName(create.getName()), create.getParameterTypes()) != null);
}
catch (NoSuchMethodException e)
{
return false;
}
}
public Method getMatchingEJBPostCreate(Class bean, Method create)
{
try
{
return bean.getMethod(getMatchingEJBPostCreateName(create.getName()), create.getParameterTypes());
}
catch (NoSuchMethodException e)
{
return null;
}
}
public Method getMatchingEJBCreate(Class bean, Method create)
{
try
{
return bean.getMethod(getMatchingEJBCreateName(create.getName()), create.getParameterTypes());
}
catch (NoSuchMethodException e)
{
return null;
}
}
public boolean hasMatchingEJBFind(Class bean, Method finder)
{
try
{
String methodName = "ejbF" + finder.getName().substring(1);
return (bean.getMethod(methodName, finder.getParameterTypes()) != null);
}
catch (NoSuchMethodException e)
{
return false;
}
}
public Method getMatchingEJBFind(Class bean, Method finder)
{
try
{
String methodName = "ejbF" + finder.getName().substring(1);
return bean.getMethod(methodName, finder.getParameterTypes());
}
catch (NoSuchMethodException e)
{
return null;
}
}
public boolean hasMatchingEJBHome(Class bean, Method home)
{
try
{
return (bean.getMethod(getMatchingEJBHomeName(home.getName()), home.getParameterTypes()) != null);
}
catch (NoSuchMethodException e)
{
return false;
}
}
protected void fireSpecViolationEvent(BeanMetaData bean, Section section)
{
fireSpecViolationEvent(bean, null , section);
}
protected void fireSpecViolationEvent(BeanMetaData bean, Method method,
Section section)
{
VerificationEvent event = factory.createSpecViolationEvent(context,
section);
event.setName(bean.getEjbName());
event.setMethod(method);
context.fireSpecViolation(event);
}
protected final void fireBeanVerifiedEvent(BeanMetaData bean)
{
fireBeanVerifiedEvent(bean, null);
}
protected final void fireBeanVerifiedEvent(BeanMetaData bean, String msg)
{
VerificationEvent event = factory.createBeanVerifiedEvent(context);
event.setName(bean.getEjbName());
if (msg != null)
{
event.setMessage(msg);
}
context.fireBeanChecked(event);
}
public void checkMessageBean(MessageDrivenMetaData bean)
{
}
public StrategyContext getContext()
{
return context;
}
protected boolean isRMIIIOPType(Class type)
{
if (type.isPrimitive())
return true;
if (type.isArray())
return isRMIIIOPType(type.getComponentType());
if (org.omg.CORBA.Object.class.isAssignableFrom(type))
return true;
if (org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(type))
return true;
if (isRMIIDLRemoteInterface(type))
return true;
if (isRMIIDLExceptionType(type))
return true;
if (isRMIIDLValueType(type))
return true;
return false;
}
private boolean isRMIIDLRemoteInterface(Class type)
{
if (!java.rmi.Remote.class.isAssignableFrom(type))
return false;
Iterator methodIterator = Arrays.asList(type.getMethods()).iterator();
while (methodIterator.hasNext())
{
Method m = (Method)methodIterator.next();
if (!throwsRemoteException(m))
return false;
Iterator it = Arrays.asList(m.getExceptionTypes()).iterator();
while (it.hasNext())
{
Class exception = (Class)it.next();
if (!isRMIIDLExceptionType(exception))
return false;
}
}
Iterator fieldIterator = Arrays.asList(type.getFields()).iterator();
while (fieldIterator.hasNext())
{
Field f = (Field)fieldIterator.next();
if (f.getType().isPrimitive())
continue;
if (f.getType().equals(java.lang.String.class))
continue;
return false;
}
return true;
}
private boolean isRMIIDLExceptionType(Class type)
{
if (!Throwable.class.isAssignableFrom(type))
return false;
if (Error.class.isAssignableFrom(type))
return false;
if (!isRMIIDLValueType(type))
return false;
return true;
}
protected boolean isRMIIDLValueType(Class type)
{
if (java.rmi.Remote.class.isAssignableFrom(type))
return false;
if (type.getDeclaringClass() != null && !isStatic(type))
{
if (!isRMIIDLValueType(type.getDeclaringClass()))
return false;
}
return true;
}
private String getMatchingEJBHomeName(String homeName)
{
return "ejbHome" + homeName.substring(0, 1).toUpperCase() +
homeName.substring(1);
}
private String getMatchingEJBCreateName(String createName)
{
return "ejb" + createName.substring(0, 1).toUpperCase() +
createName.substring(1);
}
private String getMatchingEJBPostCreateName(String createName)
{
int createIdx = createName.indexOf("Create");
return "ejbPost" + createName.substring(createIdx >= 0 ? createIdx : 0);
}
public final static String BEAN_MANAGED_TX =
"Bean";
public final static String CONTAINER_MANAGED_TX =
"Container";
public final static String STATEFUL_SESSION =
"Stateful";
public final static String STATELESS_SESSION =
"Stateless";
private final static String EJB_FIND_BY_PRIMARY_KEY =
"ejbFindByPrimaryKey";
protected final static String EJB_CREATE_METHOD =
"ejbCreate";
protected final static String EJB_REMOVE_METHOD =
"ejbRemove";
private final static String EJB_POST_CREATE_METHOD =
"ejbPostCreate";
protected final static String CREATE_METHOD =
"create";
protected final static String EJB_HOME_METHOD =
"ejbHome";
protected final static String EJB_SELECT_METHOD =
"ejbSelect";
private final static String FINALIZE_METHOD =
"finalize";
private final static String REMOVE_METHOD =
"remove";
private final static String GET_HOME_HANDLE_METHOD =
"getHomeHandle";
private final static String GET_EJB_METADATA_METHOD =
"getEJBMetaData";
}