blob: 5956bae886628fb0966157f12862851d6ea8615e [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25/*
26 * $Id: DOMUtils.java,v 1.18 2005/05/12 19:28:34 mullan Exp $
27 */
28package org.jcp.xml.dsig.internal.dom;
29
30import java.util.*;
31import java.security.spec.AlgorithmParameterSpec;
32import org.w3c.dom.Attr;
33import org.w3c.dom.Document;
34import org.w3c.dom.Element;
35import org.w3c.dom.Node;
36import org.w3c.dom.NodeList;
37import javax.xml.crypto.*;
38import javax.xml.crypto.dsig.dom.DOMSignContext;
39import javax.xml.crypto.dsig.*;
40import javax.xml.crypto.dsig.spec.*;
41
42import com.sun.org.apache.xml.internal.security.utils.IdResolver;
43
44/**
45 * Useful static DOM utility methods.
46 *
47 * @author Sean Mullan
48 */
49public class DOMUtils {
50
51 // class cannot be instantiated
52 private DOMUtils() {}
53
54 /**
55 * Returns the owner document of the specified node.
56 *
57 * @param node the node
58 * @return the owner document
59 */
60 public static Document getOwnerDocument(Node node) {
61 if (node.getNodeType() == Node.DOCUMENT_NODE) {
62 return (Document) node;
63 } else {
64 return node.getOwnerDocument();
65 }
66 }
67
68 /**
69 * Creates an element in the specified namespace, with the specified tag
70 * and namespace prefix.
71 *
72 * @param doc the owner document
73 * @param tag the tag
74 * @param nsURI the namespace URI
75 * @param prefix the namespace prefix
76 * @return the newly created element
77 */
78 public static Element createElement(Document doc, String tag, String nsURI,
79 String prefix) {
80 String qName = prefix == null ? tag : prefix + ":" + tag;
81 return doc.createElementNS(nsURI, qName);
82 }
83
84 /**
85 * Sets an element's attribute (using DOM level 2) with the
86 * specified value and namespace prefix.
87 *
88 * @param elem the element to set the attribute on
89 * @param name the name of the attribute
90 * @param value the attribute value. If null, no attribute is set.
91 */
92 public static void setAttribute(Element elem, String name, String value) {
93 if (value == null) return;
94 elem.setAttributeNS(null, name, value);
95 }
96
97 /**
98 * Sets an element's attribute (using DOM level 2) with the
99 * specified value and namespace prefix AND registers the ID value with
100 * the specified element. This is for resolving same-document
101 * ID references.
102 *
103 * @param elem the element to set the attribute on
104 * @param name the name of the attribute
105 * @param value the attribute value. If null, no attribute is set.
106 */
107 public static void setAttributeID(Element elem, String name, String value) {
108 if (value == null) return;
109 elem.setAttributeNS(null, name, value);
110 IdResolver.registerElementById(elem, value);
111 }
112
113 /**
114 * Returns the first child element of the specified node, or null if there
115 * is no such element.
116 *
117 * @param node the node
118 * @return the first child element of the specified node, or null if there
119 * is no such element
120 * @throws NullPointerException if <code>node == null</code>
121 */
122 public static Element getFirstChildElement(Node node) {
123 Node child = node.getFirstChild();
124 while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
125 child = child.getNextSibling();
126 }
127 return (Element) child;
128 }
129
130 /**
131 * Returns the last child element of the specified node, or null if there
132 * is no such element.
133 *
134 * @param node the node
135 * @return the last child element of the specified node, or null if there
136 * is no such element
137 * @throws NullPointerException if <code>node == null</code>
138 */
139 public static Element getLastChildElement(Node node) {
140 Node child = node.getLastChild();
141 while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
142 child = child.getPreviousSibling();
143 }
144 return (Element) child;
145 }
146
147 /**
148 * Returns the next sibling element of the specified node, or null if there
149 * is no such element.
150 *
151 * @param node the node
152 * @return the next sibling element of the specified node, or null if there
153 * is no such element
154 * @throws NullPointerException if <code>node == null</code>
155 */
156 public static Element getNextSiblingElement(Node node) {
157 Node sibling = node.getNextSibling();
158 while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) {
159 sibling = sibling.getNextSibling();
160 }
161 return (Element) sibling;
162 }
163
164 /**
165 * Returns the attribute value for the attribute with the specified name.
166 * Returns null if there is no such attribute, or
167 * the empty string if the attribute value is empty.
168 *
169 * <p>This works around a limitation of the DOM
170 * <code>Element.getAttributeNode</code> method, which does not distinguish
171 * between an unspecified attribute and an attribute with a value of
172 * "" (it returns "" for both cases).
173 *
174 * @param elem the element containing the attribute
175 * @param name the name of the attribute
176 * @return the attribute value (may be null if unspecified)
177 */
178 public static String getAttributeValue(Element elem, String name) {
179 Attr attr = elem.getAttributeNodeNS(null, name);
180 return (attr == null) ? null : attr.getValue();
181 }
182
183 /**
184 * Returns a Set of <code>Node</code>s, backed by the specified
185 * <code>NodeList</code>.
186 *
187 * @param nl the NodeList
188 * @return a Set of Nodes
189 */
190 public static Set nodeSet(NodeList nl) {
191 return new NodeSet(nl);
192 }
193
194 static class NodeSet extends AbstractSet {
195 private NodeList nl;
196 public NodeSet(NodeList nl) {
197 this.nl = nl;
198 }
199
200 public int size() { return nl.getLength(); }
201 public Iterator iterator() {
202 return new Iterator() {
203 int index = 0;
204
205 public void remove() {
206 throw new UnsupportedOperationException();
207 }
208 public Object next() {
209 if (!hasNext()) {
210 throw new NoSuchElementException();
211 }
212 return nl.item(index++);
213 }
214 public boolean hasNext() {
215 return index < nl.getLength() ? true : false;
216 }
217 };
218 }
219 }
220
221 /**
222 * Returns the prefix associated with the specified namespace URI
223 *
224 * @param context contains the namespace map
225 * @param nsURI the namespace URI
226 * @return the prefix associated with the specified namespace URI, or
227 * null if not set
228 */
229 public static String getNSPrefix(XMLCryptoContext context, String nsURI) {
230 if (context != null) {
231 return context.getNamespacePrefix
232 (nsURI, context.getDefaultNamespacePrefix());
233 } else {
234 return null;
235 }
236 }
237
238 /**
239 * Returns the prefix associated with the XML Signature namespace URI
240 *
241 * @param context contains the namespace map
242 * @return the prefix associated with the specified namespace URI, or
243 * null if not set
244 */
245 public static String getSignaturePrefix(XMLCryptoContext context) {
246 return getNSPrefix(context, XMLSignature.XMLNS);
247 }
248
249 /**
250 * Removes all children nodes from the specified node.
251 *
252 * @param node the parent node whose children are to be removed
253 */
254 public static void removeAllChildren(Node node) {
255 NodeList children = node.getChildNodes();
256 for (int i = 0, length = children.getLength(); i < length; i++) {
257 node.removeChild(children.item(i));
258 }
259 }
260
261 /**
262 * Compares 2 nodes for equality. Implementation is not complete.
263 */
264 public static boolean nodesEqual(Node thisNode, Node otherNode) {
265 if (thisNode == otherNode) {
266 return true;
267 }
268 if (thisNode.getNodeType() != otherNode.getNodeType()) {
269 return false;
270 }
271 // FIXME - test content, etc
272 return true;
273 }
274
275 /**
276 * Checks if child element has same owner document before
277 * appending to the parent, and imports it to the parent's document
278 * if necessary.
279 */
280 public static void appendChild(Node parent, Node child) {
281 Document ownerDoc = getOwnerDocument(parent);
282 if (child.getOwnerDocument() != ownerDoc) {
283 parent.appendChild(ownerDoc.importNode(child, true));
284 } else {
285 parent.appendChild(child);
286 }
287 }
288
289 public static boolean paramsEqual(AlgorithmParameterSpec spec1,
290 AlgorithmParameterSpec spec2) {
291 if (spec1 == spec2) {
292 return true;
293 }
294 if (spec1 instanceof XPathFilter2ParameterSpec &&
295 spec2 instanceof XPathFilter2ParameterSpec) {
296 return paramsEqual((XPathFilter2ParameterSpec) spec1,
297 (XPathFilter2ParameterSpec) spec2);
298 }
299 if (spec1 instanceof ExcC14NParameterSpec &&
300 spec2 instanceof ExcC14NParameterSpec) {
301 return paramsEqual((ExcC14NParameterSpec) spec1,
302 (ExcC14NParameterSpec) spec2);
303 }
304 if (spec1 instanceof XPathFilterParameterSpec &&
305 spec2 instanceof XPathFilterParameterSpec) {
306 return paramsEqual((XPathFilterParameterSpec) spec1,
307 (XPathFilterParameterSpec) spec2);
308 }
309 if (spec1 instanceof XSLTTransformParameterSpec &&
310 spec2 instanceof XSLTTransformParameterSpec) {
311 return paramsEqual((XSLTTransformParameterSpec) spec1,
312 (XSLTTransformParameterSpec) spec2);
313 }
314 return false;
315 }
316
317 private static boolean paramsEqual(XPathFilter2ParameterSpec spec1,
318 XPathFilter2ParameterSpec spec2) {
319
320 List types = spec1.getXPathList();
321 List otypes = spec2.getXPathList();
322 int size = types.size();
323 if (size != otypes.size()) {
324 return false;
325 }
326 for (int i = 0; i < size; i++) {
327 XPathType type = (XPathType) types.get(i);
328 XPathType otype = (XPathType) otypes.get(i);
329 if (!type.getExpression().equals(otype.getExpression()) ||
330 type.getFilter() != otype.getFilter()) {
331 return false;
332 }
333 }
334 return true;
335 }
336
337 private static boolean paramsEqual(ExcC14NParameterSpec spec1,
338 ExcC14NParameterSpec spec2) {
339 return spec1.getPrefixList().equals(spec2.getPrefixList());
340 }
341
342 private static boolean paramsEqual(XPathFilterParameterSpec spec1,
343 XPathFilterParameterSpec spec2) {
344
345 return spec1.getXPath().equals(spec2.getXPath());
346 }
347
348 private static boolean paramsEqual(XSLTTransformParameterSpec spec1,
349 XSLTTransformParameterSpec spec2) {
350
351 XMLStructure ostylesheet = spec2.getStylesheet();
352 if (!(ostylesheet instanceof javax.xml.crypto.dom.DOMStructure)) {
353 return false;
354 }
355 Node ostylesheetElem =
356 ((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode();
357 XMLStructure stylesheet = spec1.getStylesheet();
358 Node stylesheetElem =
359 ((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode();
360 return nodesEqual(stylesheetElem, ostylesheetElem);
361 }
362}