blob: bc980009146c94336329abe1ddda2613d9ba4e8d [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed 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.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.util.StAXUtils;
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.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
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) {
//log.error(Messages.getMessage("exception00"), e);
saxFactory = null;
}
} 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) {
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
*
* 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.
*
* 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 Base64.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;
}
/**
* Converts a given DOM Element to an OMElement.
* @param element
* @return Returns OMElement.
* @throws Exception
*/
public static OMElement toOM(Element element) throws Exception {
Source source = new DOMSource(element);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Result result = new StreamResult(baos);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(source, result);
ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
XMLStreamReader reader = StAXUtils
.createXMLStreamReader(is);
StAXOMBuilder builder = new StAXOMBuilder(reader);
builder.setCache(true);
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();
}
}