|
|
|
|
|
|
|
*/ |
|
/** |
|
* Licensed to the Apache Software Foundation (ASF) under one |
|
* or more contributor license agreements. See the NOTICE file |
|
* distributed with this work for additional information |
|
* regarding copyright ownership. The ASF licenses this file |
|
* to you under the Apache License, Version 2.0 (the |
|
* "License"); you may not use this file except in compliance |
|
* with the License. You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, |
|
* software distributed under the License is distributed on an |
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
* KIND, either express or implied. See the License for the |
|
* specific language governing permissions and limitations |
|
* under the License. |
|
*/ |
|
/* |
|
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. |
|
*/ |
|
|
|
|
|
*/ |
|
package org.jcp.xml.dsig.internal.dom; |
|
|
|
import java.util.*; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
import org.w3c.dom.Attr; |
|
import org.w3c.dom.Document; |
|
import org.w3c.dom.Element; |
|
import org.w3c.dom.Node; |
|
import org.w3c.dom.NodeList; |
|
|
|
import javax.xml.XMLConstants; |
|
import javax.xml.crypto.*; |
|
import javax.xml.crypto.dsig.*; |
|
import javax.xml.crypto.dsig.spec.*; |
|
|
|
|
|
|
|
|
|
*/ |
|
public final class DOMUtils { |
|
|
|
|
|
private DOMUtils() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Document getOwnerDocument(Node node) { |
|
if (node.getNodeType() == Node.DOCUMENT_NODE) { |
|
return (Document)node; |
|
} else { |
|
return node.getOwnerDocument(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getQNameString(String prefix, String localName) { |
|
String qName = prefix == null || prefix.length() == 0 |
|
? localName : prefix + ":" + localName; |
|
|
|
return qName; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element createElement(Document doc, String tag, |
|
String nsURI, String prefix) |
|
{ |
|
return doc.createElementNS(nsURI, getQNameString(prefix, tag)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void setAttribute(Element elem, String name, String value) { |
|
if (value == null) { |
|
return; |
|
} |
|
elem.setAttributeNS(null, name, value); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void setAttributeID(Element elem, String name, String value) { |
|
if (value == null) { |
|
return; |
|
} |
|
elem.setAttributeNS(null, name, value); |
|
elem.setIdAttributeNS(null, name, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element getFirstChildElement(Node node) { |
|
Node child = node.getFirstChild(); |
|
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) { |
|
child = child.getNextSibling(); |
|
} |
|
return (Element)child; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
public static Element getFirstChildElement(Node node, String localName) |
|
throws MarshalException |
|
{ |
|
return verifyElement(getFirstChildElement(node), localName); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element getFirstChildElement(Node node, String localName, String namespaceURI) |
|
throws MarshalException |
|
{ |
|
return verifyElement(getFirstChildElement(node), localName, namespaceURI); |
|
} |
|
|
|
private static Element verifyElement(Element elem, String localName) |
|
throws MarshalException |
|
{ |
|
if (elem == null) { |
|
throw new MarshalException("Missing " + localName + " element"); |
|
} |
|
String name = elem.getLocalName(); |
|
if (!name.equals(localName)) { |
|
throw new MarshalException("Invalid element name: " + |
|
name + ", expected " + localName); |
|
} |
|
return elem; |
|
} |
|
|
|
private static Element verifyElement(Element elem, String localName, String namespaceURI) |
|
throws MarshalException |
|
{ |
|
if (elem == null) { |
|
throw new MarshalException("Missing " + localName + " element"); |
|
} |
|
String name = elem.getLocalName(); |
|
String namespace = elem.getNamespaceURI(); |
|
if (!name.equals(localName) || namespace == null && namespaceURI != null |
|
|| namespace != null && !namespace.equals(namespaceURI)) { |
|
throw new MarshalException("Invalid element name: " + |
|
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName); |
|
} |
|
return elem; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element getLastChildElement(Node node) { |
|
Node child = node.getLastChild(); |
|
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) { |
|
child = child.getPreviousSibling(); |
|
} |
|
return (Element)child; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element getNextSiblingElement(Node node) { |
|
Node sibling = node.getNextSibling(); |
|
while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) { |
|
sibling = sibling.getNextSibling(); |
|
} |
|
return (Element)sibling; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
public static Element getNextSiblingElement(Node node, String localName) |
|
throws MarshalException |
|
{ |
|
return verifyElement(getNextSiblingElement(node), localName); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Element getNextSiblingElement(Node node, String localName, String namespaceURI) |
|
throws MarshalException |
|
{ |
|
return verifyElement(getNextSiblingElement(node), localName, namespaceURI); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getAttributeValue(Element elem, String name) { |
|
Attr attr = elem.getAttributeNodeNS(null, name); |
|
return (attr == null) ? null : attr.getValue(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static <N> String getIdAttributeValue(Element elem, String name) { |
|
Attr attr = elem.getAttributeNodeNS(null, name); |
|
if (attr != null && !attr.isId()) { |
|
elem.setIdAttributeNode(attr, true); |
|
} |
|
return (attr == null) ? null : attr.getValue(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Set<Node> nodeSet(NodeList nl) { |
|
return new NodeSet(nl); |
|
} |
|
|
|
static class NodeSet extends AbstractSet<Node> { |
|
private NodeList nl; |
|
public NodeSet(NodeList nl) { |
|
this.nl = nl; |
|
} |
|
|
|
@Override |
|
public int size() { return nl.getLength(); } |
|
@Override |
|
public Iterator<Node> iterator() { |
|
return new Iterator<Node>() { |
|
private int index; |
|
|
|
@Override |
|
public void remove() { |
|
throw new UnsupportedOperationException(); |
|
} |
|
@Override |
|
public Node next() { |
|
if (!hasNext()) { |
|
throw new NoSuchElementException(); |
|
} |
|
return nl.item(index++); |
|
} |
|
@Override |
|
public boolean hasNext() { |
|
return index < nl.getLength(); |
|
} |
|
}; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getNSPrefix(XMLCryptoContext context, String nsURI) { |
|
if (context != null) { |
|
return context.getNamespacePrefix |
|
(nsURI, context.getDefaultNamespacePrefix()); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getSignaturePrefix(XMLCryptoContext context) { |
|
return getNSPrefix(context, XMLSignature.XMLNS); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void removeAllChildren(Node node) { |
|
Node firstChild = node.getFirstChild(); |
|
while (firstChild != null) { |
|
Node nodeToRemove = firstChild; |
|
firstChild = firstChild.getNextSibling(); |
|
node.removeChild(nodeToRemove); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static boolean nodesEqual(Node thisNode, Node otherNode) { |
|
if (thisNode == otherNode) { |
|
return true; |
|
} |
|
if (thisNode.getNodeType() != otherNode.getNodeType()) { |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void appendChild(Node parent, Node child) { |
|
Document ownerDoc = getOwnerDocument(parent); |
|
if (child.getOwnerDocument() != ownerDoc) { |
|
parent.appendChild(ownerDoc.importNode(child, true)); |
|
} else { |
|
parent.appendChild(child); |
|
} |
|
} |
|
|
|
public static boolean paramsEqual(AlgorithmParameterSpec spec1, |
|
AlgorithmParameterSpec spec2) { |
|
if (spec1 == spec2) { |
|
return true; |
|
} |
|
if (spec1 instanceof XPathFilter2ParameterSpec && |
|
spec2 instanceof XPathFilter2ParameterSpec) { |
|
return paramsEqual((XPathFilter2ParameterSpec)spec1, |
|
(XPathFilter2ParameterSpec)spec2); |
|
} |
|
if (spec1 instanceof ExcC14NParameterSpec && |
|
spec2 instanceof ExcC14NParameterSpec) { |
|
return paramsEqual((ExcC14NParameterSpec) spec1, |
|
(ExcC14NParameterSpec)spec2); |
|
} |
|
if (spec1 instanceof XPathFilterParameterSpec && |
|
spec2 instanceof XPathFilterParameterSpec) { |
|
return paramsEqual((XPathFilterParameterSpec)spec1, |
|
(XPathFilterParameterSpec)spec2); |
|
} |
|
if (spec1 instanceof XSLTTransformParameterSpec && |
|
spec2 instanceof XSLTTransformParameterSpec) { |
|
return paramsEqual((XSLTTransformParameterSpec)spec1, |
|
(XSLTTransformParameterSpec)spec2); |
|
} |
|
return false; |
|
} |
|
|
|
private static boolean paramsEqual(XPathFilter2ParameterSpec spec1, |
|
XPathFilter2ParameterSpec spec2) |
|
{ |
|
@SuppressWarnings("unchecked") |
|
List<XPathType> types = spec1.getXPathList(); |
|
@SuppressWarnings("unchecked") |
|
List<XPathType> otypes = spec2.getXPathList(); |
|
int size = types.size(); |
|
if (size != otypes.size()) { |
|
return false; |
|
} |
|
for (int i = 0; i < size; i++) { |
|
XPathType type = types.get(i); |
|
XPathType otype = otypes.get(i); |
|
if (!type.getExpression().equals(otype.getExpression()) || |
|
!type.getNamespaceMap().equals(otype.getNamespaceMap()) || |
|
type.getFilter() != otype.getFilter()) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private static boolean paramsEqual(ExcC14NParameterSpec spec1, |
|
ExcC14NParameterSpec spec2) |
|
{ |
|
return spec1.getPrefixList().equals(spec2.getPrefixList()); |
|
} |
|
|
|
private static boolean paramsEqual(XPathFilterParameterSpec spec1, |
|
XPathFilterParameterSpec spec2) |
|
{ |
|
return spec1.getXPath().equals(spec2.getXPath()) && |
|
spec1.getNamespaceMap().equals(spec2.getNamespaceMap()); |
|
} |
|
|
|
private static boolean paramsEqual(XSLTTransformParameterSpec spec1, |
|
XSLTTransformParameterSpec spec2) |
|
{ |
|
|
|
XMLStructure ostylesheet = spec2.getStylesheet(); |
|
if (!(ostylesheet instanceof javax.xml.crypto.dom.DOMStructure)) { |
|
return false; |
|
} |
|
Node ostylesheetElem = |
|
((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode(); |
|
XMLStructure stylesheet = spec1.getStylesheet(); |
|
Node stylesheetElem = |
|
((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode(); |
|
return nodesEqual(stylesheetElem, ostylesheetElem); |
|
} |
|
|
|
public static boolean isNamespace(Node node) |
|
{ |
|
final short nodeType = node.getNodeType(); |
|
if (nodeType == Node.ATTRIBUTE_NODE) { |
|
final String namespaceURI = node.getNamespaceURI(); |
|
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI); |
|
} |
|
return false; |
|
} |
|
} |