| /* |
| * 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. |
| */ |
| |
| package org.apache.axis2.util; |
| |
| import com.ibm.wsdl.Constants; |
| import org.apache.axiom.om.OMElement; |
| import org.apache.axiom.om.OMNode; |
| import org.apache.axiom.om.OMXMLBuilderFactory; |
| import org.apache.axiom.om.OMXMLParserWrapper; |
| import org.apache.axiom.util.base64.Base64Utils; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.CharacterData; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| import javax.xml.stream.XMLStreamException; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.UnsupportedEncodingException; |
| import java.net.HttpURLConnection; |
| import java.net.MalformedURLException; |
| import java.net.ProtocolException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.Stack; |
| |
| |
| public class XMLUtils { |
| public static final String charEncoding = "ISO-8859-1"; |
| private static final String saxParserFactoryProperty = |
| "javax.xml.parsers.SAXParserFactory"; |
| |
| private static DocumentBuilderFactory dbf = getDOMFactory(); |
| private static SAXParserFactory saxFactory; |
| private static Stack saxParsers = new Stack(); |
| |
| private static String empty = ""; |
| private static ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes()); |
| |
| static { |
| // Initialize SAX Parser factory defaults |
| initSAXFactory(null, true, false); |
| } |
| |
| /** |
| * Initializes the SAX parser factory. |
| * |
| * @param factoryClassName The (optional) class name of the desired |
| * SAXParserFactory implementation. Will be |
| * assigned to the system property |
| * <b>javax.xml.parsers.SAXParserFactory</b> |
| * unless this property is already set. |
| * If <code>null</code>, leaves current setting |
| * alone. |
| * @param namespaceAware true if we want a namespace-aware parser |
| * @param validating true if we want a validating parser |
| */ |
| public static void initSAXFactory(String factoryClassName, |
| boolean namespaceAware, |
| boolean validating) { |
| if (factoryClassName != null) { |
| try { |
| saxFactory = (SAXParserFactory) Loader.loadClass(factoryClassName). |
| newInstance(); |
| /* |
| * Set the system property only if it is not already set to |
| * avoid corrupting environments in which Axis is embedded. |
| */ |
| if (System.getProperty(saxParserFactoryProperty) == null) { |
| System.setProperty(saxParserFactoryProperty, |
| factoryClassName); |
| } |
| } catch (Exception e) { |
| saxFactory = SAXParserFactory.newInstance(); |
| } |
| } else { |
| saxFactory = SAXParserFactory.newInstance(); |
| } |
| saxFactory.setNamespaceAware(namespaceAware); |
| saxFactory.setValidating(validating); |
| |
| // Discard existing parsers |
| saxParsers.clear(); |
| } |
| |
| private static DocumentBuilderFactory getDOMFactory() { |
| DocumentBuilderFactory dbf; |
| try { |
| dbf = DocumentBuilderFactory.newInstance(); |
| dbf.setNamespaceAware(true); |
| } |
| catch (Exception e) { |
| //log.error(Messages.getMessage("exception00"), e ); |
| dbf = null; |
| } |
| return (dbf); |
| } |
| |
| private static boolean tryReset = true; |
| |
| /** |
| * Returns a SAX parser for reuse. |
| * |
| * @param parser A SAX parser that is available for reuse |
| */ |
| public static void releaseSAXParser(SAXParser parser) { |
| if (!tryReset) { |
| return; |
| } |
| |
| //Free up possible ref. held by past contenthandler. |
| try { |
| XMLReader xmlReader = parser.getXMLReader(); |
| if (null != xmlReader) { |
| synchronized (XMLUtils.class) { |
| saxParsers.push(parser); |
| } |
| } else { |
| tryReset = false; |
| } |
| } catch (org.xml.sax.SAXException e) { |
| tryReset = false; |
| } |
| } |
| |
| /** |
| * Gets an empty new Document. |
| * |
| * @return Returns Document. |
| * @throws ParserConfigurationException if construction problems occur |
| */ |
| public static Document newDocument() |
| throws ParserConfigurationException { |
| synchronized (dbf) { |
| return dbf.newDocumentBuilder().newDocument(); |
| } |
| } |
| |
| /** |
| * Gets a new Document read from the input source. |
| * |
| * @return Returns Document. |
| * @throws ParserConfigurationException if construction problems occur |
| * @throws SAXException if the document has xml sax problems |
| * @throws IOException if i/o exceptions occur |
| */ |
| public static Document newDocument(InputSource inp) |
| throws ParserConfigurationException, SAXException, IOException { |
| DocumentBuilder db; |
| synchronized (dbf) { |
| try { |
| db = dbf.newDocumentBuilder(); |
| } catch (Exception e){ |
| // Under some peculiar conditions (classloader issues), just scrap the old dbf, create a new one and try again. |
| dbf = getDOMFactory(); |
| db = dbf.newDocumentBuilder(); |
| } |
| } |
| db.setEntityResolver(new DefaultEntityResolver()); |
| db.setErrorHandler(new ParserErrorHandler()); |
| return (db.parse(inp)); |
| } |
| |
| /** |
| * Gets a new Document read from the input stream |
| * |
| * @return Returns Document. |
| * @throws ParserConfigurationException if construction problems occur |
| * @throws SAXException if the document has xml sax problems |
| * @throws IOException if i/o exceptions occur |
| */ |
| public static Document newDocument(InputStream inp) |
| throws ParserConfigurationException, SAXException, IOException { |
| return XMLUtils.newDocument(new InputSource(inp)); |
| } |
| |
| /** |
| * Gets a new Document read from the indicated uri |
| * |
| * @return Returns Document. |
| * @throws ParserConfigurationException if construction problems occur |
| * @throws SAXException if the document has xml sax problems |
| * @throws IOException if i/o exceptions occur |
| */ |
| public static Document newDocument(String uri) |
| throws ParserConfigurationException, SAXException, IOException { |
| // call the authenticated version as there might be |
| // username/password info embeded in the uri. |
| return XMLUtils.newDocument(uri, null, null); |
| } |
| |
| /** |
| * Creates a new document from the given URI. Uses the username and password |
| * if the URI requires authentication. |
| * |
| * @param uri the resource to get |
| * @param username basic auth username |
| * @param password basic auth password |
| * @throws ParserConfigurationException if construction problems occur |
| * @throws SAXException if the document has xml sax problems |
| * @throws IOException if i/o exceptions occur |
| */ |
| public static Document newDocument(String uri, String username, String password) |
| throws ParserConfigurationException, SAXException, IOException { |
| InputSource ins = XMLUtils.getInputSourceFromURI(uri, username, password); |
| Document doc = XMLUtils.newDocument(ins); |
| // Close the Stream |
| if (ins.getByteStream() != null) { |
| ins.getByteStream().close(); |
| } else if (ins.getCharacterStream() != null) { |
| ins.getCharacterStream().close(); |
| } |
| return doc; |
| } |
| |
| |
| public static String getPrefix(String uri, Node e) { |
| while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) { |
| NamedNodeMap attrs = e.getAttributes(); |
| for (int n = 0; n < attrs.getLength(); n++) { |
| Attr a = (Attr) attrs.item(n); |
| String name; |
| if ((name = a.getName()).startsWith("xmlns:") && |
| a.getNodeValue().equals(uri)) { |
| return name.substring(6); |
| } |
| } |
| e = e.getParentNode(); |
| } |
| return null; |
| } |
| |
| public static String getNamespace(String prefix, Node e) { |
| while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) { |
| Attr attr = |
| ((Element) e).getAttributeNodeNS(Constants.NS_URI_XMLNS, prefix); |
| if (attr != null) { |
| return attr.getValue(); |
| } |
| e = e.getParentNode(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a QName when passed a string like "foo:bar" by mapping |
| * the "foo" prefix to a namespace in the context of the given Node. |
| * |
| * @return Returns a QName generated from the given string representation. |
| */ |
| public static QName getQNameFromString(String str, Node e) { |
| if (str == null || e == null) { |
| return null; |
| } |
| |
| int idx = str.indexOf(':'); |
| if (idx > -1) { |
| String prefix = str.substring(0, idx); |
| String ns = getNamespace(prefix, e); |
| if (ns == null) { |
| return null; |
| } |
| return new QName(ns, str.substring(idx + 1)); |
| } else { |
| return new QName("", str); |
| } |
| } |
| |
| /** |
| * Returns a string for a particular QName, mapping a new prefix |
| * if necessary. |
| */ |
| public static String getStringForQName(QName qname, Element e) { |
| String uri = qname.getNamespaceURI(); |
| String prefix = getPrefix(uri, e); |
| if (prefix == null) { |
| int i = 1; |
| prefix = "ns" + i; |
| while (getNamespace(prefix, e) != null) { |
| i++; |
| prefix = "ns" + i; |
| } |
| e.setAttributeNS(Constants.NS_URI_XMLNS, |
| "xmlns:" + prefix, uri); |
| } |
| return prefix + ":" + qname.getLocalPart(); |
| } |
| |
| /** |
| * Concatinates all the text and cdata node children of this elem and returns |
| * the resulting text. |
| * (by Matt Duftler) |
| * |
| * @param parentEl the element whose cdata/text node values are to |
| * be combined. |
| * @return Returns the concatinated string. |
| */ |
| public static String getChildCharacterData(Element parentEl) { |
| if (parentEl == null) { |
| return null; |
| } |
| Node tempNode = parentEl.getFirstChild(); |
| StringBuffer strBuf = new StringBuffer(); |
| CharacterData charData; |
| |
| while (tempNode != null) { |
| switch (tempNode.getNodeType()) { |
| case Node.TEXT_NODE : |
| case Node.CDATA_SECTION_NODE: |
| charData = (CharacterData) tempNode; |
| strBuf.append(charData.getData()); |
| break; |
| } |
| tempNode = tempNode.getNextSibling(); |
| } |
| return strBuf.toString(); |
| } |
| |
| public static class ParserErrorHandler implements ErrorHandler { |
| /** |
| * Returns a string describing parse exception details |
| */ |
| private String getParseExceptionInfo(SAXParseException spe) { |
| String systemId = spe.getSystemId(); |
| if (systemId == null) { |
| systemId = "null"; |
| } |
| return "URI=" + systemId + |
| " Line=" + spe.getLineNumber() + |
| ": " + spe.getMessage(); |
| } |
| |
| // The following methods are standard SAX ErrorHandler methods. |
| // See SAX documentation for more info. |
| |
| public void warning(SAXParseException spe) throws SAXException { |
| } |
| |
| public void error(SAXParseException spe) throws SAXException { |
| String message = "Error: " + getParseExceptionInfo(spe); |
| throw new SAXException(message); |
| } |
| |
| public void fatalError(SAXParseException spe) throws SAXException { |
| String message = "Fatal Error: " + getParseExceptionInfo(spe); |
| throw new SAXException(message); |
| } |
| } |
| |
| |
| /** |
| * Utility to get the bytes uri. |
| * Does NOT handle authenticated URLs, |
| * use getInputSourceFromURI(uri, username, password) |
| * |
| * @param uri the resource to get |
| */ |
| public static InputSource getInputSourceFromURI(String uri) { |
| return new InputSource(uri); |
| } |
| |
| |
| /** |
| * Utility to get the bytes at a protected uri |
| * <p/> |
| * Retrieves the URL if a username and password are provided. |
| * The java.net.URL class does not do Basic Authentication, so we have to |
| * do it manually in this routine. |
| * <p/> |
| * If no username is provided, creates an InputSource from the uri |
| * and lets the InputSource go fetch the contents. |
| * |
| * @param uri the resource to get |
| * @param username basic auth username |
| * @param password basic auth password |
| */ |
| private static InputSource getInputSourceFromURI(String uri, |
| String username, |
| String password) |
| throws IOException, ProtocolException, UnsupportedEncodingException { |
| URL wsdlurl = null; |
| try { |
| wsdlurl = new URL(uri); |
| } catch (MalformedURLException e) { |
| // we can't process it, it might be a 'simple' foo.wsdl |
| // let InputSource deal with it |
| return new InputSource(uri); |
| } |
| |
| // if no authentication, just let InputSource deal with it |
| if (username == null && wsdlurl.getUserInfo() == null) { |
| return new InputSource(uri); |
| } |
| |
| // if this is not an HTTP{S} url, let InputSource deal with it |
| if (!wsdlurl.getProtocol().startsWith("http")) { |
| return new InputSource(uri); |
| } |
| |
| URLConnection connection = wsdlurl.openConnection(); |
| // Does this work for https??? |
| if (!(connection instanceof HttpURLConnection)) { |
| // can't do http with this URL, let InputSource deal with it |
| return new InputSource(uri); |
| } |
| HttpURLConnection uconn = (HttpURLConnection) connection; |
| String userinfo = wsdlurl.getUserInfo(); |
| uconn.setRequestMethod("GET"); |
| uconn.setAllowUserInteraction(false); |
| uconn.setDefaultUseCaches(false); |
| uconn.setDoInput(true); |
| uconn.setDoOutput(false); |
| uconn.setInstanceFollowRedirects(true); |
| uconn.setUseCaches(false); |
| |
| // username/password info in the URL overrides passed in values |
| String auth = null; |
| if (userinfo != null) { |
| auth = userinfo; |
| } else if (username != null) { |
| auth = (password == null) ? username : username + ":" + password; |
| } |
| |
| if (auth != null) { |
| uconn.setRequestProperty("Authorization", |
| "Basic " + |
| base64encode(auth.getBytes(charEncoding))); |
| } |
| |
| uconn.connect(); |
| |
| return new InputSource(uconn.getInputStream()); |
| } |
| |
| public static String base64encode(byte[] bytes) { |
| return Base64Utils.encode(bytes); |
| } |
| |
| public static InputSource getEmptyInputSource() { |
| return new InputSource(bais); |
| } |
| |
| /** |
| * Finds a Node with a given QNameb. |
| * |
| * @param node parent node |
| * @param name QName of the child we need to find |
| * @return Returns child node. |
| */ |
| public static Node findNode(Node node, QName name) { |
| if (name.getNamespaceURI().equals(node.getNamespaceURI()) && |
| name.getLocalPart().equals(node.getLocalName())) { |
| return node; |
| } |
| NodeList children = node.getChildNodes(); |
| for (int i = 0; i < children.getLength(); i++) { |
| Node ret = findNode(children.item(i), name); |
| if (ret != null) { |
| return ret; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Convert DOM Element into a fully built OMElement |
| * @param element dom Element |
| * @return OMElement |
| * @throws Exception |
| */ |
| public static OMElement toOM(Element element) throws Exception { |
| OMXMLParserWrapper builder = OMXMLBuilderFactory.createOMBuilder(element, true); |
| builder.detach(); |
| return builder.getDocumentElement(); |
| } |
| |
| /** |
| * Converts a given OMElement to a DOM Element. |
| * |
| * @param element |
| * @return Returns Element. |
| * @throws Exception |
| */ |
| public static Element toDOM(OMElement element) throws Exception { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| element.serialize(baos); |
| ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); |
| |
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| factory.setNamespaceAware(true); |
| return factory.newDocumentBuilder().parse(bais).getDocumentElement(); |
| } |
| |
| |
| /** |
| * Converts a given inputstream to an OMNode |
| * The reurned OMNode is fully built. |
| * |
| * @param inputStream |
| * @return OMNode |
| * @throws javax.xml.stream.XMLStreamException |
| * |
| */ |
| public static OMNode toOM(InputStream inputStream) throws XMLStreamException { |
| return toOM(inputStream, true); |
| } |
| |
| /** |
| * Converts a given inputstream to an OMNode |
| * The reurned OMNode is fully built if buildAll is true. |
| * If buildAll is false, the caller is responsible for closing the parser. |
| * |
| * @param inputStream |
| * @param buildAll |
| * @return OMNode |
| * @throws javax.xml.stream.XMLStreamException |
| * |
| */ |
| public static OMNode toOM(InputStream inputStream, boolean buildAll) throws XMLStreamException { |
| OMXMLParserWrapper builder = OMXMLBuilderFactory.createOMBuilder(inputStream); |
| OMNode omNode = builder.getDocumentElement(); |
| |
| if (buildAll) { |
| omNode.build(); |
| builder.close(); |
| } |
| |
| return omNode; |
| } |
| |
| /** |
| * Converts a given Reader to an OMNode. |
| * The reurned OMNode is fully built. |
| * |
| * @param reader |
| * @return |
| * @throws XMLStreamException |
| */ |
| public static OMNode toOM(Reader reader) throws XMLStreamException { |
| return toOM(reader, true); |
| } |
| |
| /** |
| * Converts a given Reader to an OMNode. |
| * The reurned OMNode is fully built if buildAll is true. |
| * If buildAll is false, the caller is responsible for closing the parser. |
| * |
| * @param reader |
| * @param buildAll |
| * @return OMNode |
| * @throws XMLStreamException |
| */ |
| public static OMNode toOM(Reader reader, boolean buildAll) throws XMLStreamException { |
| OMXMLParserWrapper builder = OMXMLBuilderFactory.createOMBuilder(reader); |
| OMNode omNode = builder.getDocumentElement(); |
| |
| if (buildAll) { |
| omNode.build(); |
| builder.close(); |
| } |
| |
| return omNode; |
| } |
| } |