1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.xml.filters;
12
13 import static org.mule.util.ClassUtils.equal;
14 import static org.mule.util.ClassUtils.hash;
15
16 import org.mule.api.MuleContext;
17 import org.mule.api.MuleMessage;
18 import org.mule.api.context.MuleContextAware;
19 import org.mule.api.expression.ExpressionRuntimeException;
20 import org.mule.api.lifecycle.Initialisable;
21 import org.mule.api.lifecycle.InitialisationException;
22 import org.mule.api.registry.RegistrationException;
23 import org.mule.api.routing.filter.Filter;
24 import org.mule.config.i18n.CoreMessages;
25 import org.mule.module.xml.util.NamespaceManager;
26 import org.mule.module.xml.util.XMLUtils;
27
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.Map;
31
32 import org.apache.commons.jxpath.AbstractFactory;
33 import org.apache.commons.jxpath.JXPathContext;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.dom4j.Document;
37 import org.dom4j.DocumentHelper;
38 import org.dom4j.XPath;
39
40
41
42
43
44 public class JXPathFilter implements Filter, MuleContextAware, Initialisable
45 {
46
47 protected transient Log logger = LogFactory.getLog(getClass());
48
49 private String pattern;
50 private String expectedValue;
51 private Map namespaces = null;
52 private Map contextProperties = null;
53 private AbstractFactory factory;
54 private boolean lenient = true;
55
56 private MuleContext muleContext;
57 private NamespaceManager namespaceManager;
58
59 public JXPathFilter()
60 {
61 super();
62 }
63
64 public void setMuleContext(MuleContext context)
65 {
66 this.muleContext = context;
67 }
68
69 public void initialise() throws InitialisationException
70 {
71 try
72 {
73 namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
74 }
75 catch (RegistrationException e)
76 {
77 throw new ExpressionRuntimeException(CoreMessages.failedToLoad("NamespaceManager"), e);
78 }
79
80 if (namespaceManager != null)
81 {
82 if (namespaces == null)
83 {
84 namespaces = new HashMap(namespaceManager.getNamespaces());
85 }
86 else
87 {
88 namespaces.putAll(namespaceManager.getNamespaces());
89 }
90 }
91 }
92
93 public JXPathFilter(String pattern)
94 {
95 this.pattern = pattern;
96 }
97
98 public JXPathFilter(String pattern, String expectedValue)
99 {
100 this.pattern = pattern;
101 this.expectedValue = expectedValue;
102 }
103
104 public boolean accept(MuleMessage obj)
105 {
106 if (obj.getPayload() instanceof byte[])
107 {
108 try
109 {
110 return accept(obj.getPayloadAsString());
111 }
112 catch (Exception e)
113 {
114 logger.warn("JxPath filter rejected message because it could not convert from byte[] to String: " + e.getMessage(), e);
115 return false;
116 }
117 }
118 return accept(obj.getPayload());
119 }
120
121 private boolean accept(Object obj)
122 {
123 if (obj == null)
124 {
125 logger.warn("Applying JXPathFilter to null object.");
126 return false;
127 }
128 if (pattern == null)
129 {
130 logger.warn("Expression for JXPathFilter is not set.");
131 return false;
132 }
133 if (expectedValue == null)
134 {
135
136 if (pattern.endsWith("= null") || pattern.endsWith("=null"))
137 {
138 expectedValue = "null";
139 pattern = pattern.substring(0, pattern.lastIndexOf("="));
140 }
141 else
142 {
143 if (logger.isInfoEnabled())
144 {
145 logger.info("Expected value for JXPathFilter is not set, using 'true' by default");
146 }
147 expectedValue = Boolean.TRUE.toString();
148 }
149 }
150
151 Object xpathResult = null;
152 boolean accept = false;
153
154 Document dom4jDoc;
155 try
156 {
157 dom4jDoc = XMLUtils.toDocument(obj, muleContext);
158 }
159 catch (Exception e)
160 {
161 logger.warn("JxPath filter rejected message because of an error while parsing XML: " + e.getMessage(), e);
162 return false;
163 }
164
165
166 if (dom4jDoc != null)
167 {
168 if (namespaces == null)
169 {
170
171 xpathResult = dom4jDoc.valueOf(pattern);
172 }
173 else
174 {
175
176 XPath xpath = DocumentHelper.createXPath(pattern);
177 xpath.setNamespaceURIs(namespaces);
178 xpathResult = xpath.valueOf(dom4jDoc);
179 }
180 }
181
182 else
183 {
184 if (logger.isDebugEnabled())
185 {
186 logger.debug("Passing object of type " + obj.getClass().getName() + " to JXPathContext");
187 }
188 JXPathContext context = JXPathContext.newContext(obj);
189 initialise(context);
190 xpathResult = context.getValue(pattern);
191 }
192
193 if (logger.isDebugEnabled())
194 {
195 logger.debug("JXPathFilter Expression result = '" + xpathResult + "' - Expected value = '"
196 + expectedValue + "'");
197 }
198
199 if (xpathResult != null)
200 {
201 accept = xpathResult.toString().equals(expectedValue);
202 }
203 else
204 {
205
206 if (expectedValue.equals("null"))
207 {
208 accept = true;
209 }
210
211 else
212 {
213 logger.warn("JXPathFilter expression evaluates to null: " + pattern);
214 }
215 }
216
217 if (logger.isDebugEnabled())
218 {
219 logger.debug("JXPathFilter accept object : " + accept);
220 }
221
222 return accept;
223 }
224
225
226
227
228
229
230
231 protected void initialise(JXPathContext context)
232 {
233 Map.Entry entry;
234 if (namespaces != null)
235 {
236 if (logger.isDebugEnabled())
237 {
238 logger.debug("Initializing JXPathContext with namespaces: " + namespaces);
239 }
240
241 for (Iterator iterator = namespaces.entrySet().iterator(); iterator.hasNext();)
242 {
243 entry = (Map.Entry) iterator.next();
244 context.registerNamespace(entry.getKey().toString(), entry.getValue().toString());
245 }
246 }
247
248 if (contextProperties != null)
249 {
250 if (logger.isDebugEnabled())
251 {
252 logger.debug("Initializing JXPathContext with properties: " + contextProperties);
253 }
254
255 for (Iterator iterator = contextProperties.entrySet().iterator(); iterator.hasNext();)
256 {
257 entry = (Map.Entry) iterator.next();
258 context.setValue(entry.getKey().toString(), entry.getValue());
259 }
260 }
261
262 if (factory != null)
263 {
264 context.setFactory(factory);
265 }
266
267 context.setLenient(lenient);
268 }
269
270
271
272
273 public String getPattern()
274 {
275 return pattern;
276 }
277
278
279
280
281 public void setPattern(String pattern)
282 {
283 this.pattern = pattern;
284 }
285
286
287
288
289 public String getExpectedValue()
290 {
291 return expectedValue;
292 }
293
294
295
296
297 public void setExpectedValue(String expectedValue)
298 {
299 this.expectedValue = expectedValue;
300 }
301
302
303
304
305
306 public String getValue()
307 {
308 return getExpectedValue();
309 }
310
311
312
313
314
315
316 public void setValue(String value)
317 {
318 setExpectedValue(value);
319 }
320
321 public Map getNamespaces()
322 {
323 return namespaces;
324 }
325
326 public void setNamespaces(Map namespaces)
327 {
328 this.namespaces = namespaces;
329 }
330
331 public Map getContextProperties()
332 {
333 return contextProperties;
334 }
335
336 public void setContextProperties(Map contextProperties)
337 {
338 this.contextProperties = contextProperties;
339 }
340
341 public AbstractFactory getFactory()
342 {
343 return factory;
344 }
345
346 public void setFactory(AbstractFactory factory)
347 {
348 this.factory = factory;
349 }
350
351 public boolean isLenient()
352 {
353 return lenient;
354 }
355
356 public void setLenient(boolean lenient)
357 {
358 this.lenient = lenient;
359 }
360
361 public boolean equals(Object obj)
362 {
363 if (this == obj) return true;
364 if (obj == null || getClass() != obj.getClass()) return false;
365
366 final JXPathFilter other = (JXPathFilter) obj;
367 return equal(expectedValue, other.expectedValue)
368 && equal(contextProperties, other.contextProperties)
369 && equal(namespaces, other.namespaces)
370 && equal(pattern, other.pattern)
371 && lenient == other.lenient;
372 }
373
374 public int hashCode()
375 {
376 return hash(new Object[]{this.getClass(), expectedValue, contextProperties, namespaces, pattern, lenient});
377 }
378 }