1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.xml.filters;
12
13 import org.mule.api.MuleMessage;
14 import org.mule.api.lifecycle.Initialisable;
15 import org.mule.api.lifecycle.InitialisationException;
16 import org.mule.api.routing.filter.Filter;
17 import org.mule.config.i18n.CoreMessages;
18 import org.mule.module.xml.transformer.DelayedResult;
19 import org.mule.module.xml.util.XMLUtils;
20 import org.mule.util.IOUtils;
21 import org.mule.util.StringUtils;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.util.Map;
26
27 import javax.xml.stream.XMLInputFactory;
28 import javax.xml.transform.Result;
29 import javax.xml.transform.Source;
30 import javax.xml.transform.dom.DOMResult;
31 import javax.xml.transform.stream.StreamSource;
32 import javax.xml.validation.Schema;
33 import javax.xml.validation.SchemaFactory;
34 import javax.xml.validation.Validator;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.w3c.dom.ls.LSResourceResolver;
39 import org.xml.sax.ErrorHandler;
40 import org.xml.sax.SAXException;
41
42
43
44
45
46
47 public class SchemaValidationFilter extends AbstractJaxpFilter implements Filter, Initialisable
48 {
49 public static final String DEFAULT_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
50
51 protected transient Log logger = LogFactory.getLog(getClass());
52 private String schemaLocations;
53 private String schemaLanguage = DEFAULT_SCHEMA_LANGUAGE;
54 private Schema schemaObject;
55 private ErrorHandler errorHandler;
56 private Map<String, Boolean> validatorFeatures;
57 private Map<String, Object> validatorProperties;
58 private LSResourceResolver resourceResolver;
59 private boolean useStaxSource = false;
60 private boolean returnResult = true;
61 private XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
62
63
64
65
66
67
68
69 public boolean accept(MuleMessage message)
70 {
71 Source source;
72 try
73 {
74 source = loadSource(message);
75 }
76 catch (Exception e)
77 {
78 if (e instanceof RuntimeException)
79 {
80 throw (RuntimeException) e;
81 }
82
83 if (logger.isInfoEnabled())
84 {
85 logger.info("SchemaValidationFilter rejected a message because there was a problem interpreting the payload as XML.", e);
86 }
87 return false;
88 }
89
90 if (source == null)
91 {
92 if (logger.isInfoEnabled())
93 {
94 logger.info("SchemaValidationFilter rejected a message because the XML source was null.");
95 }
96 return false;
97 }
98
99
100 DOMResult result = null;
101
102 try
103 {
104 if (returnResult)
105 {
106 result = new DOMResult();
107 createValidator().validate(source, result);
108 }
109 else
110 {
111 createValidator().validate(source);
112 }
113 }
114 catch (SAXException e)
115 {
116 if (logger.isDebugEnabled())
117 {
118 logger.debug(
119 "SchemaValidationFilter rejected a message because it apparently failed to validate against the schema.",
120 e);
121 }
122 return false;
123 }
124 catch (IOException e)
125 {
126 if (logger.isInfoEnabled())
127 {
128 logger.info(
129 "SchemaValidationFilter rejected a message because there was a problem reading the XML.",
130 e);
131 }
132 return false;
133 }
134 finally
135 {
136 if (result != null && result.getNode() != null)
137 {
138 message.setPayload(result.getNode());
139 }
140 }
141
142 if (logger.isDebugEnabled())
143 {
144 logger.debug("SchemaValidationFilter accepted the message.");
145 }
146
147 return true;
148 }
149
150
151
152
153
154
155
156 protected Object getDelayedResult(final Source source)
157 {
158 return new DelayedResult()
159 {
160 private String systemId;
161
162 public void write(Result result) throws Exception
163 {
164 createValidator().validate(source, result);
165 }
166
167 public String getSystemId()
168 {
169 return systemId;
170 }
171
172 public void setSystemId(String systemId)
173 {
174 this.systemId = systemId;
175 }
176 };
177 }
178
179
180
181
182
183
184
185 protected Source loadSource(MuleMessage msg) throws Exception
186 {
187 Object payload = msg.getPayload();
188 if (returnResult)
189 {
190
191 payload = toDOMNode(payload);
192 }
193 return XMLUtils.toXmlSource(getXMLInputFactory(), isUseStaxSource(), payload);
194 }
195
196 public void initialise() throws InitialisationException
197 {
198 super.initialise();
199
200 if (getSchemaObject() == null)
201 {
202 if (schemaLocations == null)
203 {
204 throw new InitialisationException(CoreMessages.objectIsNull("schemaLocations"), this);
205 }
206
207 String[] split = StringUtils.splitAndTrim(schemaLocations, ",");
208 Source[] schemas = new Source[split.length];
209 for (int i = 0; i < split.length; i++)
210 {
211 String loc = split[i];
212 InputStream schemaStream;
213 try
214 {
215 schemaStream = loadSchemaStream(loc);
216 }
217 catch (IOException e)
218 {
219 throw new InitialisationException(e, this);
220 }
221
222 if (schemaStream == null)
223 {
224 throw new InitialisationException(CoreMessages.failedToLoad(loc), this);
225 }
226
227 schemas[i] = new StreamSource(schemaStream);
228 }
229
230 SchemaFactory schemaFactory = SchemaFactory.newInstance(getSchemaLanguage());
231
232 if (logger.isInfoEnabled())
233 {
234 logger.info("Schema factory implementation: " + schemaFactory);
235 }
236
237 if (this.errorHandler != null)
238 {
239 schemaFactory.setErrorHandler(this.errorHandler);
240 }
241
242 if (this.resourceResolver != null)
243 {
244 schemaFactory.setResourceResolver(this.resourceResolver);
245 }
246
247 Schema schema;
248 try
249 {
250 schema = schemaFactory.newSchema(schemas);
251 }
252 catch (SAXException e)
253 {
254 throw new InitialisationException(e, this);
255 }
256
257 setSchemaObject(schema);
258 }
259
260 if (getSchemaObject() == null)
261 {
262 throw new InitialisationException(CoreMessages.objectIsNull("schemaObject"), this);
263 }
264 }
265
266 protected InputStream loadSchemaStream(String schemaLocation) throws IOException
267 {
268 return IOUtils.getResourceAsStream(schemaLocation, getClass());
269 }
270
271
272
273
274
275
276 public Validator createValidator() throws SAXException
277 {
278 Validator validator = getSchemaObject().newValidator();
279
280 if (this.validatorFeatures != null)
281 {
282 for (Map.Entry<String, Boolean> feature : this.validatorFeatures.entrySet())
283 {
284 validator.setFeature(feature.getKey(), feature.getValue());
285 }
286 }
287
288 if (this.validatorProperties != null)
289 {
290 for (Map.Entry<String, Object> validatorProperty : this.validatorProperties.entrySet())
291 {
292 validator.setProperty(validatorProperty.getKey(), validatorProperty.getValue());
293 }
294 }
295
296 return validator;
297 }
298
299 public String getSchemaLocations()
300 {
301 return schemaLocations;
302 }
303
304 public void setSchemaLocations(String schemaLocations)
305 {
306 this.schemaLocations = schemaLocations;
307 }
308
309 public String getSchemaLanguage()
310 {
311 return schemaLanguage;
312 }
313
314 public void setSchemaLanguage(String schemaLanguage)
315 {
316 this.schemaLanguage = schemaLanguage;
317 }
318
319 public Schema getSchemaObject()
320 {
321 return schemaObject;
322 }
323
324 public void setSchemaObject(Schema schemaObject)
325 {
326 this.schemaObject = schemaObject;
327 }
328
329 public ErrorHandler getErrorHandler()
330 {
331 return errorHandler;
332 }
333
334 public void setErrorHandler(ErrorHandler errorHandler)
335 {
336 this.errorHandler = errorHandler;
337 }
338
339 public LSResourceResolver getResourceResolver()
340 {
341 return resourceResolver;
342 }
343
344 public void setResourceResolver(LSResourceResolver resourceResolver)
345 {
346 this.resourceResolver = resourceResolver;
347 }
348
349 public Map<String, Boolean> getValidatorFeatures()
350 {
351 return validatorFeatures;
352 }
353
354 public void setValidatorFeatures(Map<String, Boolean> validatorFeatures)
355 {
356 this.validatorFeatures = validatorFeatures;
357 }
358
359 public Map<String, Object> getValidatorProperties()
360 {
361 return validatorProperties;
362 }
363
364 public void setValidatorProperties(Map<String, Object> validatorProperties)
365 {
366 this.validatorProperties = validatorProperties;
367 }
368
369 public XMLInputFactory getXMLInputFactory()
370 {
371 return xmlInputFactory;
372 }
373
374 public void setXMLInputFactory(XMLInputFactory xmlInputFactory)
375 {
376 this.xmlInputFactory = xmlInputFactory;
377 }
378
379 public boolean isUseStaxSource()
380 {
381 return useStaxSource;
382 }
383
384 public void setUseStaxSource(boolean useStaxSource)
385 {
386 this.useStaxSource = useStaxSource;
387 }
388
389 public boolean isReturnResult()
390 {
391 return returnResult;
392 }
393
394 public void setReturnResult(boolean returnResult)
395 {
396 this.returnResult = returnResult;
397 }
398 }