blob: 49058033733936f93d6ee88f2d8bce97ebcbf1ce [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.xpath;
/**
* Validator BPEL model dependency
*/
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.eclipse.bpel.validator.model.ARule;
import org.eclipse.bpel.validator.model.IConstants;
import org.eclipse.bpel.validator.model.IFunctionMeta;
import org.eclipse.bpel.validator.model.IModelQuery;
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.Validator;
import org.eclipse.bpel.validator.tools.ParserTool;
import org.eclipse.bpel.xpath10.AdditiveExpr;
import org.eclipse.bpel.xpath10.EqualityExpr;
import org.eclipse.bpel.xpath10.Expr;
import org.eclipse.bpel.xpath10.FunctionCallExpr;
import org.eclipse.bpel.xpath10.LiteralExpr;
import org.eclipse.bpel.xpath10.LogicalExpr;
import org.eclipse.bpel.xpath10.MultiplicativeExpr;
import org.eclipse.bpel.xpath10.NumberExpr;
import org.eclipse.bpel.xpath10.RelationalExpr;
import org.eclipse.bpel.xpath10.UnaryExpr;
import org.eclipse.bpel.xpath10.VariableReferenceExpr;
import org.eclipse.bpel.xpath10.parser.XPath10Exception;
import org.eclipse.bpel.xpath10.parser.XPath10Factory;
/**
* This validator validates the XPath expressions used in the BPEL source.
* <p>
* The validation consists of 2 steps:
* <ul>
* <li>Compilation and syntax check,and
* <li>Static analysis on the expression
* </ul>
* <p>
* The static analysis is performed by visiting the parsed expression tree and
* checking certain things against the actual BPEL model.
* <p>
* The nodes which may contain XPath expressions in BPEL 2.0 and their expected
* type is as follows:
*
* <ul>
* <li>branches - unsigned integer
* <li>condition - boolean
* <li>finalCounterValue - unsigned integer
* <li>for - duration
* <li>from - any
* <li>joinCondition - boolean
* <li>repeatEvery - duration
* <li>startCounterValue - unsigned integer
* <li>to - variable reference expression ($var/foo)
* <li>transitionCondition - boolean
* <li>until - deadline
*
* </ul>
*
*
* <p>
*
* @author Michal Chmielewski (michal.chmielewski@oracle.com)
* @date Sep 27, 2006
*
*/
@SuppressWarnings({ "nls", "boxing" })
public class XPathValidator extends Validator {
/** The string format of the XPath expression */
String exprString;
String exprStringTrimmed;
/** the parsed XPath expression */
Expr xpathExpr;
/** For static analysis */
XPathVisitor mVisitor;
/** expression name by node name */
protected String fExprByNode;
/** parent node */
protected INode fParentNode;
/**
* Start the validation of this XPathExpression
*/
@Override
public void start() {
super.start();
exprString = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_TEXT_TEXT, null, null);
exprStringTrimmed = exprString.trim();
fParentNode = mNode.parentNode();
/** fExprByNode is a key to a localization map */
fExprByNode = "text.node." + mNode.nodeName().getLocalPart();
}
/**
* Do a quick sanity check.
*/
@ARule(
desc = "XPath sanity check",
author = "michal.chmielewski@oracle.com",
date = "02/16/2007",
errors="XPATH_EMPTY_EXPRESSION"
)
public void rule_SanityCheck_1() {
IProblem problem;
if (isEmptyOrWhitespace(exprString)) {
problem = createError();
problem.fill("XPATH_EMPTY_EXPRESSION", toString(mNode.nodeName()),
fExprByNode);
exprString = null;
disableRules();
}
}
/**
* Check syntax of this expression ...
*
*/
@ARule(
desc = "XPath syntax check",
author = "michal.chmielewski@oracle.com",
date = "02/16/2007",
errors="XPATH_EXPRESSION_SYNTAX"
)
public void rule_CheckExpressionSyntax_2() {
if (exprString == null) {
return;
}
IProblem problem;
try {
xpathExpr = XPath10Factory.create(exprString);
} catch (XPath10Exception e) {
problem = createError();
problem.fill("XPATH_EXPRESSION_SYNTAX", toString(mNode.nodeName()),
exprStringTrimmed, fExprByNode, e.getMessage());
repointOffsets(problem, e.getPosition(), e.getPosition() + 3);
// TODO: Position in the expression ... ?
disableRules();
}
}
protected void repointOffsets(IProblem problem, Expr expr) {
if (expr.getPosition() < 0 || expr.getEndPosition() < 0) {
return;
}
repointOffsets(problem, expr.getPosition(), expr.getEndPosition());
}
/**
* @param problem
* @param offset
* @param offsetEnd
*/
protected void repointOffsets(IProblem problem, int offset, int offsetEnd) {
int charStart = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NUMBER_CHAR_START_2, -1);
int charEnd = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NUMBER_CHAR_END_2, -1);
int lineNo = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NUMBER_LINE_NO_2, -1);
int columnNo = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NUMBER_COLUMN_NO_2, -1);
if (charStart < 0 || charEnd < 0) {
return;
}
charStart += offset;
charEnd += offsetEnd;
// Technically that should be it, but there are 3 issues:
// - have to re-point column
// - have to re-point row
// - have to adjust for \n in charStart and charEnd (JAXEN issue).
for (int i = 0, j = Math.min(exprString.length(), offset); i < j; i++) {
if (exprString.charAt(i) == '\n') {
// This is a JAXEN problem/hack
charStart += 1;
if (lineNo > 0) {
lineNo += 1;
}
columnNo = 0;
}
if (columnNo >= 0) {
columnNo += 1;
}
}
// Now do the same thing for charEnd
for (int i = 0, j = Math.min(exprString.length(), offsetEnd); i < j; i++) {
// This is a JAXEN problem/hack
if (exprString.charAt(i) == '\n') {
charEnd += 1;
}
}
problem.setAttribute(IProblem.CHAR_START, charStart);
problem.setAttribute(IProblem.CHAR_END, charEnd);
if (lineNo > 0) {
problem.setAttribute(IProblem.LINE_NUMBER, lineNo);
}
if (columnNo > 0) {
problem.setAttribute(IProblem.COLUMN_NUMBER, columnNo);
}
}
/**
* Perform static analysis of this XPath expression.
*
*/
@ARule(
sa = 0,
desc = "Create the static analysis visitor for expression analysis",
author = "michal.chmielewski@oracle.com",
date = "01/30/2007",
errors="XPATH_EXPRESSION_SYNTAX,XPATH_EXPRESSION_TYPE,XPATH_FN_ARGS,"+
"XPATH_FN_LITERAL_ARGS,XPATH_UNDEF_VARIABLE,XPATH_UNRESOLVED_NAMESPACE_PREFIX"+
"XPATH_INVALID_VARREF_PREFIX,XPATH_VARIABLE_PART,XPATH_UNDEF_VARIABLE_PART"+
"XPATH_FUNCTION_MIN_ARGS,XPATH_FUNCTION_MAX_ARGS,XPATH_EMPTY_EXPRESSION",
warnings="XPATH_URI_SYNTAX,XPATH_FUNCTION_UNKNOWN,XPATH_FUNCTION_DEPRECATED,XPATH_EXPRESSION_TYPE"
)
public void rule_StaticXPathExpressionAnalysis_10() {
mVisitor = new XPathVisitor(this);
INode typeNode = getValue("expression.type", null);
if (typeNode != null) {
mVisitor.contextPush(typeNode);
}
}
/**
* Sets the value of the expression result. This is run as the last rule in
* pass1 and it examines the top element on the stack that the
* visitor/validator combination has produced.
*
*/
public void rule_ExpressionType_999999() {
if (mVisitor == null) {
return;
}
Object obj = mVisitor.contextPop();
// Type needs to be re-mapped to XSD types that our model understands.
if (XPathVisitor.isSimpleType(obj)) {
setValue("expression.value", obj);
QName typeQName = null;
if (obj instanceof String) {
typeQName = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,
"string");
} else if (obj instanceof Number) {
Number num = (Number) obj;
if (num.intValue() == num.doubleValue()) {
if (mNode.equals(ND_START_COUNTER_VALUE)
|| mNode.equals(ND_FINAL_COUNTER_VALUE)) {
if (num.intValue() >= 0) {
typeQName = new QName(
XMLConstants.W3C_XML_SCHEMA_NS_URI,
"unsignedInt");
}
}
if (typeQName == null) {
typeQName = new QName(
XMLConstants.W3C_XML_SCHEMA_NS_URI, "integer");
}
} else {
typeQName = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,
"double");
}
} else if (obj instanceof Boolean) {
typeQName = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,
"boolean");
}
INode basicType = mModelQuery.lookup(mNode.rootNode(),
IModelQueryLookups.LOOKUP_NODE_XSD_TYPE, typeQName);
if (isUndefined(basicType)) {
setValue("expression.type", null);
} else {
setValue("expression.type", basicType);
}
} else if (obj instanceof INode) {
setValue("expression.type", obj);
} else if (obj instanceof List) {
// node list, we can't check the types
} else {
// everything else we ignore
}
}
/**
* Check the deadline expression.
*/
public void checkDeadlineExpression() {
IProblem problem;
Expr expr = xpathExpr;
// Bugzilla 320539:
if (expr instanceof UnaryExpr) {
expr = ((UnaryExpr) expr).getExpr();
}
if (expr instanceof LiteralExpr) {
LiteralExpr lexpr = (LiteralExpr) expr;
try {
ParserTool.parseDateAndTime(lexpr.getLiteral());
} catch (Exception e) {
problem = createError();
problem.fill("XPATH_EXPRESSION_SYNTAX",
toString(mNode.nodeName()), lexpr.getLiteral(),
fExprByNode, e.getMessage());
repointOffsets(problem, expr);
}
} else if (expr instanceof FunctionCallExpr) {
mVisitor.visit((FunctionCallExpr) expr);
} else {
problem = createError();
problem.fill("XPATH_EXPRESSION_TYPE", toString(mNode.nodeName()),
exprStringTrimmed, fExprByNode);
repointOffsets(problem, expr);
}
disableRules();
}
/**
* Check the duration expression variant.
*/
public void checkDurationExpression() {
IProblem problem;
Expr expr = xpathExpr;
// Bugzilla 320539:
if (expr instanceof UnaryExpr) {
expr = ((UnaryExpr) expr).getExpr();
}
if (expr instanceof LiteralExpr) {
LiteralExpr lexpr = (LiteralExpr) expr;
try {
ParserTool.parseDuration(lexpr.getLiteral());
} catch (Exception e) {
problem = createError();
problem.fill("XPATH_EXPRESSION_SYNTAX",
toString(mNode.nodeName()), lexpr.getLiteral(),
fExprByNode, e.getLocalizedMessage());
repointOffsets(problem, expr);
}
} else if (expr instanceof FunctionCallExpr) {
mVisitor.visit((FunctionCallExpr) expr);
} else {
problem = createError();
problem.fill("XPATH_EXPRESSION_TYPE", toString(mNode.nodeName()),
exprStringTrimmed, fExprByNode);
repointOffsets(problem, expr);
}
disableRules();
}
/**
* Check boolean expressions
*/
public void checkBooleanExpression() {
Expr expr = xpathExpr;
IProblem problem;
if (expr instanceof LogicalExpr) {
mVisitor.visit((LogicalExpr) expr);
} else if (expr instanceof EqualityExpr) {
mVisitor.visit((EqualityExpr) expr);
} else if (expr instanceof RelationalExpr) {
mVisitor.visit((RelationalExpr) expr);
} else if (expr instanceof UnaryExpr
&& !(((UnaryExpr) expr).getExpr() instanceof FunctionCallExpr)) {
// Bugzilla 320538:
// Allow unary expressions like variable references and literals
// Since we're using XPath 1.0 there's no XSD type checking
mVisitor.visit((UnaryExpr) expr);
} else {
FunctionCallExpr fce = null;
// Bugzilla 320535:
// apparently XPath functions are Unary expressions first
if (expr instanceof UnaryExpr
&& ((UnaryExpr) expr).getExpr() instanceof FunctionCallExpr) {
fce = (FunctionCallExpr) ((UnaryExpr) expr).getExpr();
} else if (expr instanceof FunctionCallExpr) {
fce = (FunctionCallExpr) expr;
}
if (fce != null) {
if (isBooleanFunction(fce) == false) {
problem = createWarning();
problem.fill("XPATH_EXPRESSION_TYPE",
toString(mNode.nodeName()), exprStringTrimmed,
fExprByNode);
repointOffsets(problem, fce);
}
mVisitor.visit(fce);
} else {
problem = createError();
problem.fill("XPATH_EXPRESSION_TYPE",
toString(mNode.nodeName()), exprStringTrimmed,
fExprByNode
);
repointOffsets(problem, expr);
}
}
// Once validated this type of expression we are done.
disableRules();
}
/**
* Check the integer expression.
*
* Not this is not a rule.
*/
public void checkIntegerExpression() {
IProblem problem;
Expr expr = xpathExpr;
if (expr instanceof MultiplicativeExpr) {
mVisitor.visit((MultiplicativeExpr) expr);
} else if (expr instanceof AdditiveExpr) {
mVisitor.visit((AdditiveExpr) expr);
} else if (expr instanceof UnaryExpr) {
mVisitor.visit((UnaryExpr) expr);
} else if (expr instanceof NumberExpr) {
mVisitor.visit((NumberExpr) expr);
} else if (expr instanceof VariableReferenceExpr) {
mVisitor.visit((VariableReferenceExpr) expr);
} else {
problem = createError();
problem.fill("XPATH_EXPRESSION_TYPE", toString(mNode.nodeName()),
exprStringTrimmed, fExprByNode);
}
disableRules();
}
/**
* Check function call expression.
*
* @param expr
*/
@ARule(sa = 1015, desc = "Check functions in XPath expressions", author = "michal.chmielewski@oracle.com", date = "03/02/2007", tag = "functions", order = 1)
public void checkFunctions(FunctionCallExpr expr) {
String functionPrefix = expr.getPrefix();
String nsURI = lookupNamespace(functionPrefix);
if (XPathVisitor.isBPELNS(nsURI)) {
runRules("bpel.functions", expr);
}
IFunctionMeta meta = lookup(expr);
checkFunctionMeta(expr, meta);
checkFunctionCall(expr, meta);
}
/**
* Check the GetVariableProperty function.
*
* @param expr
*/
@ARule(sa = 30, desc = "Arguments to getVariableProperty must be quoted strings", author = "michal.chmielewski@oracle.com", date = "01/29/2007", tag = "bpel.functions")
public void checkGetVariableProperty(FunctionCallExpr expr) {
String fn = expr.getFunctionName();
if ("getVariableProperty".equals(fn) == false) {
return;
}
List<?> params = expr.getParameters();
IProblem problem;
int psize = params.size();
if (psize != 2) {
problem = createError();
int pz = (params.size() - 2 < 0) ? 0 : 1;
problem.fill("XPATH_FN_ARGS", toString(mNode.nodeName()), fn,
expr.getText(), pz, 2);
repointOffsets(problem, expr);
if (psize < 1) {
return;
}
}
for (int i = 0, j = Math.min(2, params.size()); i < j; i++) {
Expr p = (Expr) params.get(i);
if ((p instanceof LiteralExpr) == false) {
problem = createError();
problem.fill("XPATH_FN_LITERAL_ARGS",
toString(mNode.nodeName()), fn, expr.getText(), i + 1,
p.getText());
repointOffsets(problem, p);
}
}
// check to see if the variable exists, it must be the 1st argument
Expr p1 = (Expr) params.get(0);
if (p1 instanceof LiteralExpr) {
LiteralExpr p1l = (LiteralExpr) p1;
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", p1l.getLiteral()) == false) {
INode variableNode = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NODE_VARIABLE,
p1l.getLiteral());
if (isUndefined(variableNode)) {
problem = createError();
problem.fill("XPATH_UNDEF_VARIABLE", //$NON-NLS-1$
p1l.getLiteral(), expr.getText());
repointOffsets(problem, p1l);
}
}
}
}
/**
* @param expr
*/
@ARule(sa = 31, desc = "The second argument MUST be a string literal conforming to the definition of QName in section 3", author = "michal.chmielewski@oracle.com", date = "01/29/2007", tag = "bpel.functions")
public void checkGetVariableProperty2ndArgument(FunctionCallExpr expr) {
String fn = expr.getFunctionName();
if ("getVariableProperty".equals(fn) == false) {
return;
}
List<?> params = expr.getParameters();
if (params.size() < 2
|| ((params.get(1) instanceof LiteralExpr) == false)) {
// already handled in previous rule.
return;
}
LiteralExpr p2l = (LiteralExpr) params.get(1);
// Make sure that the 2nd argument is a QName
QName qname = mModelQuery.createQName(mNode, p2l.getLiteral());
IProblem problem;
if (isNamespaceOK(qname) == false) {
problem = createError();
problem.fill("XPATH_UNRESOLVED_NAMESPACE_PREFIX",
qname.getPrefix(), qname.getLocalPart());
repointOffsets(problem, p2l);
return;
}
// look up variable property in the model ?
}
/**
* Check XslTransform function
*
* @param expr
*/
@ARule(sa = 39, desc = "1st arguments to doXslTransform must be quoted string", author = "michal.chmielewski@oracle.com", date = "01/29/2007", tag = "bpel.functions")
public void CheckDoXslTransform_10(FunctionCallExpr expr) {
String fn = expr.getFunctionName();
if ("doXslTransform".equals(fn) == false) {
return;
}
List<?> params = expr.getParameters();
IProblem problem;
int psize = params.size();
if (psize < 2) {
problem = createError();
problem.fill("XPATH_FN_ARGS", toString(mNode.nodeName()), fn,
expr.getText(), 0, 2);
repointOffsets(problem, expr);
if (psize < 1) {
return;
}
}
Expr p = (Expr) params.get(0);
if ((p instanceof LiteralExpr) == false) {
problem = createError();
problem.fill("XPATH_FN_LITERAL_ARGS", toString(mNode.nodeName()),
fn, expr.getText(), 1, p.getText());
repointOffsets(problem, p);
return;
}
LiteralExpr lexpr = (LiteralExpr) p;
// quick check if this is valid URI ...
try {
new java.net.URI( lexpr.getLiteral());
} catch (URISyntaxException e) {
problem = createWarning();
problem.fill("XPATH_URI_SYNTAX", toString(mNode.nodeName()),
lexpr.getLiteral(), expr.getText(), e.getMessage());
repointOffsets(problem, lexpr);
}
}
/**
* @param expr
*/
@ARule(sa = 40, desc = "There must be an even number of arguments doXslTransform", author = "michal.chmielewski@oracle.com", date = "01/29/2007", tag = "bpel.functions")
public void CheckDoXslTransform_11(FunctionCallExpr expr) {
String fn = expr.getFunctionName();
if ("doXslTransform".equals(fn) == false) {
return;
}
List<?> params = expr.getParameters();
if (params.size() < 2) {
// handled in other rule
return;
}
IProblem problem;
if (params.size() % 2 != 0) {
problem = createError();
problem.fill("XPATH_FN_ARGS", toString(mNode.nodeName()), fn,
expr.getText(), 0, 2);
repointOffsets(problem, expr);
}
}
/**
* Even number of arguments must be present.
*
* @param expr
*/
@ARule(sa = 41, desc = "3rd,5th,7th, etc. arguments must be QName strings", author = "michal.chmielewski@oracle.com", date = "01/29/2007", tag = "bpel.functions")
public void CheckDoXslTransform_15(FunctionCallExpr expr) {
String fn = expr.getFunctionName();
if ("doXslTransform".equals(fn) == false) {
return;
}
List<?> params = expr.getParameters();
if (params.size() < 3) {
// handled in other rule
return;
}
IProblem problem;
// check the 3rd, 5th, 7th etc. arguments of the XPath expression to
// make sure
// that they are QNames.
for (int i = 2, j = params.size(); i < j; i += 2) {
Expr p = (Expr) params.get(i);
if (p instanceof LiteralExpr) {
LiteralExpr p2l = (LiteralExpr) p;
QName qname = mModelQuery.createQName(mNode, p2l.getLiteral());
if (isNamespaceOK(qname) == false) {
problem = createError();
problem.fill("XPATH_UNRESOLVED_NAMESPACE_PREFIX",
qname.getPrefix(), qname.getLocalPart());
repointOffsets(problem, p);
}
} else {
problem = createError();
problem.fill("XPATH_FN_LITERAL_ARGS",
toString(mNode.nodeName()), fn, expr.getText(), i + 1,
p.getText());
repointOffsets(problem, p);
}
}
//
}
/**
* Check variables used in XPath expressions.
*
* @param expr
*/
@ARule(
sa = 0,
desc = "Check the variable namespace prefix",
author = "michal.chmielewski@oracle.com",
date = "01/30/2007",
tag = "variables",
errors="XPATH_INVALID_VARREF_PREFIX"
)
public void rule_CheckVariable_10(VariableReferenceExpr expr) {
if (isJoinCondition()) {
return;
}
String prefix = expr.getPrefix();
String name = expr.getVariableName();
IProblem problem;
// Bugzilla 320537:
// this returns too soon - only check duplicateThing if we're sure that
// there really IS a problem
// check to make sure we don't print the same message twice.
// if (duplicateThing("duplicate.variable.check.", name)) {
// return;
// }
if (isEmpty(prefix) == false) {
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", name)) {
return;
}
problem = createError();
problem.fill("XPATH_INVALID_VARREF_PREFIX", //$NON-NLS-1$
prefix + ":" + name); //$NON-NLS-1$
}
int i = name.indexOf('.');
String varName, partName;
if (i < 0) {
varName = name;
partName = null;
} else {
varName = name.substring(0, i);
partName = name.substring(i + 1);
}
INode variable = mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_NODE_VARIABLE, varName);
if (isUndefined(variable)) {
// Bugzilla 320537:
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", name)) {
return;
}
problem = createError();
problem.fill("XPATH_UNDEF_VARIABLE", //$NON-NLS-1$
varName, expr.getText());
repointOffsets(problem, expr);
// if it does not exist, we are done
mVisitor.contextPush(Collections.EMPTY_LIST);
return;
}
// Get the type reference of the variable
INode varTypeNode = getValue(variable, "type", null);
// If the variable has problems, leave now
if (hasProblems(variable) || isUndefined(varTypeNode)) {
mVisitor.contextPush(Collections.EMPTY_LIST);
return;
}
mVisitor.contextPush(Collections.EMPTY_LIST);
// check variable parts
INode variablePart = null;
if (partName != null) {
variablePart = mModelQuery.lookup(varTypeNode,
IModelQueryLookups.LOOKUP_NODE_TYPE_OF_PART, partName);
}
if (partName != null) {
if (WSDL_ND_MESSAGE.equals(varTypeNode.nodeName()) == false) {
// Bugzilla 320537:
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", name)) {
return;
}
problem = createError();
problem.fill("XPATH_VARIABLE_PART", varName, partName,
expr.getText(), 0);
repointOffsets(problem, expr);
} else if (isUndefined(variablePart)) {
// Bugzilla 320537:
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", name)) {
return;
}
problem = createError();
problem.fill("XPATH_UNDEF_VARIABLE_PART", //$NON-NLS-1$
varName, partName, expr.getText());
repointOffsets(problem, expr);
} else {
mVisitor.contextPop();
mVisitor.contextPush(variablePart);
}
} else {
// there is no part name specified, but variable does have more then
// 1 part.
if (WSDL_ND_MESSAGE.equals(varTypeNode.nodeName())) {
// Bugzilla 320537:
// check to make sure we don't print the same message twice.
if (duplicateThing("duplicate.variable.check.", name)) {
return;
}
problem = createError();
problem.fill("XPATH_VARIABLE_PART", varName,
"text.term.unspecified", expr.getText(), 1);
repointOffsets(problem, expr);
} else {
mVisitor.contextPop();
mVisitor.contextPush(varTypeNode);
}
}
}
boolean isNamespaceOK(QName qname) {
if (qname == null) {
return false;
}
return (isEmpty(qname.getNamespaceURI()) == isEmpty(qname.getPrefix()));
}
protected boolean isJoinCondition() {
/** ND_ are QNames, so make sure you compare apples to apples ... */
return ND_JOIN_CONDITION.equals(mNode.nodeName());
}
protected IModelQuery getModelQuery() {
return mModelQuery;
}
protected INode getNode() {
return mNode;
}
/**
* This exists here for visibility to XPathVisitor.
*
* @see org.eclipse.bpel.validator.model.Validator#createError()
*/
@Override
protected IProblem createError() {
return super.createError();
}
/**
* This exists here for visibility to XPathVisitor.
*
* @see org.eclipse.bpel.validator.model.Validator#createInfo()
*/
@Override
protected IProblem createInfo() {
return super.createInfo();
}
/**
* This exists here for visibility to XPathVisitor.
*
* @see org.eclipse.bpel.validator.model.Validator#createWarning()
*/
@Override
protected IProblem createWarning() {
return super.createWarning();
}
/**
* @see org.eclipse.bpel.validator.model.Validator#runRules(java.lang.String,
* java.lang.Object[])
*/
@Override
protected void runRules(String tag, Object... args) {
// this exists here for visibility to XPathVisitor.
super.runRules(tag, args);
}
protected boolean duplicateThing(String... args) {
String key = null;
if (args.length == 1) {
key = args[0];
} else {
StringBuilder sb = new StringBuilder();
for (String a : args) {
sb.append(a);
}
key = sb.toString();
}
if (containsValueKey(key)) {
return true;
}
setValue(key, Boolean.TRUE);
return false;
}
protected boolean checkPrefix(String prefix, String name) {
if (isEmptyOrWhitespace(prefix)) {
return true;
}
String nsURI = lookupNamespace(prefix);
if (isEmpty(nsURI)) {
IProblem problem = createError();
problem.fill("XPATH_UNRESOLVED_NAMESPACE_PREFIX", //$NON-NLS-1$
prefix, name);
return false;
}
return true;
}
protected String lookupNamespace(String prefix) {
return mModelQuery.lookup(mNode,
IModelQueryLookups.LOOKUP_TEXT_PREFIX2NS, prefix, null);
}
/**
* Check if the function is a boolean function.
*
* @param functionExpr
* @return true if a function is boolean, false otherwise.
*/
boolean isBooleanFunction(FunctionCallExpr functionExpr) {
IFunctionMeta meta = lookup(functionExpr);
if (meta == null) {
return false;
}
return meta.getReturnType() == Boolean.class;
}
/**
* Empty prefix in functionExpr implies an XPath function.
*
* @param functionExpr
*/
protected void checkFunctionMeta(FunctionCallExpr functionExpr,
IFunctionMeta meta) {
String fnCall = functionExpr.getFunctionName();
if (isEmptyOrWhitespace(functionExpr.getPrefix()) == false) {
fnCall = functionExpr.getPrefix() + ":" + fnCall;
}
if (duplicateThing("function.meta.", fnCall)) {
return;
}
IProblem problem;
if (meta == null) {
problem = createWarning();
problem.fill("XPATH_FUNCTION_UNKNOWN", //$NON-NLS-1$
toString(mNode.nodeName()), fnCall);
repointOffsets(problem, functionExpr);
return;
}
if (meta.isDeprecated()) {
problem = createWarning();
problem.fill(
"XPATH_FUNCTION_DEPRECATED", //$NON-NLS-1$
toString(mNode.nodeName()), fnCall,
meta.getDeprecateComment());
repointOffsets(problem, functionExpr);
}
}
protected void checkFunctionCall(FunctionCallExpr functionExpr,
IFunctionMeta meta) {
if (meta == null || functionExpr == null) {
return;
}
String fnCall = functionExpr.getFunctionName();
if (isEmptyOrWhitespace(functionExpr.getPrefix()) == false) {
fnCall = functionExpr.getPrefix() + ":" + fnCall;
}
IProblem problem;
List<?> params = functionExpr.getParameters();
if (params.size() < meta.getMinArity()) {
problem = createError();
problem.fill(
"XPATH_FUNCTION_MIN_ARGS", //$NON-NLS-1$
toString(mNode.nodeName()), fnCall, meta.getMinArity(),
params.size());
repointOffsets(problem, functionExpr);
}
if (params.size() > meta.getMaxArity()) {
problem = createError();
problem.fill(
"XPATH_FUNCTION_MAX_ARGS", //$NON-NLS-1$
toString(mNode.nodeName()), fnCall, meta.getMaxArity(),
params.size());
}
}
protected IFunctionMeta lookup(FunctionCallExpr functionExpr) {
String ns = null;
if (isEmptyOrWhitespace(functionExpr.getPrefix())) {
ns = IConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE;
} else {
ns = lookupNamespace(functionExpr.getPrefix());
}
return mModelQuery.lookupFunction(
IConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE, ns,
functionExpr.getFunctionName());
}
}