1 package org.jbpm.bpel.data.xpath; 2 3 import java.util.Collections ; 4 import java.util.Iterator ; 5 import java.util.List ; 6 7 import org.jaxen.*; 8 import org.jaxen.dom.DocumentNavigator; 9 import org.jaxen.expr.*; 10 import org.jaxen.saxpath.Axis; 11 import org.w3c.dom.Attr ; 12 import org.w3c.dom.Document ; 13 import org.w3c.dom.Element ; 14 import org.w3c.dom.Node ; 15 16 import org.jbpm.graph.exe.Token; 17 18 import org.jbpm.bpel.data.exe.VariableInstance; 19 import org.jbpm.bpel.data.spi.Script; 20 import org.jbpm.bpel.xml.BpelConstants; 21 import org.jbpm.bpel.xml.util.NodeUtil; 22 23 31 public class XPathScript extends BaseXPath implements Script { 32 33 public static final FunctionContext FUNCTION_LIBRARY; 34 35 private static final long serialVersionUID = 1L; 36 37 protected XPathScript(String snippet) throws JaxenException { 38 super(snippet, DocumentNavigator.getInstance()); 39 } 40 41 49 public Object evaluate(Object contextInfo) { 50 Object result = null; 51 try { 52 List nodeset = selectNodes(contextInfo); 53 if (nodeset != null) { 54 switch (nodeset.size()) { 55 case 0: 56 break; 57 case 1: 58 result = nodeset.get(0); 59 break; 60 default: 61 result = nodeset; 62 } 63 } 64 } 65 catch (JaxenException e) { 66 throw new RuntimeException ("Selection failure (internal error): " + 67 "snippet=" + toString(), e); 68 } 69 return result; 70 } 71 72 public void assign(Object contextInfo, Object value) { 73 Expr rootExpr = getRootExpr(); 74 Context context = getContext(contextInfo); 75 if (rootExpr instanceof VariableReferenceExpr) { 77 getVariableInstance(context, (VariableReferenceExpr) rootExpr).setValue(value); 78 } 79 else { 80 new ExprAssigner().assign(rootExpr, context, value); 81 } 82 } 83 84 protected FunctionContext createFunctionContext() { 85 return FUNCTION_LIBRARY; 86 } 87 88 96 protected Context getContext(Object node) { 97 ContextSupport support = new ContextSupport( 98 getNamespaceContext(), getFunctionContext(), 99 new ScopeVariables((Token) node), getNavigator()); 100 return new Context(support); 101 } 102 103 protected List selectOrCreateNodes(LocationPath location, Context context) throws JaxenException { 104 ContextSupport support = context.getContextSupport(); 105 List contextNodeSet = context.getNodeSet(); 106 107 Iterator stepIter = location.getSteps().iterator(); 108 while (stepIter.hasNext()) { 109 Step step = (Step) stepIter.next(); 110 Context stepContext = new Context(support); 111 stepContext.setNodeSet(contextNodeSet); 112 contextNodeSet = step.evaluate(stepContext); 113 114 if (contextNodeSet.isEmpty()) { 115 Node newNode = createNode(step, stepContext); 116 if (newNode != null) { 117 contextNodeSet = Collections.singletonList(newNode); 119 } 120 } 121 } 122 return contextNodeSet; 123 } 124 125 protected Node createNode(Step step, Context context) { 126 List nodeset = context.getNodeSet(); 127 if (!step.getPredicates().isEmpty()) { 128 throw new RuntimeException ("Selection failure (cannot create node for location steps with predicates): " + 129 "snippet=" + toString() + ", step=" + step.getText()); 130 } 131 if (nodeset.size() != 1) { 132 throw new RuntimeException ("Selection failure (cannot create node for context node sets of size other than one): " + 133 "snippet=" + toString() + ", nodeset=" + nodeset); 134 } 135 Object node = nodeset.get(0); 136 if (!(node instanceof Element )) { 137 throw new RuntimeException ("Selection failure (cannot create node for a non-element parent): " + 138 "snippet=" + toString() + ", parent=" + node); 139 } 140 Element parent = (Element ) node; 141 Document doc = parent.getOwnerDocument(); 142 143 Node newNode = null; 144 int axis = step.getAxis(); 145 switch (axis) { 146 case Axis.ATTRIBUTE: { 147 if (!(step instanceof NameStep)) { 148 throw new RuntimeException ("Selection failure (cannot create node for non-name tests on the attribute axis): " + 149 "snippet=" + toString() + ", step=" + step.getText()); 150 } 151 NameStep nameStep = (NameStep) step; 152 String localName = nameStep.getLocalName(); 153 if ("*".equals(localName)) { 154 throw new RuntimeException ("Selection failure (cannot create node for any-name node tests): " + 155 "snippet=" + toString()); 156 } 157 String namespaceURI = context.translateNamespacePrefixToUri(nameStep.getPrefix()); 158 Attr attr = doc.createAttributeNS(namespaceURI, localName); 159 parent.setAttributeNodeNS(attr); 160 newNode = attr; 161 break; 162 } 163 case Axis.CHILD: 164 if (step instanceof NameStep) { 165 NameStep nameStep = (NameStep) step; 166 String localName = nameStep.getLocalName(); 167 if ("*".equals(localName)) { 168 throw new RuntimeException ("Selection failure (cannot create node for any-name node tests): " + 169 "snippet=" + toString()); 170 } 171 String namespaceURI = context.translateNamespacePrefixToUri(nameStep.getPrefix()); 172 newNode = doc.createElementNS(namespaceURI, localName); 173 } 174 else if (step instanceof TextNodeStep) { 175 newNode = doc.createTextNode(""); 176 } 177 else if (step instanceof ProcessingInstructionNodeStep) { 178 newNode = doc.createProcessingInstruction(((ProcessingInstructionNodeStep) step).getName(), ""); 179 } 180 else if (step instanceof CommentNodeStep) { 181 newNode = doc.createComment(""); 182 } 183 else { 184 throw new RuntimeException ("Selection failure (cannot create node for any-node tests on the child axis): " + 185 "snippet=" + toString() + ", step=" + step.getText()); 186 } 187 parent.appendChild(newNode); 188 break; 189 default: 190 throw new RuntimeException ("Selection failure (cannot create node on the specified axis): " + 191 "snippet=" + toString() + ", axis=" + Axis.lookup(axis)); 192 } 193 return newNode; 194 } 195 196 protected Node getSingleNode(List nodeset) { 197 if (nodeset == null || nodeset.size() != 1) { 198 throw new RuntimeException ("Selection failure (node set of size other than one): " + 199 "snippet=" + toString() + ", nodeset=" + nodeset); 200 } 201 Object singleResult = nodeset.get(0); 202 if (!(singleResult instanceof Node )) { 203 throw new RuntimeException ("Selection failure (selection is not a node): " + 204 "snippet=" + toString() + " selection=" + singleResult); 205 } 206 return (Node ) singleResult; 207 } 208 209 public static XPathScript createExpression(String snippet) throws JaxenException { 210 XPathScript expressionPeer = new XPathScript(snippet); 211 if (!new ExprValidator().validate(expressionPeer.getRootExpr())) { 213 throw new XPathSyntaxException(snippet, 0, "Expression has no access to root/context node"); 214 } 215 return expressionPeer; 216 } 217 218 public static XPathScript createJoinCondition(String snippet) throws JaxenException { 219 JoinCondition joinConditionPeer = new JoinCondition(snippet); 220 if (!new ExprValidator().validate(joinConditionPeer.getRootExpr())) { 221 throw new XPathSyntaxException(snippet, 0, "Join condition has no access to root/context node"); 222 } 223 return joinConditionPeer; 224 } 225 226 public static XPathScript createQuery(String snippet) throws JaxenException { 227 XPathScript queryPeer = new XPathScript(snippet); 228 Expr rootExpr = queryPeer.getRootExpr(); 229 if (!(rootExpr instanceof PathExpr || rootExpr instanceof FilterExpr || 231 rootExpr instanceof VariableReferenceExpr || rootExpr instanceof FunctionCallExpr)) { 232 throw new XPathSyntaxException(snippet, 0, "Query is not a path expression"); 233 } 234 return queryPeer; 235 } 236 237 public static XPathScript createPropertyAlias(String snippet) throws JaxenException { 238 RelativePath relativePathPeer = new RelativePath(snippet); 239 Expr rootExpr = relativePathPeer.getRootExpr(); 240 if (!(rootExpr instanceof LocationPath) || ((LocationPath) rootExpr).isAbsolute()) { 241 throw new XPathSyntaxException(snippet, 0, "Property alias is not a relative location path"); 242 } 243 return relativePathPeer; 244 } 245 246 static VariableInstance getVariableInstance(Context context, VariableReferenceExpr varExpr) { 247 ScopeVariables variables = (ScopeVariables) context.getContextSupport().getVariableContext(); 248 return variables.getVariable(varExpr.getVariableName()); 249 } 250 251 private static class ExprValidator extends VisitorSupport { 252 253 private boolean valid; 254 255 public boolean validate(Expr expr) { 256 valid = true; 257 expr.accept(this); 258 return valid; 259 } 260 261 public void visit(LogicalExpr expr) { 262 propagate(expr); 263 } 264 265 public void visit(EqualityExpr expr) { 266 propagate(expr); 267 } 268 269 public void visit(RelationalExpr expr) { 270 propagate(expr); 271 } 272 273 public void visit(AdditiveExpr expr) { 274 propagate(expr); 275 } 276 277 public void visit(MultiplicativeExpr expr) { 278 propagate(expr); 279 } 280 281 public void visit(UnaryExpr expr) { 282 expr.getExpr().accept(this); 283 } 284 285 public void visit(UnionExpr expr) { 286 propagate(expr); 287 } 288 289 public void visit(LocationPath locationPath) { 290 valid = false; 291 } 292 293 private void propagate(BinaryExpr expr) { 294 expr.getLHS().accept(this); 295 expr.getRHS().accept(this); 296 } 297 } 298 299 private class ExprAssigner extends VisitorSupport { 300 301 private Context context; 302 private Object result; 303 304 public void assign(Expr pathExpr, Context context, Object value) { 305 this.context = context; 306 pathExpr.accept(this); 307 Node node = result instanceof List ? getSingleNode((List ) result) : (Node ) result; 308 NodeUtil.setValue(node, value); 309 } 310 311 public void visit(PathExpr pathExpr) { 312 pathExpr.getFilterExpr().accept(this); 313 visit(pathExpr.getLocationPath()); 314 } 315 316 public void visit(FilterExpr filterExpr) { 317 filterExpr.getExpr().accept(this); 318 if (result instanceof List ) { 320 result = evaluatePredicates(filterExpr.getPredicateSet(), (List ) result, context.getContextSupport()); 321 } 322 } 323 324 public void visit(LocationPath locationPath) { 325 context.setNodeSet(result instanceof List ? (List ) result : Collections.singletonList(result)); 326 try { 327 result = selectOrCreateNodes(locationPath, context); 328 } 329 catch (JaxenException e) { 330 throw new RuntimeException ("Selection failure (internal error)", e); 331 } 332 } 333 334 public void visit(VariableReferenceExpr varExpr) { 335 result = getVariableInstance(context, varExpr).getOrCreateValue(); 336 } 337 338 public void visit(LiteralExpr literalExpr) { 339 try { 340 result = literalExpr.evaluate(context); 341 } 342 catch (JaxenException e) { 343 throw new RuntimeException ("Selection failure (internal error)", e); 344 } 345 } 346 347 public void visit(NumberExpr numberExpr) { 348 try { 349 result = numberExpr.evaluate(context); 350 } 351 catch (JaxenException e) { 352 throw new RuntimeException ("Selection failure (internal error)", e); 353 } 354 } 355 356 public void visit(FunctionCallExpr callExpr) { 357 try { 358 result = callExpr.evaluate(context); 359 } 360 catch (JaxenException e) { 361 throw new RuntimeException ("Selection failure (internal error)", e); 362 } 363 } 364 365 private List evaluatePredicates(PredicateSet predicateSet, List nodes, ContextSupport support) { 366 List predicates = predicateSet.getPredicates(); 367 if (!predicates.isEmpty()) { 368 try { 369 Iterator predicateIt = predicateSet.getPredicates().iterator(); 370 while (predicateIt.hasNext()) { 371 nodes = predicateSet.applyPredicate((Predicate) predicateIt.next(), nodes, support); 372 } 373 } 374 catch (JaxenException e) { 375 throw new RuntimeException ("Selection failure (internal error)", e); 376 } 377 } 378 return nodes; 379 } 380 } 381 382 static { 383 XPathFunctionContext functionContext = new XPathFunctionContext(); 384 FUNCTION_LIBRARY = functionContext; 385 functionContext.registerFunction(BpelConstants.NS_BPWS_1_1, "getVariableData", new GetVariableDataFunction()); 387 functionContext.registerFunction(BpelConstants.NS_BPWS_1_1, "getVariableProperty", new GetVariablePropertyFunction()); 388 functionContext.registerFunction(BpelConstants.NS_VENDOR, "random", new RandomFunction()); 390 } 391 } 392 | Popular Tags |