/**
* Start time:17:06:21 2009-01-30<br>
* Project: mobicents-jainslee-server-core<br>
*
* @author <a href="mailto:baranowb@gmail.com">baranowb - Bartosz Baranowski
* </a>
* @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
*/
package org.mobicents.slee.container.component.validator;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.slee.EventTypeID;
import javax.slee.SLEEException;
import javax.slee.SbbID;
import javax.slee.profile.ProfileID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.profile.UnrecognizedProfileNameException;
import javax.slee.profile.UnrecognizedProfileTableNameException;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.EventTypeComponent;
import org.mobicents.slee.container.component.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.SbbComponent;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.SbbDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MEnvEntry;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.references.MEventTypeRef;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.references.MProfileSpecRef;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.references.MSbbRef;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MEventEntry;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MGetChildRelationMethod;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MGetProfileCMPMethod;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MSbbCMPField;
/**
* Start time:17:06:21 2009-01-30<br>
* Project: mobicents-jainslee-server-core<br>
* base validator for sbb components. It validates all sbb class constraints.
* However it does not check referential constraints and similar. Checks that
* have to be done before this class is used are: reference checks(this includes
* dependencies), field values - like duplicate cmps, duplicate entries.
*
* @author <a href="mailto:baranowb@gmail.com">baranowb - Bartosz Baranowski
* </a>
* @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
*/
public class SbbComponentValidator implements Validator {
public static final String _SBB_AS_SBB_ACTIVITY_CONTEXT_INTERFACE = "asSbbActivityContextInterface";
public static final String _SBB_GET_CHILD_RELATION_SIGNATURE_PART = "[]";
private SbbComponent component = null;
private ComponentRepository repository = null;
private final static transient Logger logger = Logger.getLogger(SbbComponentValidator.class);
private final static Set<String> _PRIMITIVES;
static {
Set<String> tmp = new HashSet<String>();
tmp.add("int");
tmp.add("boolean");
tmp.add("byte");
tmp.add("char");
tmp.add("double");
tmp.add("float");
tmp.add("long");
tmp.add("short");
_PRIMITIVES = Collections.unmodifiableSet(tmp);
}
private final static Set<String> _ENV_ENTRIES_TYPES;
static {
Set<String> tmp = new HashSet<String>();
tmp.add(Integer.class.getName());
tmp.add(Boolean.class.getName());
tmp.add(Byte.class.getName());
tmp.add(Character.class.getName());
tmp.add(Double.class.getName());
tmp.add(Float.class.getName());
tmp.add(Long.class.getName());
tmp.add(Short.class.getName());
tmp.add(String.class.getName());
_ENV_ENTRIES_TYPES = Collections.unmodifiableSet(tmp);
}
public boolean validate() {
boolean valid = true;
// Uf here we go
try {
if (!validateDescriptor()) {
valid = false;
return valid;
}
Map<String, Method> abstractMehotds, superClassesAbstractMethod, concreteMethods, superClassesConcreteMethods;
abstractMehotds = ClassUtils.getAbstractMethodsFromClass(this.component.getAbstractSbbClass());
superClassesAbstractMethod = ClassUtils.getAbstractMethodsFromSuperClasses(this.component.getAbstractSbbClass());
concreteMethods = ClassUtils.getConcreteMethodsFromClass(this.component.getAbstractSbbClass());
superClassesConcreteMethods = ClassUtils.getConcreteMethodsFromSuperClasses(this.component.getAbstractSbbClass());
//NOTE: wont this hide method exceptions or visibility change?
superClassesAbstractMethod.keySet().removeAll(abstractMehotds.keySet());
superClassesConcreteMethods.keySet().removeAll(concreteMethods.keySet());
if (!validateAbstractClassConstraints(concreteMethods, superClassesConcreteMethods)) {
valid = false;
}
if (!validateCmpFileds(abstractMehotds, superClassesAbstractMethod)) {
valid = false;
}
if (!validateEventHandlers(abstractMehotds, superClassesAbstractMethod, concreteMethods, superClassesConcreteMethods)) {
valid = false;
}
if (!validateGetChildRelationMethods(abstractMehotds, superClassesAbstractMethod)) {
valid = false;
}
if (!validateGetProfileCmpInterfaceMethods(abstractMehotds, superClassesAbstractMethod)) {
valid = false;
}
if (!validateSbbActivityContextInterface(abstractMehotds, superClassesAbstractMethod)) {
valid = false;
}
if (!validateSbbLocalInterface(concreteMethods, superClassesConcreteMethods)) {
valid = false;
}
if (!validateSbbUsageParameterInterface(abstractMehotds, superClassesAbstractMethod)) {
valid = false;
}
if (!validateEnvEntries()) {
valid = false;
}
// now lets test abstract methods, we have to remove all of them by
// now?
if (abstractMehotds.size() > 0 || superClassesAbstractMethod.size() > 0) {
valid = false;
if(logger.isEnabledFor(Level.ERROR))
logger
.error(this.component.getDescriptor().getSbbID()
+ " : violates sbb constraints, it declares more abstract methods than SLEE is bound to implement. Methods directly from class: "
+ Arrays.toString(abstractMehotds.keySet().toArray()) + ", methods from super classes: "
+ Arrays.toString(superClassesAbstractMethod.keySet().toArray()));
}
} catch (Exception e) {
e.printStackTrace();
valid = false;
}
return valid;
}
public void setComponentRepository(ComponentRepository repository) {
this.repository = repository;
}
public SbbComponent getComponent() {
return component;
}
public void setComponent(SbbComponent component) {
this.component = component;
}
/**
* Sbb abstract class(general rule � methods cannot start neither with �ejb�
* nor �sbb�)
* <ul>
* <li>(1.1 ?) must have package declaration
* <li>must implement in some way javax.slee.Sbb(only methods from interface
* can have �sbb� prefix)
* <ul>
* <li>each method defined must be implemented as public � not abstract,
* final or static
* </ul>
* <li>must be public and abstract
* <li>must have public no arg constructor
* <li>must implement sbbExceptionThrown method
* <ul>
* <li>
* public, not abstract, final or static no return type 3 arguments:
* java.lang.Exception, java.lang.Object,
* javax.slee.ActivityContextInterface
* </ul>
* <li>must implement sbbRolledBack
* <ul>
* <li>method must be public, not abstract, final or static
* <li>no return type
* <li>with single argument - javax.slee.RoledBackContext
* </ul>
* <li>there is no finalize method
* </ul>
*
* @return
*/
boolean validateAbstractClassConstraints(Map<String, Method> concreteMethods, Map<String, Method> concreteSuperClassesMethods) {
String errorBuffer = new String("");
boolean passed = true;
// Presence of those classes must be checked elsewhere
Class sbbAbstractClass = this.component.getAbstractSbbClass();
// Must be public and abstract
int modifiers = sbbAbstractClass.getModifiers();
// check that the class modifiers contain abstratc and public
if (!Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers)) {
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must be public and abstract", "6.1", errorBuffer);
}
// 1.1 - must be in package
if (this.component.isSlee11()) {
Package declaredPackage = sbbAbstractClass.getPackage();
if (declaredPackage == null || declaredPackage.getName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must be defined inside package space", "6.1",
errorBuffer);
}
}
// Public no arg constructor - can it have more ?
// sbbAbstractClass.getConstructor
// FIXME: no arg constructor has signature "()V" when added from
// javaassist we check for such constructor and if its public
try {
Constructor constructor = sbbAbstractClass.getConstructor();
int conMod = constructor.getModifiers();
if (!Modifier.isPublic(conMod)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must have public constructor ", "6.1",
errorBuffer);
}
} catch (SecurityException e) {
e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must have no arg constructor, error:"
+ e.getMessage(), "6.1", errorBuffer);
} catch (NoSuchMethodException e) {
e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must have no arg constructor, error:"
+ e.getMessage(), "6.1", errorBuffer);
}
// Must implements javax.slee.Sbb - and each method there defined, only
// those methods and two above can have "sbb" prefix
// those methods MUST be in concrete methods map, later we will use them
// to see if there is ant "sbbXXXX" method
// Check if we implement javax.slee.Sbb - either directly or from super
// class
Class javaxSleeSbbInterface = ClassUtils.checkInterfaces(sbbAbstractClass, "javax.slee.Sbb");
// sbbAbstractClass.getI
if (javaxSleeSbbInterface == null) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ "sbb abstract class must implement, directly or indirectly, the javax.slee.Sbb interface.", "6.1", errorBuffer);
}
// FIXME: add check for finalize method
// Now we have to check methods from javax.slee.Sbb
// This takes care of method throws clauses
if (javaxSleeSbbInterface != null) {
// if it is, we dont have those methods for sure, or maybe we do,
// implemnted by hand
// either way its a failure
// We want only java.slee.Sbb methods :)
Method[] sbbLifecycleMethods = javaxSleeSbbInterface.getDeclaredMethods();
for (Method lifecycleMehtod : sbbLifecycleMethods) {
// It must be implemented - so only in concrete methods, if we
// are left with one not checked bang, its an error
String methodKey = ClassUtils.getMethodKey(lifecycleMehtod);
Method concreteLifeCycleImpl = null;
if (concreteMethods.containsKey(methodKey)) {
concreteLifeCycleImpl = concreteMethods.remove(methodKey);
} else if (concreteSuperClassesMethods.containsKey(methodKey)) {
concreteLifeCycleImpl = concreteSuperClassesMethods.remove(methodKey);
} else {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ "sbb abstract class must implement life cycle methods, it lacks concrete implementation of: "
+ lifecycleMehtod.getName(), "6.1.1", errorBuffer);
continue;
}
// now we now there is such method, its not private and abstract
// If we are here its not null
int lifeCycleModifier = concreteLifeCycleImpl.getModifiers();
if (!Modifier.isPublic(lifeCycleModifier) || Modifier.isStatic(lifeCycleModifier) || Modifier.isFinal(lifeCycleModifier)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ "sbb abstract class must implement life cycle methods, which can not be static, final or not public, method: "
+ lifecycleMehtod.getName(), "6.1.1", errorBuffer);
}
}
}
// there can not be any method which start with ejb/sbb - we removed
// every from concrete, lets iterate over those sets
for (Method concreteMethod : concreteMethods.values()) {
if (concreteMethod.getName().startsWith("ejb") || concreteMethod.getName().startsWith("sbb")) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " with method: " + concreteMethod.getName(), "6.12", errorBuffer);
}
if (concreteMethod.getName().compareTo("finalize") == 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "sbb abstract class must not implement \"finalize\" method.",
"6.1", errorBuffer);
}
}
for (Method concreteMethod : concreteSuperClassesMethods.values()) {
if (concreteMethod.getName().startsWith("ejb") || concreteMethod.getName().startsWith("sbb")) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " with method from super classes: " + concreteMethod.getName(),
"6.12", errorBuffer);
}
if (concreteMethod.getName().compareTo("finalize") == 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ "sbb abstract class must not implement \"finalize\" method. Its implemented by super class.", "6.1", errorBuffer);
}
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
/**
* This method checks for presence of
*
* @param sbbAbstractClassAbstraMethod
* @param sbbAbstractClassAbstraMethodFromSuperClasses
* @return
*/
boolean validateSbbActivityContextInterface(Map<String, Method> sbbAbstractClassAbstraMethod,
Map<String, Method> sbbAbstractClassAbstraMethodFromSuperClasses) {
if (this.component.getDescriptor().getSbbClasses().getSbbActivityContextInterface() == null) {
// FIXME: add check for asSbbActivityContextInteface method ? This
// will be catched at the end of check anyway
if (logger.isDebugEnabled()) {
logger.debug(this.component.getDescriptor().getSbbID() + " : No Sbb activity context interface defined");
}
return true;
}
String errorBuffer = new String("");
boolean passed = true;
Class sbbAbstractClass = this.component.getAbstractSbbClass();
Method asACIMethod = null;
// lets go through methods of sbbAbstract class,
Iterator<Method> it = sbbAbstractClassAbstraMethod.values().iterator();
while(it.hasNext())
{
Method someMethod = it.next();
if (someMethod.getName().compareTo(_SBB_AS_SBB_ACTIVITY_CONTEXT_INTERFACE) == 0) {
// we have a winner, possibly - we have to check parameter
// list, cause someone can create abstract method(or crap,
// it can be concrete) with different parametrs, in case its
// abstract, it will fail later on
if (someMethod.getParameterTypes().length == 1
&& someMethod.getParameterTypes()[0].getName().compareTo("javax.slee.ActivityContextInterface") == 0) {
asACIMethod = someMethod;
it.remove();
break;
}
}
}
if (asACIMethod == null)
it = sbbAbstractClassAbstraMethodFromSuperClasses.values().iterator();
while(it.hasNext())
{
Method someMethod = it.next();
if (someMethod.getName().compareTo(_SBB_AS_SBB_ACTIVITY_CONTEXT_INTERFACE) == 0) {
// we have a winner, possibly - we have to check
// parameter
// list, cause someone can create abstract method(or
// crap,
// it can be concrete) with different parametrs, in case
// its
// abstract, it will fail later on
if (someMethod.getParameterTypes().length == 1
&& someMethod.getParameterTypes()[0].getName().compareTo("javax.slee.ActivityContextInterface") == 0) {
asACIMethod = someMethod;
it.remove();
break;
}
}
}
if (asACIMethod == null) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " must imlement narrow method asSbbActivityContextInterface",
"7.7.2", errorBuffer);
} else {
// must be public, abstract? FIXME: not native?
int asACIMethodModifiers = asACIMethod.getModifiers();
if (!Modifier.isPublic(asACIMethodModifiers) || !Modifier.isAbstract(asACIMethodModifiers) || Modifier.isNative(asACIMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " narrow method asSbbActivityContextInterface must be public,abstract and not native.", "7.7.2", errorBuffer);
}
// now this misery comes to play, return type check
Class returnType = asACIMethod.getReturnType();
// Must return something from Sbb defined aci class inheritance
// tree
Class definedReturnType = this.component.getActivityContextInterface();
if (returnType.getName().compareTo("void") == 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " narrow method asSbbActivityContextInterface must have return type.", "7.7.2", errorBuffer);
} else if (returnType.equals(definedReturnType)) {
// its ok
// } else if (ClassUtils.checkInterfaces(definedReturnType,
// returnType
// .getName()) != null) {
} else {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " narrow method asSbbActivityContextInterface has wrong return type: " + returnType, "7.7.2", errorBuffer);
}
// no throws clause
if (asACIMethod.getExceptionTypes() != null && asACIMethod.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " narrow method asSbbActivityContextInterface must not have throws clause.", "7.7.2", errorBuffer);
}
}
// Even if we fail above we can do some checks on ACI if its present.
// this has to be present
Class sbbActivityContextInterface = this.component.getActivityContextInterface();
// ACI VALIDATION
// (1.1) = must be declared in package
if (this.component.isSlee11() && sbbActivityContextInterface.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " sbb activity context interface must be declared in package.",
"7.5", errorBuffer);
}
if (!Modifier.isPublic(sbbActivityContextInterface.getModifiers())) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " sbb activity context interface must be declared as public.", "7.5",
errorBuffer);
}
// We can have here ACI objects and java primitives, ugh, both methods
// dont have to be shown
passed = checkSbbAciFieldsConstraints(this.component.getActivityContextInterface());
// finally lets remove asSbb method form abstract lists, this is used
// later to determine methods that didnt match any sbb definition
if (asACIMethod != null) {
sbbAbstractClassAbstraMethod.remove(ClassUtils.getMethodKey(asACIMethod));
sbbAbstractClassAbstraMethodFromSuperClasses.remove(ClassUtils.getMethodKey(asACIMethod));
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
/**
* This method validates all methods in ACI interface:
* <ul>
* <li>set/get methods and parameter names as in CMP fields decalration
* <li>methods must
* <ul>
* <li>be public, abstract
* <li>setters must have one param
* <li>getters return type must match setter type
* <li>allowe types are: primitives and serilizable types
* </ul>
* </ul>
* <br>
* Sbb descriptor provides method to obtain aci field names, if this test
* passes it means that all fields there should be correct and can be used
* to verify aliases
*
* @param sbbAciInterface
* @return
*/
boolean checkSbbAciFieldsConstraints(Class sbbAciInterface) {
boolean passed = true;
String errorBuffer = new String("");
try {
if (!sbbAciInterface.isInterface()) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " sbb activity context interface MUST be an interface.", "7.5",
errorBuffer);
return passed;
}
// here we need all fields :)
HashSet<String> ignore = new HashSet<String>();
ignore.add("javax.slee.ActivityContextInterface");
// FIXME: we could go other way, run this for each super interface
// we
// have???
Map<String, Method> aciInterfacesDefinedMethods = ClassUtils.getAllInterfacesMethods(sbbAciInterface, ignore);
// Here we will store fields name-type - if there is getter and
// setter,
// type must match!!!
Map<String, Class> localNameToType = new HashMap<String, Class>();
for (String methodKey : aciInterfacesDefinedMethods.keySet()) {
Method fieldMethod = aciInterfacesDefinedMethods.get(methodKey);
String methodName = fieldMethod.getName();
if (!(methodName.startsWith("get") || methodName.startsWith("set"))) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface can have only getter/setter methods.", "7.5.1", errorBuffer);
continue;
}
// let us get field name:
String fieldName = methodName.replaceFirst("set", "").replaceFirst("get", "");
if (!Character.isUpperCase(fieldName.charAt(0))) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface can have only getter/setter methods - 4th char in those methods must be capital.",
"7.5.1", errorBuffer);
}
// check throws clause.
// number of parameters
if (fieldMethod.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface getter method must have empty throws clause: " + fieldMethod.getName(), "7.5.1",
errorBuffer);
}
boolean isGetter = methodName.startsWith("get");
Class fieldType = null;
if (isGetter) {
// no params
if (fieldMethod.getParameterTypes() != null && fieldMethod.getParameterTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface getter method must not have parameters: " + fieldMethod.getName(), "7.5.1",
errorBuffer);
}
fieldType = fieldMethod.getReturnType();
if (fieldType.getName().compareTo("void") == 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface getter method must have return type: " + fieldMethod.getName(), "7.5.1",
errorBuffer);
}
} else {
if (fieldMethod.getParameterTypes() != null && fieldMethod.getParameterTypes().length != 1) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface setter method must single parameter: " + fieldMethod.getName(), "7.5.1",
errorBuffer);
// Here we quick fail
continue;
}
fieldType = fieldMethod.getParameterTypes()[0];
if (fieldMethod.getReturnType().getName().compareTo("void") != 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface setter method must not have return type: " + fieldMethod.getName(), "7.5.1",
errorBuffer);
}
}
// Field type can be primitive and serialzable
if (!(_PRIMITIVES.contains(fieldType.getName()) || ClassUtils.checkInterfaces(fieldType, "java.io.Serializable") != null)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + " sbb activity context interface field(" + fieldName
+ ") has wrong type, only primitives and serializable: " + fieldType, "7.5.1", errorBuffer);
// we fail here
continue;
}
if (localNameToType.containsKey(fieldName)) {
Class storedType = localNameToType.get(fieldName);
if (!storedType.equals(fieldType)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass()
+ " sbb activity context interface has wrong definition of parameter - setter and getter types do not match: "
+ fieldName + ", type1: " + fieldType.getName() + " typ2:" + storedType.getName(), "7.5.1", errorBuffer);
// we fail here
continue;
}
} else {
// simply store
localNameToType.put(fieldName, fieldType);
}
}
// FIXME: add check against components get aci fields ?
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateGetChildRelationMethods(Map<String, Method> sbbAbstractClassAbstractMethod,
Map<String, Method> sbbAbstractClassAbstractMethodFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
// FIXME: its cant be out of scope, since its byte....
// we look for method key
for (MGetChildRelationMethod mMetod : this.component.getDescriptor().getSbbClasses().getSbbAbstractClass().getChildRelationMethods().values()) {
if (mMetod.getDefaultPriority() > 127 || mMetod.getDefaultPriority() < -128) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "Defined get child relation method priority for method: "
+ mMetod.getChildRelationMethodName() + " is out of scope!!", "6.8", errorBuffer);
}
// This is key == <<methodName>>()Ljavax/slee/ChildRelation
// We it makes sure that method name, parameters, and return type is
// ok.
String methodKey = mMetod.getChildRelationMethodName() + _SBB_GET_CHILD_RELATION_SIGNATURE_PART;
Method childRelationMethod = null;
childRelationMethod = sbbAbstractClassAbstractMethod.get(methodKey);
if (childRelationMethod == null) {
childRelationMethod = sbbAbstractClassAbstractMethodFromSuperClasses.get(methodKey);
}
if (childRelationMethod == null) {
passed = false;
errorBuffer = appendToBuffer(
this.component.getAbstractSbbClass()
+ "Defined get child rekatuib method: "
+ mMetod.getChildRelationMethodName()
+ " is not matched by any abstract method, either its not abstract, is private, has parameter or has wrong return type(should be javax.slee.ChildRelation)!!",
"6.8", errorBuffer);
// we fail fast here
continue;
}
// if we are here we have to check throws clause, prefix - it cant
// be ejb or sbb
if (childRelationMethod.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "Defined get child relation method priority for method: "
+ mMetod.getChildRelationMethodName() + " must hot have throws clause", "6.8", errorBuffer);
}
if (childRelationMethod.getName().startsWith("ejb") || childRelationMethod.getName().startsWith("sbb")) {
// this is checked for concrete methods only
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "Defined get child relation method priority for method: "
+ mMetod.getChildRelationMethodName() + " has wrong prefix, it can not start with \"ejb\" or \"sbb\".!", "6.8", errorBuffer);
}
// remove, we will later determine methods that were not implemented
// by this
if (childRelationMethod != null) {
sbbAbstractClassAbstractMethod.remove(methodKey);
sbbAbstractClassAbstractMethodFromSuperClasses.remove(methodKey);
}
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
boolean validateSbbLocalInterface(Map<String, Method> sbbAbstractClassConcreteMethods,
Map<String, Method> sbbAbstractClassConcreteFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
try {
if (this.component.getDescriptor().getSbbClasses().getSbbLocalInterface() == null)
return passed;
Class sbbLocalInterfaceClass = this.component.getSbbLocalInterfaceClass();
if (!sbbLocalInterfaceClass.isInterface()) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "DSbbLocalInterface: " + sbbLocalInterfaceClass.getName()
+ " MUST be an interface!", "5.6", errorBuffer);
return passed;
}
Class genericSbbLocalInterface = ClassUtils.checkInterfaces(sbbLocalInterfaceClass, "javax.slee.SbbLocalObject");
if (genericSbbLocalInterface == null) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "DSbbLocalInterface: " + sbbLocalInterfaceClass.getName()
+ " does not implement javax.slee.SbbLocalInterface super interface in any way!!!", "5.6", errorBuffer);
}
int sbbLocalInterfaceClassModifiers = sbbLocalInterfaceClass.getModifiers();
if (this.component.isSlee11() && sbbLocalInterfaceClass.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "SbbLocalInterface: " + sbbLocalInterfaceClass.getName()
+ " is nto defined in package", "6.5", errorBuffer);
}
if (!Modifier.isPublic(sbbLocalInterfaceClassModifiers)) {
passed = false;
errorBuffer = appendToBuffer(this.component.getAbstractSbbClass() + "SbbLocalInterface: " + sbbLocalInterfaceClass.getName()
+ " must be public!", "5.6", errorBuffer);
}
Set<String> ignore = new HashSet<String>();
ignore.add("javax.slee.SbbLocalObject");
ignore.add("java.lang.Object");
Map<String, Method> interfaceMethods = ClassUtils.getAllInterfacesMethods(sbbLocalInterfaceClass, ignore);
// here we have all defined methods in interface, we have to checkif
// their names do not start with sbb/ejb and if they are contained
// in
// collections with concrete methods from sbb
//System.err.println(sbbAbstractClassConcreteMethods.keySet());
for (Method methodToCheck : interfaceMethods.values()) {
if (methodToCheck.getName().startsWith("ejb") || methodToCheck.getName().startsWith("sbb")) {
passed = false;
errorBuffer = appendToBuffer("Method from SbbLocalInterface: " + sbbLocalInterfaceClass.getName() + " starts with wrong prefix: "
+ methodToCheck.getName(), "5.6", errorBuffer);
}
Method methodFromSbbClass = ClassUtils.getMethodFromMap(methodToCheck.getName(), methodToCheck.getParameterTypes(),
sbbAbstractClassConcreteMethods, sbbAbstractClassConcreteFromSuperClasses);
if (methodFromSbbClass == null) {
passed = false;
errorBuffer = appendToBuffer("Method from SbbLocalInterface: " + sbbLocalInterfaceClass.getName() + " with name: "
+ methodToCheck.getName() + " is not implemented by sbb class or its super classes!", "5.6", errorBuffer);
// we fails fast here
continue;
}
// XXX: Note this does not check throws clause, only name and
// signature
// this side
// FIXME: Note that we dont check modifier, is this corerct
if (!(methodFromSbbClass.getName().compareTo(methodToCheck.getName()) == 0)
|| !methodFromSbbClass.getReturnType().equals(methodToCheck.getReturnType())
|| !Arrays.equals(methodFromSbbClass.getParameterTypes(), methodToCheck.getParameterTypes())
|| !Arrays.equals((Object[]) methodFromSbbClass.getExceptionTypes(), (Object[]) methodToCheck.getExceptionTypes())) {
passed = false;
errorBuffer = appendToBuffer("Method from SbbLocalInterface: " + sbbLocalInterfaceClass.getName() + " with name: "
+ methodToCheck.getName()
+ " is not implemented by sbb class or its super classes. Its visibility, throws clause or modifiers are different!",
"5.6", errorBuffer);
// we fails fast here
continue;
}
}
// FIXME: is this ok, is it needed ? If not checked here, abstract
// methods check will make it fail later, but not concrete ?
// now lets check javax.slee.SbbLocalObject methods - sbb cant have
// those implemented or defined as abstract.
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateCmpFileds(Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
for (MSbbCMPField entry : this.component.getDescriptor().getSbbClasses().getSbbAbstractClass().getCmpFields()) {
String fieldName = entry.getCmpFieldName();
Character c = fieldName.charAt(0);
// we must start with lower case letter
if (!Character.isLetter(c) || !Character.isLowerCase(c)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate CMP field name. Name must start with lower case letter: " + fieldName, "6.5.1",
errorBuffer);
// In this case we should fail fast?
continue;
}
// lets find method in abstracts, it cannot be implemented
// FIXME: do we have to check concrete as well?
String methodPartFieldName = Character.toUpperCase(c) + fieldName.substring(1);
String getterName = "get" + methodPartFieldName;
String setterName = "set" + methodPartFieldName;
Method getterFieldMethod = null;
Method setterFieldMethod = null;
// Both have to be present, lets do trick, first we can get getter
// so we know field type and can get setter
Class sbbAbstractClass = this.component.getAbstractSbbClass();
getterFieldMethod = ClassUtils.getMethodFromMap(getterName, new Class[0], sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses);
if (getterFieldMethod == null) {
errorBuffer = appendToBuffer("Failed to validate CMP field. Could not find getter method: " + getterName
+ ". Both accessors must be present.", "6.5.1", errorBuffer);
passed = false;
// we fail fast here
continue;
}
Class fieldType = getterFieldMethod.getReturnType();
setterFieldMethod = ClassUtils.getMethodFromMap(setterName, new Class[] { fieldType }, sbbAbstractClassMethods,
sbbAbstractMethodsFromSuperClasses);
if (setterFieldMethod == null) {
errorBuffer = appendToBuffer("Failed to validate CMP field. Could not find setter method: " + setterName
+ " with single parameter of type: " + getterFieldMethod.getReturnType()
+ ". Both accessors must be present and have the same type.", "6.5.1", errorBuffer);
passed = false;
// we fail fast here
continue;
}
// not needed
// if (setterFieldMethod.getReturnType().getName().compareTo("void")
// != 0) {
// errorBuffer = appendToBuffer(
// "Failed to validate CMP field. Setter method: "
// + setterName + " has return type of: "
// + setterFieldMethod.getReturnType(), "6.5.1",
// errorBuffer);
// }
// we know methods are here, we must check if they are - abstract,
// public, what about static and native?
int modifiers = getterFieldMethod.getModifiers();
if (!Modifier.isPublic(modifiers) || !Modifier.isAbstract(modifiers)) {
errorBuffer = appendToBuffer("Failed to validate CMP field. Getter method is either public or not abstract: " + getterName, "6.5.1",
errorBuffer);
passed = false;
}
modifiers = setterFieldMethod.getModifiers();
if (!Modifier.isPublic(modifiers) || !Modifier.isAbstract(modifiers)) {
errorBuffer = appendToBuffer("Failed to validate CMP field. Setter method is neither public nor abstract: " + getterName, "6.5.1",
errorBuffer);
passed = false;
}
// 1.1 and 1.0 allow
// primitives and serializables and if reference is present sbbLo or
// derived type
boolean referenceIsPresent = entry.getSbbAliasRef() != null;
boolean isSbbLOFieldType = false;
if (_PRIMITIVES.contains(fieldType.getName())) {
// do nothing, this does not include wrapper classes,
isSbbLOFieldType = false;
} else if (ClassUtils.checkInterfaces(fieldType, "javax.slee.SbbLocalObject") != null) {
// FIXME: is there a better way?
// in 1.0 sbb ref MUST be present always
// again, if referenced sbb has wrong type of SbbLO defined here
// it mail fail, however it a matter of validating other
// component
isSbbLOFieldType = true;
/*
* emmartins: page 70 of slee 1.1 specs say that sbb-alias-ref is now optional (it doesn't say it is just for slee 1.1 components)
*
if (!this.component.isSlee11() && !referenceIsPresent) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. In JSLEE 1.0 Sbb reference element must be present when CMP type is Sbb Local Object or derived, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
// for this we fail fast, nothing more to do.
continue;
}
*/
// now its a check for 1.1 and 1.0
if (referenceIsPresent) {
SbbID referencedSbb = null;
SbbComponent referencedComponent = null;
if (entry.getSbbAliasRef().equals(this.component.getDescriptor().getSbbAlias())) {
referencedSbb = this.component.getSbbID();
referencedComponent = this.component;
}
else {
for (MSbbRef mSbbRef : this.component.getDescriptor().getSbbRefs()) {
if (mSbbRef.getSbbAlias().equals(entry.getSbbAliasRef())) {
referencedSbb = new SbbID(mSbbRef.getSbbName(), mSbbRef.getSbbVendor(), mSbbRef.getSbbVersion());
break;
}
}
if (referencedSbb == null) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Field references sbb with alias "+entry.getSbbAliasRef()+" but no sbb ref has been found with which such alias. Field: " + fieldName,
"6.5.1", errorBuffer);
continue;
}
else {
referencedComponent = this.repository.getComponentByID(referencedSbb);
if (referencedComponent == null) {
//FIXME: throw or fail?
throw new SLEEException("Referenced (in cmp field) "+referencedSbb+" was not found in component repository, this should not happen since dependencies were already verified");
}
}
}
// FIXME: field type must be equal to defined or must be
// javax.slee.SbbLocalObject = what about intermediate types
// X -> Y -> SbbLocalObject - and we have Y?
if (referencedComponent.getDescriptor().getSbbLocalInterface()!=null && fieldType.getName().compareTo(referencedComponent.getDescriptor().getSbbLocalInterface().getSbbLocalInterfaceName()) == 0) {
// its ok
} else if (fieldType.getName().compareTo("javax.slee.SbbLocalObject") == 0) {
// its ok?
} else if (ClassUtils.checkInterfaces(referencedComponent.getSbbLocalInterfaceClass(), fieldType.getName()) != null) {
// its ok
} else {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Field type for sbb entities must be of generic type javax.slee.SbbLocalObject or type declared by referenced sbb, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
}
}
/*
* emmartins: page 70 of slee 1.1 specs say that sbb-alias-ref is now optional
*
else {
// here only 1.1 will go
if (fieldType.getName().compareTo("javax.slee.SbbLocalObject") == 0) {
// its ok?
} else {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Field type for sbb entities must be of generic type javax.slee.SbbLocalObject when no reference to sbb is present, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
}
}
*/
// FIXME: end of checks here?
} else if (this.component.isSlee11()) {
isSbbLOFieldType = false;
if (fieldType.getName().compareTo("javax.slee.EventContext") == 0) {
// we do nothing, its ok.
} else if (ClassUtils.checkInterfaces(fieldType, "javax.slee.profile.ProfileLocalObject") != null) {
// FIXME: there is no ref maybe we shoudl check referenced
// profiles?
} else if (ClassUtils.checkInterfaces(fieldType, "java.io.Serializable") != null) {
// do nothing, its check same as below
} else if (ClassUtils.checkInterfaces(fieldType, "javax.slee.ActivityContextInterface") != null) {
// we can haev generic ACI or derived object defined in
// sbb,... uffff
Class definedAciType = this.component.getActivityContextInterface();
if (definedAciType != null && definedAciType.getName().equals(fieldType.getName())) {
// do nothing
} else if (fieldType.getName().compareTo("javax.slee.ActivityContextInterface") == 0) {
// do nothing
} else if (definedAciType != null && ClassUtils.checkInterfaces(definedAciType, fieldType.getName()) != null) {
// do anything
} else {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Field type for ACIs must be of generic type javax.slee.ActivityContextInterface or defined by sbb Custom ACI, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
}
} else {
// FAIL
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Field type must be: primitive,serializable, SbbLocalObject or derived,(1.1): EventContext, ActivityContextInterface or derived, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
}
} else if (ClassUtils.checkInterfaces(fieldType, "java.io.Serializable") != null) {
// This is tricky, someone can implement serializable in SbbLO
// derived objec, however it could not be valid SBB LO(for
// isntance wrong Sbb,not extending SbbLO) but if this was first
// it would pass test without checks on constraints
// this includes all serializables and primitive wrapper classes
isSbbLOFieldType = false;
} else {
// FAIL
}
if (referenceIsPresent && !isSbbLOFieldType) {
// this is not permited?
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate CMP field. Sbb reefrence is present when field type is not Sbb Local Object or derived, field name: "
+ fieldName + " type: " + fieldType, "6.5.1", errorBuffer);
}
// Check throws clause
if (getterFieldMethod.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate CMP field. Getter method declared throws clause: "
+ Arrays.toString(getterFieldMethod.getExceptionTypes()), "6.5.1", errorBuffer);
}
if (setterFieldMethod.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate CMP field. Setter method declared throws clause: "
+ Arrays.toString(setterFieldMethod.getExceptionTypes()), "6.5.1", errorBuffer);
}
// else remove those from list
sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(setterFieldMethod));
sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(getterFieldMethod));
sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(setterFieldMethod));
sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(getterFieldMethod));
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
boolean validateEventHandlers(Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses,
Map<String, Method> concreteMethods, Map<String, Method> concreteMethodsFromSuperClasses) {
boolean passed = true;
// String errorBuffer = new String("");
// Abstract methods are for fire methods, we have to check them and
// remove if present :)
Map<EventTypeID,MEventEntry> events = this.component.getDescriptor().getEventEntries();
for (MEventEntry event : events.values()) {
switch (event.getEventDirection()) {
case Fire:
if (!validateFireEvent(event, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses)) {
passed = false;
}
break;
case Receive:
if (!validateReceiveEvent(event, concreteMethods, concreteMethodsFromSuperClasses)) {
passed = false;
}
break;
case FireAndReceive:
if (!validateFireEvent(event, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses)) {
passed = false;
}
if (!validateReceiveEvent(event, concreteMethods, concreteMethodsFromSuperClasses)) {
passed = false;
}
break;
}
}
return passed;
}
boolean validateReceiveEvent(MEventEntry event, Map<String, Method> concreteMethods, Map<String, Method> concreteMethodsFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
try {
// we can have only one receive method
EventTypeComponent eventTypeComponent = this.repository.getComponentByID(event.getEventReference().getComponentID());
if (eventTypeComponent == null) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. reference points to event comopnent that has not been validated, event name: "
+ event.getEventName(), "8.5.2", errorBuffer);
return passed;
}
Class eventClass = eventTypeComponent.getEventTypeClass();
Class sbbAbstractClass = this.component.getAbstractSbbClass();
String methodName = "on" + event.getEventName();
// lets look for basic event handler
// the thing with each event handler is that aci can be generic or
// sbb
// custom....
Method receiveMethod = null;
Method receiveMethodCustomACI = null;
boolean receiverWithContextPresent = false;
boolean receiverWithoutContextPresent = false;
if (this.component.isSlee11()) {
receiveMethod = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass, javax.slee.ActivityContextInterface.class,
javax.slee.EventContext.class }, concreteMethods, concreteMethodsFromSuperClasses);
if (this.component.getActivityContextInterface() != null)
receiveMethodCustomACI = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass,
this.component.getActivityContextInterface(), javax.slee.EventContext.class }, concreteMethods,
concreteMethodsFromSuperClasses);
// is there any clever way to lookup those?
// ok, here only one method can be present
if (receiveMethod != null && receiveMethodCustomACI != null) {
// we cant have both
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. Sbb can not define event receive method with generic and custom aci, event name: "
+ event.getEventName(), "8.5.2", errorBuffer);
}
// now here we are sure we have one or none
if (receiveMethod != null) {
receiverWithContextPresent = true;
if (!validateReceiveMethodSignature(receiveMethod, "8.5.2")) {
passed = false;
}
receiveMethod = null;
} else if (receiveMethodCustomACI != null) {
receiverWithContextPresent = true;
if (!validateReceiveMethodSignature(receiveMethodCustomACI, "8.5.2")) {
passed = false;
}
receiveMethodCustomACI = null;
}
}
// this is for all
receiveMethod = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass, javax.slee.ActivityContextInterface.class },
concreteMethods, concreteMethodsFromSuperClasses);
if (this.component.getActivityContextInterface() != null)
receiveMethodCustomACI = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass,
this.component.getActivityContextInterface() }, concreteMethods, concreteMethodsFromSuperClasses);
// is there any clever way to lookup those?
// ok, here only one method can be present
if (receiveMethod != null && receiveMethodCustomACI != null) {
// we cant have both
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. Sbb can not define event receive method with generic and custom aci, event name: "
+ event.getEventName(), "8.5.2", errorBuffer);
}
// now here we are sure we have one or none
if (receiveMethod != null) {
receiverWithoutContextPresent = true;
if (!validateReceiveMethodSignature(receiveMethod, "8.5.2"))
passed = false;
} else if (receiveMethodCustomACI != null) {
receiverWithoutContextPresent = true;
if (!validateReceiveMethodSignature(receiveMethodCustomACI, "8.5.2"))
passed = false;
}
// here we have to check, only one can be present
if (receiverWithoutContextPresent && receiverWithContextPresent) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. Sbb can not define event receive method with and without EventContext, only one can be present: "
+ event.getEventName(), "8.5.2", errorBuffer);
}
if (!receiverWithoutContextPresent && !receiverWithContextPresent) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. Sbb must define handler method when direction is \"XReceive\". Event receiver has different name or wrong parameters, event: "
+ event.getEventName(), "8.5.2", errorBuffer);
}
// now its time for initial event selector
if (event.isInitialEvent() && event.getInitialEventSelectorMethod() != null
&& !validateInitialEventSelector(event, concreteMethods, concreteMethodsFromSuperClasses)) {
// FIXME: we dont check if variable or selector method is
// present
passed = false;
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateInitialEventSelector(MEventEntry event, Map<String, Method> concreteMethods, Map<String, Method> concreteMethodsFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
try {
if (event.getInitialEventSelectorMethod().startsWith("ejb") || event.getInitialEventSelectorMethod().startsWith("sbb")) {
passed = false;
errorBuffer = appendToBuffer("Initial event seelctor method can not start with \"ejb\" or \"sbb\", method name: "
+ event.getInitialEventSelectorMethod(), "8.6.4", errorBuffer);
}
Method m = ClassUtils.getMethodFromMap(event.getInitialEventSelectorMethod(), new Class[] { javax.slee.InitialEventSelector.class },
concreteMethods, concreteMethodsFromSuperClasses);
if (m == null) {
// TODO Auto-generated catch block
// e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer("Failed to find initial event selector method, method name: " + event.getInitialEventSelectorMethod(),
"8.6.4", errorBuffer);
return passed;
}
// FIXME: It has to be concrete...
int modifiers = m.getModifiers();
if (Modifier.isAbstract(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate initial event selector method" + " Receive method is abstract, method name: "
+ m.getName(), "8.6.4", errorBuffer);
}
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate initial event selector method" + " Receive method is not public, method name: "
+ m.getName(), "8.6.4", errorBuffer);
}
if (Modifier.isStatic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate initial event selector method" + " Receive method is static, method name: "
+ m.getName(), "8.6.4", errorBuffer);
}
if (Modifier.isFinal(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate initial event selector method" + " Receive method is final, method name: "
+ m.getName(), "8.6.4", errorBuffer);
}
// FIXME: native?
if (m.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Method has throws clause, method: " + m.getName(), "8.6.4",
errorBuffer);
}
if (m.getReturnType().getName().compareTo("javax.slee.InitialEventSelector") != 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate initial event selector method"
+ " Return type must be javax.slee.InitialEventSelector, method: " + m.getName(), "8.6.4", errorBuffer);
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateReceiveMethodSignature(Method m, String section) {
boolean passed = true;
String errorBuffer = new String("");
int modifiers = m.getModifiers();
if (Modifier.isAbstract(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate receive event method" + " Receive method is abstract, method name: " + m.getName(),
section, errorBuffer);
}
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate receive event method" + " Receive method is not public, method name: " + m.getName(),
section, errorBuffer);
}
if (Modifier.isStatic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate receive event method" + " Receive method is static, method name: " + m.getName(),
section, errorBuffer);
}
if (Modifier.isFinal(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate receive event method" + " Receive method is final, method name: " + m.getName(),
section, errorBuffer);
}
// FIXME: native?
// FIXME: only runtime exceptions?
if (m.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method is has throws clause, method: " + m.getName(),
section, errorBuffer);
}
if (m.getReturnType().getName().compareTo("void") != 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate Receive event method" + " Receive method cant have return type, method: " + m.getName(),
section, errorBuffer);
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
boolean validateFireEvent(MEventEntry event, Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
try {
// we can have only one receive method
EventTypeComponent eventTypeComponent = this.repository.getComponentByID(event.getEventReference().getComponentID());
if (eventTypeComponent == null) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate event receive method. reference points to event comopnent that has not been validated, event name: "
+ event.getEventName(), "8.5.2", errorBuffer);
return passed;
}
Class eventClass = eventTypeComponent.getEventTypeClass();
Class sbbAbstractClass = this.component.getAbstractSbbClass();
String methodName = "fire" + event.getEventName();
// we we have to validate abstract methods :}
// this is 1.0
Method fireMethod = null;
// this is 1.1
Method fire11Method = null;
// FIXME: is it ok to refer directly to:
// javax.slee.ActivityContextInterface.class ??
fireMethod = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass, javax.slee.ActivityContextInterface.class,
javax.slee.Address.class }, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses);
fire11Method = ClassUtils.getMethodFromMap(methodName, new Class[] { eventClass, javax.slee.ActivityContextInterface.class,
javax.slee.Address.class, javax.slee.ServiceID.class }, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses);
if (!this.component.isSlee11()) {
if (fireMethod == null) {
// fail fast
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate fire vent method, JSLEE 1.0 sbbs have to have method with signature: public abstract void fire<event name>(<event class> event,ActivityContextInterface activity,Address address);. Event name: "
+ event.getEventName(), "8.5.1", errorBuffer);
// the end
return passed;
}
} else {
if (fireMethod == null && fire11Method == null) {
// fail fast
passed = false;
errorBuffer = appendToBuffer(
"Failed to validate fire vent method, JSLEE 1.1 sbbs have to have one of those methods. Sbb class either does not declare them, method has wrong parameters/name or is concrete. Event name: "
+ event.getEventName(), "8.5.1", errorBuffer);
// the end
return passed;
}
}
if (this.component.isSlee11() && fire11Method != null && !validateFireMethodSignature(fire11Method, "8.5.1")) {
passed = false;
}
// if we are here we are either 1.0 in which case this method is not
// null, or we are 1.1 in which case it could be
if (fireMethod != null && !validateFireMethodSignature(fireMethod, "8.5.1")) {
passed = false;
}
if (fire11Method != null) {
sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(fire11Method));
sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(fire11Method));
}
if (fireMethod != null) {
sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(fireMethod));
sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(fireMethod));
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateFireMethodSignature(Method m, String section) {
boolean passed = true;
String errorBuffer = new String("");
int modifiers = m.getModifiers();
if (!Modifier.isAbstract(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method is not abstract, method name: " + m.getName(),
section, errorBuffer);
}
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method is not public, method name: " + m.getName(), section,
errorBuffer);
}
if (Modifier.isStatic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method is static, method name: " + m.getName(), section,
errorBuffer);
}
// FIXME: native?
if (m.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method has throws clause, method: " + m.getName(), section,
errorBuffer);
}
if (m.getReturnType().getName().compareTo("void") != 0) {
passed = false;
errorBuffer = appendToBuffer("Failed to validate fire event method" + " Fire method cant have return type, method: " + m.getName(),
section, errorBuffer);
}
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
return passed;
}
boolean validateSbbUsageParameterInterface(Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses) {
if (this.component.getUsageParametersInterface() == null) {
return true;
} else {
return UsageInterfaceValidator.validateSbbUsageParameterInterface(this.component, sbbAbstractClassMethods,
sbbAbstractMethodsFromSuperClasses);
}
}
boolean validateGetProfileCmpInterfaceMethods(Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses) {
// Section 6.7
boolean passed = true;
String errorBuffer = new String("");
try {
Map<String,MGetProfileCMPMethod> profileCmpMethods = this.component.getDescriptor().getSbbClasses().getSbbAbstractClass()
.getProfileCMPMethods();
if (profileCmpMethods.size() == 0) {
return passed;
}
// eh, else we have to do all checks
for (MGetProfileCMPMethod method : profileCmpMethods.values()) {
if (method.getProfileCmpMethodName().startsWith("ejb") || method.getProfileCmpMethodName().startsWith("sbb")) {
passed = false;
errorBuffer = appendToBuffer(
"Wrong method prefix, get profile cmp interface method must not start with \"sbb\" or \"ejb\", method: "
+ method.getProfileCmpMethodName(), "6,7", errorBuffer);
}
Method m = ClassUtils.getMethodFromMap(method.getProfileCmpMethodName(), new Class[] { ProfileID.class }, sbbAbstractClassMethods,
sbbAbstractMethodsFromSuperClasses);
;
if (m == null) {
passed = false;
errorBuffer = appendToBuffer(
"Failed to find method in sbb abstract class - it either does not exist,is private or has wrong parameter, method: "
+ method.getProfileCmpMethodName(), "6,7", errorBuffer);
continue;
}
sbbAbstractClassMethods.values().remove(m);
sbbAbstractMethodsFromSuperClasses.values().remove(m);
int modifiers = m.getModifiers();
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Get profile CMP interface method must be public, method: " + method.getProfileCmpMethodName(),
"6,7", errorBuffer);
continue;
}
if (!Modifier.isAbstract(modifiers)) {
passed = false;
errorBuffer = appendToBuffer("Get profile CMP interface method must be abstract, method: " + method.getProfileCmpMethodName(),
"6,7", errorBuffer);
continue;
}
Class methodReturnType = m.getReturnType();
// this is referential integrity
Map<String, ProfileSpecificationID> map = new HashMap<String, ProfileSpecificationID>();
for (MProfileSpecRef rf : this.component.getDescriptor().getProfileSpecRefs()) {
map.put(rf.getProfileSpecAlias(), rf.getComponentID());
}
ProfileSpecificationID profileID = map.get(method.getProfileSpecAliasRef());
ProfileSpecificationComponent profileComponent = this.repository.getComponentByID(profileID);
if (profileComponent == null) {
// this means referential integrity is nto met, possibly
// class is not loaded
passed = false;
errorBuffer = appendToBuffer("Get profile CMP interface method references profile which has not been validated, method: "
+ method.getProfileCmpMethodName() + " , reference: " + method.getProfileSpecAliasRef(), "6,7", errorBuffer);
continue;
}
Class profileDefinedCMPInterface = profileComponent.getProfileCmpInterfaceClass();
if (methodReturnType.getName().compareTo(profileDefinedCMPInterface.getName()) != 0
&& ClassUtils.checkInterfaces(profileDefinedCMPInterface, methodReturnType.getName()) == null) {
passed = false;
errorBuffer = appendToBuffer(
"Get profile CMP interface method has wrong return type - it has to be defined CMP interface or its super class, method: "
+ method.getProfileCmpMethodName(), "6,7", errorBuffer);
}
Class[] exceptions = m.getExceptionTypes();
// UnrecognizedProfileTableNameException,
// UnrecognizedProfileNameException
if (exceptions.length != 2) {
passed = false;
errorBuffer = appendToBuffer(
"Get profile CMP interface method has wrong number of exceptions, it can throw only two - UnrecognizedProfileNameException and UnrecognizedProfileTableNameException, method: "
+ method.getProfileCmpMethodName(), "6,7", errorBuffer);
}
HashSet<String> possibleExcpetions = new HashSet<String>();
possibleExcpetions.add(UnrecognizedProfileTableNameException.class.getName());
possibleExcpetions.add(UnrecognizedProfileNameException.class.getName());
for (Class c : exceptions) {
if (possibleExcpetions.contains(c.getName())) {
possibleExcpetions.remove(c.getName());
}
}
if (possibleExcpetions.size() != 0) {
passed = false;
errorBuffer = appendToBuffer("Get profile CMP interface method has decalration of throws clause, it lacks following exceptions: "
+ Arrays.toString(possibleExcpetions.toArray()) + " , method: " + method.getProfileCmpMethodName(), "6,7", errorBuffer);
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateEnvEntries() {
boolean passed = true;
String errorBuffer = new String("");
try {
List<MEnvEntry> envEntries = this.component.getDescriptor().getEnvEntries();
for (MEnvEntry e : envEntries) {
if (!_ENV_ENTRIES_TYPES.contains(e.getEnvEntryType())) {
passed = false;
errorBuffer = appendToBuffer("Env entry has wrong type: " + e.getEnvEntryType() + " , method: " + e.getEnvEntryName(), "6.13",
errorBuffer);
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
boolean validateDescriptor() {
boolean passed = true;
String errorBuffer = new String("");
try {
Map<String, MProfileSpecRef> declaredProfileReferences = new HashMap<String, MProfileSpecRef>();
Map<String, MSbbRef> declaredSbbreferences = new HashMap<String, MSbbRef>();
SbbDescriptorImpl descriptor = this.component.getDescriptor();
for (MProfileSpecRef ref : descriptor.getProfileSpecRefs()) {
// if(ref.getProfileSpecAlias()==null ||
// ref.getProfileSpecAlias().compareTo("")==0)
if (ref.getProfileSpecAlias() != null && ref.getProfileSpecAlias().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares profile spec reference without alias, id: " + ref.getComponentID(),
"3.1.8", errorBuffer);
} else if (declaredProfileReferences.containsKey(ref.getProfileSpecAlias())) {
passed = false;
errorBuffer = appendToBuffer(
"Sbb descriptor declares profile spec reference more than once, alias: " + ref.getProfileSpecAlias(), "3.1.8",
errorBuffer);
} else {
declaredProfileReferences.put(ref.getProfileSpecAlias(), ref);
}
}
for (MSbbRef ref : descriptor.getSbbRefs()) {
if (ref.getSbbAlias() == null || ref.getSbbAlias().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares sbb reference without alias, id: " + ref.getComponentID(), "3.1.8",
errorBuffer);
} else if (declaredSbbreferences.containsKey(ref.getSbbAlias())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares sbb reference more than once, alias: " + ref.getSbbAlias(), "3.1.8",
errorBuffer);
} else {
declaredSbbreferences.put(ref.getSbbAlias(), ref);
}
}
Set<String> childRelationMethods = new HashSet<String>();
for (MGetChildRelationMethod childMethod : descriptor.getSbbClasses().getSbbAbstractClass().getChildRelationMethods().values()) {
if (childMethod.getChildRelationMethodName() == null || childMethod.getChildRelationMethodName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer(
"Sbb descriptor declares child relation method without name, alias: " + childMethod.getSbbAliasRef(), "3.1.8",
errorBuffer);
} else if (childMethod.getSbbAliasRef() == null || childMethod.getSbbAliasRef().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares child relation method without sbb alias, name: "
+ childMethod.getChildRelationMethodName(), "3.1.8", errorBuffer);
} else if (!declaredSbbreferences.containsKey(childMethod.getSbbAliasRef())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares child relation method with sbb alias that has not been declared, name: "
+ childMethod.getChildRelationMethodName() + ", method alias: " + childMethod.getSbbAliasRef(), "3.1.8", errorBuffer);
} else if (childRelationMethods.contains(childMethod.getChildRelationMethodName())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares child relation method more than once, name: "
+ childMethod.getChildRelationMethodName(), "3.1.8", errorBuffer);
} else {
childRelationMethods.add(childMethod.getChildRelationMethodName());
}
}
Map<String, MSbbCMPField> declaredCmps = new HashMap<String, MSbbCMPField>();
for (MSbbCMPField cmp : descriptor.getSbbClasses().getSbbAbstractClass().getCmpFields()) {
if (cmp.getCmpFieldName() == null || cmp.getCmpFieldName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor cmp field with empty name.", "3.1.8", errorBuffer);
} else if (cmp.getSbbAliasRef() != null && cmp.getSbbAliasRef().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares cmp field with empty sbb alias, name: " + cmp.getCmpFieldName(), "3.1.8",
errorBuffer);
} else if (declaredCmps.containsKey(cmp.getCmpFieldName())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares cmp field more than once, name: " + cmp.getCmpFieldName(), "3.1.8",
errorBuffer);
} else {
declaredCmps.put(cmp.getCmpFieldName(), cmp);
}
}
// This is required, events can be decalred once
Map<String, MEventTypeRef> eventNameToReference = new HashMap<String, MEventTypeRef>();
for (MEventEntry event : descriptor.getEventEntries().values()) {
if (event.getEventName() == null || event.getEventName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares event with empty event name, ", "3.1.8", errorBuffer);
} else if (eventNameToReference.containsKey(event.getEventName())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares event with the same event name more than once, name: "
+ event.getEventName(), "3.1.8", errorBuffer);
} else if (eventNameToReference.containsValue(event.getEventReference())) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares event reference twice, events can be references only once, name: "
+ event.getEventName(), "3.1.8", errorBuffer);
} else {
eventNameToReference.put(event.getEventName(), event.getEventReference());
}
}
// FIXME: ra part?
if (descriptor.getSbbClasses().getSbbActivityContextInterface() != null) {
if (descriptor.getSbbClasses().getSbbActivityContextInterface().getInterfaceName() == null
|| descriptor.getSbbClasses().getSbbActivityContextInterface().getInterfaceName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares sbb aci which is empty.", "3.1.8", errorBuffer);
}
}
if (descriptor.getSbbClasses().getSbbLocalInterface() != null) {
if (descriptor.getSbbClasses().getSbbLocalInterface().getSbbLocalInterfaceName() == null
|| descriptor.getSbbClasses().getSbbLocalInterface().getSbbLocalInterfaceName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares sbb local interface which is empty.", "3.1.8", errorBuffer);
}
}
if (descriptor.getSbbClasses().getSbbUsageParametersInterface() != null) {
if (descriptor.getSbbClasses().getSbbUsageParametersInterface().getUsageParametersInterfaceName() == null
|| descriptor.getSbbClasses().getSbbUsageParametersInterface().getUsageParametersInterfaceName().compareTo("") == 0) {
passed = false;
errorBuffer = appendToBuffer("Sbb descriptor declares sbb usage interface which is empty.", "3.1.8", errorBuffer);
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
/**
* See section 1.3 of jslee 1.1 specs
*
* @return
*/
boolean validateCompatibilityReferenceConstraints() {
boolean passed = true;
String errorBuffer = new String("");
try {
if (!this.component.isSlee11()) {
// A 1.0 SBB must not reference or use a 1.1 Profile
// Specification. This must be enforced by a 1.1
// JAIN SLEE.
for (MProfileSpecRef profileReference : this.component.getDescriptor().getProfileSpecRefs()) {
ProfileSpecificationComponent specComponent = this.repository.getComponentByID(profileReference.getComponentID());
if (specComponent == null) {
// should not happen
passed = false;
errorBuffer = appendToBuffer("Referenced "+profileReference.getComponentID()+" was not found in component repository, this should not happen since dependencies were already verified","1.3", errorBuffer);
} else {
if (specComponent.isSlee11()) {
passed = false;
errorBuffer = appendToBuffer("Sbb is following 1.0 JSLEE contract, it must not reference 1.1 profile specification: " + profileReference.getComponentID(), "1.3", errorBuffer);
}
}
}
}
} finally {
if (!passed) {
if (logger.isEnabledFor(Level.ERROR)) {
logger.error(errorBuffer);
}
}
}
return passed;
}
protected String appendToBuffer(String message, String section, String buffer) {
buffer += (this.component.getDescriptor().getSbbID() + " : violates section " + section + " of jSLEE 1.1 specification : " + message + "\n");
return buffer;
}
}