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