001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.ws.security.opt.impl.util;
024:
025: import org.w3c.dom.Document;
026: import org.w3c.dom.NamedNodeMap;
027: import org.w3c.dom.Node;
028: import org.w3c.dom.NodeList;
029: import org.w3c.dom.Element;
030: import org.xml.sax.SAXException;
031:
032: import javax.xml.parsers.DocumentBuilder;
033: import javax.xml.parsers.DocumentBuilderFactory;
034: import javax.xml.parsers.FactoryConfigurationError;
035: import javax.xml.parsers.ParserConfigurationException;
036: import javax.xml.stream.XMLStreamException;
037: import javax.xml.stream.XMLStreamWriter;
038: import javax.xml.XMLConstants;
039: import javax.xml.namespace.NamespaceContext;
040: import java.io.IOException;
041: import java.io.InputStream;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.ArrayList;
045:
046: import com.sun.istack.NotNull;
047: import com.sun.istack.Nullable;
048:
049: /**
050: * $author: JAXWS Development Team
051: */
052: public class DOMUtil {
053:
054: private static DocumentBuilder db;
055:
056: /**
057: * Creates a new DOM document.
058: */
059: public static Document createDom() {
060: synchronized (DOMUtil.class) {
061: if (db == null) {
062: try {
063: DocumentBuilderFactory dbf = DocumentBuilderFactory
064: .newInstance();
065: dbf.setNamespaceAware(true);
066: db = dbf.newDocumentBuilder();
067: } catch (ParserConfigurationException e) {
068: throw new FactoryConfigurationError(e);
069: }
070: }
071: return db.newDocument();
072: }
073: }
074:
075: public static Node createDOMNode(InputStream inputStream) {
076:
077: DocumentBuilderFactory dbf = DocumentBuilderFactory
078: .newInstance();
079: dbf.setNamespaceAware(true);
080: dbf.setValidating(false);
081: try {
082: DocumentBuilder builder = dbf.newDocumentBuilder();
083: try {
084: return builder.parse(inputStream);
085: } catch (SAXException e) {
086: e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
087: } catch (IOException e) {
088: e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
089: }
090: } catch (ParserConfigurationException pce) {
091: IllegalArgumentException iae = new IllegalArgumentException(
092: pce.getMessage());
093: iae.initCause(pce);
094: throw iae;
095: }
096: return null;
097: }
098:
099: /**
100: * Traverses a DOM node and writes out on a streaming writer.
101: *
102: * @param node
103: * @param writer
104: */
105: public static void serializeNode(Element node,
106: XMLStreamWriter writer) throws XMLStreamException {
107: writeTagWithAttributes(node, writer);
108:
109: if (node.hasChildNodes()) {
110: NodeList children = node.getChildNodes();
111: for (int i = 0; i < children.getLength(); i++) {
112: Node child = children.item(i);
113: switch (child.getNodeType()) {
114: case Node.PROCESSING_INSTRUCTION_NODE:
115: writer.writeProcessingInstruction(child
116: .getNodeValue());
117: break;
118: case Node.DOCUMENT_TYPE_NODE:
119: break;
120: case Node.CDATA_SECTION_NODE:
121: writer.writeCData(child.getNodeValue());
122: break;
123: case Node.COMMENT_NODE:
124: writer.writeComment(child.getNodeValue());
125: break;
126: case Node.TEXT_NODE:
127: writer.writeCharacters(child.getNodeValue());
128: break;
129: case Node.ELEMENT_NODE:
130: serializeNode((Element) child, writer);
131: break;
132: }
133: }
134: }
135: writer.writeEndElement();
136: }
137:
138: public static void writeTagWithAttributes(Element node,
139: XMLStreamWriter writer) throws XMLStreamException {
140: String nodePrefix = fixNull(node.getPrefix());
141: String nodeNS = fixNull(node.getNamespaceURI());
142:
143: // See if nodePrefix:nodeNS is declared in writer's NamespaceContext before writing start element
144: // Writing start element puts nodeNS in NamespaceContext even though namespace declaration not written
145: boolean prefixDecl = isPrefixDeclared(writer, nodeNS,
146: nodePrefix);
147: writer.writeStartElement(nodePrefix, node.getLocalName(),
148: nodeNS);
149:
150: if (node.hasAttributes()) {
151: NamedNodeMap attrs = node.getAttributes();
152: int numOfAttributes = attrs.getLength();
153: // write namespace declarations first.
154: // if we interleave this with attribue writing,
155: // Zephyr will try to fix it and we end up getting inconsistent namespace bindings.
156: for (int i = 0; i < numOfAttributes; i++) {
157: Node attr = attrs.item(i);
158: String nsUri = fixNull(attr.getNamespaceURI());
159: if (nsUri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
160: // handle default ns declarations
161: String local = attr.getLocalName().equals(
162: XMLConstants.XMLNS_ATTRIBUTE) ? "" : attr
163: .getLocalName();
164: if (local.equals(nodePrefix)
165: && attr.getNodeValue().equals(nodeNS)) {
166: prefixDecl = true;
167: }
168: if (local.equals("")) {
169: writer.writeDefaultNamespace(attr
170: .getNodeValue());
171: } else {
172: // this is a namespace declaration, not an attribute
173: writer.setPrefix(attr.getLocalName(), attr
174: .getNodeValue());
175: writer.writeNamespace(attr.getLocalName(), attr
176: .getNodeValue());
177: }
178: }
179: }
180: }
181: // node's namespace is not declared as attribute, but declared on ancestor
182: if (!prefixDecl) {
183: writer.writeNamespace(nodePrefix, nodeNS);
184: }
185:
186: // Write all other attributes which are not namespace decl.
187: if (node.hasAttributes()) {
188: NamedNodeMap attrs = node.getAttributes();
189: int numOfAttributes = attrs.getLength();
190:
191: for (int i = 0; i < numOfAttributes; i++) {
192: Node attr = attrs.item(i);
193: String attrPrefix = fixNull(attr.getPrefix());
194: String attrNS = fixNull(attr.getNamespaceURI());
195: if (!attrNS.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
196: String localName = attr.getLocalName();
197: if (localName == null) {
198: // TODO: this is really a bug in the caller for not creating proper DOM tree.
199: // will remove this workaround after plugfest
200: localName = attr.getNodeName();
201: }
202: boolean attrPrefixDecl = isPrefixDeclared(writer,
203: attrNS, attrPrefix);
204: if (!attrPrefix.equals("") && !attrPrefixDecl) {
205: // attr has namespace but namespace decl is there in ancestor node
206: // So write the namespace decl before writing the attr
207: writer.setPrefix(attr.getLocalName(), attr
208: .getNodeValue());
209: writer.writeNamespace(attrPrefix, attrNS);
210: }
211: writer.writeAttribute(attrPrefix, attrNS,
212: localName, attr.getNodeValue());
213: }
214: }
215: }
216: }
217:
218: private static boolean isPrefixDeclared(XMLStreamWriter writer,
219: String nsUri, String prefix) {
220: boolean prefixDecl = false;
221: NamespaceContext nscontext = writer.getNamespaceContext();
222: Iterator prefixItr = nscontext.getPrefixes(nsUri);
223: while (prefixItr.hasNext()) {
224: if (prefix.equals(prefixItr.next())) {
225: prefixDecl = true;
226: break;
227: }
228: }
229: return prefixDecl;
230: }
231:
232: /**
233: * Gets the first child of the given name, or null.
234: */
235: public static Element getFirstChild(Element e, String nsUri,
236: String local) {
237: for (Node n = e.getFirstChild(); n != null; n = n
238: .getNextSibling()) {
239: if (n.getNodeType() == Node.ELEMENT_NODE) {
240: Element c = (Element) n;
241: if (c.getLocalName().equals(local)
242: && c.getNamespaceURI().equals(nsUri))
243: return c;
244: }
245: }
246: return null;
247: }
248:
249: private static @NotNull
250: String fixNull(@Nullable
251: String s) {
252: if (s == null)
253: return "";
254: else
255: return s;
256: }
257:
258: /**
259: * Gets the first element child.
260: */
261: public static @Nullable
262: Element getFirstElementChild(Node parent) {
263: for (Node n = parent.getFirstChild(); n != null; n = n
264: .getNextSibling()) {
265: if (n.getNodeType() == Node.ELEMENT_NODE) {
266: return (Element) n;
267: }
268: }
269: return null;
270: }
271:
272: public static @NotNull
273: List<Element> getChildElements(Node parent) {
274: List<Element> elements = new ArrayList<Element>();
275: for (Node n = parent.getFirstChild(); n != null; n = n
276: .getNextSibling()) {
277: if (n.getNodeType() == Node.ELEMENT_NODE) {
278: elements.add((Element) n);
279: }
280: }
281: return elements;
282: }
283: }
|