KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jbpm > bpel > data > xpath > XPathScript


1 package org.jbpm.bpel.data.xpath;
2
3 import java.util.Collections JavaDoc;
4 import java.util.Iterator JavaDoc;
5 import java.util.List JavaDoc;
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 JavaDoc;
12 import org.w3c.dom.Document JavaDoc;
13 import org.w3c.dom.Element JavaDoc;
14 import org.w3c.dom.Node JavaDoc;
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 /**
24  * An expression coded in XPath 1.0. It can be any XPath expression except for
25  * those directly using location paths. This restriction essentialy disallows
26  * access to the context node, which is unspecified for expressions.
27  * @see "WS-BPEL 2.0 §9.1"
28  * @author Alejandro Guízar
29  * @version $Revision: 1.8 $ $Date: 2005/06/23 02:22:46 $
30  */

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 JavaDoc snippet) throws JaxenException {
38     super(snippet, DocumentNavigator.getInstance());
39   }
40   
41   /**
42    * Evaluates this expression. The context of XPath evaluation is:<ul>
43    * <li>the context node, position and size are unspecified</li>
44    * <li>the function library, namespace declaration and variable bindings
45    * are obtained by a call to {@link #getContext(Object)}</li><ul>
46    * @param contextInfo the state of one path of execution
47    * @return the result of evaluation
48    */

49   public Object JavaDoc evaluate(Object JavaDoc contextInfo) {
50     Object JavaDoc result = null;
51     try {
52       List JavaDoc 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 JavaDoc("Selection failure (internal error): " +
67             "snippet=" + toString(), e);
68     }
69     return result;
70   }
71   
72   public void assign(Object JavaDoc contextInfo, Object JavaDoc value) {
73     Expr rootExpr = getRootExpr();
74     Context context = getContext(contextInfo);
75     // direct variable assignment?
76
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   /**
89    * Gets a context for XPath evaluation. The context for an expression
90    * expression is:<ul>
91    * <li>the variable bindings are the variables in the scope of the given token</li>
92    * <li>the function library is {@link #FUNCTION_LIBRARY}</li>
93    * <li>the namespace declarations are taken from the snippet</li></ul>
94    * @param node an instance of {@link Token}
95    */

96   protected Context getContext(Object JavaDoc 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 JavaDoc selectOrCreateNodes(LocationPath location, Context context) throws JaxenException {
104     ContextSupport support = context.getContextSupport();
105     List JavaDoc contextNodeSet = context.getNodeSet();
106     
107     Iterator JavaDoc 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 JavaDoc newNode = createNode(step, stepContext);
116         if (newNode != null) {
117           // create a new list, since the existing empty list is immutable
118
contextNodeSet = Collections.singletonList(newNode);
119         }
120       }
121     }
122     return contextNodeSet;
123   }
124   
125   protected Node JavaDoc createNode(Step step, Context context) {
126     List JavaDoc nodeset = context.getNodeSet();
127     if (!step.getPredicates().isEmpty()) {
128       throw new RuntimeException JavaDoc("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 JavaDoc("Selection failure (cannot create node for context node sets of size other than one): " +
133             "snippet=" + toString() + ", nodeset=" + nodeset);
134     }
135     Object JavaDoc node = nodeset.get(0);
136     if (!(node instanceof Element JavaDoc)) {
137       throw new RuntimeException JavaDoc("Selection failure (cannot create node for a non-element parent): " +
138             "snippet=" + toString() + ", parent=" + node);
139     }
140     Element JavaDoc parent = (Element JavaDoc) node;
141     Document JavaDoc doc = parent.getOwnerDocument();
142     
143     Node JavaDoc newNode = null;
144     int axis = step.getAxis();
145     switch (axis) {
146     case Axis.ATTRIBUTE: {
147       if (!(step instanceof NameStep)) {
148         throw new RuntimeException JavaDoc("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 JavaDoc localName = nameStep.getLocalName();
153       if ("*".equals(localName)) {
154         throw new RuntimeException JavaDoc("Selection failure (cannot create node for any-name node tests): " +
155                 "snippet=" + toString());
156       }
157       String JavaDoc namespaceURI = context.translateNamespacePrefixToUri(nameStep.getPrefix());
158       Attr JavaDoc 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 JavaDoc localName = nameStep.getLocalName();
167         if ("*".equals(localName)) {
168           throw new RuntimeException JavaDoc("Selection failure (cannot create node for any-name node tests): " +
169                 "snippet=" + toString());
170         }
171         String JavaDoc 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 JavaDoc("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 JavaDoc("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 JavaDoc getSingleNode(List JavaDoc nodeset) {
197     if (nodeset == null || nodeset.size() != 1) {
198       throw new RuntimeException JavaDoc("Selection failure (node set of size other than one): " +
199             "snippet=" + toString() + ", nodeset=" + nodeset);
200     }
201     Object JavaDoc singleResult = nodeset.get(0);
202     if (!(singleResult instanceof Node JavaDoc)) {
203       throw new RuntimeException JavaDoc("Selection failure (selection is not a node): " +
204             "snippet=" + toString() + " selection=" + singleResult);
205     }
206     return (Node JavaDoc) singleResult;
207   }
208   
209   public static XPathScript createExpression(String JavaDoc snippet) throws JaxenException {
210     XPathScript expressionPeer = new XPathScript(snippet);
211     // expressions are general xpath expressions, excluding the direct usage of location paths
212
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 JavaDoc 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 JavaDoc snippet) throws JaxenException {
227     XPathScript queryPeer = new XPathScript(snippet);
228     Expr rootExpr = queryPeer.getRootExpr();
229     // queries are path expressions, excluding the direct usage of location paths
230
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 JavaDoc 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 JavaDoc result;
303     
304     public void assign(Expr pathExpr, Context context, Object JavaDoc value) {
305       this.context = context;
306       pathExpr.accept(this);
307       Node JavaDoc node = result instanceof List JavaDoc ? getSingleNode((List JavaDoc) result) : (Node JavaDoc) 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       // result is a node set so far?
319
if (result instanceof List JavaDoc) {
320         result = evaluatePredicates(filterExpr.getPredicateSet(), (List JavaDoc) result, context.getContextSupport());
321       }
322     }
323     
324     public void visit(LocationPath locationPath) {
325       context.setNodeSet(result instanceof List JavaDoc ? (List JavaDoc) result : Collections.singletonList(result));
326       try {
327         result = selectOrCreateNodes(locationPath, context);
328       }
329       catch (JaxenException e) {
330         throw new RuntimeException JavaDoc("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 JavaDoc("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 JavaDoc("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 JavaDoc("Selection failure (internal error)", e);
362       }
363     }
364
365     private List JavaDoc evaluatePredicates(PredicateSet predicateSet, List JavaDoc nodes, ContextSupport support) {
366       List JavaDoc predicates = predicateSet.getPredicates();
367       if (!predicates.isEmpty()) {
368         try {
369           Iterator JavaDoc 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 JavaDoc("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     // WS-BPEL 2.0 library
386
functionContext.registerFunction(BpelConstants.NS_BPWS_1_1, "getVariableData", new GetVariableDataFunction());
387     functionContext.registerFunction(BpelConstants.NS_BPWS_1_1, "getVariableProperty", new GetVariablePropertyFunction());
388     // Vendor-specific library
389
functionContext.registerFunction(BpelConstants.NS_VENDOR, "random", new RandomFunction());
390   }
391 }
392
Popular Tags