You are viewing a plain text version of this content. The canonical link for it is here.
Posted to muse-commits@ws.apache.org by ct...@apache.org on 2009/09/28 14:11:47 UTC

svn commit: r819504 - in /webservices/muse/trunk/modules: muse-util-xml/src/org/apache/muse/util/xml/ muse-wsn-impl/src/org/apache/muse/ws/notification/impl/

Author: ctwiner
Date: Mon Sep 28 12:11:47 2009
New Revision: 819504

URL: http://svn.apache.org/viewvc?rev=819504&view=rev
Log:
MUSE-293

Modified:
    webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XPathUtils.java
    webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XmlUtils.java
    webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilter.java
    webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilterHandler.java
    webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/PublishAllMessagesFilter.java

Modified: webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XPathUtils.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XPathUtils.java?rev=819504&r1=819503&r2=819504&view=diff
==============================================================================
--- webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XPathUtils.java (original)
+++ webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XPathUtils.java Mon Sep 28 12:11:47 2009
@@ -20,15 +20,18 @@
 
 package org.apache.muse.util.xml;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import javax.xml.transform.TransformerException;
 
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.XPathAPI;
+import org.apache.xpath.objects.XObject;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import org.apache.xpath.XPathAPI;
-import org.apache.xpath.objects.XObject;
-
 /**
  *
  * XPathUtils is a collection of utility methods related to XPath 1.0. It 
@@ -50,7 +53,8 @@
     
     /**
      * 
-     * Evaluates the given XPath as a Boolean expression against the given XML.
+     * Evaluates the given XPath as a Boolean expression against the given XML. <b>NOTE</b> as this version uses namespaces from the given context  
+     * it can give unexpected results when using fixed prefixes in the xpath.  Prefer using isMatch(Node, String, Map)
      *
      * @param context
      *        The node from which to start all XPath evaluations. This 
@@ -74,6 +78,77 @@
         return result.bool();
     }
     
+	/**
+	 * Issue 293 - NOTE as the xml nodes are not thread safe we work out the namespaces at the time of declaration of
+	 * a given xpath and cash the map.
+	 * <br/><br/>
+	 * The access to the underlying HashMap should be thread safe as it is only lookup no changes possible and 
+	 * no iterator usage.
+	 * 
+	 * @author Chris Twiner
+	 *
+	 */
+	public static class MapNSResolver implements PrefixResolver{
+
+		private Map map = new HashMap();
+		
+		public void addMap(Map prefixmappings){
+			map.putAll(prefixmappings);
+		}
+		
+		public void addMapping(String prefix, String namespace){
+			map.put(prefix, namespace);
+		}
+		
+		public String getBaseIdentifier() {
+			return null;
+		}
+
+		public String getNamespaceForPrefix(String prefix) {
+			return (String) map.get(prefix);
+		}
+
+		public String getNamespaceForPrefix(String prefix, Node context) {
+			return null;
+		}
+
+		public boolean handlesNullPrefixes() {
+			return false;
+		}
+    	
+    }
+    
+    /**
+     * 
+     * Evaluates the given XPath as a Boolean expression against the given XML.
+     *
+     * @param context
+     *        The node from which to start all XPath evaluations. This 
+     *        node becomes irrelevant if the expression is an absolute path.
+     * 
+     * @param xpath
+     *        The XPath expression to evaluate.
+     *
+     * @param namespaces
+     *        A map of prefix to namespace uri mappings (String -> String)
+     * 
+     * @return True if the XPath evaluates to "true" or a collection of Nodes.
+     * 
+     * @throws TransformerException
+     *         <ul>
+     *         <li>If the XPath expression is invalid.</li>
+     *         </ul>
+     *
+     */
+    public static boolean isMatch(Node context, String xpath, Map namespaces) 
+    throws TransformerException
+	{
+		MapNSResolver resolver = new MapNSResolver();
+		resolver.addMap(namespaces);
+		XObject result = XPathAPI.eval(context, xpath, resolver);
+	    return result.bool();
+	}
+    
     /**
      * 
      * Returns the first Node that matches the given XPath expression. The 

Modified: webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XmlUtils.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XmlUtils.java?rev=819504&r1=819503&r2=819504&view=diff
==============================================================================
--- webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XmlUtils.java (original)
+++ webservices/muse/trunk/modules/muse-util-xml/src/org/apache/muse/util/xml/XmlUtils.java Mon Sep 28 12:11:47 2009
@@ -31,7 +31,6 @@
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -40,6 +39,8 @@
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -49,9 +50,6 @@
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
-import org.apache.xml.serialize.OutputFormat;
-import org.apache.xml.serialize.XMLSerializer;
-
 /**
  *
  * XmlUtils is a collection of utility methods related to XML parsing and 
@@ -2137,4 +2135,95 @@
         
         return prefix + ':' + name;
     }
+    
+    
+    /**
+     * 
+     * Searches the given sub-tree and returns all of the namespace URIs that 
+     * are used to declare the root Element and its child Elements. Unlike getAllNamespaces
+     * it only retrieves the namespace declarations i.e. xmlns:prefix="namespace".
+     * 
+     * Also unlike getAllNamespaces this works up the xml nodes to the root.  Namespace
+     * prefixes are therefore correct for that node, reassigned prefixes higher up the tree are ignored.
+     * 
+     * 
+     * @param xml 
+     *        The root of the sub-tree to perform the search on.
+     * 
+     * @return A Map containing all namespaces used in Element QNames. The 
+     *         Map is keyed by the namespace prefixes. The Map does not 
+     *         include namespaces outside of the Element QNames.
+     *         
+     *
+     */
+    public static Map getNamespaceDeclarations(Element xml)
+    {
+        return getNamespaceDeclarations(xml, new HashMap());
+    }
+    
+    /**
+     * 
+     * This is an auxiliary method used to recursively search an Element 
+     * and its parent nodes for namespace/prefix definitions. It is used to implement 
+     * getNamespaceDeclarations(Element).
+     *
+     * @param xml
+     *        The current Element in the recursive search. All namespace prefixes will be searched.
+     *        , and then its children will be searched.
+     * 
+     * @param namespacesByPrefix
+     *        The result Map so far. This is a Map[prefix, namespace].
+     * 
+     * @return The same Map as the second parameter (namespacesByPrefix), 
+     *         but with more entries.
+     * 
+     * @see #getAllNamespaces(Element)
+     *
+     */
+    private static Map getNamespaceDeclarations(Element xml, Map namespacesByPrefix)
+    {
+        // get the prefixes declared here and head up the tree
+    	// code borrowed from Xalan XPathUtils, as it works.  
+    	
+    	// Its important to really check for the NS but this usually only works on
+    	// a fresh parse. Developers may manually add declarations that are not in the
+    	// correct namespace, then we guess.  As the xmlns prefix is reserved its safe just
+    	// to use this code.
+    	
+        Node parent = xml;
+
+          int type;
+
+          while ((null != parent)
+                 && (((type = parent.getNodeType()) == Node.ELEMENT_NODE)
+                     || (type == Node.ENTITY_REFERENCE_NODE)))
+          {
+            if (type == Node.ELEMENT_NODE)
+            {
+              NamedNodeMap nnm = parent.getAttributes();
+
+              for (int i = 0; i < nnm.getLength(); i++)
+              {
+                Node attr = nnm.item(i);
+                String aname = attr.getNodeName();
+                boolean isPrefix = aname.startsWith("xmlns:");
+
+                if (isPrefix || aname.equals("xmlns"))
+                {
+                  int index = aname.indexOf(':');
+                  String pre = isPrefix ? aname.substring(index + 1) : "";
+                  String namespace = attr.getNodeValue();
+                  
+                  namespacesByPrefix.put(pre, namespace);
+                }
+              }
+            }
+
+            parent = parent.getParentNode();
+          }
+        
+
+        return namespacesByPrefix;
+    }
+
 }

Modified: webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilter.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilter.java?rev=819504&r1=819503&r2=819504&view=diff
==============================================================================
--- webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilter.java (original)
+++ webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilter.java Mon Sep 28 12:11:47 2009
@@ -20,10 +20,10 @@
 
 package org.apache.muse.ws.notification.impl;
 
-import javax.xml.transform.TransformerException;
+import java.util.Iterator;
+import java.util.Map;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import javax.xml.transform.TransformerException;
 
 import org.apache.muse.util.messages.Messages;
 import org.apache.muse.util.messages.MessagesFactory;
@@ -33,6 +33,8 @@
 import org.apache.muse.ws.notification.NotificationMessage;
 import org.apache.muse.ws.notification.WsnConstants;
 import org.apache.muse.ws.notification.faults.InvalidMessageContentExpressionFault;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 /**
  * 
@@ -55,9 +57,56 @@
     //
     private String _pattern = null;
     
+    /**
+     * The map of prefixes that makes _pattern work
+     */
+    private final Map _namespaces;
+    
+    /**
+     * 
+     * @param pattern
+     * @param namespaces a map containing prefix to uri maps, in general they should be taken from the message (from MessagePatternFilterHandler):<br/>
+     * <code>
+        public Filter newInstance(Element filterXML)
+            throws BaseFault
+        {
+            String dialect = filterXML.getAttribute(WsnConstants.DIALECT);
+            String pattern = XmlUtils.extractText(filterXML);
+            return new MessagePatternFilter(pattern, 
+            		XmlUtils.getNamespaceDeclarations(filterXML)
+            				, dialect);
+        }</code>
+     * @param dialect
+     * @throws InvalidMessageContentExpressionFault
+     */
+    public MessagePatternFilter(String pattern, Map namespaces, String dialect) 
+        throws InvalidMessageContentExpressionFault
+    {
+        //
+        // we only support xpath
+        //
+        if (!dialect.equals(XPathUtils.NAMESPACE_URI))
+        {
+            Object[] filler = { dialect, XPathUtils.NAMESPACE_URI };
+            throw new InvalidMessageContentExpressionFault(_MESSAGES.get("InvalidDialect", filler));
+        }
+        
+        _pattern = pattern;
+        _namespaces = namespaces;
+    }
+    
+    /**
+     * @deprecated Construct with relevant namespace mappings to gaurantee correct results
+     * @param pattern
+     * @param dialect
+     * @throws InvalidMessageContentExpressionFault
+     */
     public MessagePatternFilter(String pattern, String dialect) 
         throws InvalidMessageContentExpressionFault
     {
+    	// CTw - set the _namespaces to null => take namespaces from message, old behaviour
+    	_namespaces = null;
+    	
         //
         // we only support xpath
         //
@@ -82,7 +131,11 @@
         
         try
         {
-            return XPathUtils.isMatch(messageXML, _pattern);
+        	if (_namespaces == null) {
+        		return XPathUtils.isMatch(messageXML, _pattern);
+        	} else {
+        		return XPathUtils.isMatch(messageXML, _pattern, _namespaces);
+        	}
         }
         
         catch (TransformerException error)
@@ -107,6 +160,18 @@
         
         Element message = XmlUtils.createElement(doc, WsnConstants.MESSAGE_CONTENT_QNAME, _pattern);
         message.setAttribute(WsnConstants.DIALECT, XPathUtils.NAMESPACE_URI);
+        
+        // for each namespace add the prefix and uri
+        if (_namespaces != null) {
+        	Iterator pairs = _namespaces.entrySet().iterator();
+        	while (pairs.hasNext()) {
+				Map.Entry pair = (Map.Entry) pairs.next();
+				XmlUtils.setNamespaceAttribute(message, 
+                        pair.getKey().toString(), 
+                        pair.getValue().toString());
+			}
+        }
+        
         filter.appendChild(message);
         
         return filter;

Modified: webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilterHandler.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilterHandler.java?rev=819504&r1=819503&r2=819504&view=diff
==============================================================================
--- webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilterHandler.java (original)
+++ webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/MessagePatternFilterHandler.java Mon Sep 28 12:11:47 2009
@@ -22,13 +22,12 @@
 
 import javax.xml.namespace.QName;
 
-import org.w3c.dom.Element;
-
 import org.apache.muse.util.xml.XPathUtils;
 import org.apache.muse.util.xml.XmlUtils;
 import org.apache.muse.ws.notification.Filter;
 import org.apache.muse.ws.notification.WsnConstants;
 import org.apache.muse.ws.resource.basefaults.BaseFault;
+import org.w3c.dom.Element;
 
 /**
  *
@@ -48,8 +47,10 @@
     public Filter newInstance(Element filterXML)
         throws BaseFault
     {
-        String dialect = filterXML.getAttribute(WsnConstants.DIALECT);
+    	String dialect = filterXML.getAttribute(WsnConstants.DIALECT);
         String pattern = XmlUtils.extractText(filterXML);
-        return new MessagePatternFilter(pattern, dialect);
+        return new MessagePatternFilter(pattern, 
+        		XmlUtils.getNamespaceDeclarations(filterXML)
+        				, dialect);
     }
 }

Modified: webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/PublishAllMessagesFilter.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/PublishAllMessagesFilter.java?rev=819504&r1=819503&r2=819504&view=diff
==============================================================================
--- webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/PublishAllMessagesFilter.java (original)
+++ webservices/muse/trunk/modules/muse-wsn-impl/src/org/apache/muse/ws/notification/impl/PublishAllMessagesFilter.java Mon Sep 28 12:11:47 2009
@@ -45,7 +45,7 @@
     private PublishAllMessagesFilter() 
         throws InvalidMessageContentExpressionFault
     {
-        super("*", XPathUtils.NAMESPACE_URI);
+        super("*", null, XPathUtils.NAMESPACE_URI);
     }
     
     public static PublishAllMessagesFilter getInstance()