1 /*
2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.org.apache.xpath.internal.jaxp;
27 
28 import com.sun.org.apache.xpath.internal.objects.XObject;
29 import java.util.Objects;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.xpath.XPathNodes;
32 import javax.xml.xpath.XPathEvaluationResult;
33 import javax.xml.xpath.XPathEvaluationResult.XPathResultType;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.NodeList;
36 import org.w3c.dom.traversal.NodeIterator;
37 
38 
39 /**
40  * This is the implementation of XPathEvaluationResult that represents the
41  * result of the evaluation of an XPath expression within the context of a
42  * particular node.
43  */
44 class XPathResultImpl<T> implements XPathEvaluationResult<T> {
45 
46     XObject resultObject;
47     int resultType;
48     Class<T> type;
49     XPathResultType mapToType;
50     NodeList nodeList = null;
51     int currentIndex;
52     Node currentNode;
53 
54     boolean boolValue = false;
55     Node node = null;
56     double numValue;
57     String strValue;
58 
59     /**
60      * Construct an XPathEvaluationResult object.
61      *
62      * @param resultObject internal XPath result object
63      * @param type class type
64      * @throws TransformerException if there is an error reading the XPath
65      * result.
66      */
XPathResultImpl(XObject resultObject, Class<T> type)67     public XPathResultImpl(XObject resultObject, Class<T> type)
68             throws TransformerException {
69         this.resultObject = resultObject;
70         resultType = resultObject.getType();
71         this.type = type;
72         getResult(resultObject);
73     }
74 
75     /**
76      * Return the result type as an enum specified by {@code XPathResultType}
77      * @return the result type
78      */
79     @Override
type()80     public XPathResultType type() {
81         return mapToType;
82     }
83 
84     /**
85      * Returns the value of the result as the type &lt;T&gt; specified for the class.
86      *
87      * @return The value of the result.
88      */
89     @Override
value()90     public T value() {
91         Objects.requireNonNull(type);
92         try {
93             return getValue(resultObject, type);
94         } catch (TransformerException ex) {
95             throw new RuntimeException(ex);
96         }
97     }
98 
99     /**
100      * Read the XObject and set values in accordance with the result type
101      * @param resultObject  internal XPath result object
102      * @throws TransformerException  if there is an error reading the XPath
103      * result.
104      */
getResult(XObject resultObject)105     private void getResult(XObject resultObject) throws TransformerException {
106         switch (resultType) {
107             case XObject.CLASS_BOOLEAN:
108                 boolValue = resultObject.bool();
109                 mapToType = XPathResultType.BOOLEAN;
110                 break;
111             case XObject.CLASS_NUMBER:
112                 numValue = resultObject.num();
113                 mapToType = XPathResultType.NUMBER;
114                 break;
115             case XObject.CLASS_STRING:
116                 strValue = resultObject.str();
117                 mapToType = XPathResultType.STRING;
118                 break;
119             case XObject.CLASS_NODESET:
120                 mapToType = XPathResultType.NODESET;
121                 nodeList = resultObject.nodelist();
122                 break;
123             case XObject.CLASS_RTREEFRAG:  //NODE
124                 mapToType = XPathResultType.NODE;
125                 NodeIterator ni = resultObject.nodeset();
126                 //Return the first node, or null
127                 node = ni.nextNode();
128                 break;
129         }
130     }
131 
132     /**
133      * Read the internal result object and return the value in accordance with
134      * the type specified.
135      *
136      * @param <T> The expected class type.
137      * @param resultObject internal XPath result object
138      * @param type the class type
139      * @return The value of the result, null in case of unexpected type.
140      * @throws TransformerException  if there is an error reading the XPath
141      * result.
142      */
getValue(XObject resultObject, Class<T> type)143     static <T> T getValue(XObject resultObject, Class<T> type) throws TransformerException {
144         Objects.requireNonNull(type);
145         if (type.isAssignableFrom(XPathEvaluationResult.class)) {
146             return type.cast(new XPathResultImpl<T>(resultObject, type));
147         }
148         int resultType = classToInternalType(type);
149         switch (resultType) {
150             case XObject.CLASS_BOOLEAN:
151                 return type.cast(resultObject.bool());
152             case XObject.CLASS_NUMBER:
153                 if (Double.class.isAssignableFrom(type)) {
154                     return type.cast(resultObject.num());
155                 } else if (Integer.class.isAssignableFrom(type)) {
156                     return type.cast((int)resultObject.num());
157                 } else if (Long.class.isAssignableFrom(type)) {
158                     return type.cast((long)resultObject.num());
159                 }
160                 /*
161                   This is to suppress warnings. By the current specification,
162                 among numeric types, only Double, Integer and Long are supported.
163                 */
164                 break;
165             case XObject.CLASS_STRING:
166                 return type.cast(resultObject.str());
167             case XObject.CLASS_NODESET:
168                 XPathNodes nodeSet = new XPathNodesImpl(resultObject.nodelist(),
169                         Node.class);
170                 return type.cast(nodeSet);
171             case XObject.CLASS_RTREEFRAG:  //NODE
172                 NodeIterator ni = resultObject.nodeset();
173                 //Return the first node, or null
174                 return type.cast(ni.nextNode());
175         }
176 
177         return null;
178     }
179 
180     /**
181      * Map the specified class type to the internal result type
182      *
183      * @param <T> The expected class type.
184      * @param type the class type
185      * @return the internal XObject type.
186      */
classToInternalType(Class<T> type)187     static <T> int classToInternalType(Class<T> type) {
188         if (type.isAssignableFrom(Boolean.class)) {
189             return XObject.CLASS_BOOLEAN;
190         } else if (Number.class.isAssignableFrom(type)) {
191             return XObject.CLASS_NUMBER;
192         } else if (type.isAssignableFrom(String.class)) {
193             return XObject.CLASS_STRING;
194         } else if (type.isAssignableFrom(XPathNodes.class)) {
195             return XObject.CLASS_NODESET;
196         } else if (type.isAssignableFrom(Node.class)) {
197             return XObject.CLASS_RTREEFRAG;
198         }
199         return XObject.CLASS_NULL;
200     }
201 }
202