Source code: org/apache/axis/utils/XMLUtils.java
1 /*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.axis.utils ;
18
19 import org.apache.axis.AxisEngine;
20 import org.apache.axis.Constants;
21 import org.apache.axis.InternalException;
22 import org.apache.axis.Message;
23 import org.apache.axis.MessageContext;
24 import org.apache.axis.AxisProperties;
25 import org.apache.axis.components.encoding.XMLEncoder;
26 import org.apache.axis.components.encoding.XMLEncoderFactory;
27 import org.apache.axis.components.logger.LogFactory;
28 import org.apache.commons.logging.Log;
29 import org.w3c.dom.Attr;
30 import org.w3c.dom.CharacterData;
31 import org.w3c.dom.Document;
32 import org.w3c.dom.Element;
33 import org.w3c.dom.NamedNodeMap;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.NodeList;
36 import org.w3c.dom.Text;
37 import org.xml.sax.ErrorHandler;
38 import org.xml.sax.InputSource;
39 import org.xml.sax.SAXException;
40 import org.xml.sax.SAXParseException;
41 import org.xml.sax.XMLReader;
42 import org.xml.sax.helpers.DefaultHandler;
43
44 import javax.xml.namespace.QName;
45 import javax.xml.parsers.DocumentBuilder;
46 import javax.xml.parsers.DocumentBuilderFactory;
47 import javax.xml.parsers.ParserConfigurationException;
48 import javax.xml.parsers.SAXParser;
49 import javax.xml.parsers.SAXParserFactory;
50 import javax.xml.soap.SOAPException;
51 import javax.xml.soap.SOAPMessage;
52 import javax.xml.transform.Source;
53 import javax.xml.transform.dom.DOMSource;
54 import javax.xml.transform.sax.SAXSource;
55 import javax.xml.transform.stream.StreamSource;
56 import java.io.ByteArrayInputStream;
57 import java.io.ByteArrayOutputStream;
58 import java.io.IOException;
59 import java.io.InputStream;
60 import java.io.OutputStream;
61 import java.io.OutputStreamWriter;
62 import java.io.StringWriter;
63 import java.io.UnsupportedEncodingException;
64 import java.io.Writer;
65 import java.net.HttpURLConnection;
66 import java.net.MalformedURLException;
67 import java.net.ProtocolException;
68 import java.net.URL;
69 import java.net.URLConnection;
70 import java.util.Iterator;
71 import java.util.List;
72 import java.util.Stack;
73
74
75 public class XMLUtils {
76 protected static Log log =
77 LogFactory.getLog(XMLUtils.class.getName());
78
79 public static final String httpAuthCharEncoding = "ISO-8859-1";
80 private static final String saxParserFactoryProperty =
81 "javax.xml.parsers.SAXParserFactory";
82
83 private static DocumentBuilderFactory dbf = getDOMFactory();
84 private static SAXParserFactory saxFactory;
85 private static Stack saxParsers = new Stack();
86 private static DefaultHandler doNothingContentHandler = new DefaultHandler();
87
88 private static String EMPTY = "";
89 private static ByteArrayInputStream bais = new ByteArrayInputStream(EMPTY.getBytes());
90
91 private static boolean tryReset= true;
92
93 protected static boolean enableParserReuse = false;
94
95 private static class ThreadLocalDocumentBuilder extends ThreadLocal {
96 protected Object initialValue() {
97 try {
98 return getDOMFactory().newDocumentBuilder();
99 } catch (ParserConfigurationException e) {
100 log.error(Messages.getMessage("parserConfigurationException00"),
101 e);
102 }
103 return null;
104 }
105 }
106 private static ThreadLocalDocumentBuilder documentBuilder = new ThreadLocalDocumentBuilder();
107
108 static {
109 // Initialize SAX Parser factory defaults
110 initSAXFactory(null, true, false);
111
112 String value = AxisProperties.getProperty(AxisEngine.PROP_XML_REUSE_SAX_PARSERS,
113 "" + false);
114 if (value.equalsIgnoreCase("true") ||
115 value.equals("1") ||
116 value.equalsIgnoreCase("yes")) {
117 enableParserReuse = true;
118 } else {
119 enableParserReuse = false;
120 }
121 }
122
123 /**
124 * Encode a string appropriately for XML.
125 * @param orig the String to encode
126 * @return a String in which XML special chars are repalced by entities
127 */
128 public static String xmlEncodeString(String orig)
129 {
130 XMLEncoder encoder = getXMLEncoder(MessageContext.getCurrentContext());
131 return encoder.encode(orig);
132 }
133
134 /**
135 * Get the current XMLEncoder
136 * @return XMLEncoder
137 */
138 public static XMLEncoder getXMLEncoder(MessageContext msgContext) {
139 return getXMLEncoder(getEncoding(null, msgContext));
140 }
141
142 /**
143 * Get the XMLEncoder for specific encoding
144 * @return XMLEncoder
145 */
146 public static XMLEncoder getXMLEncoder(String encoding) {
147 XMLEncoder encoder = null;
148 try {
149 encoder = XMLEncoderFactory.getEncoder(encoding);
150 } catch (Exception e) {
151 log.error(Messages.getMessage("exception00"), e);
152 encoder = XMLEncoderFactory.getDefaultEncoder();
153 }
154 return encoder;
155 }
156
157 /**
158 * Get the current encoding in effect
159 * @return string
160 */
161 public static String getEncoding(MessageContext msgContext) {
162 XMLEncoder encoder = getXMLEncoder(msgContext);
163 return encoder.getEncoding();
164 }
165
166 /**
167 * Get the current encoding in effect
168 * @return string
169 */
170 public static String getEncoding() {
171 XMLEncoder encoder = getXMLEncoder(MessageContext.getCurrentContext());
172 return encoder.getEncoding();
173 }
174
175 /** Initialize the SAX parser factory.
176 *
177 * @param factoryClassName The (optional) class name of the desired
178 * SAXParserFactory implementation. Will be
179 * assigned to the system property
180 * <b>javax.xml.parsers.SAXParserFactory</b>
181 * unless this property is already set.
182 * If <code>null</code>, leaves current setting
183 * alone.
184 * @param namespaceAware true if we want a namespace-aware parser
185 * @param validating true if we want a validating parser
186 *
187 */
188 public static void initSAXFactory(String factoryClassName,
189 boolean namespaceAware,
190 boolean validating)
191 {
192 if (factoryClassName != null) {
193 try {
194 saxFactory = (SAXParserFactory)Class.forName(factoryClassName).
195 newInstance();
196 /*
197 * Set the system property only if it is not already set to
198 * avoid corrupting environments in which Axis is embedded.
199 */
200 if (System.getProperty(saxParserFactoryProperty) == null) {
201 System.setProperty(saxParserFactoryProperty,
202 factoryClassName);
203 }
204 } catch (Exception e) {
205 log.error(Messages.getMessage("exception00"), e);
206 saxFactory = null;
207 }
208 } else {
209 saxFactory = SAXParserFactory.newInstance();
210 }
211 saxFactory.setNamespaceAware(namespaceAware);
212 saxFactory.setValidating(validating);
213
214 // Discard existing parsers
215 saxParsers.clear();
216 }
217
218 private static DocumentBuilderFactory getDOMFactory() {
219 DocumentBuilderFactory dbf;
220 try {
221 dbf = DocumentBuilderFactory.newInstance();
222 dbf.setNamespaceAware(true);
223 }
224 catch( Exception e ) {
225 log.error(Messages.getMessage("exception00"), e );
226 dbf = null;
227 }
228 return( dbf );
229 }
230
231 /**
232 * Gets a DocumentBuilder
233 * @return DocumentBuilder
234 * @throws ParserConfigurationException
235 */
236 public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException {
237 return (DocumentBuilder) documentBuilder.get();
238 }
239
240 /**
241 * Releases a DocumentBuilder
242 * @param db
243 */
244 public static void releaseDocumentBuilder(DocumentBuilder db) {
245 try {
246 db.setErrorHandler(null); // setting implementation default
247 } catch (Throwable t) {
248 log.debug("Failed to set ErrorHandler to null on DocumentBuilder",
249 t);
250 }
251 try {
252 db.setEntityResolver(null); // setting implementation default
253 } catch (Throwable t) {
254 log.debug("Failed to set EntityResolver to null on DocumentBuilder",
255 t);
256 }
257 }
258
259 /** Get a SAX parser instance from the JAXP factory.
260 *
261 * @return a SAXParser instance.
262 */
263 public static synchronized SAXParser getSAXParser() {
264 if(enableParserReuse && !saxParsers.empty()) {
265 return (SAXParser )saxParsers.pop();
266 }
267
268 try {
269 SAXParser parser = saxFactory.newSAXParser();
270 XMLReader reader = parser.getXMLReader();
271 // parser.getParser().setEntityResolver(new DefaultEntityResolver());
272 // The above commented line and the following line are added
273 // for preventing XXE (bug #14105).
274 // We may need to uncomment the deprecated setting
275 // in case that it is considered necessary.
276 try {
277 reader.setEntityResolver(new DefaultEntityResolver());
278 } catch (Throwable t) {
279 log.debug("Failed to set EntityResolver on DocumentBuilder", t);
280 }
281 reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
282 return parser;
283 } catch (ParserConfigurationException e) {
284 log.error(Messages.getMessage("parserConfigurationException00"), e);
285 return null;
286 } catch (SAXException se) {
287 log.error(Messages.getMessage("SAXException00"), se);
288 return null;
289 }
290 }
291
292
293 /** Return a SAX parser for reuse.
294 * @param parser A SAX parser that is available for reuse
295 */
296 public static void releaseSAXParser(SAXParser parser) {
297 if(!tryReset || !enableParserReuse) return;
298
299 //Free up possible ref. held by past contenthandler.
300 try{
301 XMLReader xmlReader= parser.getXMLReader();
302 if(null != xmlReader){
303 xmlReader.setContentHandler(doNothingContentHandler);
304 xmlReader.setDTDHandler(doNothingContentHandler);
305 try {
306 xmlReader.setEntityResolver(doNothingContentHandler);
307 } catch (Throwable t) {
308 log.debug("Failed to set EntityResolver on DocumentBuilder", t);
309 }
310 try {
311 xmlReader.setErrorHandler(doNothingContentHandler);
312 } catch (Throwable t) {
313 log.debug("Failed to set ErrorHandler on DocumentBuilder", t);
314 }
315
316 synchronized (XMLUtils.class ) {
317 saxParsers.push(parser);
318 }
319 }
320 else {
321 tryReset= false;
322 }
323 } catch (org.xml.sax.SAXException e) {
324 tryReset= false;
325 }
326 }
327 /**
328 * Get an empty new Document
329 *
330 * @return Document
331 * @throws ParserConfigurationException if construction problems occur
332 */
333 public static Document newDocument()
334 throws ParserConfigurationException {
335 DocumentBuilder db = null;
336 try {
337 db = getDocumentBuilder();
338 Document doc = db.newDocument();
339 return doc;
340 } finally {
341 if (db != null) {
342 releaseDocumentBuilder(db);
343 }
344 }
345 }
346
347 /**
348 * Get a new Document read from the input source
349 * @return Document
350 * @throws ParserConfigurationException if construction problems occur
351 * @throws SAXException if the document has xml sax problems
352 * @throws IOException if i/o exceptions occur
353 */
354 public static Document newDocument(InputSource inp)
355 throws ParserConfigurationException, SAXException, IOException {
356 DocumentBuilder db = null;
357 try {
358 db = getDocumentBuilder();
359 try {
360 db.setEntityResolver(new DefaultEntityResolver());
361 } catch (Throwable t) {
362 log.debug("Failed to set EntityResolver on DocumentBuilder", t);
363 }
364 try {
365 db.setErrorHandler(new XMLUtils.ParserErrorHandler());
366 } catch (Throwable t) {
367 log.debug("Failed to set ErrorHandler on DocumentBuilder", t);
368 }
369 Document doc = db.parse(inp);
370 return doc;
371 } finally {
372 if (db != null) {
373 releaseDocumentBuilder(db);
374 }
375 }
376 }
377
378 /**
379 * Get a new Document read from the input stream
380 * @return Document
381 * @throws ParserConfigurationException if construction problems occur
382 * @throws SAXException if the document has xml sax problems
383 * @throws IOException if i/o exceptions occur
384 */
385 public static Document newDocument(InputStream inp)
386 throws ParserConfigurationException, SAXException, IOException
387 {
388 return XMLUtils.newDocument(new InputSource(inp));
389 }
390
391 /**
392 * Get a new Document read from the indicated uri
393 * @return Document
394 * @throws ParserConfigurationException if construction problems occur
395 * @throws SAXException if the document has xml sax problems
396 * @throws IOException if i/o exceptions occur
397 */
398 public static Document newDocument(String uri)
399 throws ParserConfigurationException, SAXException, IOException
400 {
401 // call the authenticated version as there might be
402 // username/password info embeded in the uri.
403 return XMLUtils.newDocument(uri, null, null);
404 }
405
406 /**
407 * Create a new document from the given URI, use the username and password
408 * if the URI requires authentication.
409 * @param uri the resource to get
410 * @param username basic auth username
411 * @param password basic auth password
412 * @throws ParserConfigurationException if construction problems occur
413 * @throws SAXException if the document has xml sax problems
414 * @throws IOException if i/o exceptions occur
415 */
416 public static Document newDocument(String uri, String username, String password)
417 throws ParserConfigurationException, SAXException, IOException
418 {
419 InputSource ins = XMLUtils.getInputSourceFromURI(uri, username, password);
420 Document doc = XMLUtils.newDocument(ins);
421 // Close the Stream
422 if (ins.getByteStream() != null) {
423 ins.getByteStream().close();
424 } else if (ins.getCharacterStream() != null) {
425 ins.getCharacterStream().close();
426 }
427 return doc;
428 }
429
430 private static String privateElementToString(Element element,
431 boolean omitXMLDecl)
432 {
433 return DOM2Writer.nodeToString(element, omitXMLDecl);
434 }
435
436 /**
437 * turn an element into an XML fragment
438 * @param element
439 * @return stringified element
440 */
441 public static String ElementToString(Element element) {
442 return privateElementToString(element, true);
443 }
444
445 /**
446 * turn a whole DOM document into XML
447 * @param doc DOM document
448 * @return string representation of the document, including XML declaration
449 */
450 public static String DocumentToString(Document doc) {
451 return privateElementToString(doc.getDocumentElement(), false);
452 }
453
454 public static String PrettyDocumentToString(Document doc) {
455 StringWriter sw = new StringWriter();
456 PrettyElementToWriter(doc.getDocumentElement(), sw);
457 return sw.toString();
458 }
459
460 public static void privateElementToWriter(Element element, Writer writer,
461 boolean omitXMLDecl,
462 boolean pretty) {
463 DOM2Writer.serializeAsXML(element, writer, omitXMLDecl, pretty);
464 }
465
466 public static void ElementToStream(Element element, OutputStream out) {
467 Writer writer = getWriter(out);
468 privateElementToWriter(element, writer, true, false);
469 }
470
471 public static void PrettyElementToStream(Element element, OutputStream out) {
472 Writer writer = getWriter(out);
473 privateElementToWriter(element, writer, true, true);
474 }
475
476 public static void ElementToWriter(Element element, Writer writer) {
477 privateElementToWriter(element, writer, true, false);
478 }
479
480 public static void PrettyElementToWriter(Element element, Writer writer) {
481 privateElementToWriter(element, writer, true, true);
482 }
483
484 public static void DocumentToStream(Document doc, OutputStream out) {
485 Writer writer = getWriter(out);
486 privateElementToWriter(doc.getDocumentElement(), writer, false, false);
487 }
488
489 public static void PrettyDocumentToStream(Document doc, OutputStream out) {
490 Writer writer = getWriter(out);
491 privateElementToWriter(doc.getDocumentElement(), writer, false, true);
492 }
493
494 private static Writer getWriter(OutputStream os) {
495 Writer writer = null;
496 try {
497 writer = new OutputStreamWriter(os, "UTF-8");
498 } catch (UnsupportedEncodingException uee) {
499 log.error(Messages.getMessage("exception00"), uee);
500 writer = new OutputStreamWriter(os);
501 }
502 return writer;
503 }
504
505 public static void DocumentToWriter(Document doc, Writer writer) {
506 privateElementToWriter(doc.getDocumentElement(), writer, false, false);
507 }
508
509 public static void PrettyDocumentToWriter(Document doc, Writer writer) {
510 privateElementToWriter(doc.getDocumentElement(), writer, false, true);
511 }
512 /**
513 * Convert a simple string to an element with a text node
514 *
515 * @param namespace - element namespace
516 * @param name - element name
517 * @param string - value of the text node
518 * @return element - an XML Element, null if no element was created
519 */
520 public static Element StringToElement(String namespace, String name, String string) {
521 try {
522 Document doc = XMLUtils.newDocument();
523 Element element = doc.createElementNS(namespace, name);
524 Text text = doc.createTextNode(string);
525 element.appendChild(text);
526 return element;
527 }
528 catch (ParserConfigurationException e) {
529 // This should not occur
530 throw new InternalException(e);
531 }
532 }
533
534 /**
535 * get the inner XML inside an element as a string. This is done by
536 * converting the XML to its string representation, then extracting the
537 * subset between beginning and end tags.
538 * @param element
539 * @return textual body of the element, or null for no inner body
540 */
541 public static String getInnerXMLString(Element element) {
542 String elementString = ElementToString(element);
543 int start, end;
544 start = elementString.indexOf(">") + 1;
545 end = elementString.lastIndexOf("</");
546 if (end > 0)
547 return elementString.substring(start,end);
548 else
549 return null;
550 }
551
552 public static String getPrefix(String uri, Node e) {
553 while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) {
554 NamedNodeMap attrs = e.getAttributes();
555 for (int n = 0; n < attrs.getLength(); n++) {
556 Attr a = (Attr)attrs.item(n);
557 String name;
558 if ((name = a.getName()).startsWith("xmlns:") &&
559 a.getNodeValue().equals(uri)) {
560 return name.substring(6);
561 }
562 }
563 e = e.getParentNode();
564 }
565 return null;
566 }
567
568 /**
569 * Searches for the namespace URI of the given prefix in the given DOM range.
570 *
571 * The namespace is not searched in parent of the "stopNode". This is
572 * usefull to get all the needed namespaces when you need to ouput only a
573 * subtree of a DOM document.
574 *
575 * @param prefix the prefix to find
576 * @param e the starting node
577 * @param stopNode null to search in all the document or a parent node where the search must stop.
578 * @return null if no namespace is found, or the namespace URI.
579 */
580 public static String getNamespace(String prefix, Node e, Node stopNode) {
581 while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) {
582 Attr attr = null;
583 if (prefix == null) {
584 attr = ((Element) e).getAttributeNode("xmlns");
585 } else {
586 attr = ((Element) e).getAttributeNodeNS(Constants.NS_URI_XMLNS,
587 prefix);
588 }
589 if (attr != null) return attr.getValue();
590 if (e == stopNode)
591 return null;
592 e = e.getParentNode();
593 }
594 return null;
595 }
596
597 public static String getNamespace(String prefix, Node e) {
598 return getNamespace(prefix, e, null);
599 }
600
601 /**
602 * Return a QName when passed a string like "foo:bar" by mapping
603 * the "foo" prefix to a namespace in the context of the given Node.
604 *
605 * @return a QName generated from the given string representation
606 */
607 public static QName getQNameFromString(String str, Node e) {
608 return getQNameFromString(str, e, false);
609 }
610 /**
611 * Return a QName when passed a string like "foo:bar" by mapping
612 * the "foo" prefix to a namespace in the context of the given Node.
613 * If default namespace is found it is returned as part of the QName.
614 *
615 * @return a QName generated from the given string representation
616 */
617 public static QName getFullQNameFromString(String str, Node e) {
618 return getQNameFromString(str, e, true);
619 }
620 private static QName getQNameFromString(String str, Node e, boolean defaultNS) {
621 if (str == null || e == null)
622 return null;
623
624 int idx = str.indexOf(':');
625 if (idx > -1) {
626 String prefix = str.substring(0, idx);
627 String ns = getNamespace(prefix, e);
628 if (ns == null)
629 return null;
630 return new QName(ns, str.substring(idx + 1));
631 } else {
632 if (defaultNS) {
633 String ns = getNamespace(null, e);
634 if (ns != null)
635 return new QName(ns, str);
636 }
637 return new QName("", str);
638 }
639 }
640
641 /**
642 * Return a string for a particular QName, mapping a new prefix
643 * if necessary.
644 */
645 public static String getStringForQName(QName qname, Element e)
646 {
647 String uri = qname.getNamespaceURI();
648 String prefix = getPrefix(uri, e);
649 if (prefix == null) {
650 int i = 1;
651 prefix = "ns" + i;
652 while (getNamespace(prefix, e) != null) {
653 i++;
654 prefix = "ns" + i;
655 }
656 e.setAttributeNS(Constants.NS_URI_XMLNS,
657 "xmlns:" + prefix, uri);
658 }
659 return prefix + ":" + qname.getLocalPart();
660 }
661
662 /**
663 * Concat all the text and cdata node children of this elem and return
664 * the resulting text.
665 * (by Matt Duftler)
666 *
667 * @param parentEl the element whose cdata/text node values are to
668 * be combined.
669 * @return the concatanated string.
670 */
671 public static String getChildCharacterData (Element parentEl) {
672 if (parentEl == null) {
673 return null;
674 }
675 Node tempNode = parentEl.getFirstChild();
676 StringBuffer strBuf = new StringBuffer();
677 CharacterData charData;
678
679 while (tempNode != null) {
680 switch (tempNode.getNodeType()) {
681 case Node.TEXT_NODE :
682 case Node.CDATA_SECTION_NODE : charData = (CharacterData)tempNode;
683 strBuf.append(charData.getData());
684 break;
685 }
686 tempNode = tempNode.getNextSibling();
687 }
688 return strBuf.toString();
689 }
690
691 public static class ParserErrorHandler implements ErrorHandler {
692 protected static Log log =
693 LogFactory.getLog(ParserErrorHandler.class.getName());
694 /**
695 * Returns a string describing parse exception details
696 */
697 private String getParseExceptionInfo(SAXParseException spe) {
698 String systemId = spe.getSystemId();
699 if (systemId == null) {
700 systemId = "null";
701 }
702 String info = "URI=" + systemId +
703 " Line=" + spe.getLineNumber() +
704 ": " + spe.getMessage();
705 return info;
706 }
707
708 // The following methods are standard SAX ErrorHandler methods.
709 // See SAX documentation for more info.
710
711 public void warning(SAXParseException spe) throws SAXException {
712 if (log.isDebugEnabled())
713 log.debug( Messages.getMessage("warning00", getParseExceptionInfo(spe)));
714 }
715
716 public void error(SAXParseException spe) throws SAXException {
717 String message = "Error: " + getParseExceptionInfo(spe);
718 throw new SAXException(message);
719 }
720
721 public void fatalError(SAXParseException spe) throws SAXException {
722 String message = "Fatal Error: " + getParseExceptionInfo(spe);
723 throw new SAXException(message);
724 }
725 }
726
727
728 /**
729 * Utility to get the bytes uri.
730 * Does NOT handle authenticated URLs,
731 * use getInputSourceFromURI(uri, username, password)
732 *
733 * @param uri the resource to get
734 * @see #getInputSourceFromURI(String uri, String username, String password)
735 */
736 public static InputSource getInputSourceFromURI(String uri) {
737 return new InputSource(uri);
738 }
739
740 /**
741 * Utility to get the bytes uri
742 *
743 * @param source the resource to get
744 */
745 public static InputSource sourceToInputSource(Source source) {
746 if (source instanceof SAXSource) {
747 return ((SAXSource) source).getInputSource();
748 } else if (source instanceof DOMSource) {
749 ByteArrayOutputStream baos = new ByteArrayOutputStream();
750 Node node = ((DOMSource)source).getNode();
751 if (node instanceof Document) {
752 node = ((Document)node).getDocumentElement();
753 }
754 Element domElement = (Element)node;
755 ElementToStream(domElement, baos);
756 InputSource isource = new InputSource(source.getSystemId());
757 isource.setByteStream(new ByteArrayInputStream(baos.toByteArray()));
758 return isource;
759 } else if (source instanceof StreamSource) {
760 StreamSource ss = (StreamSource) source;
761 InputSource isource = new InputSource(ss.getSystemId());
762 isource.setByteStream(ss.getInputStream());
763 isource.setCharacterStream(ss.getReader());
764 isource.setPublicId(ss.getPublicId());
765 return isource;
766 } else {
767 return getInputSourceFromURI(source.getSystemId());
768 }
769 }
770
771 /**
772 * Utility to get the bytes at a protected uri
773 *
774 * This will retrieve the URL if a username and password are provided.
775 * The java.net.URL class does not do Basic Authentication, so we have to
776 * do it manually in this routine.
777 *
778 * If no username is provided, we create an InputSource from the uri
779 * and let the InputSource go fetch the contents.
780 *
781 * @param uri the resource to get
782 * @param username basic auth username
783 * @param password basic auth password
784 */
785 private static InputSource getInputSourceFromURI(String uri,
786 String username,
787 String password)
788 throws IOException, ProtocolException, UnsupportedEncodingException
789 {
790 URL wsdlurl = null;
791 try {
792 wsdlurl = new URL(uri);
793 } catch (MalformedURLException e) {
794 // we can't process it, it might be a 'simple' foo.wsdl
795 // let InputSource deal with it
796 return new InputSource(uri);
797 }
798
799 // if no authentication, just let InputSource deal with it
800 if (username == null && wsdlurl.getUserInfo() == null) {
801 return new InputSource(uri);
802 }
803
804 // if this is not an HTTP{S} url, let InputSource deal with it
805 if (!wsdlurl.getProtocol().startsWith("http")) {
806 return new InputSource(uri);
807 }
808
809 URLConnection connection = wsdlurl.openConnection();
810 // Does this work for https???
811 if (!(connection instanceof HttpURLConnection)) {
812 // can't do http with this URL, let InputSource deal with it
813 return new InputSource(uri);
814 }
815 HttpURLConnection uconn = (HttpURLConnection) connection;
816 String userinfo = wsdlurl.getUserInfo();
817 uconn.setRequestMethod("GET");
818 uconn.setAllowUserInteraction(false);
819 uconn.setDefaultUseCaches(false);
820 uconn.setDoInput(true);
821 uconn.setDoOutput(false);
822 uconn.setInstanceFollowRedirects(true);
823 uconn.setUseCaches(false);
824
825 // username/password info in the URL overrides passed in values
826 String auth = null;
827 if (userinfo != null) {
828 auth = userinfo;
829 } else if (username != null) {
830 auth = (password == null) ? username : username + ":" + password;
831 }
832
833 if (auth != null) {
834 uconn.setRequestProperty("Authorization",
835 "Basic " +
836 base64encode(auth.getBytes(httpAuthCharEncoding)));
837 }
838
839 uconn.connect();
840
841 return new InputSource(uconn.getInputStream());
842 }
843
844 public static final String base64encode(byte[] bytes) {
845 return new String(Base64.encode(bytes));
846 }
847
848 public static InputSource getEmptyInputSource() {
849 return new InputSource(bais);
850 }
851
852 /**
853 * Find a Node with a given QName
854 *
855 * @param node parent node
856 * @param name QName of the child we need to find
857 * @return child node
858 */
859 public static Node findNode(Node node, QName name){
860 if(name.getNamespaceURI().equals(node.getNamespaceURI()) &&
861 name.getLocalPart().equals(node.getLocalName()))
862 return node;
863 NodeList children = node.getChildNodes();
864 for(int i=0;i<children.getLength();i++){
865 Node ret = findNode(children.item(i), name);
866 if(ret != null)
867 return ret;
868 }
869 return null;
870 }
871
872 /**
873 * Trim all new lines from text nodes.
874 *
875 * @param node
876 */
877 public static void normalize(Node node) {
878 if (node.getNodeType() == Node.TEXT_NODE) {
879 String data = ((Text) node).getData();
880 if (data.length() > 0) {
881 char ch = data.charAt(data.length()-1);
882 if(ch == '\n' || ch == '\r' || ch == ' ') {
883 String data2 = trim(data);
884 ((Text) node).setData(data2);
885 }
886 }
887 }
888 for (Node currentChild = node.getFirstChild(); currentChild != null; currentChild = currentChild.getNextSibling()) {
889 normalize(currentChild);
890 }
891 }
892
893 public static String trim(String str) {
894 if (str.length() == 0) {
895 return str;
896 }
897
898 if (str.length() == 1) {
899 if ("\r".equals(str) || "\n".equals(str)) {
900 return "";
901 } else {
902 return str;
903 }
904 }
905
906 int lastIdx = str.length() - 1;
907 char last = str.charAt(lastIdx);
908 while(lastIdx > 0) {
909 if(last != '\n' && last != '\r' && last != ' ')
910 break;
911 lastIdx--;
912 last = str.charAt(lastIdx);
913 }
914 if(lastIdx == 0)
915 return "";
916 return str.substring(0, lastIdx);
917 }
918
919 /**
920 * Converts a List with org.w3c.dom.Element objects to an Array
921 * with org.w3c.dom.Element objects.
922 * @param list List containing org.w3c.dom.Element objects
923 * @return Element[] Array with org.w3c.dom.Element objects
924 */
925 public static Element[] asElementArray(List list) {
926
927 Element[] elements = new Element[list.size()];
928
929 int i = 0;
930 Iterator detailIter = list.iterator();
931 while (detailIter.hasNext()) {
932 elements[i++] = (Element) detailIter.next();
933 }
934
935 return elements;
936 }
937
938 public static String getEncoding(Message message,
939 MessageContext msgContext) {
940 return getEncoding(message, msgContext,
941 XMLEncoderFactory.getDefaultEncoder());
942 }
943
944 public static String getEncoding(Message message,
945 MessageContext msgContext,
946 XMLEncoder defaultEncoder) {
947 String encoding = null;
948 try {
949 if(message != null) {
950 encoding = (String) message.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
951 }
952 } catch (SOAPException e) {
953 }
954 if(msgContext == null) {
955 msgContext = MessageContext.getCurrentContext();
956 }
957 if(msgContext != null && encoding == null){
958 encoding = (String) msgContext.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
959 }
960 if (msgContext != null && encoding == null && msgContext.getAxisEngine() != null) {
961 encoding = (String) msgContext.getAxisEngine().getOption(AxisEngine.PROP_XML_ENCODING);
962 }
963 if (encoding == null && defaultEncoder != null) {
964 encoding = defaultEncoder.getEncoding();
965 }
966 return encoding;
967 }
968 }