[jboss-svn-commits] JBossWS SVN: r896 - in branches/tdiesler/trunk/src/main/java/org/jboss/ws: transport/jms utils

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Sep 4 18:47:41 EDT 2006


Author: thomas.diesler at jboss.com
Date: 2006-09-04 18:47:36 -0400 (Mon, 04 Sep 2006)
New Revision: 896

Added:
   branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/JMSTransportSupport.java
   branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/MessageDispatcher.java
   branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMUtils.java
   branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMWriter.java
Log:
Enforce that DOM expansion only happens when a handler accesses the DOM API.
SOAPContentElement provides read only access to attributes without DOM expansion
Pull in DOMWriter and add support for attribute namespace completion.
Pull in DOMUtils and fix copyAttributes.


Added: branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/JMSTransportSupport.java
===================================================================
--- branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/JMSTransportSupport.java	2006-09-04 22:42:49 UTC (rev 895)
+++ branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/JMSTransportSupport.java	2006-09-04 22:47:36 UTC (rev 896)
@@ -0,0 +1,255 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ws.transport.jms;
+
+// $Id$
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.rmi.RemoteException;
+
+import javax.ejb.EJBException;
+import javax.ejb.MessageDrivenBean;
+import javax.ejb.MessageDrivenContext;
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.naming.InitialContext;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+
+import org.jboss.logging.Logger;
+import org.jboss.util.NestedRuntimeException;
+import org.jboss.ws.common.SOAPMessageContextBase;
+import org.jboss.ws.jaxrpc.handler.SOAPMessageContextJAXRPC;
+import org.jboss.ws.soap.MessageContextAssociation;
+
+/**
+ * The abstract base class for MDBs that want to act as web service endpoints.
+ * A subclass should only need to implement the service endpoint interface.
+ *
+ * @author Thomas.Diesler at jboss.org
+ */
+public abstract class JMSTransportSupport implements MessageDrivenBean, MessageListener
+{
+   // logging support
+   protected Logger log = Logger.getLogger(JMSTransportSupport.class);
+
+   //private MessageDrivenContext mdbCtx;
+   private QueueConnectionFactory queueFactory;
+
+   /**
+    * All messages come in here, if it is a BytesMessage we pass it on for further processing.
+    */
+   public void onMessage(Message message)
+   {
+      try
+      {
+         String msgStr = null;
+         if (message instanceof BytesMessage)
+         {
+            msgStr = getMessageStr((BytesMessage)message);
+         }
+         else if (message instanceof TextMessage)
+         {
+            msgStr = ((TextMessage)message).getText();
+         }
+         else
+         {
+            log.warn("Invalid message type: " + message);
+            return;
+         }
+
+         log.debug("Incomming SOAP message: " + msgStr);
+
+         String fromName = null;
+         Destination destination = message.getJMSDestination();
+         if (destination instanceof Queue)
+            fromName = "queue/" + ((Queue)destination).getQueueName();
+         if (destination instanceof Topic)
+            fromName = "topic/" + ((Topic)destination).getTopicName();
+
+         // Associate a message context with the current thread
+         SOAPMessageContextBase msgContext = new SOAPMessageContextJAXRPC();
+         MessageContextAssociation.pushMessageContext(msgContext);
+         try
+         {
+
+            InputStream reqMessage = new ByteArrayInputStream(msgStr.getBytes());
+            SOAPMessage resMessage = processSOAPMessage(fromName, reqMessage);
+
+            if (resMessage != null)
+            {
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               resMessage.writeTo(baos);
+
+               msgStr = new String(baos.toByteArray());
+               log.debug("Outgoing SOAP message: " + msgStr);
+
+               Queue replyQueue = getReplyQueue(message);
+               if (replyQueue != null)
+               {
+                  sendResponse(replyQueue, msgStr);
+               }
+               else
+               {
+                  log.warn("No reply queue, ignore response message");
+               }
+            }
+            else
+            {
+               log.debug("SOAP response message is null");
+            }
+         }
+         finally
+         {
+            MessageContextAssociation.popMessageContext();
+         }
+      }
+      catch (RuntimeException rte)
+      {
+         throw rte;
+      }
+      catch (Exception e)
+      {
+         throw new EJBException(e);
+      }
+   }
+
+   protected SOAPMessage processSOAPMessage(String fromName, InputStream reqMessage) throws SOAPException, IOException, RemoteException
+   {
+      MessageDispatcher msgDispatcher = new JMSMessageDispatcher();
+      SOAPMessage resMessage = msgDispatcher.dipatchMessage(fromName, this, reqMessage);
+      return resMessage;
+   }
+
+   private String getMessageStr(BytesMessage message) throws Exception
+   {
+      byte[] buffer = new byte[8 * 1024];
+      ByteArrayOutputStream out = new ByteArrayOutputStream(buffer.length);
+      int read = message.readBytes(buffer);
+      while (read != -1)
+      {
+         out.write(buffer, 0, read);
+         read = message.readBytes(buffer);
+      }
+
+      byte[] msgBytes = out.toByteArray();
+      return new String(msgBytes);
+   }
+
+   /**
+    * Get the reply queue.
+    */
+   protected Queue getReplyQueue(Message message) throws JMSException
+   {
+      Queue replyQueue = (Queue)message.getJMSReplyTo();
+      return replyQueue;
+   }
+
+   /**
+    * Respond to the call by sending a message to the reply queue
+    */
+   protected void sendResponse(Queue replyQueue, String msgStr) throws SOAPException, IOException, JMSException
+   {
+      QueueConnection qc = queueFactory.createQueueConnection();
+      QueueSession session = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+      QueueSender sender = null;
+      try
+      {
+         sender = session.createSender(replyQueue);
+         TextMessage responseMessage = session.createTextMessage(msgStr);
+         sender.send(responseMessage);
+         log.info("Sent response");
+      }
+      finally
+      {
+         try
+         {
+            sender.close();
+         }
+         catch (JMSException ignored)
+         {
+         }
+         try
+         {
+            session.close();
+         }
+         catch (JMSException ignored)
+         {
+         }
+         try
+         {
+            qc.close();
+         }
+         catch (JMSException ignored)
+         {
+         }
+      }
+   }
+
+   // MDB lifecycle methods ********************************************************************************************
+
+   public void ejbCreate()
+   {
+      try
+      {
+         InitialContext ctx = new InitialContext();
+         queueFactory = (QueueConnectionFactory)ctx.lookup("java:/ConnectionFactory");
+      }
+      catch (RuntimeException rte)
+      {
+         throw rte;
+      }
+      catch (Exception e)
+      {
+         throw new NestedRuntimeException(e);
+      }
+   }
+
+   /**
+    * A container invokes this method before it ends the life of the message-driven object.
+    */
+   public void ejbRemove() throws EJBException
+   {
+   }
+
+   /**
+    * Set the associated message-driven context.
+    */
+   public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException
+   {
+      //this.mdbCtx = ctx;
+   }
+}


Property changes on: branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/JMSTransportSupport.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/MessageDispatcher.java
===================================================================
--- branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/MessageDispatcher.java	2006-09-04 22:42:49 UTC (rev 895)
+++ branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/MessageDispatcher.java	2006-09-04 22:47:36 UTC (rev 896)
@@ -0,0 +1,46 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ws.transport.jms;
+
+// $Id: $
+
+import java.io.InputStream;
+import java.rmi.RemoteException;
+
+import javax.xml.soap.SOAPMessage;
+
+/**
+ * A dispatcher for SOAPMessages 
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 19-Feb-2006
+ */
+public interface MessageDispatcher
+{
+   /** Dispatch the message to the underlying SOAP engine
+    */
+   SOAPMessage dipatchMessage(String fromName, Object targetImplBean, InputStream reqMessage) throws RemoteException;
+   
+   /** Dispatch the message to the underlying SOAP engine
+    */
+   SOAPMessage delegateMessage(String serviceID, InputStream reqMessage) throws RemoteException;
+}
\ No newline at end of file


Property changes on: branches/tdiesler/trunk/src/main/java/org/jboss/ws/transport/jms/MessageDispatcher.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMUtils.java
===================================================================
--- branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMUtils.java	2006-09-04 22:42:49 UTC (rev 895)
+++ branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMUtils.java	2006-09-04 22:47:36 UTC (rev 896)
@@ -0,0 +1,506 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ws.utils;
+
+// $Id$
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.jboss.logging.Logger;
+import org.jboss.util.xml.JBossEntityResolver;
+import org.w3c.dom.Attr;
+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.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * DOM2 utilites
+ *
+ * @author Thomas.Diesler at jboss.org
+ * @version $Revision$
+ */
+public final class DOMUtils
+{
+    private static Logger log = Logger.getLogger(DOMUtils.class);
+
+    // All elements created by the same thread are created by the same builder and belong to the same doc
+    private static ThreadLocal documentThreadLocal = new ThreadLocal();
+    private static ThreadLocal builderThreadLocal = new ThreadLocal() {
+        protected Object initialValue() {
+            try
+            {
+                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+                factory.setValidating(false);
+                factory.setNamespaceAware(true);
+                DocumentBuilder builder = factory.newDocumentBuilder();
+                builder.setEntityResolver(new JBossEntityResolver());
+                return builder;
+            }
+            catch (ParserConfigurationException e)
+            {
+                throw new RuntimeException("Failed to create DocumentBuilder", e);
+            }
+        }
+    };
+
+    // Hide the constructor
+    private DOMUtils()
+    {
+    }
+
+    /** Initialise the the DocumentBuilder
+     */
+    public static DocumentBuilder getDocumentBuilder()
+    {
+        DocumentBuilder builder = (DocumentBuilder)builderThreadLocal.get();
+        return builder;
+    }
+
+    /** Parse the given XML string and return the root Element
+     */
+    public static Element parse(String xmlString) throws IOException
+    {
+        try
+        {
+            return parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
+        }
+        catch (IOException e)
+        {
+            log.error("Cannot parse: " + xmlString);
+            throw e;
+        }
+    }
+
+    /** Parse the given XML stream and return the root Element
+     */
+    public static Element parse(InputStream xmlStream) throws IOException
+    {
+        try
+        {
+            Document doc = getDocumentBuilder().parse(xmlStream);
+            Element root = doc.getDocumentElement();
+            return root;
+        }
+        catch (SAXException e)
+        {
+            throw new IOException(e.toString());
+        }
+    }
+
+    /** Parse the given input source and return the root Element
+     */
+    public static Element parse(InputSource source) throws IOException
+    {
+        try
+        {
+            Document doc = getDocumentBuilder().parse(source);
+            Element root = doc.getDocumentElement();
+            return root;
+        }
+        catch (SAXException e)
+        {
+            throw new IOException(e.toString());
+        }
+    }
+
+    /** Create an Element for a given name
+     */
+    public static Element createElement(String localPart)
+    {
+        Document doc = getOwnerDocument();
+        log.trace("createElement {}" + localPart);
+        return doc.createElement(localPart);
+    }
+
+    /** Create an Element for a given name and prefix
+     */
+    public static Element createElement(String localPart, String prefix)
+    {
+        Document doc = getOwnerDocument();
+        log.trace("createElement {}" + prefix + ":" + localPart);
+        return doc.createElement(prefix + ":" + localPart);
+    }
+
+    /** Create an Element for a given name, prefix and uri
+     */
+    public static Element createElement(String localPart, String prefix, String uri)
+    {
+        Document doc = getOwnerDocument();
+        if (prefix == null || prefix.length() == 0)
+        {
+            log.trace("createElement {" + uri + "}" + localPart);
+            return doc.createElementNS(uri, localPart);
+        }
+        else
+        {
+            log.trace("createElement {" + uri + "}" + prefix + ":" + localPart);
+            return doc.createElementNS(uri, prefix + ":" + localPart);
+        }
+    }
+
+    /** Create an Element for a given QName
+     */
+    public static Element createElement(QName qname)
+    {
+        return createElement(qname.getLocalPart(), qname.getPrefix(), qname.getNamespaceURI());
+    }
+
+    /** Create a org.w3c.dom.Text node
+     */
+    public static Text createTextNode(String value)
+    {
+        Document doc = getOwnerDocument();
+        return doc.createTextNode(value);
+    }
+
+    /** Get the qname of the given node.
+     */
+    public static QName getElementQName(Element el)
+    {
+        String qualifiedName = el.getNodeName();
+        return resolveQName(el, qualifiedName);
+    }
+
+    /** Transform the giveen qualified name into a QName
+     */
+    public static QName resolveQName(Element el, String qualifiedName)
+    {
+        QName qname;
+        String prefix = "";
+        String namespaceURI = "";
+        String localPart = qualifiedName;
+
+        int colIndex = qualifiedName.indexOf(":");
+        if (colIndex > 0)
+        {
+            prefix = qualifiedName.substring(0, colIndex);
+            localPart = qualifiedName.substring(colIndex + 1);
+
+            if ("xmlns".equals(prefix))
+            {
+                namespaceURI = "URI:XML_PREDEFINED_NAMESPACE";
+            }
+            else
+            {
+                Element nsElement = el;
+                while (namespaceURI.equals("") && nsElement != null)
+                {
+                    namespaceURI = nsElement.getAttribute("xmlns:" + prefix);
+                    if (namespaceURI.equals(""))
+                        nsElement = getParentElement(nsElement);
+                }
+            }
+
+            if (namespaceURI.equals(""))
+                throw new IllegalArgumentException("Cannot find namespace uri for: " + qualifiedName);
+        }
+
+        qname = new QName(namespaceURI, localPart, prefix);
+        return qname;
+    }
+
+    /** Get the value from the given attribute
+     *
+     * @return null if the attribute value is empty or the attribute is not present
+     */
+    public static String getAttributeValue(Element el, String attrName)
+    {
+        return getAttributeValue(el, new QName(attrName));
+    }
+
+    /** Get the value from the given attribute
+     *
+     * @return null if the attribute value is empty or the attribute is not present
+     */
+    public static String getAttributeValue(Element el, QName attrName)
+    {
+        String attr = null;
+        if ("".equals(attrName.getNamespaceURI()))
+            attr = el.getAttribute(attrName.getLocalPart());
+        else attr = el.getAttributeNS(attrName.getNamespaceURI(), attrName.getLocalPart());
+
+        if ("".equals(attr))
+            attr = null;
+
+        return attr;
+    }
+
+    /** Get the qname value from the given attribute
+     */
+    public static QName getAttributeValueAsQName(Element el, String attrName)
+    {
+        return getAttributeValueAsQName(el, new QName(attrName));
+
+    }
+
+    /** Get the qname value from the given attribute
+     */
+    public static QName getAttributeValueAsQName(Element el, QName attrName)
+    {
+        QName qname = null;
+
+        String qualifiedName = getAttributeValue(el, attrName);
+        if (qualifiedName != null)
+        {
+            qname = resolveQName(el, qualifiedName);
+        }
+
+        return qname;
+    }
+
+    /** Get the boolean value from the given attribute
+     */
+    public static boolean getAttributeValueAsBoolean(Element el, String attrName)
+    {
+        return getAttributeValueAsBoolean(el, new QName(attrName));
+    }
+
+    /** Get the boolean value from the given attribute
+     */
+    public static boolean getAttributeValueAsBoolean(Element el, QName attrName)
+    {
+        String attrVal = getAttributeValue(el, attrName);
+        boolean ret = "true".equalsIgnoreCase(attrVal) || "1".equalsIgnoreCase(attrVal);
+        return ret;
+    }
+
+    /** Get the integer value from the given attribute
+     */
+    public static Integer getAttributeValueAsInteger(Element el, String attrName)
+    {
+        return getAttributeValueAsInteger(el, new QName(attrName));
+    }
+
+    /** Get the integer value from the given attribute
+     */
+    public static Integer getAttributeValueAsInteger(Element el, QName attrName)
+    {
+        String attrVal = getAttributeValue(el, attrName);
+        return (attrVal != null ? new Integer(attrVal) : null);
+    }
+
+    /** Get the attributes as Map<QName, String>
+     */
+    public static Map getAttributes(Element el)
+    {
+        Map attmap = new HashMap();
+        NamedNodeMap attribs = el.getAttributes();
+        for (int i = 0; i < attribs.getLength(); i++)
+        {
+            Attr attr = (Attr)attribs.item(i);
+            String name = attr.getName();
+            QName qname = resolveQName(el, name);
+            String value = attr.getNodeValue();
+            attmap.put(qname, value);
+        }
+        return attmap;
+    }
+
+    /** Copy attributes between elements
+     */
+    public static void copyAttributes(Element destElement, Element srcElement)
+    {
+        NamedNodeMap attribs = srcElement.getAttributes();
+        for (int i = 0; i < attribs.getLength(); i++)
+        {
+            Attr attr = (Attr)attribs.item(i);
+            String uri = attr.getNamespaceURI();
+            String qname = attr.getName();
+            String value = attr.getNodeValue();
+            
+            // Prevent DOMException: NAMESPACE_ERR: An attempt is made to create or 
+            // change an object in a way which is incorrect with regard to namespaces.
+            if (uri == null && qname.startsWith("xmlns"))
+            {
+               log.trace("Ignore attribute: [uri=" + uri + ",qname=" + qname + ",value=" + value + "]");
+            }
+            else
+            {
+               destElement.setAttributeNS(uri, qname, value);
+            }
+        }
+    }
+
+    /** True if the node has child elements
+     */
+    public static boolean hasChildElements(Node node)
+    {
+        NodeList nlist = node.getChildNodes();
+        for (int i = 0; i < nlist.getLength(); i++)
+        {
+            Node child = nlist.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE)
+                return true;
+        }
+        return false;
+    }
+
+    /** Gets child elements
+     */
+    public static Iterator getChildElements(Node node)
+    {
+        ArrayList list = new ArrayList();
+        NodeList nlist = node.getChildNodes();
+        for (int i = 0; i < nlist.getLength(); i++)
+        {
+            Node child = nlist.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE)
+                list.add(child);
+        }
+        return list.iterator();
+    }
+
+    /** Get the concatenated text content, or null.
+     */
+    public static String getTextContent(Node node)
+    {
+        boolean hasTextContent = false;
+        StringBuffer buffer = new StringBuffer();
+        NodeList nlist = node.getChildNodes();
+        for (int i = 0; i < nlist.getLength(); i++)
+        {
+            Node child = nlist.item(i);
+            if (child.getNodeType() == Node.TEXT_NODE)
+            {
+                buffer.append(child.getNodeValue());
+                hasTextContent = true;
+            }
+        }
+        return (hasTextContent ? buffer.toString() : null);
+    }
+
+    /** Gets the first child element
+     */
+    public static Element getFirstChildElement(Node node)
+    {
+        return getFirstChildElementIntern(node, null);
+    }
+
+    /** Gets the first child element for a given local name without namespace
+     */
+    public static Element getFirstChildElement(Node node, String nodeName)
+    {
+        return getFirstChildElementIntern(node, new QName(nodeName));
+    }
+
+    /** Gets the first child element for a given qname
+     */
+    public static Element getFirstChildElement(Node node, QName nodeName)
+    {
+        return getFirstChildElementIntern(node, nodeName);
+    }
+
+    private static Element getFirstChildElementIntern(Node node, QName nodeName)
+    {
+        Element childElement = null;
+        Iterator it = getChildElementsIntern(node, nodeName);
+        if (it.hasNext())
+        {
+            childElement = (Element)it.next();
+        }
+        return childElement;
+    }
+
+    /** Gets the child elements for a given local name without namespace
+     */
+    public static Iterator getChildElements(Node node, String nodeName)
+    {
+        return getChildElementsIntern(node, new QName(nodeName));
+    }
+
+    /** Gets the child element for a given qname
+     */
+    public static Iterator getChildElements(Node node, QName nodeName)
+    {
+        return getChildElementsIntern(node, nodeName);
+    }
+
+    private static Iterator getChildElementsIntern(Node node, QName nodeName)
+    {
+        ArrayList list = new ArrayList();
+        NodeList nlist = node.getChildNodes();
+        for (int i = 0; i < nlist.getLength(); i++)
+        {
+            Node child = nlist.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE)
+            {
+                if (nodeName == null)
+                {
+                    list.add(child);
+                }
+                else
+                {
+                    QName qname;
+                    if (nodeName.getNamespaceURI().length() > 0)
+                    {
+                        qname = new QName(child.getNamespaceURI(), child.getLocalName());
+                    }
+                    else
+                    {
+                        qname = new QName(child.getLocalName());
+                    }
+                    if (qname.equals(nodeName))
+                    {
+                        list.add(child);
+                    }
+                }
+            }
+        }
+        return list.iterator();
+    }
+
+    /** Gets parent element or null if there is none
+     */
+    public static Element getParentElement(Node node)
+    {
+        Node parent = node.getParentNode();
+        return (parent instanceof Element ? (Element)parent : null);
+    }
+
+    /** Get the owner document that is associated with the current thread */
+    public static Document getOwnerDocument()
+    {
+        Document doc = (Document)documentThreadLocal.get();
+        if (doc == null)
+        {
+            doc = getDocumentBuilder().newDocument();
+            documentThreadLocal.set(doc);
+        }
+        return doc;
+    }
+}


Property changes on: branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMUtils.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMWriter.java
===================================================================
--- branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMWriter.java	2006-09-04 22:42:49 UTC (rev 895)
+++ branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMWriter.java	2006-09-04 22:47:36 UTC (rev 896)
@@ -0,0 +1,545 @@
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:  
+ *       "This product includes software developed by the 
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written 
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.jboss.ws.utils;
+
+// $Id$
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Traverse a DOM tree in order to print a document that is parsed.
+ *
+ * @author Andy Clark, IBM
+ * @author Thomas.Diesler at jboss.org
+ * @version $Revision$
+ */
+public class DOMWriter
+{
+   // Print writer
+   private PrintWriter out;
+   // True, if canonical output
+   private boolean canonical;
+   // True, if pretty printing should be used
+   private boolean prettyprint;
+   // True, if the XML declaration should be written
+   private boolean writeXMLDeclaration;
+   // Explicit character set encoding
+   private String charsetName;
+   // indent for the pretty printer
+   private int prettyIndent;
+   // True, if the XML declaration has been written
+   private boolean wroteXMLDeclaration;
+   // The node that started the write
+   private Node rootNode;
+   
+   public DOMWriter(Writer w)
+   {
+      this.out = new PrintWriter(w);
+   }
+
+   public DOMWriter(OutputStream stream)
+   {
+      try
+      {
+         this.out = new PrintWriter(new OutputStreamWriter(stream, "UTF-8"));
+      }
+      catch (UnsupportedEncodingException e)
+      {
+         // ignore, UTF-8 should be available
+      }
+   }
+
+   public DOMWriter(OutputStream stream, String charsetName)
+   {
+      try
+      {
+         this.out = new PrintWriter(new OutputStreamWriter(stream, charsetName));
+         this.charsetName = charsetName;
+         this.writeXMLDeclaration = true;
+      }
+      catch (UnsupportedEncodingException e)
+      {
+         throw new IllegalArgumentException("Unsupported encoding: " + charsetName);
+      }
+   }
+
+   /** 
+    * Print a node with explicit prettyprinting.
+    * The defaults for all other DOMWriter properties apply. 
+    *  
+    */
+   public static String printNode(Node node, boolean prettyprint)
+   {
+      StringWriter strw = new StringWriter();
+      new DOMWriter(strw).setPrettyprint(prettyprint).print(node);
+      return strw.toString();
+   }
+
+   public boolean isCanonical()
+   {
+      return canonical;
+   }
+
+   /** 
+    * Set wheter entities should appear in their canonical form.
+    * The default is false.
+    */
+   public DOMWriter setCanonical(boolean canonical)
+   {
+      this.canonical = canonical;
+      return this;
+   }
+
+   public boolean isPrettyprint()
+   {
+      return prettyprint;
+   }
+
+   /** 
+    * Set wheter element should be indented.
+    * The default is false.
+    */
+   public DOMWriter setPrettyprint(boolean prettyprint)
+   {
+      this.prettyprint = prettyprint;
+      return this;
+   }
+
+   public boolean isWriteXMLDeclaration()
+   {
+      return writeXMLDeclaration;
+   }
+
+   /** 
+    * Set wheter the XML declaration should be written.
+    * The default is false.
+    */
+   public DOMWriter setWriteXMLDeclaration(boolean writeXMLDeclaration)
+   {
+      this.writeXMLDeclaration = writeXMLDeclaration;
+      return this;
+   }
+
+   public void print(Node node)
+   {
+      rootNode = node;
+      printInternal(node, false);
+   }
+
+   private void printInternal(Node node, boolean indentEndMarker)
+   {
+      // is there anything to do?
+      if (node == null)
+      {
+         return;
+      }
+
+      // JBAS-2117 - Don't skip the DOCUMENT_NODE
+      // if (node instanceof Document) node = ((Document)node).getDocumentElement();
+
+      if (wroteXMLDeclaration == false && writeXMLDeclaration == true && canonical == false)
+      {
+         out.print("<?xml version='1.0'");
+         if (charsetName != null)
+            out.print(" encoding='" + charsetName + "'");
+
+         out.println("?>");
+         wroteXMLDeclaration = true;
+      }
+
+      int type = node.getNodeType();
+      boolean hasChildNodes = node.getChildNodes().getLength() > 0;
+
+      String nodeName = node.getNodeName();
+      switch (type)
+      {
+         // print document
+         case Node.DOCUMENT_NODE:
+         {
+            NodeList children = node.getChildNodes();
+            for (int iChild = 0; iChild < children.getLength(); iChild++)
+            {
+               printInternal(children.item(iChild), false);
+            }
+            out.flush();
+            break;
+         }
+
+         // print element with attributes
+         case Node.ELEMENT_NODE:
+         {
+            Element element = (Element)node;
+            if (prettyprint)
+            {
+               for (int i = 0; i < prettyIndent; i++)
+               {
+                  out.print(' ');
+               }
+               prettyIndent++;
+            }
+
+            out.print('<');
+            out.print(nodeName);
+            
+            Map nsMap = new HashMap();
+            String elPrefix = node.getPrefix();
+            if (elPrefix != null)
+            {
+               String nsURI = getNamespaceURI(elPrefix, element, rootNode);
+               nsMap.put(elPrefix, nsURI);
+            }
+            
+            Attr attrs[] = sortAttributes(node.getAttributes());
+            for (int i = 0; i < attrs.length; i++)
+            {
+               Attr attr = attrs[i];
+               String atPrefix = attr.getPrefix();
+               String atName = attr.getNodeName();
+               String atValue = normalize(attr.getNodeValue());
+               
+               if (atPrefix != null && (atPrefix.equals("xmlns") || atPrefix.equals("xml")) == false)
+               {
+                  String nsURI = getNamespaceURI(atPrefix, element, rootNode);
+                  nsMap.put(atPrefix, nsURI);
+               }
+               
+               out.print(" " + atName + "='" + atValue + "'");
+            }
+            
+            // Add missing namespace declaration
+            Iterator itPrefix = nsMap.keySet().iterator();
+            while (itPrefix.hasNext())
+            {
+               String prefix = (String)itPrefix.next();
+               String nsURI = (String)nsMap.get(prefix);
+               if (nsURI == null)
+               {
+                  nsURI = getNamespaceURI(prefix, element, null);
+                  out.print(" xmlns:" + prefix + "='" + nsURI + "'");
+               }
+            }
+
+            if (hasChildNodes)
+            {
+               out.print('>');
+            }
+
+            // Find out if the end marker is indented
+            indentEndMarker = isEndMarkerIndented(node);
+
+            if (indentEndMarker)
+            {
+               out.print('\n');
+            }
+
+            NodeList childNodes = node.getChildNodes();
+            int len = childNodes.getLength();
+            for (int i = 0; i < len; i++)
+            {
+               Node childNode = childNodes.item(i);
+               printInternal(childNode, false);
+            }
+            break;
+         }
+
+            // handle entity reference nodes
+         case Node.ENTITY_REFERENCE_NODE:
+         {
+            if (canonical)
+            {
+               NodeList children = node.getChildNodes();
+               if (children != null)
+               {
+                  int len = children.getLength();
+                  for (int i = 0; i < len; i++)
+                  {
+                     printInternal(children.item(i), false);
+                  }
+               }
+            }
+            else
+            {
+               out.print('&');
+               out.print(nodeName);
+               out.print(';');
+            }
+            break;
+         }
+
+            // print cdata sections
+         case Node.CDATA_SECTION_NODE:
+         {
+            if (canonical)
+            {
+               out.print(normalize(node.getNodeValue()));
+            }
+            else
+            {
+               out.print("<![CDATA[");
+               out.print(node.getNodeValue());
+               out.print("]]>");
+            }
+            break;
+         }
+
+            // print text
+         case Node.TEXT_NODE:
+         {
+            String text = normalize(node.getNodeValue());
+            if (prettyprint == false || text.trim().length() > 0)
+               out.print(text);
+            break;
+         }
+
+            // print processing instruction
+         case Node.PROCESSING_INSTRUCTION_NODE:
+         {
+            out.print("<?");
+            out.print(nodeName);
+            String data = node.getNodeValue();
+            if (data != null && data.length() > 0)
+            {
+               out.print(' ');
+               out.print(data);
+            }
+            out.print("?>");
+            break;
+         }
+
+            // print comment
+         case Node.COMMENT_NODE:
+         {
+            for (int i = 0; i < prettyIndent; i++)
+            {
+               out.print(' ');
+            }
+
+            out.print("<!--");
+            String data = node.getNodeValue();
+            if (data != null)
+            {
+               out.print(data);
+            }
+            out.print("-->");
+
+            if (prettyprint)
+            {
+               out.print('\n');
+            }
+
+            break;
+         }
+      }
+
+      if (type == Node.ELEMENT_NODE)
+      {
+         if (prettyprint)
+            prettyIndent--;
+
+         if (hasChildNodes == false)
+         {
+            out.print("/>");
+         }
+         else
+         {
+            if (indentEndMarker)
+            {
+               for (int i = 0; i < prettyIndent; i++)
+               {
+                  out.print(' ');
+               }
+            }
+
+            out.print("</");
+            out.print(nodeName);
+            out.print('>');
+         }
+
+         if (prettyIndent > 0)
+         {
+            out.print('\n');
+         }
+      }
+      out.flush();
+   }
+
+   private String getNamespaceURI(String prefix, Element element, Node stopNode)
+   {
+      Node parent = element.getParentNode();
+      String nsURI = element.getAttribute("xmlns:" + prefix);
+      if (nsURI.length() == 0 && element != stopNode && parent instanceof Element)
+         return getNamespaceURI(prefix, (Element)parent, stopNode);
+
+      return (nsURI.length() > 0 ? nsURI : null);
+   }
+
+   private boolean isEndMarkerIndented(Node node)
+   {
+      if (prettyprint)
+      {
+         NodeList childNodes = node.getChildNodes();
+         int len = childNodes.getLength();
+         for (int i = 0; i < len; i++)
+         {
+            Node children = childNodes.item(i);
+            if (children.getNodeType() == Node.ELEMENT_NODE)
+            {
+               return true;
+            }
+         }
+      }
+      return false;
+   }
+
+   /** Returns a sorted list of attributes. */
+   private Attr[] sortAttributes(NamedNodeMap attrs)
+   {
+
+      int len = (attrs != null) ? attrs.getLength() : 0;
+      Attr array[] = new Attr[len];
+      for (int i = 0; i < len; i++)
+      {
+         array[i] = (Attr)attrs.item(i);
+      }
+      for (int i = 0; i < len - 1; i++)
+      {
+         String name = array[i].getNodeName();
+         int index = i;
+         for (int j = i + 1; j < len; j++)
+         {
+            String curName = array[j].getNodeName();
+            if (curName.compareTo(name) < 0)
+            {
+               name = curName;
+               index = j;
+            }
+         }
+         if (index != i)
+         {
+            Attr temp = array[i];
+            array[i] = array[index];
+            array[index] = temp;
+         }
+      }
+      return (array);
+   }
+
+   /** Normalizes the given string. */
+   private String normalize(String s)
+   {
+      StringBuffer str = new StringBuffer();
+
+      int len = (s != null) ? s.length() : 0;
+      for (int i = 0; i < len; i++)
+      {
+         char ch = s.charAt(i);
+         switch (ch)
+         {
+            case '<':
+            {
+               str.append("&lt;");
+               break;
+            }
+            case '>':
+            {
+               str.append("&gt;");
+               break;
+            }
+            case '&':
+            {
+               str.append("&amp;");
+               break;
+            }
+            case '"':
+            {
+               str.append("&quot;");
+               break;
+            }
+            case '\r':
+            case '\n':
+            {
+               if (canonical)
+               {
+                  str.append("&#");
+                  str.append(Integer.toString(ch));
+                  str.append(';');
+                  break;
+               }
+               // else, default append char
+            }
+            default:
+            {
+               str.append(ch);
+            }
+         }
+      }
+      return (str.toString());
+   }
+}
\ No newline at end of file


Property changes on: branches/tdiesler/trunk/src/main/java/org/jboss/ws/utils/DOMWriter.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF




More information about the jboss-svn-commits mailing list