blob: 5631b1cb7621409f70548f9c2629cce448ffa54e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Oracle Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Oracle Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.validator.rules;
import java.lang.reflect.Field;
import java.util.List;
import javax.xml.namespace.QName;
import org.eclipse.bpel.validator.model.ARule;
import org.eclipse.bpel.validator.model.Filters;
import org.eclipse.bpel.validator.model.IConstants;
import org.eclipse.bpel.validator.model.IFilter;
import org.eclipse.bpel.validator.model.IModelQueryLookups;
import org.eclipse.bpel.validator.model.INode;
import org.eclipse.bpel.validator.model.IProblem;
import org.eclipse.bpel.validator.model.NodeNameFilter;
import org.eclipse.bpel.validator.model.RuleFactory;
import org.eclipse.bpel.validator.model.Validator;
/**
* @author Michal Chmielewski (michal.chmielewski@oracle.com)
* @date Oct 12, 2006
*
*/
@SuppressWarnings("nls")
public class CValidator extends Validator {
/** The parent node */
protected INode fParentNode;
/** Children nodes */
protected List<INode> fChildren;
List<INode> fTypeToCheckList;
@Override
protected void start () {
super.start();
fParentNode = mNode.parentNode();
// get the children, as we will be checking them
fChildren = mNode.children() ;
}
/**
* Check to make sure that parent node
* of my node is within the set of nodes
* that is allowed.
*/
@ARule(
sa = 2001,
desc = "Check to make sure that my parent node is within a set of allowed nodes",
author = "michal.chmielewski@oracle.com",
date = "02/15/2007"
)
public void rule_CheckParentNode_1 () {
checkParentNode ();
}
/**
* Check the parent Node
*/
public void checkParentNode () {
IFilter<INode> filter = parentNodeNames();
if (fParentNode == null) {
return ;
}
if (filter.select(fParentNode) ) {
return ;
}
// Otherwise, we have a problem ...
IProblem problem;
problem = createError();
problem.fill("BPELC__WRONG_PARENT", //$NON-NLS-1$
toString(mNode.nodeName()),
toString(fParentNode.nodeName()),
filter.toString() );
// Disable all the rules from being run, if we get here.
disableRules();
}
/**
* Check the children nodes, to make sure that they are present
*/
@ARule(
sa = 2002,
desc = "Check my children nodes (types and occurances)",
author = "michal.chmielewski@oracle.com",
date = "02/15/2007"
)
public void rule_CheckChildrenNodes_0 () {
checkChildren();
}
/**
* Check the children nodes
*
*/
public void checkChildren () {
}
/**
* Check to make sure that the node nodeName appears in the
* children as specified by he min/max parameters.
* @param node
* @param min
* @param max
* @return the number of occurrences of this child.
*/
public int checkChild (QName node, int min, int max) {
return checkChild ( new NodeNameFilter(node),min,max) ;
}
/**
* @param filter
* @param min
* @param max
* @return the # of occurrences of this child
*/
@SuppressWarnings("boxing")
public int checkChild ( IFilter<INode> filter, int min, int max) {
int count = 0;
for(INode n : fChildren) {
if (filter.select(n)) {
count += 1;
}
}
IProblem problem;
if (count < min) {
problem = createError();
problem.fill("BPELC__MIN_IN_PARENT",
toString(mNode.nodeName()),
getNodeKind ( mNode ),
IConstants.KIND_NODE,
filter.toString(),
count,
min
);
} else if (count > max) {
problem = createError();
problem.fill("BPELC__MAX_IN_PARENT",
toString(mNode.nodeName()),
getNodeKind ( mNode ),
IConstants.KIND_NODE,
filter.toString(),
count,
max
);
}
return count;
}
/**
* Answer with my parent nodes. Subclasses must override this
* because most nodes can only be children of certain nodes.
*
* @return an array of valid parent nodes.
*/
@SuppressWarnings("unchecked")
public IFilter<INode> parentNodeNames () {
try {
Field f = getClass().getField("PARENTS");
return (IFilter) f.get(null);
} catch (java.lang.NoSuchFieldException nsfe) {
// do nothing.
} catch (Throwable t) {
t.printStackTrace();
}
return Filters.EMPTY ;
}
/**
* Return the value of getExitOnStandardFault
*
* @param node
* @return either yes or no, depending on the setting in the scopes.
*/
public String getExitOnStandardFault ( INode node ) {
INode nn = mSelector.selectParent(node, new IFilter<INode>() {
public boolean select(INode n) {
QName name = n.nodeName();
if (name.equals(ND_SCOPE) == false && name.equals(ND_PROCESS) == false) {
return false;
}
String value = n.getAttribute(AT_EXIT_ON_STANDARD_FAULT);
if (isEmpty(value) == false) {
return true;
}
return false;
}
});
if (nn != null) {
return nn.getAttribute(AT_EXIT_ON_STANDARD_FAULT);
}
return NO;
}
/**
* Register a type to check.
* @param node
*/
public void registerTypeToCheck (INode node) {
if (isUndefined(node)) {
return;
}
if ( fTypeToCheckList == null) {
INode process = mNode.rootNode();
fTypeToCheckList = getValue(process, "types.to.check", null);
}
if (fTypeToCheckList == null) {
return ;
}
if ( fTypeToCheckList.contains ( node ) == false ) {
fTypeToCheckList.add ( node );
}
}
/**
* Check if the copy is compatible
*
* @param fromNode
* @param toNode
*/
public void compatibleCopyCheck ( INode fromNode, INode toNode ) {
INode fromTypeNode = getValue(fromNode,"type",null);
INode toTypeNode = getValue(toNode,"type",null);
if (hasProblems(fromNode) || hasProblems(toNode)) {
return ;
}
if (fromTypeNode == null && toTypeNode == null) {
return ;
}
/** Compatible assign */
IProblem problem ;
if (fromTypeNode == null || toTypeNode == null) {
problem = createInfo();
problem.fill("BPELC_COPY__NOT_CHECKED",
toString(mNode.nodeName()),
"text.term.from",
fromTypeNode == null ? "text.term.unspecified" : fromTypeNode ,
"text.term.to",
toTypeNode == null ? "text.term.unspecified" : toTypeNode );
return ;
}
// source -> destination
boolean bCompatible = mModelQuery.check(IModelQueryLookups.TEST_COMPATIBLE_TYPE, fromTypeNode, toTypeNode);
// if these are simple types, warn if incompatibility found as engines may perform implicit conversion
// much like XPath does.
if (mModelQuery.check(IModelQueryLookups.TEST_IS_SIMPLE_TYPE,fromTypeNode,null) &&
mModelQuery.check(IModelQueryLookups.TEST_IS_SIMPLE_TYPE,toTypeNode,null)) {
if (bCompatible == false) {
problem = createWarning();
problem.fill("BPELC_COPY__INCOMPATIBLE_SIMPLE",
toString(mNode.nodeName()),
"text.term.from",
fromTypeNode,
"text.term.to",
toTypeNode
);
}
// Temporary workaround for 3369 - disable check if from/to has a part attr
String fromPart = fromNode.getAttribute(AT_PART);
String toPart = toNode.getAttribute(AT_PART);
if (fromPart != null || toPart != null){
return;
}
} else if (bCompatible == false) {
problem = createError();
problem.fill("BPELC_COPY__INCOMPATIBLE",
toString(mNode.nodeName()),
"text.term.from",
fromTypeNode,
"text.term.to",
toTypeNode
);
}
}
/**
* A generic check against attributes
*
* @param node the context node.
* @param name name of the attribute
* @param kind 1 for activity node, 0 for generic node
* @param filter the filter that checks the allowed values
* @param bMandatory true for mandatory, false otherwise.
* @return the attribute value or null if the value does not exist or is not allowed.
*/
@SuppressWarnings("boxing")
public String getAttribute ( INode node, QName name, int kind, IFilter<String> filter, boolean bMandatory ) {
IProblem problem;
String value = node.getAttribute(name);
if (bMandatory) {
if (isEmpty(value)) {
problem = createError(node);
problem.setAttribute(IProblem.CONTEXT, name.getLocalPart() );
problem.fill("BPELC__UNSET_ATTRIBUTE", //$NON-NLS-1$
toString(node.nodeName()) ,
toString(name), kind );
return null;
}
}
if (filter == null || isEmpty(value) ) {
return value;
}
if (filter.select(value)) {
return value;
}
problem = createError(node);
problem.setAttribute(IProblem.CONTEXT, name.getLocalPart());
problem.fill("BPELC__INVALID_ATTRIBUTE_VALUE", //$NON-NLS-1$
toString(node.nodeName()),
toString(name),
value,
filter.toString() ,
kind);
return null ;
}
/**
* A generic check against all attributes that are pointers to other
* objects. For example, portType on invoke, partnerLink, etc. are
* represented as attributes but in fact refer to larger objects in the
* models.
*
* @param node
* @param ref the referenced node
* @param name the name of the attribute that references the node
* @param kind 1 for activity node, 0 for generic node
* @return true if the attribute pointer can be resolved, false otherwise
*/
@SuppressWarnings("boxing")
public boolean checkAttributeNode ( INode node, INode ref, QName name, int kind ) {
IProblem problem;
if (ref == null) {
problem = createError(node);
problem.setAttribute(IProblem.CONTEXT, name);
problem.fill("BPELC__UNSET_ATTRIBUTE", //$NON-NLS-1$
toString(node.nodeName()) ,
toString(name), kind );
return false;
}
if (ref.isResolved() == false) {
String atValue = node.getAttribute( name );
problem = createError(node);
problem.setAttribute(IProblem.CONTEXT, name);
problem.fill("BPELC__UNRESOLVED_ATTRIBUTE", //$NON-NLS-1$
toString(node.nodeName()),
toString(name), kind , atValue );
return false;
}
return true;
}
/**
* Check if NCName is valid.
*
* @param node the node on which we are checking.
* @param ncName the ncName
* @param atName the attribute name from where the ncName came from.
* @return return true if checkName succeeds, false otherwise.
*/
@SuppressWarnings("boxing")
public boolean checkNCName ( INode node, String ncName, QName atName ) {
if (ncName == null || ncName.length() == 0) {
IProblem problem = createError( node );
problem.setAttribute(IProblem.CONTEXT, atName.getLocalPart() );
problem.fill("BPELC__UNSET_ATTRIBUTE",
toString(node.nodeName()) ,
atName,
IConstants.KIND_NODE);
return false ;
}
if (Filters.NC_NAME.select(ncName) == false) {
IProblem problem = createError( node );
problem.setAttribute(IProblem.CONTEXT, atName.getLocalPart() );
problem.fill("General.NCName_Bad", //$NON-NLS-1$
toString(atName),
toString(node.nodeName()) , ncName );
return false;
}
// Check for uniqueness of name within a scope or process ?
return true;
}
/**
* Check the node's validator to see if there are any problems reported on the
* node.
*
* @param node the context node
* @param ref the referenced node that comes from the node via an attribute
* @param name the name of the attribute reference
* @param kind 0 for node, 1 for activity
* @return true if there are any problems, false otherwise.
*/
@SuppressWarnings("boxing")
public boolean checkValidator ( INode node, INode ref, QName name, int kind ) {
if (ref == null) {
return false;
}
Validator validator = ref.nodeValidator();
if (validator == null) {
return true;
}
IProblem problem;
if (validator.hasProblems()) {
problem = createWarning(node);
problem.setAttribute(IProblem.CONTEXT, name.getLocalPart() );
problem.fill("BPELC_REF_NODE_PROBLEMS", //$NON-NLS-1$
toString(node.nodeName()),
toString(ref.nodeName()),
name,
kind);
return false;
}
return true;
}
/**
*
* Return the language (expression or query) from the node.
*
* @param node
* @param atName the attribute name
* @return the default language.
*/
public String getLanguage (INode node, QName atName) {
// get the expression language
String lang = node.getAttribute (atName);
if (lang == null) {
INode process = node.rootNode ();
lang = process.getAttribute(atName);
}
// the default language
if (lang == null) {
return IConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE;
}
return lang;
}
protected int getNodeKind ( INode node ) {
if (Filters.ACTIVITIES.select(node)) {
return IConstants.KIND_ACTIVITY;
}
return IConstants.KIND_NODE;
}
protected Validator createExpressionValidator ( QName qname ) {
Validator object = RuleFactory.INSTANCE.createValidator ( qname );
IProblem problem;
if (object == null) {
problem = createWarning();
problem.fill("BPELC__NO_EXPRESSION_VALIDATOR", //$NON-NLS-1$
toString(mNode.nodeName()),
qname.getNamespaceURI()
);
return null;
}
return object;
}
}