View Javadoc

1   /*
2    * $Id: JXPathFilter.java 11195 2008-03-06 04:13:01Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.xml.filters;
12  
13  import org.mule.api.MuleMessage;
14  import org.mule.api.routing.filter.Filter;
15  import org.mule.module.xml.util.XMLUtils;
16  
17  import java.io.InputStream;
18  import java.util.Iterator;
19  import java.util.Map;
20  
21  import javax.xml.transform.dom.DOMSource;
22  
23  import org.apache.commons.jxpath.AbstractFactory;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.dom4j.Document;
27  import org.jaxen.BaseXPath;
28  import org.jaxen.JaxenException;
29  import org.jaxen.dom.DOMXPath;
30  import org.jaxen.dom4j.Dom4jXPath;
31  import org.jaxen.javabean.JavaBeanXPath;
32  
33  /**
34   * <code>JaxenFilter</code> evaluates an XPath expression against an XML document
35   * using Jaxen.
36   */
37  public class JaxenFilter implements Filter
38  {
39      protected transient Log logger = LogFactory.getLog(getClass());
40  
41      private String pattern;
42      private String expectedValue;
43      private Map namespaces = null;
44      private Map contextProperties = null;
45      private AbstractFactory factory;
46  
47      public JaxenFilter()
48      {
49          super();
50      }
51  
52      public JaxenFilter(String pattern)
53      {
54          this.pattern = pattern;
55      }
56  
57      public JaxenFilter(String pattern, String expectedValue)
58      {
59          this.pattern = pattern;
60          this.expectedValue = expectedValue;
61      }
62  
63      public boolean accept(MuleMessage obj)
64      {
65          Object payload = obj.getPayload();
66          
67          try 
68          {
69              // Ensure that we have an object we can run an XPath on
70              if (payload instanceof DOMSource)
71              {
72                  accept(((DOMSource) payload).getNode());
73              }
74              else if (payload instanceof byte[] 
75                       || payload instanceof InputStream 
76                       || payload instanceof String)
77              {
78                  try
79                  {
80                      return accept(obj.getPayload(org.w3c.dom.Document.class));
81                  }
82                  catch (Exception e)
83                  {
84                      logger.warn("JaxenPath filter rejected message because it could not convert from " 
85                              + payload.getClass() 
86                              + " to Source: "+ e.getMessage(), e);
87                      return false;
88                  }
89              }
90          
91              return accept(payload);
92          }
93          catch (JaxenException e) 
94          {
95              logger.warn("JaxenPath filter rejected message because it could not build/evaluate the XPath expression.", e);
96              return false;
97          }
98      }
99  
100     private boolean accept(Object obj) throws JaxenException
101     {
102         if (obj == null)
103         {
104             logger.warn("Applying JaxenFilter to null object.");
105             return false;
106         }
107         if (pattern == null)
108         {
109             logger.warn("Expression for JaxenFilter is not set.");
110             return false;
111         }
112         if (expectedValue == null)
113         {
114             // Handle the special case where the expected value really is null.
115             if (pattern.endsWith("= null") || pattern.endsWith("=null"))
116             {
117                 expectedValue = "null";
118                 pattern = pattern.substring(0, pattern.lastIndexOf("="));
119             }
120             else
121             {
122                 if (logger.isInfoEnabled())
123                 {
124                     logger.info("Expected value for JaxenFilter is not set, using 'true' by default");
125                 }
126                 expectedValue = Boolean.TRUE.toString();
127             }
128         }
129 
130         Object xpathResult = null;
131         boolean accept = false;
132 
133         Document dom4jDoc;
134         try
135         {
136             dom4jDoc = XMLUtils.toDocument(obj);
137         }
138         catch (Exception e)
139         {
140             throw new JaxenException(e);
141         }
142         
143         // Payload is a DOM Document
144         if (dom4jDoc != null)
145         {
146             xpathResult = getDom4jXPath().valueOf(dom4jDoc);
147         }
148         // Payload is a W3C Document
149         else if (obj instanceof DOMSource)
150         {
151             xpathResult = getDOMXPath().valueOf(obj);
152         }
153         // Payload is a W3C Document
154         else if (obj instanceof org.w3c.dom.Document)
155         {
156             xpathResult = getDOMXPath().valueOf(obj);
157         }
158         // Payload is a Java object
159         else
160         {
161             if (logger.isDebugEnabled())
162             {
163                 logger.debug("Passing object of type " + obj.getClass().getName() + " to JaxenContext");
164             }
165             xpathResult = getJavaBeanXPath().valueOf(obj);
166         }
167 
168         if (logger.isDebugEnabled())
169         {
170             logger.debug("JaxenFilter Expression result = '" + xpathResult + "' -  Expected value = '"
171                     + expectedValue + "'");
172         }
173         // Compare the XPath result with the expected result.
174         if (xpathResult != null)
175         {
176             accept = xpathResult.toString().equals(expectedValue);
177         }
178         else
179         {
180             // A null result was actually expected.
181             if (expectedValue.equals("null"))
182             {
183                 accept = true;
184             }
185             // A null result was not expected, something probably went wrong.
186             else
187             {
188                 logger.warn("JaxenFilter expression evaluates to null: " + pattern);
189             }
190         }
191 
192         if (logger.isDebugEnabled())
193         {
194             logger.debug("JaxenFilter accept object  : " + accept);
195         }
196 
197         return accept;
198     }
199 
200     protected DOMXPath getDOMXPath() throws JaxenException
201     {
202         DOMXPath xpath = new DOMXPath(pattern);
203         setupNamespaces(xpath);
204         return xpath;
205     }
206 
207     protected Dom4jXPath getDom4jXPath() throws JaxenException
208     {
209         Dom4jXPath xpath = new Dom4jXPath(pattern);
210         setupNamespaces(xpath);
211         return xpath;
212     }
213     
214     protected JavaBeanXPath getJavaBeanXPath() throws JaxenException
215     {
216         JavaBeanXPath xpath = new JavaBeanXPath(pattern);
217         setupNamespaces(xpath);
218         return xpath;
219     }
220 
221     private void setupNamespaces(BaseXPath xpath) throws JaxenException
222     {
223         if (namespaces != null) 
224         {
225             for (Iterator itr = namespaces.entrySet().iterator(); itr.hasNext();)
226             {
227                 Map.Entry entry = (Map.Entry) itr.next();
228                 
229                 xpath.addNamespace((String) entry.getKey(), (String) entry.getValue());
230             }
231         }
232     }
233 
234     /** @return XPath expression */
235     public String getPattern()
236     {
237         return pattern;
238     }
239 
240     /** @param pattern The XPath expression */
241     public void setPattern(String pattern)
242     {
243         this.pattern = pattern;
244     }
245 
246     /** @return The expected result value of the XPath expression */
247     public String getExpectedValue()
248     {
249         return expectedValue;
250     }
251 
252     /** Sets the expected result value of the XPath expression */
253     public void setExpectedValue(String expectedValue)
254     {
255         this.expectedValue = expectedValue;
256     }
257 
258     public Map getNamespaces()
259     {
260         return namespaces;
261     }
262 
263     public void setNamespaces(Map namespaces)
264     {
265         this.namespaces = namespaces;
266     }
267 
268     public Map getContextProperties()
269     {
270         return contextProperties;
271     }
272 
273     public void setContextProperties(Map contextProperties)
274     {
275         this.contextProperties = contextProperties;
276     }
277 
278     public AbstractFactory getFactory()
279     {
280         return factory;
281     }
282 
283     public void setFactory(AbstractFactory factory)
284     {
285         this.factory = factory;
286     }
287 }