/**
* Start time:10:45:52 2009-02-09<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.beans.Introspector;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
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 java.util.Map.Entry;
import javassist.Modifier;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ProfileSpecificationDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MEnvEntry;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MCMPField;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MCollator;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MIndexHint;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MCompare;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MHasPrefix;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MLongestPrefixMatch;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MQuery;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MQueryExpression;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MQueryParameter;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.query.MRangeMatch;
import org.mobicents.slee.container.component.profile.ProfileAttribute;
/**
* Start time:10:45:52 2009-02-09<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>
*/
public class ProfileSpecificationComponentValidator implements Validator {
private ComponentRepository repository = null;
private ProfileSpecificationComponent component = null;
private final static transient Logger logger = Logger
.getLogger(ProfileSpecificationComponentValidator.class);
// this does not include serializables
private final static Set<String> _ALLOWED_MANAGEMENT_TYPES;
static {
Set<String> tmp = new HashSet<String>();
// Section 10.17
tmp.add("int");
tmp.add("boolean");
tmp.add("byte");
tmp.add("char");
tmp.add("double");
tmp.add("float");
tmp.add("long");
tmp.add("short");
tmp.add(int[].class.toString());
tmp.add(boolean[].class.toString());
tmp.add(byte[].class.toString());
tmp.add(char[].class.toString());
tmp.add(double[].class.toString());
tmp.add(float[].class.toString());
tmp.add(long[].class.toString());
tmp.add(short[].class.toString());
tmp.add(Integer.class.toString());
tmp.add(Boolean.class.toString());
tmp.add(Byte.class.toString());
tmp.add(Character.class.toString());
tmp.add(Double.class.toString());
tmp.add(Float.class.toString());
tmp.add(Long.class.toString());
tmp.add(Short.class.toString());
tmp.add(Integer[].class.toString());
tmp.add(Boolean[].class.toString());
tmp.add(Byte[].class.toString());
tmp.add(Character[].class.toString());
tmp.add(Double[].class.toString());
tmp.add(Float[].class.toString());
tmp.add(Long[].class.toString());
tmp.add(Short[].class.toString());
tmp.add(Serializable.class.toString());
tmp.add(Serializable[].class.toString());
//Its serializable.
// tmp.add(String[].class.toString());
// tmp.add(String.class.toString());
_ALLOWED_MANAGEMENT_TYPES = Collections.unmodifiableSet(tmp);
}
//See section
private final static Set<String> _TYPES_WITH_ALLOWED_INDEX_HINTS;
static{
Set<String> tmp = new HashSet<String>();
tmp.add(java.lang.String.class.toString());
tmp.add(javax.slee.Address.class.toString());
tmp.add("int");
tmp.add("boolean");
tmp.add("byte");
tmp.add("char");
tmp.add("double");
tmp.add("float");
tmp.add("long");
tmp.add("short");
tmp.add(int[].class.toString());
tmp.add(boolean[].class.toString());
tmp.add(byte[].class.toString());
tmp.add(char[].class.toString());
tmp.add(double[].class.toString());
tmp.add(float[].class.toString());
tmp.add(long[].class.toString());
tmp.add(short[].class.toString());
tmp.add(Integer.class.toString());
tmp.add(Boolean.class.toString());
tmp.add(Byte.class.toString());
tmp.add(Character.class.toString());
tmp.add(Double.class.toString());
tmp.add(Float.class.toString());
tmp.add(Long.class.toString());
tmp.add(Short.class.toString());
tmp.add(Integer[].class.toString());
tmp.add(Boolean[].class.toString());
tmp.add(Byte[].class.toString());
tmp.add(Character[].class.toString());
tmp.add(Double[].class.toString());
tmp.add(Float[].class.toString());
tmp.add(Long[].class.toString());
tmp.add(Short[].class.toString());
_TYPES_WITH_ALLOWED_INDEX_HINTS=Collections.unmodifiableSet(tmp);;
}
private final static Set<String> _FORBIDEN_METHODS;
static {
// section 10.18 in SLEE 1.1
Set<String> _tmp = new HashSet<String>();
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
Map<String, Method> tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.slee.profile.ProfileManagement.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.slee.profile.ProfileManagement.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.slee.profile.ProfileMBean.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.slee.profile.Profile.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.management.DynamicMBean.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
tmpMethodsMap = ClassUtils.getAllInterfacesMethods(
javax.management.MBeanRegistration.class, ignore);
_tmp.addAll(tmpMethodsMap.keySet());
_FORBIDEN_METHODS = Collections.unmodifiableSet(_tmp);
}
private final static Set<String> _ALLOWED_QUERY_PARAMETER_TYPES;
static {
Set<String> tmp = new HashSet<String>();
// Section 10.17
tmp.add("int");
tmp.add("boolean");
tmp.add("byte");
tmp.add("char");
tmp.add("double");
tmp.add("float");
tmp.add("long");
tmp.add("short");
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());
_ALLOWED_QUERY_PARAMETER_TYPES = 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);
}
private final static Set<String> _JAVA_RESERVED_WORDS;
static {
Set<String> tmp = new HashSet<String>();
tmp.add("boolean");
tmp.add("abstract");
tmp.add("break");
tmp.add("future");
tmp.add("byte");
tmp.add("class");
tmp.add("case");
tmp.add("generic");
tmp.add("char");
tmp.add("extends");
tmp.add("continue");
tmp.add("goto");
tmp.add("double");
tmp.add("implements");
tmp.add("default");
tmp.add("inner");
tmp.add("float");
tmp.add("import");
tmp.add("do");
tmp.add("native");
tmp.add("int");
tmp.add("instanceof");
tmp.add("else");
tmp.add("operator");
tmp.add("short");
tmp.add("interface");
tmp.add("for");
tmp.add("outer");
tmp.add("long");
tmp.add("super");
tmp.add("if");
tmp.add("package");
tmp.add("this");
tmp.add("new");
tmp.add("rest");
tmp.add("void");
tmp.add("return");
tmp.add("synchronized");
tmp.add("switch");
tmp.add("transient");
tmp.add("while");
tmp.add("var");
tmp.add("volatile");
tmp.add("false");
tmp.add("catch");
tmp.add("const");
tmp.add("null");
tmp.add("finally");
tmp.add("final");
tmp.add("true");
tmp.add("throw");
tmp.add("private");
tmp.add("throws");
tmp.add("protected");
tmp.add("try");
tmp.add("public");
tmp.add("static");
_JAVA_RESERVED_WORDS = Collections.unmodifiableSet(tmp);
}
private boolean requiredProfileAbstractClass = false;
public void setComponentRepository(ComponentRepository repository) {
this.repository = repository;
}
public ProfileSpecificationComponent getComponent() {
return component;
}
public void setComponent(ProfileSpecificationComponent component) {
this.component = component;
}
/*
* (non-Javadoc)
*
* @see
* org.mobicents.slee.container.component.validator.Validator#validate()
*/
public boolean validate() {
boolean passed = true;
try {
if (!validateDescriptor()) {
// this is quick fail
passed = false;
return passed;
}
// we cant validate some parts on fail here
if (!validateCMPInterface()) {
passed = false;
} else {
if (!validateProfileTableInterface()) {
passed = false;
}
}
if (!validateProfileLocalInterface()) {
passed = false;
}
if (!validateProfileManagementInterface()) {
passed = false;
}
if (!validateAbstractClass()) {
passed = false;
}
} catch (Exception e) {
e.printStackTrace();
}
return passed;
}
boolean validateCMPInterface() {
// this is kind of quick failure for each method/field, since when
// something goes wrong for one method we can validate it further... -
// CMPs in sbbs are different since we know their names.
boolean passed = true;
String errorBuffer = new String("");
try {
// this is obligatory
Class interfaceClass = this.component.getProfileCmpInterfaceClass();
if (!interfaceClass.isInterface()) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface class is not an interface. ",
"10.6", errorBuffer);
return passed;
}
if (this.component.isSlee11()
&& interfaceClass.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface in SLEE 1.1 components must be defined in package. ",
"10.6", errorBuffer);
}
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
Map<String, Method> interfaceMethods = ClassUtils
.getAllInterfacesMethods(interfaceClass, ignore);
// holds fieldName->occurances - EACH field MUST occure twice, as
// setter and getter
Map<String, Integer> fieldOccurances = new HashMap<String, Integer>();
// holds fieldName->type mapp, setter and getter type must match
Map<String, Class> fieldToType = new HashMap<String, Class>();
Iterator<Entry<String, Method>> methodsIterator = interfaceMethods
.entrySet().iterator();
while (methodsIterator.hasNext()) {
Entry<String, Method> entry = methodsIterator.next();
Method m = entry.getValue();
String methodName = m.getName();
if (_FORBIDEN_METHODS.contains(entry.getKey())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface defines methods that are prohibited.: "
+ methodName, "10.17", errorBuffer);
methodsIterator.remove();
continue;
}
if (!(methodName.startsWith("get") || methodName
.startsWith("set"))) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface methods must follow java bean setter/getter accessors. Offending method: "
+ methodName, "10.6", errorBuffer);
methodsIterator.remove();
continue;
}
Class fieldType = null;
String cmpFieldName = null;
if (methodName.startsWith("get")) {
if (!validateCMPInterfaceGetter(m)) {
passed = false;
methodsIterator.remove();
continue;
}
fieldType = m.getReturnType();
cmpFieldName = methodName.replaceFirst("get", "");
} else {
if (!validateCMPInterfaceSetter(m)) {
passed = false;
methodsIterator.remove();
continue;
}
fieldType = m.getParameterTypes()[0];
cmpFieldName = methodName.replaceFirst("set", "");
}
if (!(ProfileAttribute.ALLOWED_PROFILE_ATTRIBUTE_TYPES.contains(fieldType.getName()) || validateSerializableType(
fieldType, methodName))) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface field has wrong type, only java primitives, serializables and arrays of those types are allowed. Offending field: "
+ cmpFieldName, "10.6", errorBuffer);
}
Character c = cmpFieldName.charAt(0);
if (!Character.isUpperCase(c)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface field has wrong type, of first char in name. Offending field: "
+ cmpFieldName, "10.6", errorBuffer);
// FIXME: should we fail here
methodsIterator.remove();
continue;
}
if(_JAVA_RESERVED_WORDS.contains(cmpFieldName.toLowerCase()))
{
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface field has forbidden name (JAVA reserved word). Field: "
+ cmpFieldName, "10.6", errorBuffer);
}
cmpFieldName = cmpFieldName.replaceFirst(c + "", Character.toLowerCase(c) + "");
// XXX: this will fail even for duplicate delcarations of
// fields, but meesages might be missleading.
if (!fieldOccurances.containsKey(cmpFieldName)) {
fieldOccurances.put(cmpFieldName, new Integer(1));
fieldToType.put(cmpFieldName, fieldType);
} else if (fieldOccurances.get(cmpFieldName) == 1) {
fieldOccurances.put(cmpFieldName, new Integer(2));
if (fieldToType.get(cmpFieldName).getName().compareTo(
fieldType.getName()) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface field has wrong type, current type does not match previously encountered. Field: "
+ cmpFieldName, "10.6", errorBuffer);
}
} else {
// it should be one
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface field has been defined more than once, offending method: "
+ methodName, "10.6", errorBuffer);
// FIXME: should we fail here
methodsIterator.remove();
continue;
}
}
// here we have to check if we are 1.1 - declaredcmp fields vs
// occurances + collators, those can be present only for String type
// fields
if (this.component.isSlee11()) {
// if we are here we know there are no dups
List<MCMPField> cmpFields = this.component.getDescriptor()
.getProfileClasses().getProfileCMPInterface().getCmpFields();
for(MCMPField cmpField : cmpFields)
{
if(!fieldOccurances.containsKey(cmpField.getCmpFieldName()))
{
passed = false;
//System.err.println(fieldToType.keySet());
errorBuffer = appendToBuffer("Profile Specification descriptor declares CMP Field which is not present in Profile CMP interface (" + cmpField.getCmpFieldName() + ").", "3.3.7", errorBuffer);
}
}
/*
* FIXME: Alexandre: This is not needed, remove.
*
* # Zero or more cmp-field elements.
* These elements are option. They must be specified for any Profile CMP fields
* that have characteristics differing from the deployment descriptor defaults. Each
* ...
*
if (cmpFields.size() != fieldToType.size()) {
passed = false;
//System.err.println(fieldToType.keySet());
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface cmp field declarations do not match declaredfields in descriptor.",
"10.6", errorBuffer);
// FIXME: should we fail here
methodsIterator.remove();
}
*/
for (MCMPField f : cmpFields) {
Class type = fieldToType.get(f.getCmpFieldName());
// might be null in case of above errror
if (type != null) {
if (f.getUniqueCollatorRef() != null
&& type.getName().compareTo("java.lang.String") != 0) {
// only stirng fields can have it
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp field declares collator ref, but field type is not java.lang.String. Cmpfield: "
+ f.getCmpFieldName(), "10.6",
errorBuffer);
}
for (MIndexHint indexHint : f.getIndexHints()) {
//See section 10.22 of JSLEE 1.1
if(!_TYPES_WITH_ALLOWED_INDEX_HINTS.contains(type.toString()))
{
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp field declares index hint, but field type is:"+type+". Cmpfield: "
+ f.getCmpFieldName(), "10.22",
errorBuffer);
}
if (indexHint.getCollatorRef() != null
&& type.getName().compareTo(
"java.lang.String") != 0) {
// only stirng fields can have it
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp field decalres index hint with collator ref, but field type is not java.lang.String. Cmpfield: "
+ f.getCmpFieldName(), "10.6",
errorBuffer);
}
}
}
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateSerializableType(Class fieldType, String method) {
boolean passed = true;
String errorBuffer = new String("");
try {
// in case of array we have from getName() something like:
// [Ljava.io.Serializable;
if (fieldType.isArray()) {
// ech
String typStringName = fieldType.getComponentType().getName();
try {
Class type = Thread.currentThread().getContextClassLoader().loadClass(typStringName);
if (ClassUtils.checkInterfaces(type,
"java.io.Serializable") == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface allows to store primitive types and serializables, offending method: "
+ method + " . Type: " + fieldType,
"10.6", errorBuffer);
}
} catch (Exception e) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface allows to store primitive types and serializables, offending method: "
+ method + " . Type: " + fieldType, "10.6",
errorBuffer);
}
} else {
if (ClassUtils.checkInterfaces(fieldType,
"java.io.Serializable") == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface allows to store primitive types and serializables, offending method: "
+ method + " . Type: " + fieldType, "10.6",
errorBuffer);
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateCMPInterfaceSetter(Method m) {
boolean passed = true;
String errorBuffer = new String("");
try {
// no throws
if (m.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface setter method must not defined throws clause, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
int modifiers = m.getModifiers();
// its interface method so it has to be public and abstract ONLY!!!!
// if (Modifier.isStatic(modifiers)) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile cmp interface setter method must not be static, offending method: "
// + m.getName(), "10.6", errorBuffer);
// }
//
// if (!Modifier.isAbstract(modifiers)) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile cmp interface setter method must be abstract, offending method: "
// + m.getName(), "10.6", errorBuffer);
// }
if (m.getParameterTypes().length != 1) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface setter method must have exactly one parameter, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
if (m.getReturnType().getName().compareTo("void") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface setter method must not declare return type, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateCMPInterfaceGetter(Method m) {
boolean passed = true;
String errorBuffer = new String("");
try {
// no throws
// no throws
if (m.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface getter method must not defined throws clause, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
int modifiers = m.getModifiers();
// its interface method so it has to be public and abstract ONLY!!!!
// if (Modifier.isStatic(modifiers)) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile cmp interface setter method must not be static, offending method: "
// + m.getName(), "10.6", errorBuffer);
// }
//
// if (!Modifier.isAbstract(modifiers)) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile cmp interface setter method must be abstract, offending method: "
// + m.getName(), "10.6", errorBuffer);
// }
if (m.getParameterTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface getter method must have no parameters, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
if (m.getReturnType().getName().compareTo("void") == 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile cmp interface getter method must declare return type, offending method: "
+ m.getName(), "10.6", errorBuffer);
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
/**
* Should not be called when CMP interface validation fails cause it depends
* on result of it
*
* @return
*/
boolean validateProfileManagementInterface() {
// this is optional
boolean passed = true;
String errorBuffer = new String("");
if (this.component.getProfileManagementInterfaceClass() == null) {
// it can hapen when its not present
return passed;
}
try {
Class profileManagementInterfaceClass = this.component
.getProfileManagementInterfaceClass();
if (!profileManagementInterfaceClass.isInterface()) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface is not an interface class!!!",
"10.10", errorBuffer);
return passed;
}
if (this.component.isSlee11()
&& profileManagementInterfaceClass.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface must be declared within named package.",
"10.10", errorBuffer);
}
if (!Modifier.isPublic(profileManagementInterfaceClass
.getModifiers())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface must be declaredas public.",
"10.10", errorBuffer);
}
// now here comes the fun. methods are subject to restrictions form
// 10.17 and 10.18, BUT interface may implement or just define CMPs
// that MUST reasemlbe CMPs definition from CMP interface - that is
// all getter/setter methods defined
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
Map<String, Method> cmpInterfaceMethods = ClassUtils
.getAllInterfacesMethods(this.component
.getProfileCmpInterfaceClass(), ignore);
Map<String, Method> managementInterfaceMethods = ClassUtils
.getAllInterfacesMethods(profileManagementInterfaceClass,
ignore);
// we cant simply remove all methods from
// managementInterfaceMethods.removeAll(cmpInterfaceMethods) since
// with abstract classes it becomes comp;licated
// we can have doubling definition with for instance return type or
// throws clause (as diff) which until concrete class wont be
// noticed - and is an error....
// FIXME: does mgmt interface have to define both CMP accessors?
Iterator<Entry<String, Method>> entryIterator = managementInterfaceMethods
.entrySet().iterator();
while (entryIterator.hasNext()) {
Entry<String, Method> entry = entryIterator.next();
String key = entry.getKey();
if (cmpInterfaceMethods.containsKey(key)) {
// FIXME: possibly we shoudl iterate over names?
if (!compareMethod(entry.getValue(), cmpInterfaceMethods
.get(key))) {
// return type or throws clause, or modifiers differ
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface declares method which has signature simlar to CMP method, but it has different throws clause, return type or modifiers, which is wrong.",
"10.10", errorBuffer);
}
} else {
// we can have setter/getter like as stand alone ?
if (_FORBIDEN_METHODS.contains(key)) {
// this is forrbiden, section 10.18
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface declares method from forbiden list, method: "
+ entry.getKey(), "10.18", errorBuffer);
continue;
}
// is this the right place? This tells validator
// wheather it should require profile abstract class in
// case of 1.1
requiredProfileAbstractClass = true;
// we know that name is ok.
// FIXME: SPECS Are weird - Management methods may not
// have the same name and arguments as a Profile CMP
// field get or set accessor method. <---- ITS CMP
// METHOD< SIGNATURE IS NAME AND
// PARAMETERS and its implemented if its doubled from
// CMP or this interface extends CMP
// interface.....!!!!!!!!!!!!!!!!!!
if (key.startsWith("ejb")) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface declares method with wrong prefix, method: "
+ entry.getKey(), "10.18", errorBuffer);
continue;
}
// there are no reqs other than parameters?
Class[] params = entry.getValue().getParameterTypes();
for (int index = 0; index < params.length; index++) {
if (_ALLOWED_MANAGEMENT_TYPES.contains(params[index]
.toString()) || ClassUtils.checkInterfaces(params[index], "java.io.Serializable")!=null) {
} else {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface declares management method with wrong parameter at index["
+ index
+ "], method: "
+ entry.getKey(), "10.18",
errorBuffer);
}
}
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateProfileLocalInterface() {
boolean passed = true;
String errorBuffer = new String("");
// FIXME: should not this return generic?
if (!this.component.isSlee11()
|| this.component.getProfileLocalInterfaceClass() == null) {
// its nto mandatory
return passed;
}
try {
Class profileLocalObjectInterface = this.component
.getProfileLocalInterfaceClass();
if (!profileLocalObjectInterface.isInterface()) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface is not an interface class!!!",
"10.7.4", errorBuffer);
return passed;
}
if (profileLocalObjectInterface.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface must be declared within named package.",
"10.7.4", errorBuffer);
}
if (!Modifier.isPublic(profileLocalObjectInterface.getModifiers())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface must be declared as public.",
"10.7.4", errorBuffer);
}
Class genericProfleLocalObject = ClassUtils.checkInterfaces(
profileLocalObjectInterface,
"javax.slee.profile.ProfileLocalObject");
if (genericProfleLocalObject == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface must implement javax.slee.profile.ProfileLocalObject.",
"10.7.4", errorBuffer);
}
// now here comes the fun. methods are subject to restrictions form
// 10.17 and 10.18, BUT interface may implement or just define CMPs
// that MUST reasemlbe CMPs definition from CMP interface - that is
// all getter/setter methods defined
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
ignore.add("javax.slee.profile.ProfileLocalObject");
Map<String, Method> cmpInterfaceMethods = ClassUtils
.getAllInterfacesMethods(this.component
.getProfileCmpInterfaceClass(), ignore);
Map<String, Method> managementInterfaceMethods = ClassUtils
.getAllInterfacesMethods(profileLocalObjectInterface,
ignore);
// we cant simply remove all methods from
// managementInterfaceMethods.removeAll(cmpInterfaceMethods) since
// with abstract classes it becomes comp;licated
// we can have doubling definition with for instance return type or
// throws clause (as diff) which until concrete class wont be
// noticed - and is an error....
// FIXME: does mgmt interface have to define both CMP accessors?
Iterator<Entry<String, Method>> entryIterator = managementInterfaceMethods
.entrySet().iterator();
while (entryIterator.hasNext()) {
Entry<String, Method> entry = entryIterator.next();
String key = entry.getKey();
if (cmpInterfaceMethods.containsKey(key)) {
if (!compareMethod(entry.getValue(), cmpInterfaceMethods
.get(key))) {
// return type or throws clause, or modifiers differ
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface declares method which has signature similar to CMP method, but it has different throws clause, return type or modifiers, which is wrong.",
"10.7.4", errorBuffer);
}
} else {
// we can have setter/getter like as stand alone ?
if (_FORBIDEN_METHODS.contains(key)) {
// this is forrbiden, section 10.18
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface declares method from forbiden list, method: "
+ entry.getKey(), "10.18", errorBuffer);
continue;
}
// The method name must not begin with �profile� or �ejb�. A SLEE implementation can use method
// names that begin with �profile� when needed without being concerned with possible method name
// conflicts with Profile Specification Developer declared method names.
// This restriction does not apply when the Profile Specification Developer implements a
// �profile<XXX>� method declared by the SLEE, such as the life cycle methods declared in the
// javax.profile.Profile interface.
// FIXME: Alexandre: do we need to verify this exception at this point?
else if (key.startsWith("ejb") || key.startsWith("profile")) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface method name must not begin with �profile� or �ejb�. Offending method: "
+ entry.getKey(), "10.18", errorBuffer);
continue;
}
// FIXME: Alexandre: Business method may have the same name as long as it has different arguments from CMP accessor method.
//else if (key.startsWith("get") || key.startsWith("set")) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile local interface declares method which is setter/getter and does not match CMP interface method, method: "
// + entry.getKey(), "10.18", errorBuffer);
//
// continue;
//}
// is this the right place? This tells validator
// wheather it should require profile abstract class in
// case of 1.1
requiredProfileAbstractClass = true;
// we know that name is ok.
// FIXME: SPECS Are weird - Management methods may not
// have the same name and arguments as a Profile CMP
// field get or set accessor method. <---- ITS CMP
// METHOD< SIGNATURE IS NAME AND
// PARAMETERS and its implemented if its doubled from
// CMP or this interface extends CMP
// interface.....!!!!!!!!!!!!!!!!!!
if (key.startsWith("ejb")) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile local interface declares method with wrong prefix, method: "
+ entry.getKey(), "10.18", errorBuffer);
continue;
}
// FIXME: Alexandre: There's no restriction here, I guess!
// Class[] params = entry.getValue().getParameterTypes();
// for (int index = 0; index < params.length; index++) {
// // FIXME: whichc should we use here?
// if ((_ALLOWED_CMPS_TYPES.contains(params[index]
// .toString()) || ClassUtils.checkInterfaces(params[index], "java.io.Serializable")!=null)) {
//
// } else {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile management interface declares management method with wrong parameter at index["
// + index
// + "], method: "
// + entry.getKey(), "10.18",
// errorBuffer);
// }
// }
// lets check exceptions, we can define all except
// java.rmi.RemoteException
for (Class exceptionClass : entry.getValue()
.getExceptionTypes()) {
// FIXME: should we check unckecked exceptions here
// ?
if (ClassUtils.checkClasses(exceptionClass,
"java.rmi.RemoteException") != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management interface declares management method with wrong exception in throws clause, it can not throw java.rmi.RemoteException(or its sub classes), method: "
+ entry.getKey(), "10.7.4",
errorBuffer);
}
}
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
/**
* shoudl not be run if other interfaces vaildation fails.
*
* @return
*/
boolean validateAbstractClass() {
boolean passed = true;
String errorBuffer = new String("");
try {
if (this.component.getDescriptor().getProfileClasses().getProfileAbstractClass() == null) {
if (this.requiredProfileAbstractClass) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management abstract class must be present",
"3.X", errorBuffer);
return passed;
}
} else {
if (this.component.getProfileAbstractClass() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile management abstract class has not been loaded",
"3.X", errorBuffer);
return passed;
}
}
Class profileAbstractClass = this.component.getProfileAbstractClass();
// FIXME: Alexandre: Added this, was making some tests fail. Review!
if(profileAbstractClass == null)
{
return passed;
}
// if (profileAbstractClass.isInterface()
// || profileAbstractClass.isEnum()) {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile abstract class in not a clas.",
// "10.11", errorBuffer);
// return passed;
// }
if (this.component.isSlee11()) {
if (profileAbstractClass.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must be defined in package.",
"10.11", errorBuffer);
}
// FIXME: what about 1.0 ?
// public, no arg constructor without throws clause
Constructor c = null;
try {
c = profileAbstractClass.getConstructor(null);
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
if (c == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must define public no arg constructor.",
"10.11", errorBuffer);
} else {
if (!Modifier.isPublic(c.getModifiers())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must define public no arg constructor.",
"10.11", errorBuffer);
}
if (c.getExceptionTypes().length > 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must define public no arg constructor without throws clause.",
"10.11", errorBuffer);
}
}
}
int modifiers = profileAbstractClass.getModifiers();
if (!Modifier.isAbstract(modifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must be defined abstract.",
"10.11", errorBuffer);
}
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must be defined public.",
"10.11", errorBuffer);
}
// in case of 1.0 it has to implement as concrete methods from
// javax.slee.profile.ProfileManagement - section 10.8 of 1.0 specs
Map<String, Method> requiredLifeCycleMethods = null;
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
if (this.component.isSlee11()) {
Class javaxSleeProfileProfileClass = ClassUtils
.checkInterfaces(profileAbstractClass,
"javax.slee.profile.Profile");
if (javaxSleeProfileProfileClass == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement javax.slee.profile.Profile.",
"10.11", errorBuffer);
requiredLifeCycleMethods = ClassUtils
.getAllInterfacesMethods(
javax.slee.profile.ProfileLocalObject.class,
ignore);
} else {
requiredLifeCycleMethods = ClassUtils
.getAllInterfacesMethods(
javaxSleeProfileProfileClass, ignore);
}
} else {
Class javaxSleeProfileProfileManagement = ClassUtils
.checkInterfaces(profileAbstractClass,
"javax.slee.profile.ProfileManagement");
if (javaxSleeProfileProfileManagement == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement javax.slee.profile.ProfileManagement.",
"10.8", errorBuffer);
requiredLifeCycleMethods = ClassUtils
.getAllInterfacesMethods(
javax.slee.profile.ProfileManagement.class,
ignore);
} else {
requiredLifeCycleMethods = ClassUtils
.getAllInterfacesMethods(
javaxSleeProfileProfileManagement, ignore);
}
}
Map<String, Method> abstractMethods = ClassUtils
.getAbstractMethodsFromClass(profileAbstractClass);
Map<String, Method> abstractMethodsFromSuperClasses = ClassUtils
.getAbstractMethodsFromSuperClasses(profileAbstractClass);
Map<String, Method> concreteMethods = ClassUtils
.getConcreteMethodsFromClass(profileAbstractClass);
Map<String, Method> concreteMethodsFromSuperClasses = ClassUtils
.getConcreteMethodsFromSuperClasses(profileAbstractClass);
// FIXME: Alexandre: Verify if this is correct
// The isProfileDirty, markProfileDirty and isProfileValid methods must not be
// implemented as they are implemented by the SLEE. These three methods are implemented by the
// SLEE at deployment time.
Set<String> toBeImplementedBySlee = new HashSet<String>();
toBeImplementedBySlee.add("isProfileDirty");
toBeImplementedBySlee.add("markProfileDirty");
toBeImplementedBySlee.add("isProfileValid");
for (Entry<String, Method> entry : requiredLifeCycleMethods
.entrySet()) {
Method m = entry.getValue();
//
Method methodFromClass = ClassUtils.getMethodFromMap(m
.getName(), m.getParameterTypes(), concreteMethods,
concreteMethodsFromSuperClasses);
if (methodFromClass == null)
{
if(this.component.isSlee11() || (!this.component.isSlee11() && !toBeImplementedBySlee.contains(m.getName())))
{
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method not found in concrete(non private) methods: "
+ m.getName(), "10.11", errorBuffer);
}
continue;
}
if ( methodFromClass != null && toBeImplementedBySlee.contains(m.getName()) )
{
passed = false;
errorBuffer = appendToBuffer(
"[JAIN SLEE 1.0] The " + m.getName() + " method must not be implemented as they are implemented by the SLEE.", "10.11", errorBuffer);
continue;
}
// it concrete - must check return type
if (!m.getReturnType().getName().equals(methodFromClass.getReturnType().getName())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method with name: "
+ m.getName()
+ " found in concrete(non private) methods has different return type: "
+ methodFromClass.getReturnType()
+ ", than one declared in interface: "
+ m.getReturnType(), "10.11", errorBuffer);
}
if (!Arrays.equals(m.getExceptionTypes(), methodFromClass
.getExceptionTypes())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method with name: "
+ m.getName()
+ " found in concrete(non private) methods has different throws clause than one found in class.",
"10.11", errorBuffer);
}
// must be public, not abstract, not final, not static
modifiers = methodFromClass.getModifiers();
if (!Modifier.isPublic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method with name: "
+ m.getName()
+ " found in concrete(non private) methods must be public.",
"10.11", errorBuffer);
}
if (Modifier.isStatic(modifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method with name: "
+ m.getName()
+ " found in concrete(non private) methods must not be static.",
"10.11", errorBuffer);
}
if (Modifier.isFinal(modifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement certain lifecycle methods. Method with name: "
+ m.getName()
+ " found in concrete(non private) methods must not be final.",
"10.11", errorBuffer);
}
// FIXME: native?
}
// in 1.1 and 1.0 it must implement CMP interfaces, but methods
// defined there MUST stay abstract
Class profileCMPInterface = ClassUtils.checkInterfaces(
profileAbstractClass, this.component
.getProfileCmpInterfaceClass().getName());
if (profileCMPInterface == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement profile CMP interface.",
"10.11", errorBuffer);
return passed;
}
// abstract class implements CMP Interface, but leaves all methods
// as abstract
Map<String, Method> cmpInterfaceMethods = ClassUtils
.getAllInterfacesMethods(profileCMPInterface, ignore);
if (profileCMPInterface == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement defined profile CMP interface.",
"10.11", errorBuffer);
} else {
for (Entry<String, Method> entry : cmpInterfaceMethods
.entrySet()) {
Method m = entry.getValue();
//
Method methodFromClass = ClassUtils.getMethodFromMap(m
.getName(), m.getParameterTypes(), concreteMethods,
concreteMethodsFromSuperClasses);
if (methodFromClass != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must leave CMP interface methods as abstract, it can not be concrete: "
+ m.getName(), "10.11", errorBuffer);
continue;
}
methodFromClass = ClassUtils.getMethodFromMap(m.getName(),
m.getParameterTypes(), abstractMethods,
abstractMethodsFromSuperClasses);
// it concrete - must check return type
if (m.getReturnType().getName().compareTo(
methodFromClass.getReturnType().getName()) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must not decalre methods from CMP interface with different return type. Method with name: "
+ m.getName()
+ " found in (non private) class methods has different return type: "
+ methodFromClass.getReturnType()
+ ", than one declared in interface: "
+ m.getReturnType(), "10.11",
errorBuffer);
}
if (!Arrays.equals(m.getExceptionTypes(), methodFromClass
.getExceptionTypes())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must not change throws clause. Method with name: "
+ m.getName()
+ " found in (non private) class methods has different throws clause than one found in class.",
"10.11", errorBuffer);
}
// FIXME: should we do that?
abstractMethods.remove(entry.getKey());
abstractMethodsFromSuperClasses.remove(entry.getKey());
}
}
// those checks are......
// 1.0 and 1.1 if we define management interface we have to
// implement it, and all methods that are not CMPs
if (this.component.getDescriptor().getProfileClasses().getProfileManagementInterface() != null) {
Class profileManagementInterfaceClass = this.component
.getProfileManagementInterfaceClass();
// if abstract class and management interface are both defined than abstract class must implement the management interface
if (this.component.getProfileAbstractClass() != null && !profileManagementInterfaceClass.isAssignableFrom(this.component.getProfileAbstractClass())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile abstract class must implement profile management interface if both are specified", "10.11",
errorBuffer);
}
Map<String, Method> profileManagementInterfaceMethods = ClassUtils
.getAllInterfacesMethods(
profileManagementInterfaceClass, ignore);
// methods except those defined in CMP interface must be
// concrete
for (Entry<String, Method> entry : profileManagementInterfaceMethods
.entrySet()) {
Method m = entry.getValue();
// CMP methods must stay abstract
// check if this method is the same as in CMP interface is
// done elsewhere
// that check shoudl be ok to run this one!!! XXX
if (cmpInterfaceMethods.containsKey(entry.getKey())) {
// we do nothing, cmp interface is validate above
} else {
// 10.8/10.11
Method concreteMethodFromAbstractClass = ClassUtils
.getMethodFromMap(m.getName(), m
.getParameterTypes(), concreteMethods,
concreteMethodsFromSuperClasses);
if (concreteMethodFromAbstractClass == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement as non private methods from profile management interface other than CMP methods",
"10.11", errorBuffer);
continue;
}
int concreteMethodModifiers = concreteMethodFromAbstractClass
.getModifiers();
// public, and cannot be static,abstract, or final.
if (!Modifier.isPublic(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile management interface as public, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
if (Modifier.isStatic(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile management interface as not static, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
if (Modifier.isFinal(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile management interface as not final, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
}
}
}
if (this.component.isSlee11()) {
// ProfileLocalObject and UsageInterface are domains of 1.1
// uff, ProfileLocal again that stupid check cross two
// interfaces and one abstract class.....
if (this.component.getDescriptor().getProfileClasses().getProfileLocalInterface() != null) {
// abstract class MUST NOT implement it
if (ClassUtils.checkInterfaces(profileAbstractClass,
this.component.getDescriptor()
.getProfileClasses().getProfileLocalInterface()
.getProfileLocalInterfaceName()) != null
|| ClassUtils.checkInterfaces(profileAbstractClass,
"javax.slee.profile.ProfileLocalObject") != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must not implement profile local interface in any way(only methods must be implemented)",
"10.11", errorBuffer);
}
Class profileLocalObjectClass = this.component
.getProfileLocalInterfaceClass();
ignore.add("javax.slee.profile.ProfileLocalObject");
Map<String, Method> profileLocalObjectInterfaceMethods = ClassUtils
.getAllInterfacesMethods(profileLocalObjectClass,
ignore);
ignore.remove("javax.slee.profile.ProfileLocalObject");
// methods except those defined in CMP interface must be
// concrete
for (Entry<String, Method> entry : profileLocalObjectInterfaceMethods
.entrySet()) {
Method m = entry.getValue();
// CMP methods must stay abstract
// check if this method is the same as in CMP interface
// is done elsewhere
// that check shoudl be ok to run this one!!! XXX
if (cmpInterfaceMethods.containsKey(entry.getKey())) {
// we do nothing, cmp interface is validate above
} else {
// 10.8/10.11
Method concreteMethodFromAbstractClass = ClassUtils
.getMethodFromMap(m.getName(), m
.getParameterTypes(),
concreteMethods,
concreteMethodsFromSuperClasses);
if (concreteMethodFromAbstractClass == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement as non private methods from profile local interface other than CMP methods",
"10.11", errorBuffer);
continue;
}
int concreteMethodModifiers = concreteMethodFromAbstractClass
.getModifiers();
// public, and cannot be static,abstract, or final.
if (!Modifier.isPublic(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile local interface as public, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
if (Modifier.isStatic(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile local interface as not static, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
if (Modifier.isFinal(concreteMethodModifiers)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile abstract class must implement methods from profile management interface as not final, offending method: "
+ concreteMethodFromAbstractClass
.getName(), "10.11",
errorBuffer);
}
}
}
}
// usage parameters
if (this.component.getDescriptor().getProfileClasses()
.getProfileUsageParameterInterface() != null) {
if (!validateProfileUsageInterface(abstractMethods,
abstractMethodsFromSuperClasses)) {
passed = false;
}
}
}
// FIXME: add check on abstract methods same as in SBB ?
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateProfileUsageInterface(
Map<String, Method> abstractClassMethods,
Map<String, Method> abstractMethodsFromSuperClasses) {
boolean passed = true;
String errorBuffer = new String("");
// FIXME: should not this return generic?
if (!this.component.isSlee11()) {
// its nto mandatory
return passed;
}
try {
if (this.component.getUsageParametersInterface() == null) {
if (this.component.getDescriptor().getProfileClasses()
.getProfileUsageParameterInterface() != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile usage interface class is null, it should not be.",
"10.X", errorBuffer);
return passed;
} else {
return passed;
}
}
// we only validate usage interface here
if (!UsageInterfaceValidator
.validateProfileSpecificationUsageParameterInterface(
this.component, abstractClassMethods,
abstractMethodsFromSuperClasses)) {
passed = false;
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateProfileTableInterface() {
boolean passed = true;
String errorBuffer = new String("");
// FIXME: should not this return generic?
if (!this.component.isSlee11()
|| this.component.getDescriptor().getProfileClasses().getProfileTableInterface() == null) {
// its nto mandatory
return passed;
}
try {
Class profileTableInterface = this.component
.getProfileTableInterfaceClass();
// must be in pacakge
if (profileTableInterface.getPackage() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface must be declared inside pacakge.",
"10.8", errorBuffer);
}
if (!Modifier.isPublic(profileTableInterface.getModifiers())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface must be declared as public.",
"10.8", errorBuffer);
}
Class genericProfileTableInterface = ClassUtils.checkInterfaces(
profileTableInterface, "javax.slee.profile.ProfileTable");
if (genericProfileTableInterface == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface must extend in some way javax.slee.profile.ProfileTable.",
"10.8", errorBuffer);
// we fail here fast?
return passed;
}
Set<String> ignore = new HashSet<String>();
ignore.add("java.lang.Object");
// There is no clause in specs saying custom can not override
// methods, this will fail on concrete class generation though, let
// filter
Map<String, Method> javaxSleeProfileProfileTableMethods = ClassUtils
.getAllInterfacesMethods(genericProfileTableInterface,
ignore);
ignore.add("javax.slee.profile.ProfileTable");
Map<String, Method> profileTableInterfaceMethods = ClassUtils
.getAllInterfacesMethods(profileTableInterface, ignore);
// if we have common part here, this means that methods are double
// declared, either exactly the same or with different return type
// or exceptions
Set<String> tmpKeySet = new HashSet<String>();
Set<String> tmpKeySetToCompare = new HashSet<String>();
tmpKeySet.addAll(javaxSleeProfileProfileTableMethods.keySet());
tmpKeySetToCompare.addAll(profileTableInterfaceMethods.keySet());
tmpKeySet.retainAll(tmpKeySetToCompare);
if (tmpKeySet.size() != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares methods that double generic profile table interface, this may cause concrete class generation/instantion to fail.",
"10.8", errorBuffer);
}
// else its query validation, here we have slightly different
// approach, let iterate over methods, as we shoudl validate them
// here we asume that xml constraints/conent is ok, - for intance
// compare->parameter == query-parameter->name, parameter types have
// been checked
// here we just validate method against required ones
// by now all queries are validated, no doubling
Iterator<Entry<String, Method>> iterator = profileTableInterfaceMethods
.entrySet().iterator();
// FIXME: all queries have to match?
Map<String, MQuery> nameToQueryMap = new HashMap<String, MQuery>();
nameToQueryMap.putAll(this.component.getDescriptor()
.getQueriesMap());
Class cmpInterfaceClass = this.component
.getProfileCmpInterfaceClass();
while (iterator.hasNext()) {
Entry<String, Method> entry = iterator.next();
Method m = entry.getValue();
String methodName = m.getName();
if (!methodName.startsWith("query")) {
passed = false;
iterator.remove();
errorBuffer = appendToBuffer(
"The first letter of the name of the static query must be upper-cased and prefixed by 'query'. Offending method: "
+ methodName, "10.8.2", errorBuffer);
continue;
}
String queryName = methodName.replace("query", "");
if(Character.toUpperCase(queryName.charAt(0)) != queryName.charAt(0))
{
passed = false;
iterator.remove();
errorBuffer = appendToBuffer(
"The first letter of the name of the query must be upper-cased. Offending method: "
+ methodName, "10.8.2", errorBuffer);
continue;
}
queryName = queryName.replaceFirst(queryName.charAt(0) + "",
Character.toLowerCase(queryName.charAt(0)) + "");
if (!nameToQueryMap.containsKey(queryName)) {
passed = false;
iterator.remove();
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares wrong method with name: "
+ methodName
+ ", it does not match any query defined in descriptor",
"10.8.2", errorBuffer);
continue;
}
MQuery query = nameToQueryMap.remove(queryName);
// defined parameter types are ok in case of xml, we need to
// check method
Class returnType = m.getReturnType();
if (returnType.getName().compareTo("java.util.Collection") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares wrong return type: "
+ returnType + " in method with name: "
+ methodName
+ ", it should be java.util.Collection.",
"10.8.2", errorBuffer);
}
// If this option is not specified for a query, the default value is equal to the value of the
// profile-read-only attribute of the enclosing profile-spec element.
// It is a deployment error to specify false for this element if the value of the profile-
// read-only attribute of the enclosing profile-spec element is true
if(query.getQueryOptions() != null && this.component.getDescriptor().getReadOnly() && !query.getQueryOptions().isReadOnly())
{
passed = false;
errorBuffer = appendToBuffer("It is a deployment error to specify false for this element if the value of the profile read-only attribute of the enclosing profile-spec element is true. Offending query: " + queryName, "10.20.2", errorBuffer);
}
// Zero or more query-parameter elements.
// Each of these elements identifies a parameter of the query. The value of the parameter is provided
// at runtime. Each query-parameter elements has the following attributes:
// o A name attribute.
// This attribute defines the name of the query parameter.
// o A type attribute.
// This attribute defines the type of the query parameter. The type must be a Java primitive
// type or its equivalent object wrapper class, or java.lang.String.
for(MQueryParameter qParam : query.getQueryParameters())
{
if(!_ALLOWED_QUERY_PARAMETER_TYPES.contains(qParam.getType()))
{
// Alexandre: Let it pass if it's javax.slee.Address. This is not in spec, but should. See the link below.
// https://jsleetck11.dev.java.net/servlets/ProjectForumMessageView?messageID=25143&forumID=3225
if(!qParam.getType().equals(javax.slee.Address.class.getName()))
{
passed = false;
errorBuffer = appendToBuffer("Query parameter type must be a Java primitive type or its equivalent object wrapper class, or java.lang.String. Offending query: " + queryName, "10.20.2", errorBuffer);
}
}
}
Class[] exceptions = m.getExceptionTypes();
boolean foundTransactionRequiredLocalException = false;
boolean foundSLEEException = false;
for (Class c : exceptions) {
if (c.getName().compareTo(
"javax.slee.TransactionRequiredLocalException") == 0)
foundTransactionRequiredLocalException = true;
else if (c.getName().compareTo("javax.slee.SLEEException") == 0) {
foundSLEEException = true;
} else {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares method with wrong exception in throws method with name: "
+ methodName
+ ", exception: "
+ c.getName(), "10.8.2", errorBuffer);
}
}
//Those are runtime,...., so why this is in throws clause in specs - like it has to be there , but methods in tck dont declare....
// if (foundSLEEException
// && foundTransactionRequiredLocalException) {
// // do nothing
// } else {
// passed = false;
// errorBuffer = appendToBuffer(
// "Profile specification profile table interface declares method with wrong exception in throws method with name: "
// + methodName
// + ", it shoudl declare SLEEException["
// + foundSLEEException
// + "] and TransactionRequiredLocalException["
// + foundTransactionRequiredLocalException
// + "]", "10.8.2", errorBuffer);
// }
// lets see params - param type must match declared in MQuery,
// also type must match CMP field from interface (and there must
// be that kind of cmp
Class[] parameterTypes = m.getParameterTypes();
List<MQueryParameter> queryParameters = new ArrayList<MQueryParameter>();
queryParameters.addAll(query.getQueryParameters());
if (parameterTypes.length != queryParameters.size()) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares method with wrong parameters count, present: "
+ parameterTypes.length
+ ", expected: "
+ queryParameters.size(), "10.8.2",
errorBuffer);
} else {
// yes, a bit different
String parametersErrorBuffer = "Parameters that did not match descriptor: ";
boolean failedOnQueries = false;
Map<String, String> parameter2Type = new HashMap<String, String>();
for (int index = 0; index < parameterTypes.length; index++) {
// we can make some checks
// first lets check type it must be the same, even
// though it could be bad type, this is checked lower.
// However this is method check
if (parameterTypes[index].getName().compareTo(
queryParameters.get(index).getType()) != 0) {
failedOnQueries = true;
passed = false;
parametersErrorBuffer += " parameter: "
+ queryParameters.get(index).getName()
+ " declared type: "
+ queryParameters.get(index).getType()
+ " method type: " + parameterTypes[index]
+ " in query method at index: " + index
+ ",";
}
parameter2Type.put(
queryParameters.get(index).getName(),
queryParameters.get(index).getType());
// here we can check only for equality
// if (!_ALLOWED_QUERY_PARAMETER_TYPES
// .contains(parameterTypes[index].getName())) {
//
//
// parametersErrorBuffer += " method parameter: "
// + queryParameters.get(index).getName()
// + "has wrong type: "
// + parameterTypes[index] + ", ";
// }
}
if (failedOnQueries) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface declares wrong method["
+ methodName
+ "] to match declared query, failed to match parameters - \n"
+ parametersErrorBuffer, "10.20.2",
errorBuffer);
}
if (!validateQueryAgainstCMPFields(queryName,
cmpInterfaceClass, query.getQueryExpression(),
parameter2Type)) {
passed = false;
}
}
// now we have to validate CMP part
}
if (nameToQueryMap.size() != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification profile table interface does not decalre query method for all queries, no methods for: "
+ nameToQueryMap.keySet(), "10.20.2",
errorBuffer);
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
boolean validateQueryAgainstCMPFields(String queryName,
Class cmpInterfaceClass, MQueryExpression expression,
Map<String, String> parameter2Type) {
boolean passed = true;
String attributeName = null;
// this is the place where we can check for types, before that we could
// do this half way
String errorBuffer = new String("");
try {
switch (expression.getType()) {
// "complex types"
case And:
for (MQueryExpression mqe : expression.getAnd()) {
if (!validateQueryAgainstCMPFields(queryName,
cmpInterfaceClass, mqe, parameter2Type)) {
passed = false;
}
}
break;
case Or:
for (MQueryExpression mqe : expression.getOr()) {
if (!validateQueryAgainstCMPFields(queryName,
cmpInterfaceClass, mqe, parameter2Type)) {
passed = false;
}
}
break;
// "simple" types
case Not:
// this is one akward case :)
if (!validateQueryAgainstCMPFields(queryName,
cmpInterfaceClass, expression.getNot(), parameter2Type)) {
passed = false;
}
break;
// FIXME: tahts not nice, but lets have sippet for each case
case Compare:
// XXX: We know that attribute starts with lower case
attributeName = expression.getCompare().getAttributeName();
attributeName = attributeName.replaceFirst(""
+ attributeName.charAt(0), ""
+ Character.toUpperCase(attributeName.charAt(0)));
// now we have to validate CMP field and type
MCompare compare = expression.getCompare();
String op = compare.getOp();
try {
Method m = cmpInterfaceClass.getMethod("get"
+ attributeName, null);
// attribute must be present and valid, now we have to
// validate
// its type and possibly parameter type.
// return type must be the
String returnType = m.getReturnType().getName();
if (returnType.compareTo("boolean") == 0
|| returnType.compareTo("Boolean") == 0) {
// only op that can be used are: �equals�, or
// �not-equals�
if (op.compareTo("equals") == 0
|| op.compareTo("not-equals") == 0) {
// its ok, those are allowed
} else {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - only operators in Compare expression allowed on boolean attribute are \"equals\" and \"not-equals\": "
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
}
// now lets chec type
if (!_ALLOWED_QUERY_PARAMETER_TYPES.contains(returnType)) {
// there is one case we can not be wrogn here:
if ((op.compareTo("equals") == 0 || op
.compareTo("not-equals") == 0)
&& returnType.compareTo("javax.slee.Address") == 0) {
// its ok, those are allowed
} else {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - Compare expression references attribute of wrong type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
}
// we know that parameter references are ok
if (compare.getParameter() != null
&& parameter2Type.get(compare.getParameter())
.compareTo(returnType) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - Compare expression references attribute type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", does not match parameter type: "
+ parameter2Type.get(compare
.getParameter())
+ ", parameter name: "
+ compare.getParameter()
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// FIXME: test get constructor from type and use string
// constructor if its present, if not or if it fails make
// fail validation?
if (compare.getCollatorRef() != null
&& returnType.compareTo("java.lang.String") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - Compare expression references attribute of wrong type(only string parameter references can declare collator): "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
} catch (Exception e) {
// This should not happen, lets leave exception for this
// case to
// be alarmed.
// e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - operator does not match against cmp field, requested cmp attribute: "
+ attributeName, "10.20.2", errorBuffer);
}
break;
case HasPrefix:
MHasPrefix mhp = expression.getHasPrefix();
attributeName = expression.getHasPrefix().getAttributeName();
attributeName = attributeName.replaceFirst(""
+ attributeName.charAt(0), ""
+ Character.toUpperCase(attributeName.charAt(0)));
try {
Method m = cmpInterfaceClass.getMethod("get"
+ attributeName, null);
// attribute must be present and valid, now we have to
// validate
// its type and possibly parameter type.
// return type must be the
String returnType = m.getReturnType().getName();
if (returnType.compareTo("java.lang.String") != 0) {
// only op that can be used are: �equals�, or
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - HasPrefix expression references attribute of wrong type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// we know that parameter references are ok
if (mhp.getParameter() != null
&& parameter2Type.get(mhp.getParameter())
.compareTo(returnType) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - HasPrefix expression references attribute type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", does not match parameter type: "
+ parameter2Type
.get(mhp.getParameter())
+ ", parameter name: "
+ mhp.getParameter()
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// FIXME: test get constructor from type and use string
// constructor if its present, if not or if it fails make
// fail validation?
if (mhp.getCollatorRef() != null
&& returnType.compareTo("java.lang.String") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - HasPrefix expression references attribute of wrong type(only string parameter references can declare collator): "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
} catch (Exception e) {
// This should not happen, lets leave exception for this
// case to
// be alarmed.
// e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - operator does not match against cmp field, requested cmp attribute: "
+ attributeName, "10.20.2", errorBuffer);
}
break;
case LongestPrefixMatch:
MLongestPrefixMatch mlpm = expression.getLongestPrefixMatch();
attributeName = expression.getLongestPrefixMatch()
.getAttributeName();
attributeName = attributeName.replaceFirst(""
+ attributeName.charAt(0), ""
+ Character.toUpperCase(attributeName.charAt(0)));
try {
Method m = cmpInterfaceClass.getMethod("get"
+ attributeName, null);
// attribute must be present and valid, now we have to
// validate
// its type and possibly parameter type.
// return type must be the
String returnType = m.getReturnType().getName();
if (returnType.compareTo("java.lang.String") != 0) {
// only op that can be used are: �equals�, or
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - LongestPrefixMatch expression references attribute of wrong type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// we know that parameter references are ok
if (mlpm.getParameter() != null
&& parameter2Type.get(mlpm.getParameter())
.compareTo(returnType) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - LongestPrefixMatch expression references attribute type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", does not match parameter type: "
+ parameter2Type.get(mlpm
.getParameter())
+ ", parameter name: "
+ mlpm.getParameter()
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// FIXME: test get constructor from type and use string
// constructor if its present, if not or if it fails make
// fail validation?
if (mlpm.getCollatorRef() != null
&& returnType.compareTo("java.lang.String") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - LongestPrefixMatch expression references attribute of wrong type(only string parameter references can declare collator): "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
} catch (Exception e) {
// This should not happen, lets leave exception for this
// case to
// be alarmed.
// e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - operator does not match against cmp field, requested cmp attribute: "
+ attributeName, "10.20.2", errorBuffer);
}
break;
case RangeMatch:
attributeName = expression.getRangeMatch().getAttributeName();
attributeName = attributeName.replaceFirst(""
+ attributeName.charAt(0), ""
+ Character.toUpperCase(attributeName.charAt(0)));
MRangeMatch mrm = expression.getRangeMatch();
try {
Method m = cmpInterfaceClass.getMethod("get"
+ attributeName, null);
// attribute must be present and valid, now we have to
// validate
// its type and possibly parameter type.
// return type must be the
String returnType = m.getReturnType().getName();
// now lets chec type
if (!_ALLOWED_QUERY_PARAMETER_TYPES.contains(returnType)) {
// there is one case we can not be wrogn here:
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - RangeMatch expression references attribute of wrong type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// we know that parameter references are ok
if (mrm.getToParameter() != null
&& parameter2Type.get(mrm.getToParameter())
.compareTo(returnType) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - RangeMatch expression references attribute type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", does not match parameter type: "
+ parameter2Type.get(mrm
.getToParameter())
+ ", toParameter name: "
+ mrm.getToParameter()
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// we know that parameter references are ok
if (mrm.getFromParameter() != null
&& parameter2Type.get(mrm.getFromParameter())
.compareTo(returnType) != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - RangeMatch expression references attribute type: "
+ returnType
+ ", attribute:"
+ attributeName
+ ", does not match parameter type: "
+ parameter2Type.get(mrm
.getFromParameter())
+ ", fromParameter name: "
+ mrm.getFromParameter()
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
// FIXME: test get constructor from type and use string
// constructor if its present, if not or if it fails make
// fail validation?
if (mrm.getCollatorRef() != null
&& returnType.compareTo("java.lang.String") != 0) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - RangeMatch expression references attribute of wrong type(only string parameter references can declare collator): "
+ returnType
+ ", attribute:"
+ attributeName
+ ", query: "
+ queryName, "10.20.2", errorBuffer);
}
} catch (Exception e) {
// This should not happen, lets leave exception for this
// case to
// be alarmed.
// e.printStackTrace();
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declared wrong static query - operator does not match against cmp field, requested cmp attribute: "
+ attributeName, "10.20.2", errorBuffer);
}
break;
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(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(), "10.19.4", errorBuffer);
}
}
} finally {
if (!passed) {
// //System.err.println(errorBuffer);
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
}
}
return passed;
}
/**
* Validated descriptor against some basic constraints: all references are
* correct, some fields are declaredproperly, no double definitions, if
* proper elements are present - for instance some elements exclude others.
*
* @return
*/
boolean validateDescriptor() {
boolean passed = true;
String errorBuffer = new String("");
if (!this.component.isSlee11()) {
return passed;
// there is not much we can do for those oldies.
}
try {
HashSet<String> collatorAlliases = new HashSet<String>();
ProfileSpecificationDescriptorImpl desc = this.component
.getDescriptor();
for (MCollator mc : desc.getCollators()) {
if (collatorAlliases.contains(mc.getCollatorAlias())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares collator alias twice: "
+ mc.getCollatorAlias(), "3.3.7",
errorBuffer);
} else {
collatorAlliases.add(mc.getCollatorAlias());
}
}
// double deifnition of refs is allowed.
Map<String, MCMPField> cmpName2Field = new HashMap<String, MCMPField>();
for (MCMPField c : desc.getProfileClasses().getProfileCMPInterface().getCmpFields()) {
if (!Character.isLowerCase(c.getCmpFieldName().charAt(0))) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares wrong cmp field name, first char is not lower case, field: "
+ c.getCmpFieldName(), "3.3.7", errorBuffer);
}
if (cmpName2Field.containsKey(c.getCmpFieldName())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares cmp field twice: "
+ c.getCmpFieldName(), "3.3.7", errorBuffer);
} else {
cmpName2Field.put(c.getCmpFieldName(), c);
}
if (c.getUniqueCollatorRef() != null
&& !collatorAlliases.contains(c.getUniqueCollatorRef())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares cmp field: "
+ c.getCmpFieldName()
+ ", with wrong collator reference: "
+ c.getUniqueCollatorRef(), "3.3.7",
errorBuffer);
}
for (MIndexHint indexHint : c.getIndexHints()) {
if (indexHint.getCollatorRef() != null
&& !collatorAlliases.contains(indexHint
.getCollatorRef())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares cmp field: "
+ c.getCmpFieldName()
+ ", with index hint declaring wrong collator reference: "
+ c.getUniqueCollatorRef(), "3.3.7",
errorBuffer);
}
}
}
Set<String> queriesNames = new HashSet<String>();
for (MQuery mq : desc.getQueryElements()) {
if (queriesNames.contains(mq.getName())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares queries with the same name: "
+ mq.getName(), "3.3.7", errorBuffer);
} else {
// FIXME: all declaredparameters have to be used in
// expressions?
HashSet<String> decalredParameters = new HashSet<String>();
HashSet<String> usedParameters = new HashSet<String>();
for (MQueryParameter mqp : mq.getQueryParameters()) {
if (decalredParameters.contains(mqp.getName())) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares query parameter twice, parameter name: "
+ mqp.getName() + ", in query: "
+ mq.getName(), "3.3.7",
errorBuffer);
} else {
decalredParameters.add(mqp.getName());
}
}
if (!validateExpression(mq.getName(), mq
.getQueryExpression(), usedParameters,
cmpName2Field.keySet(), collatorAlliases)) {
passed = false;
}
if (!usedParameters.containsAll(decalredParameters)
&& !decalredParameters.containsAll(usedParameters)) {
passed = false;
decalredParameters.retainAll(usedParameters);
errorBuffer = appendToBuffer(
"Profile specification declares query parameter that are not used, in query: "
+ mq.getName()
+ ", not used parameters: "
+ Arrays.toString(decalredParameters
.toArray()), "3.3.7",
errorBuffer);
}
}
}
// FIXME: this should be here or not?
if (!validateEnvEntries()) {
passed = false;
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
/**
* Checks expression to check if collator refs and cmp fields are referenced
* correctly. type constraints are checked later. Since in case of lack of
* parameter we have to relly totaly on CMP field type. Additionaly this
* check if parameter and value are present together.
*
* @param queryName
* @param cmpInterfaceClass
* @param expression
* @param decalredQueryParameter
* @param usedQueryParameter
* @return
*/
boolean validateExpression(String queryName, MQueryExpression expression,
Set<String> usedQueryParameter, Set<String> cmpFieldNames,
Set<String> collatorAliasses) {
boolean passed = true;
String attributeName = null;
String collatorRef = null;
String parameter = null;
String value = null;
boolean ignoreAbsence = false;
// We dont have access to type of cmp, we just simply check parameter
String errorBuffer = new String("");
try {
switch (expression.getType()) {
// "complex types"
case And:
for (MQueryExpression mqe : expression.getAnd()) {
if (!validateExpression(queryName, mqe, usedQueryParameter,
cmpFieldNames, collatorAliasses)) {
passed = false;
}
}
break;
case Or:
for (MQueryExpression mqe : expression.getOr()) {
if (!validateExpression(queryName, mqe, usedQueryParameter,
cmpFieldNames, collatorAliasses)) {
passed = false;
}
}
break;
// "simple" types
case Not:
// this is one akward case :)
if (!validateExpression(queryName, expression.getNot(),
usedQueryParameter, cmpFieldNames, collatorAliasses)) {
passed = false;
}
break;
case Compare:
attributeName = expression.getCompare().getAttributeName();
collatorRef = expression.getCompare().getCollatorRef();
parameter = expression.getCompare().getParameter();
value = expression.getCompare().getValue();
break;
case HasPrefix:
attributeName = expression.getHasPrefix().getAttributeName();
collatorRef = expression.getHasPrefix().getCollatorRef();
parameter = expression.getHasPrefix().getParameter();
value = expression.getHasPrefix().getValue();
break;
case LongestPrefixMatch:
attributeName = expression.getLongestPrefixMatch()
.getAttributeName();
collatorRef = expression.getLongestPrefixMatch()
.getCollatorRef();
parameter = expression.getLongestPrefixMatch().getParameter();
value = expression.getLongestPrefixMatch().getValue();
break;
case RangeMatch:
attributeName = expression.getRangeMatch().getAttributeName();
collatorRef = expression.getRangeMatch().getCollatorRef();
MRangeMatch mrm = expression.getRangeMatch();
ignoreAbsence = true;
if (mrm.getFromParameter() == null
&& mrm.getFromValue() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, either fromValue or fromParameter can be present, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (mrm.getFromParameter() != null
&& mrm.getFromValue() != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, either fromValue or fromParameter can be present, not both, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (mrm.getToParameter() == null && mrm.getToValue() == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, either toValue or toParameter can be present, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (mrm.getToParameter() != null && mrm.getToValue() != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, either toValue or toParameter can be present, not both, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (mrm.getFromParameter() != null) {
usedQueryParameter.add(mrm.getFromParameter());
}
if (mrm.getToParameter() != null) {
usedQueryParameter.add(mrm.getToParameter());
}
break;
}
//This will hapen for Not,And, Or operators
if (attributeName != null) {
if (!Character.isLowerCase(attributeName.charAt(0))) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query usage of cmp attribute that is not valid cmp identifier, declared cmp field: "
+ attributeName
+ ", query name: "
+ queryName, "10.20.2", errorBuffer);
} else if (!cmpFieldNames.contains(attributeName) && !checkForCmpMethodFromFieldName(attributeName)) {
//we have to check this. stupid specs for profile cmps are not so strict..... You can defined CMP methods but not define them in descriptor.....!!!!!!!
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query usage of cmp field that does not exist(its not declared in descritpro and in cmp interface), declared cmp field: "
+ attributeName
+ ", query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (collatorRef != null
&& !collatorAliasses.contains(collatorRef)) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query usage of collator that is not aliased, collator alias: "
+ collatorRef
+ ", query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (!ignoreAbsence && parameter != null && value != null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, value and parameter can not be present at the same time, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (!ignoreAbsence && parameter == null && value == null) {
passed = false;
errorBuffer = appendToBuffer(
"Profile specification declares in static query wrong properties, either value or parameter must be present, query name: "
+ queryName, "10.20.2", errorBuffer);
}
if (parameter != null) {
usedQueryParameter.add(parameter);
}
}
} finally {
if (!passed) {
if(logger.isEnabledFor(Level.ERROR))
logger.error(errorBuffer);
//System.err.println(errorBuffer);
}
}
return passed;
}
private boolean checkForCmpMethodFromFieldName(String fieldName)
{
//This is required since we can have weird CMPs like getAHHCmp
Set<String> ignore=new HashSet<String>();
ignore.add("java.lang.Object");
Map<String, Method> allMethods = ClassUtils.getAllInterfacesMethods(this.component.getProfileCmpInterfaceClass(), ignore);
for(Method m:allMethods.values())
{
String methodName = Introspector.decapitalize(m.getName().replace(ClassUtils.GET_PREFIX, ""));
if(methodName.equals(fieldName))
return true;
}
return false;
}
boolean compareMethod(Method m1, Method m2) {
// those two are in key
if (m1.getModifiers() != m2.getModifiers())
return false;
if (!Arrays.equals(m1.getParameterTypes(), m2.getParameterTypes())) {
return false;
}
if (m1.getName().compareTo(m2.getName()) != 0)
return false;
if (!Arrays.equals(m1.getExceptionTypes(), m2.getExceptionTypes())) {
return false;
}
if (m1.getReturnType().getName()
.compareTo(m2.getReturnType().getName()) != 0) {
return false;
}
return true;
}
protected String appendToBuffer(String message, String section,
String buffer) {
buffer += (this.component.getDescriptor().getProfileSpecificationID()
+ " : violates section " + section
+ " of jSLEE 1.1 specification : " + message + "\n");
return buffer;
}
}