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