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()