1
2
3
4
5
6
7
8
9
10
11 package org.mule.routing.outbound;
12
13 import org.mule.impl.MuleMessage;
14 import org.mule.umo.UMOMessage;
15 import org.mule.umo.endpoint.UMOEndpoint;
16 import org.mule.util.ExceptionUtils;
17 import org.mule.util.IOUtils;
18 import org.mule.util.StringUtils;
19
20 import java.io.InputStream;
21 import java.io.StringReader;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.dom4j.Document;
29 import org.dom4j.DocumentHelper;
30 import org.dom4j.Element;
31 import org.dom4j.Node;
32 import org.dom4j.XPath;
33 import org.dom4j.io.SAXReader;
34
35
36
37
38
39
40
41
42
43
44
45
46 public class FilteringXmlMessageSplitter extends AbstractMessageSplitter
47 {
48
49 public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema";
50 public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING = "http://apache.org/xml/features/validation/schema-full-checking";
51
52
53 public static final String JAXP_PROPERTIES_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
54
55
56
57 public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
58 public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE = "http://www.w3.org/2001/XMLSchema";
59
60 protected final ThreadLocal propertiesContext = new ThreadLocal();
61 protected final ThreadLocal nodesContext = new ThreadLocal();
62
63 protected volatile String splitExpression = "";
64 protected volatile Map namespaces = null;
65 protected volatile boolean validateSchema = false;
66 protected volatile String externalSchemaLocation = "";
67
68 public void setSplitExpression(String splitExpression)
69 {
70 this.splitExpression = StringUtils.trimToEmpty(splitExpression);
71 }
72
73 public void setNamespaces(Map namespaces)
74 {
75 this.namespaces = namespaces;
76 }
77
78 public String getSplitExpression()
79 {
80 return splitExpression;
81 }
82
83 public boolean isValidateSchema()
84 {
85 return validateSchema;
86 }
87
88 public void setValidateSchema(boolean validateSchema)
89 {
90 this.validateSchema = validateSchema;
91 }
92
93 public String getExternalSchemaLocation()
94 {
95 return externalSchemaLocation;
96 }
97
98
99
100
101
102
103
104 public void setExternalSchemaLocation(String externalSchemaLocation)
105 {
106 this.externalSchemaLocation = externalSchemaLocation;
107 }
108
109
110
111
112
113
114
115
116 protected void initialise(UMOMessage message)
117 {
118 super.initialise(message);
119
120 if (logger.isDebugEnabled())
121 {
122 if (splitExpression.length() == 0)
123 {
124 logger.warn("splitExpression is not specified, no processing will take place");
125 }
126 else
127 {
128 logger.debug("splitExpression is " + splitExpression);
129 }
130 }
131
132 Object src = message.getPayload();
133
134 try
135 {
136 if (src instanceof byte[])
137 {
138 src = new String((byte[])src);
139 }
140
141 Document dom4jDoc;
142
143 if (src instanceof String)
144 {
145 String xml = (String)src;
146 SAXReader reader = new SAXReader();
147 setDoSchemaValidation(reader, isValidateSchema());
148
149 dom4jDoc = reader.read(new StringReader(xml));
150 }
151 else if (src instanceof org.dom4j.Document)
152 {
153 dom4jDoc = (org.dom4j.Document)src;
154 }
155 else
156 {
157 logger.error("Non-XML message payload: " + src.getClass().toString());
158 return;
159 }
160
161 if (dom4jDoc != null)
162 {
163 if (splitExpression.length() > 0)
164 {
165 XPath xpath = dom4jDoc.createXPath(splitExpression);
166 if (namespaces != null)
167 {
168 xpath.setNamespaceURIs(namespaces);
169 }
170
171 List foundNodes = xpath.selectNodes(dom4jDoc);
172 if (enableCorrelation != ENABLE_CORRELATION_NEVER)
173 {
174 message.setCorrelationGroupSize(foundNodes.size());
175 }
176 if (logger.isDebugEnabled())
177 {
178 logger.debug("Split into " + foundNodes.size());
179 }
180
181 List parts = new LinkedList();
182
183
184
185 for (Iterator iterator = foundNodes.iterator(); iterator.hasNext();)
186 {
187 Node node = (Node)iterator.next();
188 if (node instanceof Element)
189 {
190
191
192 node = (Node)node.clone();
193 parts.add(DocumentHelper.createDocument((Element)node));
194 }
195 else
196 {
197 logger.warn("Dcoument node: " + node.asXML()
198 + " is not an element and thus is not a valid part");
199 }
200 }
201 nodesContext.set(parts);
202 }
203 }
204 else
205 {
206 logger.warn("Unsupported message type, ignoring");
207 }
208 }
209 catch (Exception ex)
210 {
211 throw new IllegalArgumentException("Failed to initialise the payload: "
212 + ExceptionUtils.getStackTrace(ex));
213 }
214
215 Map theProperties = new HashMap();
216 for (Iterator iterator = message.getPropertyNames().iterator(); iterator.hasNext();)
217 {
218 String propertyKey = (String)iterator.next();
219 theProperties.put(propertyKey, message.getProperty(propertyKey));
220 }
221 propertiesContext.set(theProperties);
222 }
223
224
225 protected void cleanup()
226 {
227 nodesContext.set(null);
228 propertiesContext.set(null);
229 super.cleanup();
230 }
231
232
233
234
235
236
237
238
239
240
241 protected UMOMessage getMessagePart(UMOMessage message, UMOEndpoint endpoint)
242 {
243 List nodes = (List)nodesContext.get();
244
245 if (nodes == null)
246 {
247 logger.error("Error: nodes are null");
248 return null;
249 }
250
251 for (Iterator i = nodes.iterator(); i.hasNext();)
252 {
253 Document doc = (Document)i.next();
254
255 try
256 {
257 Map theProperties = (Map)propertiesContext.get();
258 UMOMessage result = new MuleMessage(doc, new HashMap(theProperties));
259
260 if (endpoint.getFilter() == null || endpoint.getFilter().accept(result))
261 {
262 if (logger.isDebugEnabled())
263 {
264 logger.debug("Endpoint filter matched for node " + i + " of " + nodes.size()
265 + ". Routing message over: " + endpoint.getEndpointURI().toString());
266 }
267 i.remove();
268 return result;
269 }
270 else
271 {
272 if (logger.isDebugEnabled())
273 {
274 logger.debug("Endpoint filter did not match, returning null");
275 }
276 }
277 }
278 catch (Exception e)
279 {
280 logger.error("Unable to create message for node at position " + i, e);
281 return null;
282 }
283 }
284
285 return null;
286 }
287
288 protected void setDoSchemaValidation(SAXReader reader, boolean validate) throws Exception
289 {
290 reader.setValidation(validate);
291 reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA, validate);
292 reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, true);
293
294
295
296
297
298 if (!validate)
299 {
300 return;
301 }
302
303 InputStream xsdAsStream = IOUtils.getResourceAsStream(getExternalSchemaLocation(), getClass());
304 if (xsdAsStream == null)
305 {
306 throw new IllegalArgumentException("Couldn't find schema at "
307 + getExternalSchemaLocation());
308 }
309
310
311
312 reader.setProperty(JAXP_PROPERTIES_SCHEMA_LANGUAGE, JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE);
313
314
315 reader.setProperty(JAXP_PROPERTIES_SCHEMA_SOURCE, xsdAsStream);
316 }
317 }