Could you please open a bug report with a "diff -u" against latest XMLUtils.java?
thanks, dims On Mon, 06 Dec 2004 16:40:34 +0100, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote: > Hi, > > While doing performance tests on deserialization, I noticed that Axis > scales very poorly when increasing the number of threads. > > Here are the figures: > 5 threads, 1000 messages: 15 seconds > 10 threads, 1000 messages: 56 seconds > 15 threads, 1000 messages: 93 seconds > > The root of the problem is in XMLUtils. Each time a node is created via > the static fuction newDocument(...), there are two functions, > getDocumentBuilder() and realeaseDocumentBuilder(), called which both > peform synchronisation over a pool of document builders > (documentBuilders ). Since XML documents contain many nodes and there > are at least two synchronization points in the code per node created, I > let you imagine the overhead suffered when more threads come into play. > > I was able to achieve a significant performance boost by replacing the > pool of DocumentBuilders (documentBuilders) by a single document builder > stored in a ThreadLocal variable. This was already suggested a while ago > in this mailing list (see "Performance Issues with AXIS & Axis Response > time appears linear with load"). > > The results of my benchmark with the changes brought to the code are > shown below. > > 5 threads, 1000 messages: 13seconds > 10 threads, 1000 messages: 25,5 seconds > 15 threads, 1000 messages: 37 seconds > > As you can see, deserialization time scales now linearly with the number > of threads which is a lot better. I placed the code in attachment. Could > you include sth equivalent in the next release of the Axis. > > Thanks, > Sebastien > > > /* > * Copyright 2001-2004 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.axis.utils ; > > import org.apache.axis.AxisEngine; > import org.apache.axis.Constants; > import org.apache.axis.InternalException; > import org.apache.axis.Message; > import org.apache.axis.MessageContext; > import org.apache.axis.AxisProperties; > import org.apache.axis.components.encoding.XMLEncoder; > import org.apache.axis.components.encoding.XMLEncoderFactory; > import org.apache.axis.components.logger.LogFactory; > import org.apache.commons.logging.Log; > 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.w3c.dom.Text; > 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 org.xml.sax.helpers.DefaultHandler; > > 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.soap.SOAPException; > import javax.xml.soap.SOAPMessage; > import javax.xml.transform.Source; > import javax.xml.transform.dom.DOMSource; > import javax.xml.transform.sax.SAXSource; > import javax.xml.transform.stream.StreamSource; > import java.io.ByteArrayInputStream; > import java.io.ByteArrayOutputStream; > import java.io.IOException; > import java.io.InputStream; > import java.io.OutputStream; > import java.io.OutputStreamWriter; > import java.io.StringWriter; > import java.io.UnsupportedEncodingException; > import java.io.Writer; > import java.net.HttpURLConnection; > import java.net.MalformedURLException; > import java.net.ProtocolException; > import java.net.URL; > import java.net.URLConnection; > import java.util.Iterator; > import java.util.List; > import java.util.Stack; > > public class XMLUtils { > protected static Log log = > LogFactory.getLog(XMLUtils.class.getName()); > > public static final String httpAuthCharEncoding = "ISO-8859-1"; > private static final String saxParserFactoryProperty = > "javax.xml.parsers.SAXParserFactory"; > > // @Alcatel DocumentBuilderFactory is not thread-safe. Place > DocumentBuilder > // in thread local variable to remove synchronization overhead. > > // private static DocumentBuilderFactory dbf = getDOMFactory(); > // private static Stack documentBuilders = new Stack(); > private static class ThreadLocalDocumentBuilder extends ThreadLocal { > protected Object initialValue() { > try { > return getDOMFactory().newDocumentBuilder(); > } catch (ParserConfigurationException e) { > > log.error(Messages.getMessage("parserConfigurationException00"), e); > } > return null; > } > } > private static ThreadLocalDocumentBuilder documentBuilder = new > ThreadLocalDocumentBuilder(); > > private static SAXParserFactory saxFactory; > private static Stack saxParsers = new Stack(); > private static DefaultHandler doNothingContentHandler = new > DefaultHandler(); > > private static String EMPTY = ""; > private static ByteArrayInputStream bais = new > ByteArrayInputStream(EMPTY.getBytes()); > > protected static boolean enableParserReuse = false; > > static { > // Initialize SAX Parser factory defaults > initSAXFactory(null, true, false); > > String value = > AxisProperties.getProperty(AxisEngine.PROP_XML_REUSE_SAX_PARSERS, > "" + false); > if (value.equalsIgnoreCase("true") || > value.equals("1") || > value.equalsIgnoreCase("yes")) { > enableParserReuse = true; > } else { > enableParserReuse = false; > } > } > > /** > * Encode a string appropriately for XML. > * @param orig the String to encode > * @return a String in which XML special chars are repalced by entities > */ > public static String xmlEncodeString(String orig) > { > XMLEncoder encoder = > getXMLEncoder(MessageContext.getCurrentContext()); > return encoder.encode(orig); > } > > /** > * Get the current XMLEncoder > * @return XMLEncoder > */ > public static XMLEncoder getXMLEncoder(MessageContext msgContext) { > XMLEncoder encoder = null; > String encoding = getEncoding(null, msgContext); > try { > encoder = XMLEncoderFactory.getEncoder(encoding); > } catch (Exception e) { > log.error(Messages.getMessage("exception00"), e); > encoder = XMLEncoderFactory.getDefaultEncoder(); > } > return encoder; > } > > /** > * Get the current encoding in effect > * @return string > */ > public static String getEncoding(MessageContext msgContext) { > XMLEncoder encoder = getXMLEncoder(msgContext); > return encoder.getEncoding(); > } > > /** > * Get the current encoding in effect > * @return string > */ > public static String getEncoding() { > XMLEncoder encoder = > getXMLEncoder(MessageContext.getCurrentContext()); > return encoder.getEncoding(); > } > > /** Initialize 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)Class.forName(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; > > /** Get a SAX parser instance from the JAXP factory. > * > * @return a SAXParser instance. > */ > public static synchronized SAXParser getSAXParser() { > if(enableParserReuse && !saxParsers.empty()) { > return (SAXParser )saxParsers.pop(); > } > > try { > SAXParser parser = saxFactory.newSAXParser(); > XMLReader reader = parser.getXMLReader(); > // parser.getParser().setEntityResolver(new > DefaultEntityResolver()); > // The above commented line and the following line are added > // for preventing XXE (bug #14105). > // We may need to uncomment the deprecated setting > // in case that it is considered necessary. > reader.setEntityResolver(new DefaultEntityResolver()); > > reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); > return parser; > } catch (ParserConfigurationException e) { > log.error(Messages.getMessage("parserConfigurationException00"), > e); > return null; > } catch (SAXException se) { > log.error(Messages.getMessage("SAXException00"), se); > return null; > } > } > > /** Return a SAX parser for reuse. > * @param parser A SAX parser that is available for reuse > */ > public static void releaseSAXParser(SAXParser parser) { > if(!tryReset || !enableParserReuse) return; > > //Free up possible ref. held by past contenthandler. > try{ > XMLReader xmlReader= parser.getXMLReader(); > if(null != xmlReader){ > xmlReader.setContentHandler(doNothingContentHandler); > xmlReader.setDTDHandler(doNothingContentHandler); > xmlReader.setEntityResolver(doNothingContentHandler); > xmlReader.setErrorHandler(doNothingContentHandler); > synchronized (XMLUtils.class ) { > saxParsers.push(parser); > } > } > else { > tryReset= false; > } > } catch (org.xml.sax.SAXException e) { > tryReset= false; > } > } > /** > * Get an empty new Document > * > * @return Document > * @throws ParserConfigurationException if construction problems occur > */ > public static Document newDocument() > throws ParserConfigurationException { > DocumentBuilder db = (DocumentBuilder) documentBuilder.get(); > Document doc = db.newDocument(); > return doc; > } > > /** > * Get a new Document read from the input source > * @return 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 = (DocumentBuilder) documentBuilder.get(); > db.setEntityResolver(new DefaultEntityResolver()); > db.setErrorHandler(new ParserErrorHandler()); > Document doc = db.parse(inp); > return doc; > } > > /** > * Get a new Document read from the input stream > * @return 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)); > } > > /** > * Get a new Document read from the indicated uri > * @return 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); > } > > /** > * Create a new document from the given URI, use 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; > } > > private static String privateElementToString(Element element, > boolean omitXMLDecl) > { > return DOM2Writer.nodeToString(element, omitXMLDecl); > } > > /** > * turn an element into an XML fragment > * @param element > * @return stringified element > */ > public static String ElementToString(Element element) { > return privateElementToString(element, true); > } > > /** > * turn a whole DOM document into XML > * @param doc DOM document > * @return string representation of the document, including XML > declaration > */ > public static String DocumentToString(Document doc) { > return privateElementToString(doc.getDocumentElement(), false); > } > > public static String PrettyDocumentToString(Document doc) { > StringWriter sw = new StringWriter(); > PrettyElementToWriter(doc.getDocumentElement(), sw); > return sw.toString(); > } > > public static void privateElementToWriter(Element element, Writer writer, > boolean omitXMLDecl, > boolean pretty) { > DOM2Writer.serializeAsXML(element, writer, omitXMLDecl, pretty); > } > > public static void ElementToStream(Element element, OutputStream out) { > Writer writer = getWriter(out); > privateElementToWriter(element, writer, true, false); > } > > public static void PrettyElementToStream(Element element, OutputStream > out) { > Writer writer = getWriter(out); > privateElementToWriter(element, writer, true, true); > } > > public static void ElementToWriter(Element element, Writer writer) { > privateElementToWriter(element, writer, true, false); > } > > public static void PrettyElementToWriter(Element element, Writer writer) { > privateElementToWriter(element, writer, true, true); > } > > public static void DocumentToStream(Document doc, OutputStream out) { > Writer writer = getWriter(out); > privateElementToWriter(doc.getDocumentElement(), writer, false, > false); > } > > public static void PrettyDocumentToStream(Document doc, OutputStream out) > { > Writer writer = getWriter(out); > privateElementToWriter(doc.getDocumentElement(), writer, false, true); > } > > private static Writer getWriter(OutputStream os) { > Writer writer = null; > try { > writer = new OutputStreamWriter(os, "UTF-8"); > } catch (UnsupportedEncodingException uee) { > log.error(Messages.getMessage("exception00"), uee); > writer = new OutputStreamWriter(os); > } > return writer; > } > > public static void DocumentToWriter(Document doc, Writer writer) { > privateElementToWriter(doc.getDocumentElement(), writer, false, > false); > } > > public static void PrettyDocumentToWriter(Document doc, Writer writer) { > privateElementToWriter(doc.getDocumentElement(), writer, false, true); > } > /** > * Convert a simple string to an element with a text node > * > * @param namespace - element namespace > * @param name - element name > * @param string - value of the text node > * @return element - an XML Element, null if no element was created > */ > public static Element StringToElement(String namespace, String name, > String string) { > try { > Document doc = XMLUtils.newDocument(); > Element element = doc.createElementNS(namespace, name); > Text text = doc.createTextNode(string); > element.appendChild(text); > return element; > } > catch (ParserConfigurationException e) { > // This should not occur > throw new InternalException(e); > } > } > > /** > * get the inner XML inside an element as a string. This is done by > * converting the XML to its string representation, then extracting the > * subset between beginning and end tags. > * @param element > * @return textual body of the element, or null for no inner body > */ > public static String getInnerXMLString(Element element) { > String elementString = ElementToString(element); > int start, end; > start = elementString.indexOf(">") + 1; > end = elementString.lastIndexOf("</"); > if (end > 0) > return elementString.substring(start,end); > else > return null; > } > > 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; > } > > /** > * Searches for the namespace URI of the given prefix in the given DOM > range. > * > * The namespace is not searched in parent of the "stopNode". This is > * usefull to get all the needed namespaces when you need to ouput only a > * subtree of a DOM document. > * > * @param prefix the prefix to find > * @param e the starting node > * @param stopNode null to search in all the document or a parent node > where the search must stop. > * @return null if no namespace is found, or the namespace URI. > */ > public static String getNamespace(String prefix, Node e, Node stopNode) { > while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) { > Attr attr = null; > if (prefix == null) { > attr = ((Element) e).getAttributeNode("xmlns"); > } else { > attr = ((Element) > e).getAttributeNodeNS(Constants.NS_URI_XMLNS, > prefix); > } > if (attr != null) return attr.getValue(); > if (e == stopNode) > return null; > e = e.getParentNode(); > } > return null; > } > > public static String getNamespace(String prefix, Node e) { > return getNamespace(prefix, e, null); > } > > /** > * Return 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 a QName generated from the given string representation > */ > public static QName getQNameFromString(String str, Node e) { > return getQNameFromString(str, e, false); > } > /** > * Return a QName when passed a string like "foo:bar" by mapping > * the "foo" prefix to a namespace in the context of the given Node. > * If default namespace is found it is returned as part of the QName. > * > * @return a QName generated from the given string representation > */ > public static QName getFullQNameFromString(String str, Node e) { > return getQNameFromString(str, e, true); > } > private static QName getQNameFromString(String str, Node e, boolean > defaultNS) { > 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 { > if (defaultNS) { > String ns = getNamespace(null, e); > if (ns != null) > return new QName(ns, str); > } > return new QName("", str); > } > } > > /** > * Return 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(); > } > > /** > * Concat all the text and cdata node children of this elem and return > * the resulting text. > * (by Matt Duftler) > * > * @param parentEl the element whose cdata/text node values are to > * be combined. > * @return the concatanated 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 > { > protected static Log log = > LogFactory.getLog(ParserErrorHandler.class.getName()); > /** > * Returns a string describing parse exception details > */ > private String getParseExceptionInfo(SAXParseException spe) { > String systemId = spe.getSystemId(); > if (systemId == null) { > systemId = "null"; > } > String info = "URI=" + systemId + > " Line=" + spe.getLineNumber() + > ": " + spe.getMessage(); > return info; > } > > // The following methods are standard SAX ErrorHandler methods. > // See SAX documentation for more info. > > public void warning(SAXParseException spe) throws SAXException { > if (log.isDebugEnabled()) > log.debug( Messages.getMessage("warning00", > getParseExceptionInfo(spe))); > } > > 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 > * @see #getInputSourceFromURI(String uri, String username, String > password) > */ > public static InputSource getInputSourceFromURI(String uri) { > return new InputSource(uri); > } > > /** > * Utility to get the bytes uri > * > * @param source the resource to get > */ > public static InputSource sourceToInputSource(Source source) { > if (source instanceof SAXSource) { > return ((SAXSource) source).getInputSource(); > } else if (source instanceof DOMSource) { > ByteArrayOutputStream baos = new ByteArrayOutputStream(); > Node node = ((DOMSource)source).getNode(); > if (node instanceof Document) { > node = ((Document)node).getDocumentElement(); > } > Element domElement = (Element)node; > ElementToStream(domElement, baos); > InputSource isource = new InputSource(source.getSystemId()); > isource.setByteStream(new > ByteArrayInputStream(baos.toByteArray())); > return isource; > } else if (source instanceof StreamSource) { > StreamSource ss = (StreamSource) source; > InputSource isource = new InputSource(ss.getSystemId()); > isource.setByteStream(ss.getInputStream()); > isource.setCharacterStream(ss.getReader()); > isource.setPublicId(ss.getPublicId()); > return isource; > } else { > return getInputSourceFromURI(source.getSystemId()); > } > } > > /** > * Utility to get the bytes at a protected uri > * > * This will retrieve 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, we create an InputSource from the uri > * and let 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(httpAuthCharEncoding))); > } > > uconn.connect(); > > return new InputSource(uconn.getInputStream()); > } > > public static final String base64encode(byte[] bytes) { > return new String(Base64.encode(bytes)); > } > > public static InputSource getEmptyInputSource() { > return new InputSource(bais); > } > > /** > * Find a Node with a given QName > * > * @param node parent node > * @param name QName of the child we need to find > * @return 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; > } > > /** > * Trim all new lines from text nodes. > * > * @param node > */ > public static void normalize(Node node) { > if (node.getNodeType() == Node.TEXT_NODE) { > String data = ((Text) node).getData(); > if (data.length() > 0) { > char ch = data.charAt(data.length()-1); > if(ch == '\n' || ch == '\r' || ch == ' ') { > String data2 = trim(data); > ((Text) node).setData(data2); > } > } > } > for (Node currentChild = node.getFirstChild(); currentChild != null; > currentChild = currentChild.getNextSibling()) { > normalize(currentChild); > } > } > > public static String trim(String str) { > if (str.length() == 0) { > return str; > } > > if (str.length() == 1) { > if ("\r".equals(str) || "\n".equals(str)) { > return ""; > } else { > return str; > } > } > > int lastIdx = str.length() - 1; > char last = str.charAt(lastIdx); > while(lastIdx > 0) { > if(last != '\n' && last != '\r' && last != ' ') > break; > lastIdx--; > last = str.charAt(lastIdx); > } > if(lastIdx == 0) > return ""; > return str.substring(0, lastIdx); > } > > /** > * Converts a List with org.w3c.dom.Element objects to an Array > * with org.w3c.dom.Element objects. > * @param list List containing org.w3c.dom.Element objects > * @return Element[] Array with org.w3c.dom.Element objects > */ > public static Element[] asElementArray(List list) { > > Element[] elements = new Element[list.size()]; > > int i = 0; > Iterator detailIter = list.iterator(); > while (detailIter.hasNext()) { > elements[i++] = (Element) detailIter.next(); > } > > return elements; > } > > public static String getEncoding(Message message, > MessageContext msgContext) { > return getEncoding(message, msgContext, > XMLEncoderFactory.getDefaultEncoder()); > } > > public static String getEncoding(Message message, > MessageContext msgContext, > XMLEncoder defaultEncoder) { > String encoding = null; > try { > if(message != null) { > encoding = (String) > message.getProperty(SOAPMessage.CHARACTER_SET_ENCODING); > } > } catch (SOAPException e) { > } > if(msgContext == null) { > msgContext = MessageContext.getCurrentContext(); > } > if(msgContext != null && encoding == null){ > encoding = (String) > msgContext.getProperty(SOAPMessage.CHARACTER_SET_ENCODING); > } > if (msgContext != null && encoding == null) { > encoding = (String) > msgContext.getAxisEngine().getOption(AxisEngine.PROP_XML_ENCODING); > } > if (encoding == null && defaultEncoder != null) { > encoding = defaultEncoder.getEncoding(); > } > return encoding; > } > } > > > -- Davanum Srinivas - http://webservices.apache.org/~dims/