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