View Javadoc

1   /*
2    * $Id: JXPathFilter.java 7976 2007-08-21 14:26:13Z dirk.olmes $
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.routing.filters.xml;
12  
13  import org.mule.umo.UMOFilter;
14  import org.mule.umo.UMOMessage;
15  import org.mule.util.StringMessageUtils;
16  
17  import java.util.Iterator;
18  import java.util.Map;
19  
20  import org.apache.commons.jxpath.AbstractFactory;
21  import org.apache.commons.jxpath.JXPathContext;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.dom4j.Document;
25  import org.dom4j.DocumentException;
26  import org.dom4j.DocumentHelper;
27  import org.dom4j.XPath;
28  
29  /**
30   * <code>JXPathFilter</code> evaluates an XPath expression against a W3C Document,
31   * XML string, or Java bean and returns true if the result is as expected.
32   */
33  public class JXPathFilter implements UMOFilter
34  {
35  
36      protected transient Log logger = LogFactory.getLog(getClass());
37  
38      private String expression;
39      private String expectedValue;
40      private Map namespaces = null;
41      private Map contextProperties = null;
42      private AbstractFactory factory;
43      private boolean lenient = true;
44  
45      public JXPathFilter()
46      {
47          super();
48      }
49  
50      public JXPathFilter(String expression)
51      {
52          this.expression = expression;
53      }
54  
55      public JXPathFilter(String expression, String expectedValue)
56      {
57          this.expression = expression;
58          this.expectedValue = expectedValue;
59      }
60  
61      public boolean accept(UMOMessage obj)
62      {
63          return accept(obj.getPayload());
64      }
65  
66      private boolean accept(Object obj)
67      {
68          if (obj == null)
69          {
70              logger.warn("Applying JXPathFilter to null object.");
71              return false;
72          }
73          if (expression == null)
74          {
75              logger.warn("Expression for JXPathFilter is not set.");
76              return false;
77          }
78          if (expectedValue == null)
79          {
80              // Handle the special case where the expected value really is null.
81              if (expression.endsWith("= null") || expression.endsWith("=null"))
82              {
83                  expectedValue = "null";
84                  expression = expression.substring(0, expression.lastIndexOf("="));
85              }
86              else
87              {
88                  if (logger.isInfoEnabled())
89                  {
90                      logger.info("Expected value for JXPathFilter is not set, using 'true' by default");
91                  }
92                  expectedValue = Boolean.TRUE.toString();
93              }
94          }
95  
96          Object xpathResult = null;
97          boolean accept = false;
98  
99          // Payload is a DOM Document
100         if (obj instanceof Document)
101         {
102             if (namespaces == null)
103             {
104                 // no namespace defined, let's perform a direct evaluation
105                 xpathResult = ((Document)obj).valueOf(expression);
106             }
107             else
108             {
109                 // create an xpath expression with namespaces and evaluate it
110                 XPath xpath = DocumentHelper.createXPath(expression);
111                 xpath.setNamespaceURIs(namespaces);
112                 xpathResult = xpath.valueOf(obj);
113             }
114 
115         }
116         // Payload is a String of XML
117         else if (obj instanceof String)
118         {
119             try
120             {
121                 return accept(DocumentHelper.parseText((String)obj));
122             }
123             catch (DocumentException e)
124             {
125                 logger.warn("JXPathFilter unable to parse XML document: " + e.getMessage(), e);
126                 if (logger.isDebugEnabled())
127                     logger.debug("XML = " + StringMessageUtils.truncate((String)obj, 200, false));
128                 return false;
129             }
130         }
131         // Payload is a Java object
132         else
133         {
134             if (logger.isDebugEnabled())
135             {
136                 logger.debug("Passing object of type " + obj.getClass().getName() + " to JXPathContext");
137             }
138             JXPathContext context = JXPathContext.newContext(obj);
139             initialise(context);
140             xpathResult = context.getValue(expression);
141         }
142 
143         if (logger.isDebugEnabled())
144         {
145             logger.debug("JXPathFilter Expression result = '" + xpathResult + "' -  Expected value = '"
146                          + expectedValue + "'");
147         }
148         // Compare the XPath result with the expected result.
149         if (xpathResult != null)
150         {
151             accept = xpathResult.toString().equals(expectedValue);
152         }
153         else
154         {
155             // A null result was actually expected.
156             if (expectedValue.equals("null"))
157             {
158                 accept = true;
159             }
160             // A null result was not expected, something probably went wrong.
161             else
162             {
163                 logger.warn("JXPathFilter expression evaluates to null: " + expression);
164             }
165         }
166 
167         if (logger.isDebugEnabled())
168         {
169             logger.debug("JXPathFilter accept object  : " + accept);
170         }
171 
172         return accept;
173     }
174 
175     /**
176      * Initializes the JXPathContext based on any relevant properties set for the
177      * filter.
178      * 
179      * @param the JXPathContext to initialize
180      */
181     protected void initialise(JXPathContext context)
182     {
183         Map.Entry entry = null;
184         if (namespaces != null)
185         {
186             if (logger.isDebugEnabled())
187             {
188                 logger.debug("Initializing JXPathContext with namespaces: " + namespaces);
189             }
190 
191             for (Iterator iterator = namespaces.entrySet().iterator(); iterator.hasNext();)
192             {
193                 entry = (Map.Entry)iterator.next();
194                 context.registerNamespace(entry.getKey().toString(), entry.getValue().toString());
195             }
196         }
197 
198         if (contextProperties != null)
199         {
200             if (logger.isDebugEnabled())
201             {
202                 logger.debug("Initializing JXPathContext with properties: " + contextProperties);
203             }
204 
205             for (Iterator iterator = contextProperties.entrySet().iterator(); iterator.hasNext();)
206             {
207                 entry = (Map.Entry)iterator.next();
208                 context.setValue(entry.getKey().toString(), entry.getValue());
209             }
210         }
211 
212         if (factory != null)
213         {
214             context.setFactory(factory);
215         }
216 
217         context.setLenient(lenient);
218     }
219 
220     /**
221      * @return XPath expression
222      */
223     public String getExpression()
224     {
225         return expression;
226     }
227 
228     /**
229      * @param expression The XPath expression
230      */
231     public void setExpression(String expression)
232     {
233         this.expression = expression;
234     }
235 
236     /**
237      * @return The expected result value of the XPath expression
238      */
239     public String getExpectedValue()
240     {
241         return expectedValue;
242     }
243 
244     /**
245      * Sets the expected result value of the XPath expression
246      */
247     public void setExpectedValue(String expectedValue)
248     {
249         this.expectedValue = expectedValue;
250     }
251 
252     /**
253      * @return The expected result value of the XPath expression
254      * @deprecated Use <code>getExpectedValue()</code>.
255      */
256     public String getValue()
257     {
258         return getExpectedValue();
259     }
260 
261     /**
262      * Sets the expected result value of the XPath expression
263      * 
264      * @deprecated Use <code>setExpectedValue(String expectedValue)</code>.
265      */
266     public void setValue(String value)
267     {
268         setExpectedValue(value);
269     }
270 
271     public Map getNamespaces()
272     {
273         return namespaces;
274     }
275 
276     public void setNamespaces(Map namespaces)
277     {
278         this.namespaces = namespaces;
279     }
280 
281     public Map getContextProperties()
282     {
283         return contextProperties;
284     }
285 
286     public void setContextProperties(Map contextProperties)
287     {
288         this.contextProperties = contextProperties;
289     }
290 
291     public AbstractFactory getFactory()
292     {
293         return factory;
294     }
295 
296     public void setFactory(AbstractFactory factory)
297     {
298         this.factory = factory;
299     }
300 
301     public boolean isLenient()
302     {
303         return lenient;
304     }
305 
306     public void setLenient(boolean lenient)
307     {
308         this.lenient = lenient;
309     }
310 }