KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xpath > internal > jaxp > XPathImpl


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 // $Id: XPathImpl.java,v 1.15 2004/07/10 21:39:19 rameshm Exp $
17

18 package com.sun.org.apache.xpath.internal.jaxp;
19
20 import javax.xml.namespace.QName JavaDoc;
21 import javax.xml.namespace.NamespaceContext JavaDoc;
22 import javax.xml.xpath.XPathExpressionException JavaDoc;
23 import javax.xml.xpath.XPathConstants JavaDoc;
24 import javax.xml.xpath.XPathFunctionResolver JavaDoc;
25 import javax.xml.xpath.XPathVariableResolver JavaDoc;
26 import javax.xml.xpath.XPathExpression JavaDoc;
27
28 import com.sun.org.apache.xml.internal.dtm.DTM;
29 import com.sun.org.apache.xpath.internal.*;
30 import com.sun.org.apache.xpath.internal.objects.XObject;
31 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
32 import com.sun.org.apache.xalan.internal.res.XSLMessages;
33
34 import org.w3c.dom.Node JavaDoc;
35 import org.w3c.dom.DOMImplementation JavaDoc;
36 import org.w3c.dom.Document JavaDoc;
37 import org.w3c.dom.traversal.NodeIterator;
38
39 import org.xml.sax.InputSource JavaDoc;
40 import org.xml.sax.SAXException JavaDoc;
41
42 import javax.xml.parsers.*;
43
44 import java.io.IOException JavaDoc;
45
46 /**
47  * The XPathImpl class provides implementation for the methods defined in
48  * javax.xml.xpath.XPath interface. This provide simple access to the results
49  * of an XPath expression.
50  *
51  *
52  * @version $Revision: 1.15 $
53  * @author Ramesh Mandava
54  */

55 public class XPathImpl implements javax.xml.xpath.XPath JavaDoc {
56
57     // Private variables
58
private XPathVariableResolver JavaDoc variableResolver;
59     private XPathFunctionResolver JavaDoc functionResolver;
60     private XPathVariableResolver JavaDoc origVariableResolver;
61     private XPathFunctionResolver JavaDoc origFunctionResolver;
62     private NamespaceContext JavaDoc namespaceContext=null;
63     private JAXPPrefixResolver prefixResolver;
64     // By default Extension Functions are allowed in XPath Expressions. If
65
// Secure Processing Feature is set on XPathFactory then the invocation of
66
// extensions function need to throw XPathFunctionException
67
private boolean featureSecureProcessing = false;
68
69     XPathImpl( XPathVariableResolver JavaDoc vr, XPathFunctionResolver JavaDoc fr ) {
70         this.origVariableResolver = this.variableResolver = vr;
71         this.origFunctionResolver = this.functionResolver = fr;
72     }
73
74     XPathImpl( XPathVariableResolver JavaDoc vr, XPathFunctionResolver JavaDoc fr,
75             boolean featureSecureProcessing ) {
76         this.origVariableResolver = this.variableResolver = vr;
77         this.origFunctionResolver = this.functionResolver = fr;
78         this.featureSecureProcessing = featureSecureProcessing;
79     }
80
81     /**
82      * <p>Establishes a variable resolver.</p>
83      *
84      * @param resolver Variable Resolver
85      */

86     public void setXPathVariableResolver(XPathVariableResolver JavaDoc resolver) {
87         if ( resolver == null ) {
88             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
89                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
90                     new Object JavaDoc[] {"XPathVariableResolver"} );
91             throw new NullPointerException JavaDoc( fmsg );
92         }
93         this.variableResolver = resolver;
94     }
95
96     /**
97      * <p>Returns the current variable resolver.</p>
98      *
99      * @return Current variable resolver
100      */

101     public XPathVariableResolver JavaDoc getXPathVariableResolver() {
102         return variableResolver;
103     }
104
105     /**
106      * <p>Establishes a function resolver.</p>
107      *
108      * @param resolver XPath function resolver
109      */

110     public void setXPathFunctionResolver(XPathFunctionResolver JavaDoc resolver) {
111         if ( resolver == null ) {
112             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
113                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
114                     new Object JavaDoc[] {"XPathFunctionResolver"} );
115             throw new NullPointerException JavaDoc( fmsg );
116         }
117         this.functionResolver = resolver;
118     }
119
120     /**
121      * <p>Returns the current function resolver.</p>
122      *
123      * @return Current function resolver
124      */

125     public XPathFunctionResolver JavaDoc getXPathFunctionResolver() {
126         return functionResolver;
127     }
128
129     /**
130      * <p>Establishes a namespace context.</p>
131      *
132      * @param nsContext Namespace context to use
133      */

134     public void setNamespaceContext(NamespaceContext JavaDoc nsContext) {
135         if ( nsContext == null ) {
136             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
137                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
138                     new Object JavaDoc[] {"NamespaceContext"} );
139             throw new NullPointerException JavaDoc( fmsg );
140         }
141         this.namespaceContext = nsContext;
142         this.prefixResolver = new JAXPPrefixResolver ( nsContext );
143     }
144
145     /**
146      * <p>Returns the current namespace context.</p>
147      *
148      * @return Current Namespace context
149      */

150     public NamespaceContext JavaDoc getNamespaceContext() {
151         return namespaceContext;
152     }
153
154     private static Document JavaDoc d = null;
155     
156     private static DocumentBuilder getParser() {
157         try {
158             // we'd really like to cache those DocumentBuilders, but we can't because:
159
// 1. thread safety. parsers are not thread-safe, so at least
160
// we need one instance per a thread.
161
// 2. parsers are non-reentrant, so now we are looking at having a
162
// pool of parsers.
163
// 3. then the class loading issue. The look-up procedure of
164
// DocumentBuilderFactory.newInstance() depends on context class loader
165
// and system properties, which may change during the execution of JVM.
166
//
167
// so we really have to create a fresh DocumentBuilder every time we need one
168
// - KK
169
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
170             dbf.setNamespaceAware( true );
171             dbf.setValidating( false );
172             return dbf.newDocumentBuilder();
173         } catch (ParserConfigurationException e) {
174             // this should never happen with a well-behaving JAXP implementation.
175
throw new Error JavaDoc(e);
176         }
177     }
178
179     private static Document JavaDoc getDummyDocument( ) {
180         // we don't need synchronization here; even if two threads
181
// enter this code at the same time, we just waste a little time
182
if(d==null) {
183             DOMImplementation JavaDoc dim = getParser().getDOMImplementation();
184             d = dim.createDocument("http://java.sun.com/jaxp/xpath",
185                 "dummyroot", null);
186         }
187         return d;
188     }
189
190     
191     private XObject eval(String JavaDoc expression, Object JavaDoc contextItem)
192         throws javax.xml.transform.TransformerException JavaDoc {
193         com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression,
194             null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT );
195         com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null;
196         if ( functionResolver != null ) {
197             JAXPExtensionsProvider jep = new JAXPExtensionsProvider(
198                     functionResolver, featureSecureProcessing );
199             xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep );
200         } else {
201             xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext();
202         }
203
204         XObject xobj = null;
205         
206         xpathSupport.setVarStack(new JAXPVariableStack(variableResolver));
207         
208         // If item is null, then we will create a a Dummy contextNode
209
if ( contextItem instanceof Node JavaDoc ) {
210             xobj = xpath.execute (xpathSupport, (Node JavaDoc)contextItem,
211                     prefixResolver );
212         } else {
213             xobj = xpath.execute ( xpathSupport, DTM.NULL, prefixResolver );
214         }
215  
216         return xobj;
217     }
218         
219     /**
220      * <p>Evaluate an <code>XPath</code> expression in the specified context and return the result as the specified type.</p>
221      *
222      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
223      * for context item evaluation,
224      * variable, function and <code>QName</code> resolution and return type conversion.</p>
225      *
226      * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants} (
227      * {@link XPathConstants#NUMBER NUMBER},
228      * {@link XPathConstants#STRING STRING},
229      * {@link XPathConstants#BOOLEAN BOOLEAN},
230      * {@link XPathConstants#NODE NODE} or
231      * {@link XPathConstants#NODESET NODESET})
232      * then an <code>IllegalArgumentException</code> is thrown.</p>
233      *
234      * <p>If a <code>null</code> value is provided for
235      * <code>item</code>, an empty document will be used for the
236      * context.
237      * If <code>expression</code> or <code>returnType</code> is <code>null</code>, then a
238      * <code>NullPointerException</code> is thrown.</p>
239      *
240      * @param expression The XPath expression.
241      * @param item The starting context (node or node list, for example).
242      * @param returnType The desired return type.
243      *
244      * @return Result of evaluating an XPath expression as an <code>Object</code> of <code>returnType</code>.
245      *
246      * @throws XPathExpressionException If <code>expression</code> cannot be evaluated.
247      * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
248      * @throws NullPointerException If <code>expression</code> or <code>returnType</code> is <code>null</code>.
249      */

250     public Object JavaDoc evaluate(String JavaDoc expression, Object JavaDoc item, QName JavaDoc returnType)
251             throws XPathExpressionException JavaDoc {
252         if ( expression == null ) {
253             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
254                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
255                     new Object JavaDoc[] {"XPath expression"} );
256             throw new NullPointerException JavaDoc ( fmsg );
257         }
258         if ( returnType == null ) {
259             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
260                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
261                     new Object JavaDoc[] {"returnType"} );
262             throw new NullPointerException JavaDoc ( fmsg );
263         }
264         // Checking if requested returnType is supported. returnType need to
265
// be defined in XPathConstants
266
if ( !isSupported ( returnType ) ) {
267             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
268                     XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
269                     new Object JavaDoc[] { returnType.toString() } );
270             throw new IllegalArgumentException JavaDoc ( fmsg );
271         }
272
273         try {
274  
275             XObject resultObject = eval( expression, item );
276             return getResultAsType( resultObject, returnType );
277         } catch ( java.lang.NullPointerException JavaDoc npe ) {
278             // If VariableResolver returns null Or if we get
279
// NullPointerException at this stage for some other reason
280
// then we have to reurn XPathException
281
throw new XPathExpressionException JavaDoc ( npe );
282         } catch ( javax.xml.transform.TransformerException JavaDoc te ) {
283             Throwable JavaDoc nestedException = te.getException();
284             if ( nestedException instanceof javax.xml.xpath.XPathFunctionException JavaDoc ) {
285                 throw (javax.xml.xpath.XPathFunctionException JavaDoc)nestedException;
286             } else {
287                 // For any other exceptions we need to throw
288
// XPathExpressionException ( as per spec )
289
throw new XPathExpressionException JavaDoc ( te );
290             }
291         }
292         
293     }
294
295     private boolean isSupported( QName JavaDoc returnType ) {
296         if ( ( returnType.equals( XPathConstants.STRING ) ) ||
297              ( returnType.equals( XPathConstants.NUMBER ) ) ||
298              ( returnType.equals( XPathConstants.BOOLEAN ) ) ||
299              ( returnType.equals( XPathConstants.NODE ) ) ||
300              ( returnType.equals( XPathConstants.NODESET ) ) ) {
301   
302             return true;
303         }
304         return false;
305      }
306
307     private Object JavaDoc getResultAsType( XObject resultObject, QName JavaDoc returnType )
308         throws javax.xml.transform.TransformerException JavaDoc {
309         // XPathConstants.STRING
310
if ( returnType.equals( XPathConstants.STRING ) ) {
311             return resultObject.str();
312         }
313         // XPathConstants.NUMBER
314
if ( returnType.equals( XPathConstants.NUMBER ) ) {
315             return new Double JavaDoc ( resultObject.num());
316         }
317         // XPathConstants.BOOLEAN
318
if ( returnType.equals( XPathConstants.BOOLEAN ) ) {
319             return new Boolean JavaDoc( resultObject.bool());
320         }
321         // XPathConstants.NODESET ---ORdered, UNOrdered???
322
if ( returnType.equals( XPathConstants.NODESET ) ) {
323             return resultObject.nodelist();
324         }
325         // XPathConstants.NODE
326
if ( returnType.equals( XPathConstants.NODE ) ) {
327             NodeIterator ni = resultObject.nodeset();
328             //Return the first node, or null
329
return ni.nextNode();
330         }
331         String JavaDoc fmsg = XSLMessages.createXPATHMessage(
332                 XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
333                 new Object JavaDoc[] { returnType.toString()});
334         throw new IllegalArgumentException JavaDoc( fmsg );
335     }
336          
337             
338         
339     /**
340      * <p>Evaluate an XPath expression in the specified context and return the result as a <code>String</code>.</p>
341      *
342      * <p>This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a <code>returnType</code> of
343      * {@link XPathConstants#STRING}.</p>
344      *
345      * <p>See "Evaluation of XPath Expressions" of JAXP 1.3 spec
346      * for context item evaluation,
347      * variable, function and QName resolution and return type conversion.</p>
348      *
349      * <p>If a <code>null</code> value is provided for
350      * <code>item</code>, an empty document will be used for the
351      * context.
352      * If <code>expression</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
353      *
354      * @param expression The XPath expression.
355      * @param item The starting context (node or node list, for example).
356      *
357      * @return The <code>String</code> that is the result of evaluating the expression and
358      * converting the result to a <code>String</code>.
359      *
360      * @throws XPathExpressionException If <code>expression</code> cannot be evaluated.
361      * @throws NullPointerException If <code>expression</code> is <code>null</code>.
362      */

363     public String JavaDoc evaluate(String JavaDoc expression, Object JavaDoc item)
364         throws XPathExpressionException JavaDoc {
365         return (String JavaDoc)this.evaluate( expression, item, XPathConstants.STRING );
366     }
367
368     /**
369      * <p>Compile an XPath expression for later evaluation.</p>
370      *
371      * <p>If <code>expression</code> contains any {@link XPathFunction}s,
372      * they must be available via the {@link XPathFunctionResolver}.
373      * An {@link XPathExpressionException} will be thrown if the <code>XPathFunction</code>
374      * cannot be resovled with the <code>XPathFunctionResolver</code>.</p>
375      *
376      * <p>If <code>expression</code> is <code>null</code>, a <code>NullPointerException</code> is thrown.</p>
377      *
378      * @param expression The XPath expression.
379      *
380      * @return Compiled XPath expression.
381
382      * @throws XPathExpressionException If <code>expression</code> cannot be compiled.
383      * @throws NullPointerException If <code>expression</code> is <code>null</code>.
384      */

385     public XPathExpression JavaDoc compile(String JavaDoc expression)
386         throws XPathExpressionException JavaDoc {
387         if ( expression == null ) {
388             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
389                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
390                     new Object JavaDoc[] {"XPath expression"} );
391             throw new NullPointerException JavaDoc ( fmsg );
392         }
393         try {
394             com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null,
395                     prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT );
396             // Can have errorListener
397
XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath,
398                     prefixResolver, functionResolver, variableResolver,
399                     featureSecureProcessing );
400             return ximpl;
401         } catch ( javax.xml.transform.TransformerException JavaDoc te ) {
402             throw new XPathExpressionException JavaDoc ( te ) ;
403         }
404     }
405
406
407     /**
408      * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code>
409      * and return the result as the specified type.</p>
410      *
411      * <p>This method builds a data model for the {@link InputSource} and calls
412      * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.</p>
413      *
414      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
415      * for context item evaluation,
416      * variable, function and QName resolution and return type conversion.</p>
417      *
418      * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants},
419      * then an <code>IllegalArgumentException</code> is thrown.</p>
420      *
421      * <p>If <code>expression</code>, <code>source</code> or <code>returnType</code> is <code>null</code>,
422      * then a <code>NullPointerException</code> is thrown.</p>
423      *
424      * @param expression The XPath expression.
425      * @param source The input source of the document to evaluate over.
426      * @param returnType The desired return type.
427      *
428      * @return The <code>Object</code> that encapsulates the result of evaluating the expression.
429      *
430      * @throws XPathExpressionException If expression cannot be evaluated.
431      * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
432      * @throws NullPointerException If <code>expression</code>, <code>source</code> or <code>returnType</code>
433      * is <code>null</code>.
434      */

435     public Object JavaDoc evaluate(String JavaDoc expression, InputSource JavaDoc source,
436             QName JavaDoc returnType) throws XPathExpressionException JavaDoc {
437         // Checking validity of different parameters
438
if( source== null ) {
439             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
440                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
441                     new Object JavaDoc[] {"source"} );
442             throw new NullPointerException JavaDoc ( fmsg );
443         }
444         if ( expression == null ) {
445             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
446                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
447                     new Object JavaDoc[] {"XPath expression"} );
448             throw new NullPointerException JavaDoc ( fmsg );
449         }
450         if ( returnType == null ) {
451             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
452                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
453                     new Object JavaDoc[] {"returnType"} );
454             throw new NullPointerException JavaDoc ( fmsg );
455         }
456
457         //Checking if requested returnType is supported.
458
//returnType need to be defined in XPathConstants
459
if ( !isSupported ( returnType ) ) {
460             String JavaDoc fmsg = XSLMessages.createXPATHMessage(
461                     XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
462                     new Object JavaDoc[] { returnType.toString() } );
463             throw new IllegalArgumentException JavaDoc ( fmsg );
464         }
465         
466         try {
467
468             Document JavaDoc document = getParser().parse( source );
469
470             XObject resultObject = eval( expression, document );
471             return getResultAsType( resultObject, returnType );
472         } catch ( SAXException JavaDoc e ) {
473             throw new XPathExpressionException JavaDoc ( e );
474         } catch( IOException JavaDoc e ) {
475             throw new XPathExpressionException JavaDoc ( e );
476         } catch ( javax.xml.transform.TransformerException JavaDoc te ) {
477             Throwable JavaDoc nestedException = te.getException();
478             if ( nestedException instanceof javax.xml.xpath.XPathFunctionException JavaDoc ) {
479                 throw (javax.xml.xpath.XPathFunctionException JavaDoc)nestedException;
480             } else {
481                 throw new XPathExpressionException JavaDoc ( te );
482             }
483         }
484
485     }
486  
487
488
489
490     /**
491      * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code>
492      * and return the result as a <code>String</code>.</p>
493      *
494      * <p>This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a
495      * <code>returnType</code> of {@link XPathConstants#STRING}.</p>
496      *
497      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
498      * for context item evaluation,
499      * variable, function and QName resolution and return type conversion.</p>
500      *
501      * <p>If <code>expression</code> or <code>source</code> is <code>null</code>,
502      * then a <code>NullPointerException</code> is thrown.</p>
503      *
504      * @param expression The XPath expression.
505      * @param source The <code>InputSource</code> of the document to evaluate over.
506      *
507      * @return The <code>String</code> that is the result of evaluating the expression and
508      * converting the result to a <code>String</code>.
509      *
510      * @throws XPathExpressionException If expression cannot be evaluated.
511      * @throws NullPointerException If <code>expression</code> or <code>source</code> is <code>null</code>.
512      */

513     public String JavaDoc evaluate(String JavaDoc expression, InputSource JavaDoc source)
514         throws XPathExpressionException JavaDoc {
515         return (String JavaDoc)this.evaluate( expression, source, XPathConstants.STRING );
516     }
517
518     /**
519      * <p>Reset this <code>XPath</code> to its original configuration.</p>
520      *
521      * <p><code>XPath</code> is reset to the same state as when it was created with
522      * {@link XPathFactory#newXPath()}.
523      * <code>reset()</code> is designed to allow the reuse of existing <code>XPath</code>s
524      * thus saving resources associated with the creation of new <code>XPath</code>s.</p>
525      *
526      * <p>The reset <code>XPath</code> is not guaranteed to have the same
527      * {@link XPathFunctionResolver}, {@link XPathVariableResolver}
528      * or {@link NamespaceContext} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.
529      * It is guaranteed to have a functionally equal <code>XPathFunctionResolver</code>,
530      * <code>XPathVariableResolver</code>
531      * and <code>NamespaceContext</code>.</p>
532      */

533     public void reset() {
534         this.variableResolver = this.origVariableResolver;
535         this.functionResolver = this.origFunctionResolver;
536         this.namespaceContext = null;
537     }
538  
539 }
540
Popular Tags