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 static final ThreadLocal propertiesContext = new ThreadLocal();
61 protected static 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 protected void initialise(UMOMessage message)
116 {
117 if (logger.isDebugEnabled())
118 {
119 if (splitExpression.length() == 0)
120 {
121 logger.warn("splitExpression is not specified, no processing will take place");
122 }
123 else
124 {
125 logger.debug("splitExpression is " + splitExpression);
126 }
127 }
128
129 Object src = message.getPayload();
130
131 try
132 {
133 if (src instanceof byte[])
134 {
135 src = new String((byte[])src);
136 }
137
138 Document dom4jDoc;
139
140 if (src instanceof String)
141 {
142 String xml = (String)src;
143 SAXReader reader = new SAXReader();
144 setDoSchemaValidation(reader, isValidateSchema());
145
146 dom4jDoc = reader.read(new StringReader(xml));
147 }
148 else if (src instanceof org.dom4j.Document)
149 {
150 dom4jDoc = (org.dom4j.Document)src;
151 }
152 else
153 {
154 logger.error("Non-XML message payload: " + src.getClass().toString());
155 return;
156 }
157
158 if (dom4jDoc != null)
159 {
160 if (splitExpression.length() > 0)
161 {
162 XPath xpath = dom4jDoc.createXPath(splitExpression);
163 if (namespaces != null)
164 {
165 xpath.setNamespaceURIs(namespaces);
166 }
167
168 List foundNodes = xpath.selectNodes(dom4jDoc);
169 if (logger.isDebugEnabled())
170 {
171 logger.debug("Split into " + foundNodes.size());
172 }
173
174 List parts = new LinkedList();
175
176
177
178 for (Iterator iterator = foundNodes.iterator(); iterator.hasNext();)
179 {
180 Node node = (Node)iterator.next();
181 if (node instanceof Element)
182 {
183
184
185 node = (Node)node.clone();
186 parts.add(DocumentHelper.createDocument((Element)node));
187 }
188 else
189 {
190 logger.warn("Dcoument node: " + node.asXML()
191 + " is not an element and thus is not a valid part");
192 }
193 }
194 nodesContext.set(parts);
195 }
196 }
197 else
198 {
199 logger.warn("Unsupported message type, ignoring");
200 }
201 }
202 catch (Exception ex)
203 {
204 throw new IllegalArgumentException("Failed to initialise the payload: "
205 + ExceptionUtils.getStackTrace(ex));
206 }
207
208 Map theProperties = new HashMap();
209 for (Iterator iterator = message.getPropertyNames().iterator(); iterator.hasNext();)
210 {
211 String propertyKey = (String)iterator.next();
212 theProperties.put(propertyKey, message.getProperty(propertyKey));
213 }
214 propertiesContext.set(theProperties);
215 }
216
217
218
219
220
221
222
223
224
225
226 protected UMOMessage getMessagePart(UMOMessage message, UMOEndpoint endpoint)
227 {
228 List nodes = (List)nodesContext.get();
229
230 if (nodes == null)
231 {
232 logger.error("Error: nodes are null");
233 return null;
234 }
235
236 for (Iterator i = nodes.iterator(); i.hasNext();)
237 {
238 Document doc = (Document)i.next();
239
240 try
241 {
242 Map theProperties = (Map)propertiesContext.get();
243 UMOMessage result = new MuleMessage(doc, new HashMap(theProperties));
244
245 if (endpoint.getFilter() == null || endpoint.getFilter().accept(result))
246 {
247 if (logger.isDebugEnabled())
248 {
249 logger.debug("Endpoint filter matched for node " + i + " of " + nodes.size()
250 + ". Routing message over: " + endpoint.getEndpointURI().toString());
251 }
252 i.remove();
253 return result;
254 }
255 else
256 {
257 if (logger.isDebugEnabled())
258 {
259 logger.debug("Endpoint filter did not match, returning null");
260 }
261 }
262 }
263 catch (Exception e)
264 {
265 logger.error("Unable to create message for node at position " + i, e);
266 return null;
267 }
268 }
269
270 return null;
271 }
272
273 protected void setDoSchemaValidation(SAXReader reader, boolean validate) throws Exception
274 {
275 reader.setValidation(validate);
276 reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA, validate);
277 reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, true);
278
279
280
281
282
283 if (!validate) {
284 return;
285 }
286
287 InputStream xsdAsStream = IOUtils.getResourceAsStream(getExternalSchemaLocation(), getClass());
288 if (xsdAsStream == null)
289 {
290 throw new IllegalArgumentException("Couldn't find schema at "
291 + getExternalSchemaLocation());
292 }
293
294
295
296 reader.setProperty(JAXP_PROPERTIES_SCHEMA_LANGUAGE, JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE);
297
298
299 reader.setProperty(JAXP_PROPERTIES_SCHEMA_SOURCE, xsdAsStream);
300 }
301 }