001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.util;
021:
022: import com.ibm.wsdl.Constants;
023: import org.apache.axiom.om.OMAbstractFactory;
024: import org.apache.axiom.om.OMElement;
025: import org.apache.axiom.om.OMFactory;
026: import org.apache.axiom.om.OMNode;
027: import org.apache.axiom.om.impl.builder.StAXOMBuilder;
028: import org.apache.axiom.om.util.Base64;
029: import org.apache.axiom.om.util.StAXUtils;
030: import org.w3c.dom.Attr;
031: import org.w3c.dom.CharacterData;
032: import org.w3c.dom.Document;
033: import org.w3c.dom.Element;
034: import org.w3c.dom.NamedNodeMap;
035: import org.w3c.dom.Node;
036: import org.w3c.dom.NodeList;
037: import org.xml.sax.ErrorHandler;
038: import org.xml.sax.InputSource;
039: import org.xml.sax.SAXException;
040: import org.xml.sax.SAXParseException;
041: import org.xml.sax.XMLReader;
042:
043: import javax.xml.namespace.QName;
044: import javax.xml.parsers.DocumentBuilder;
045: import javax.xml.parsers.DocumentBuilderFactory;
046: import javax.xml.parsers.ParserConfigurationException;
047: import javax.xml.parsers.SAXParser;
048: import javax.xml.parsers.SAXParserFactory;
049: import javax.xml.stream.XMLStreamException;
050: import javax.xml.stream.XMLStreamReader;
051: import javax.xml.transform.Result;
052: import javax.xml.transform.Source;
053: import javax.xml.transform.Transformer;
054: import javax.xml.transform.TransformerFactory;
055: import javax.xml.transform.dom.DOMSource;
056: import javax.xml.transform.stream.StreamResult;
057: import java.io.ByteArrayInputStream;
058: import java.io.ByteArrayOutputStream;
059: import java.io.IOException;
060: import java.io.InputStream;
061: import java.io.Reader;
062: import java.io.UnsupportedEncodingException;
063: import java.net.HttpURLConnection;
064: import java.net.MalformedURLException;
065: import java.net.ProtocolException;
066: import java.net.URL;
067: import java.net.URLConnection;
068: import java.util.Stack;
069:
070: public class XMLUtils {
071: public static final String charEncoding = "ISO-8859-1";
072: private static final String saxParserFactoryProperty = "javax.xml.parsers.SAXParserFactory";
073:
074: private static DocumentBuilderFactory dbf = getDOMFactory();
075: private static SAXParserFactory saxFactory;
076: private static Stack saxParsers = new Stack();
077:
078: private static String empty = "";
079: private static ByteArrayInputStream bais = new ByteArrayInputStream(
080: empty.getBytes());
081:
082: static {
083: // Initialize SAX Parser factory defaults
084: initSAXFactory(null, true, false);
085: }
086:
087: /**
088: * Initializes the SAX parser factory.
089: *
090: * @param factoryClassName The (optional) class name of the desired
091: * SAXParserFactory implementation. Will be
092: * assigned to the system property
093: * <b>javax.xml.parsers.SAXParserFactory</b>
094: * unless this property is already set.
095: * If <code>null</code>, leaves current setting
096: * alone.
097: * @param namespaceAware true if we want a namespace-aware parser
098: * @param validating true if we want a validating parser
099: */
100: public static void initSAXFactory(String factoryClassName,
101: boolean namespaceAware, boolean validating) {
102: if (factoryClassName != null) {
103: try {
104: saxFactory = (SAXParserFactory) Loader.loadClass(
105: factoryClassName).newInstance();
106: /*
107: * Set the system property only if it is not already set to
108: * avoid corrupting environments in which Axis is embedded.
109: */
110: if (System.getProperty(saxParserFactoryProperty) == null) {
111: System.setProperty(saxParserFactoryProperty,
112: factoryClassName);
113: }
114: } catch (Exception e) {
115: //log.error(Messages.getMessage("exception00"), e);
116: saxFactory = null;
117: }
118: } else {
119: saxFactory = SAXParserFactory.newInstance();
120: }
121: saxFactory.setNamespaceAware(namespaceAware);
122: saxFactory.setValidating(validating);
123:
124: // Discard existing parsers
125: saxParsers.clear();
126: }
127:
128: private static DocumentBuilderFactory getDOMFactory() {
129: DocumentBuilderFactory dbf;
130: try {
131: dbf = DocumentBuilderFactory.newInstance();
132: dbf.setNamespaceAware(true);
133: } catch (Exception e) {
134: //log.error(Messages.getMessage("exception00"), e );
135: dbf = null;
136: }
137: return (dbf);
138: }
139:
140: private static boolean tryReset = true;
141:
142: /**
143: * Returns a SAX parser for reuse.
144: *
145: * @param parser A SAX parser that is available for reuse
146: */
147: public static void releaseSAXParser(SAXParser parser) {
148: if (!tryReset) {
149: return;
150: }
151:
152: //Free up possible ref. held by past contenthandler.
153: try {
154: XMLReader xmlReader = parser.getXMLReader();
155: if (null != xmlReader) {
156: synchronized (XMLUtils.class) {
157: saxParsers.push(parser);
158: }
159: } else {
160: tryReset = false;
161: }
162: } catch (org.xml.sax.SAXException e) {
163: tryReset = false;
164: }
165: }
166:
167: /**
168: * Gets an empty new Document.
169: *
170: * @return Returns Document.
171: * @throws ParserConfigurationException if construction problems occur
172: */
173: public static Document newDocument()
174: throws ParserConfigurationException {
175: synchronized (dbf) {
176: return dbf.newDocumentBuilder().newDocument();
177: }
178: }
179:
180: /**
181: * Gets a new Document read from the input source.
182: *
183: * @return Returns Document.
184: * @throws ParserConfigurationException if construction problems occur
185: * @throws SAXException if the document has xml sax problems
186: * @throws IOException if i/o exceptions occur
187: */
188: public static Document newDocument(InputSource inp)
189: throws ParserConfigurationException, SAXException,
190: IOException {
191: DocumentBuilder db;
192: synchronized (dbf) {
193: try {
194: db = dbf.newDocumentBuilder();
195: } catch (Exception e) {
196: // Under some peculiar conditions (classloader issues), just scrap the old dbf, create a new one and try again.
197: dbf = getDOMFactory();
198: db = dbf.newDocumentBuilder();
199: }
200: }
201: db.setEntityResolver(new DefaultEntityResolver());
202: db.setErrorHandler(new ParserErrorHandler());
203: return (db.parse(inp));
204: }
205:
206: /**
207: * Gets a new Document read from the input stream
208: *
209: * @return Returns Document.
210: * @throws ParserConfigurationException if construction problems occur
211: * @throws SAXException if the document has xml sax problems
212: * @throws IOException if i/o exceptions occur
213: */
214: public static Document newDocument(InputStream inp)
215: throws ParserConfigurationException, SAXException,
216: IOException {
217: return XMLUtils.newDocument(new InputSource(inp));
218: }
219:
220: /**
221: * Gets a new Document read from the indicated uri
222: *
223: * @return Returns Document.
224: * @throws ParserConfigurationException if construction problems occur
225: * @throws SAXException if the document has xml sax problems
226: * @throws IOException if i/o exceptions occur
227: */
228: public static Document newDocument(String uri)
229: throws ParserConfigurationException, SAXException,
230: IOException {
231: // call the authenticated version as there might be
232: // username/password info embeded in the uri.
233: return XMLUtils.newDocument(uri, null, null);
234: }
235:
236: /**
237: * Creates a new document from the given URI. Uses the username and password
238: * if the URI requires authentication.
239: *
240: * @param uri the resource to get
241: * @param username basic auth username
242: * @param password basic auth password
243: * @throws ParserConfigurationException if construction problems occur
244: * @throws SAXException if the document has xml sax problems
245: * @throws IOException if i/o exceptions occur
246: */
247: public static Document newDocument(String uri, String username,
248: String password) throws ParserConfigurationException,
249: SAXException, IOException {
250: InputSource ins = XMLUtils.getInputSourceFromURI(uri, username,
251: password);
252: Document doc = XMLUtils.newDocument(ins);
253: // Close the Stream
254: if (ins.getByteStream() != null) {
255: ins.getByteStream().close();
256: } else if (ins.getCharacterStream() != null) {
257: ins.getCharacterStream().close();
258: }
259: return doc;
260: }
261:
262: public static String getPrefix(String uri, Node e) {
263: while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) {
264: NamedNodeMap attrs = e.getAttributes();
265: for (int n = 0; n < attrs.getLength(); n++) {
266: Attr a = (Attr) attrs.item(n);
267: String name;
268: if ((name = a.getName()).startsWith("xmlns:")
269: && a.getNodeValue().equals(uri)) {
270: return name.substring(6);
271: }
272: }
273: e = e.getParentNode();
274: }
275: return null;
276: }
277:
278: public static String getNamespace(String prefix, Node e) {
279: while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) {
280: Attr attr = ((Element) e).getAttributeNodeNS(
281: Constants.NS_URI_XMLNS, prefix);
282: if (attr != null) {
283: return attr.getValue();
284: }
285: e = e.getParentNode();
286: }
287: return null;
288: }
289:
290: /**
291: * Returns a QName when passed a string like "foo:bar" by mapping
292: * the "foo" prefix to a namespace in the context of the given Node.
293: *
294: * @return Returns a QName generated from the given string representation.
295: */
296: public static QName getQNameFromString(String str, Node e) {
297: if (str == null || e == null) {
298: return null;
299: }
300:
301: int idx = str.indexOf(':');
302: if (idx > -1) {
303: String prefix = str.substring(0, idx);
304: String ns = getNamespace(prefix, e);
305: if (ns == null) {
306: return null;
307: }
308: return new QName(ns, str.substring(idx + 1));
309: } else {
310: return new QName("", str);
311: }
312: }
313:
314: /**
315: * Returns a string for a particular QName, mapping a new prefix
316: * if necessary.
317: */
318: public static String getStringForQName(QName qname, Element e) {
319: String uri = qname.getNamespaceURI();
320: String prefix = getPrefix(uri, e);
321: if (prefix == null) {
322: int i = 1;
323: prefix = "ns" + i;
324: while (getNamespace(prefix, e) != null) {
325: i++;
326: prefix = "ns" + i;
327: }
328: e.setAttributeNS(Constants.NS_URI_XMLNS, "xmlns:" + prefix,
329: uri);
330: }
331: return prefix + ":" + qname.getLocalPart();
332: }
333:
334: /**
335: * Concatinates all the text and cdata node children of this elem and returns
336: * the resulting text.
337: * (by Matt Duftler)
338: *
339: * @param parentEl the element whose cdata/text node values are to
340: * be combined.
341: * @return Returns the concatinated string.
342: */
343: public static String getChildCharacterData(Element parentEl) {
344: if (parentEl == null) {
345: return null;
346: }
347: Node tempNode = parentEl.getFirstChild();
348: StringBuffer strBuf = new StringBuffer();
349: CharacterData charData;
350:
351: while (tempNode != null) {
352: switch (tempNode.getNodeType()) {
353: case Node.TEXT_NODE:
354: case Node.CDATA_SECTION_NODE:
355: charData = (CharacterData) tempNode;
356: strBuf.append(charData.getData());
357: break;
358: }
359: tempNode = tempNode.getNextSibling();
360: }
361: return strBuf.toString();
362: }
363:
364: public static class ParserErrorHandler implements ErrorHandler {
365: /**
366: * Returns a string describing parse exception details
367: */
368: private String getParseExceptionInfo(SAXParseException spe) {
369: String systemId = spe.getSystemId();
370: if (systemId == null) {
371: systemId = "null";
372: }
373: return "URI=" + systemId + " Line=" + spe.getLineNumber()
374: + ": " + spe.getMessage();
375: }
376:
377: // The following methods are standard SAX ErrorHandler methods.
378: // See SAX documentation for more info.
379:
380: public void warning(SAXParseException spe) throws SAXException {
381: }
382:
383: public void error(SAXParseException spe) throws SAXException {
384: String message = "Error: " + getParseExceptionInfo(spe);
385: throw new SAXException(message);
386: }
387:
388: public void fatalError(SAXParseException spe)
389: throws SAXException {
390: String message = "Fatal Error: "
391: + getParseExceptionInfo(spe);
392: throw new SAXException(message);
393: }
394: }
395:
396: /**
397: * Utility to get the bytes uri.
398: * Does NOT handle authenticated URLs,
399: * use getInputSourceFromURI(uri, username, password)
400: *
401: * @param uri the resource to get
402: */
403: public static InputSource getInputSourceFromURI(String uri) {
404: return new InputSource(uri);
405: }
406:
407: /**
408: * Utility to get the bytes at a protected uri
409: * <p/>
410: * Retrieves the URL if a username and password are provided.
411: * The java.net.URL class does not do Basic Authentication, so we have to
412: * do it manually in this routine.
413: * <p/>
414: * If no username is provided, creates an InputSource from the uri
415: * and lets the InputSource go fetch the contents.
416: *
417: * @param uri the resource to get
418: * @param username basic auth username
419: * @param password basic auth password
420: */
421: private static InputSource getInputSourceFromURI(String uri,
422: String username, String password) throws IOException,
423: ProtocolException, UnsupportedEncodingException {
424: URL wsdlurl = null;
425: try {
426: wsdlurl = new URL(uri);
427: } catch (MalformedURLException e) {
428: // we can't process it, it might be a 'simple' foo.wsdl
429: // let InputSource deal with it
430: return new InputSource(uri);
431: }
432:
433: // if no authentication, just let InputSource deal with it
434: if (username == null && wsdlurl.getUserInfo() == null) {
435: return new InputSource(uri);
436: }
437:
438: // if this is not an HTTP{S} url, let InputSource deal with it
439: if (!wsdlurl.getProtocol().startsWith("http")) {
440: return new InputSource(uri);
441: }
442:
443: URLConnection connection = wsdlurl.openConnection();
444: // Does this work for https???
445: if (!(connection instanceof HttpURLConnection)) {
446: // can't do http with this URL, let InputSource deal with it
447: return new InputSource(uri);
448: }
449: HttpURLConnection uconn = (HttpURLConnection) connection;
450: String userinfo = wsdlurl.getUserInfo();
451: uconn.setRequestMethod("GET");
452: uconn.setAllowUserInteraction(false);
453: uconn.setDefaultUseCaches(false);
454: uconn.setDoInput(true);
455: uconn.setDoOutput(false);
456: uconn.setInstanceFollowRedirects(true);
457: uconn.setUseCaches(false);
458:
459: // username/password info in the URL overrides passed in values
460: String auth = null;
461: if (userinfo != null) {
462: auth = userinfo;
463: } else if (username != null) {
464: auth = (password == null) ? username : username + ":"
465: + password;
466: }
467:
468: if (auth != null) {
469: uconn.setRequestProperty("Authorization", "Basic "
470: + base64encode(auth.getBytes(charEncoding)));
471: }
472:
473: uconn.connect();
474:
475: return new InputSource(uconn.getInputStream());
476: }
477:
478: public static String base64encode(byte[] bytes) {
479: return Base64.encode(bytes);
480: }
481:
482: public static InputSource getEmptyInputSource() {
483: return new InputSource(bais);
484: }
485:
486: /**
487: * Finds a Node with a given QNameb.
488: *
489: * @param node parent node
490: * @param name QName of the child we need to find
491: * @return Returns child node.
492: */
493: public static Node findNode(Node node, QName name) {
494: if (name.getNamespaceURI().equals(node.getNamespaceURI())
495: && name.getLocalPart().equals(node.getLocalName())) {
496: return node;
497: }
498: NodeList children = node.getChildNodes();
499: for (int i = 0; i < children.getLength(); i++) {
500: Node ret = findNode(children.item(i), name);
501: if (ret != null) {
502: return ret;
503: }
504: }
505: return null;
506: }
507:
508: /**
509: * Converts a given DOM Element to an OMElement.
510: *
511: * @param element
512: * @return Returns OMElement.
513: * @throws Exception
514: */
515: public static OMElement toOM(Element element) throws Exception {
516:
517: Source source = new DOMSource(element);
518:
519: ByteArrayOutputStream baos = new ByteArrayOutputStream();
520: Result result = new StreamResult(baos);
521:
522: Transformer xformer = TransformerFactory.newInstance()
523: .newTransformer();
524: xformer.transform(source, result);
525:
526: ByteArrayInputStream is = new ByteArrayInputStream(baos
527: .toByteArray());
528: XMLStreamReader reader = StAXUtils.createXMLStreamReader(is);
529:
530: StAXOMBuilder builder = new StAXOMBuilder(reader);
531: builder.setCache(true);
532:
533: return builder.getDocumentElement();
534: }
535:
536: /**
537: * Converts a given OMElement to a DOM Element.
538: *
539: * @param element
540: * @return Returns Element.
541: * @throws Exception
542: */
543: public static Element toDOM(OMElement element) throws Exception {
544: ByteArrayOutputStream baos = new ByteArrayOutputStream();
545: element.serialize(baos);
546: ByteArrayInputStream bais = new ByteArrayInputStream(baos
547: .toByteArray());
548:
549: DocumentBuilderFactory factory = DocumentBuilderFactory
550: .newInstance();
551: factory.setNamespaceAware(true);
552: return factory.newDocumentBuilder().parse(bais)
553: .getDocumentElement();
554: }
555:
556: /**
557: * Converts a given inputstream to an OMNode
558: *
559: * @param inputStream
560: * @return
561: * @throws javax.xml.stream.XMLStreamException
562: *
563: */
564: public static OMNode toOM(InputStream inputStream)
565: throws XMLStreamException {
566: XMLStreamReader xmlReader = StAXUtils
567: .createXMLStreamReader(inputStream);
568: OMFactory fac = OMAbstractFactory.getOMFactory();
569: StAXOMBuilder staxOMBuilder = new StAXOMBuilder(fac, xmlReader);
570: return staxOMBuilder.getDocumentElement();
571: }
572:
573: /**
574: * Converts a given Reader to an OMNode
575: *
576: * @param reader
577: * @return
578: * @throws XMLStreamException
579: */
580: public static OMNode toOM(Reader reader) throws XMLStreamException {
581: XMLStreamReader xmlReader = StAXUtils
582: .createXMLStreamReader(reader);
583: OMFactory fac = OMAbstractFactory.getOMFactory();
584: StAXOMBuilder staxOMBuilder = new StAXOMBuilder(fac, xmlReader);
585: return staxOMBuilder.getDocumentElement();
586: }
587: }
|