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