1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.oxm.castor;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.Reader;
23 import java.io.Writer;
24 import java.util.Iterator;
25 import java.util.Properties;
26 import javax.xml.stream.XMLEventReader;
27 import javax.xml.stream.XMLEventWriter;
28 import javax.xml.stream.XMLStreamReader;
29 import javax.xml.stream.XMLStreamWriter;
30
31 import org.exolab.castor.mapping.Mapping;
32 import org.exolab.castor.mapping.MappingException;
33 import org.exolab.castor.xml.MarshalException;
34 import org.exolab.castor.xml.Marshaller;
35 import org.exolab.castor.xml.ResolverException;
36 import org.exolab.castor.xml.UnmarshalHandler;
37 import org.exolab.castor.xml.Unmarshaller;
38 import org.exolab.castor.xml.XMLContext;
39 import org.exolab.castor.xml.XMLException;
40 import org.w3c.dom.Node;
41 import org.xml.sax.ContentHandler;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xml.sax.XMLReader;
45 import org.xml.sax.ext.LexicalHandler;
46
47 import org.springframework.beans.factory.InitializingBean;
48 import org.springframework.core.io.Resource;
49 import org.springframework.oxm.AbstractMarshaller;
50 import org.springframework.oxm.XmlMappingException;
51 import org.springframework.util.ObjectUtils;
52 import org.springframework.util.StringUtils;
53 import org.springframework.xml.dom.DomContentHandler;
54 import org.springframework.xml.sax.SaxUtils;
55 import org.springframework.xml.stream.StaxEventContentHandler;
56 import org.springframework.xml.stream.StaxEventXmlReader;
57 import org.springframework.xml.stream.StaxStreamContentHandler;
58 import org.springframework.xml.stream.StaxStreamXmlReader;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public class CastorMarshaller extends AbstractMarshaller implements InitializingBean {
80
81
82 public static final String DEFAULT_ENCODING = "UTF-8";
83
84 private Resource[] mappingLocations;
85
86 private String encoding = DEFAULT_ENCODING;
87
88 private Class targetClass;
89
90 private XMLContext xmlContext;
91
92 private boolean validating = false;
93
94 private boolean whitespacePreserve = false;
95
96 private boolean ignoreExtraAttributes = true;
97
98 private boolean ignoreExtraElements = false;
99
100 private Properties namespaceMappings;
101
102 private boolean suppressNamespaces = false;
103
104 private boolean suppressXsiType = false;
105
106
107 public boolean getIgnoreExtraAttributes() {
108 return ignoreExtraAttributes;
109 }
110
111
112
113
114
115
116
117 public void setIgnoreExtraAttributes(boolean ignoreExtraAttributes) {
118 this.ignoreExtraAttributes = ignoreExtraAttributes;
119 }
120
121
122 public boolean getIgnoreExtraElements() {
123 return ignoreExtraElements;
124 }
125
126
127
128
129
130
131
132 public void setIgnoreExtraElements(boolean ignoreExtraElements) {
133 this.ignoreExtraElements = ignoreExtraElements;
134 }
135
136
137 public boolean getWhitespacePreserve() {
138 return whitespacePreserve;
139 }
140
141
142
143
144
145
146
147 public void setWhitespacePreserve(boolean whitespacePreserve) {
148 this.whitespacePreserve = whitespacePreserve;
149 }
150
151
152 public boolean isValidating() {
153 return validating;
154 }
155
156
157
158
159
160
161 public void setValidating(boolean validating) {
162 this.validating = validating;
163 }
164
165
166 public Properties getNamespaceMappings() {
167 return namespaceMappings;
168 }
169
170
171
172
173
174
175 public void setNamespaceMappings(Properties namespaceMappings) {
176 this.namespaceMappings = namespaceMappings;
177 }
178
179
180
181
182
183
184 public void setEncoding(String encoding) {
185 this.encoding = encoding;
186 }
187
188
189 public void setMappingLocation(Resource mappingLocation) {
190 mappingLocations = new Resource[]{mappingLocation};
191 }
192
193
194 public void setMappingLocations(Resource[] mappingLocations) {
195 this.mappingLocations = mappingLocations;
196 }
197
198
199 public boolean isSuppressNamespaces() {
200 return suppressNamespaces;
201 }
202
203
204
205
206
207
208
209 public void setSuppressNamespaces(boolean suppressNamespaces) {
210 this.suppressNamespaces = suppressNamespaces;
211 }
212
213
214 public boolean isSuppressXsiType() {
215 return suppressXsiType;
216 }
217
218
219
220
221
222
223
224 public void setSuppressXsiType(boolean suppressXsiType) {
225 this.suppressXsiType = suppressXsiType;
226 }
227
228
229
230
231
232 public void setTargetClass(Class targetClass) {
233 this.targetClass = targetClass;
234 }
235
236 public final void afterPropertiesSet() throws IOException {
237 if (mappingLocations != null && targetClass != null) {
238 throw new IllegalArgumentException("Cannot set both the 'mappingLocations' and 'targetClass' property. " +
239 "Set targetClass for unmarshalling a single class, and 'mappingLocations' for multiple classes'");
240 }
241 if (logger.isInfoEnabled()) {
242 if (mappingLocations != null) {
243 logger.info("Configured using " + StringUtils.arrayToCommaDelimitedString(mappingLocations));
244 }
245 else if (targetClass != null) {
246 logger.info("Configured for target class [" + targetClass.getName() + "]");
247 }
248 else {
249 logger.info("Using default configuration");
250 }
251 }
252 try {
253 xmlContext = createXMLContext(mappingLocations, targetClass);
254 }
255 catch (MappingException ex) {
256 throw new CastorSystemException("Could not load Castor mapping: " + ex.getMessage(), ex);
257 }
258 catch (ResolverException rex) {
259 throw new CastorSystemException("Could not load Castor mapping: " + rex.getMessage(), rex);
260 }
261 }
262
263
264 public boolean supports(Class clazz) {
265 return true;
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279 protected XMLContext createXMLContext(Resource[] mappingLocations, Class targetClass)
280 throws MappingException, IOException, ResolverException {
281 XMLContext context = new XMLContext();
282 if (!ObjectUtils.isEmpty(mappingLocations)) {
283 Mapping mapping = new Mapping();
284 for (int i = 0; i < mappingLocations.length; i++) {
285 mapping.loadMapping(SaxUtils.createInputSource(mappingLocations[i]));
286 }
287 context.addMapping(mapping);
288 }
289 if (targetClass != null) {
290 context.addClass(targetClass);
291 }
292 return context;
293 }
294
295
296
297
298
299 protected final void marshalDomNode(Object graph, Node node) throws XmlMappingException {
300 marshalSaxHandlers(graph, new DomContentHandler(node), null);
301 }
302
303 protected final void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler)
304 throws XmlMappingException {
305 Marshaller marshaller = xmlContext.createMarshaller();
306 marshaller.setContentHandler(contentHandler);
307 marshal(graph, marshaller);
308 }
309
310 protected final void marshalOutputStream(Object graph, OutputStream outputStream)
311 throws XmlMappingException, IOException {
312 marshalWriter(graph, new OutputStreamWriter(outputStream, encoding));
313 }
314
315 protected final void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
316 Marshaller marshaller = xmlContext.createMarshaller();
317 marshaller.setWriter(writer);
318 marshal(graph, marshaller);
319 }
320
321 protected final void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
322 marshalSaxHandlers(graph, new StaxEventContentHandler(eventWriter), null);
323 }
324
325 protected final void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
326 marshalSaxHandlers(graph, new StaxStreamContentHandler(streamWriter), null);
327 }
328
329 private void marshal(Object graph, Marshaller marshaller) {
330 try {
331 customizeMarshaller(marshaller);
332 marshaller.marshal(graph);
333 }
334 catch (XMLException ex) {
335 throw convertCastorException(ex, true);
336 }
337 }
338
339
340
341
342
343
344
345
346 protected void customizeMarshaller(Marshaller marshaller) {
347 marshaller.setValidation(isValidating());
348 marshaller.setSuppressNamespaces(isSuppressNamespaces());
349 marshaller.setSuppressXSIType(isSuppressXsiType());
350 Properties namespaceMappings = getNamespaceMappings();
351 if (namespaceMappings != null) {
352 for (Iterator iterator = namespaceMappings.keySet().iterator(); iterator.hasNext();) {
353 String prefix = (String) iterator.next();
354 String uri = namespaceMappings.getProperty(prefix);
355 marshaller.setNamespaceMapping(prefix, uri);
356 }
357 }
358 }
359
360
361
362
363
364 protected final Object unmarshalDomNode(Node node) throws XmlMappingException {
365 try {
366 return createUnmarshaller().unmarshal(node);
367 }
368 catch (XMLException ex) {
369 throw convertCastorException(ex, false);
370 }
371 }
372
373 protected final Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException {
374 try {
375 return createUnmarshaller().unmarshal(new InputSource(inputStream));
376 }
377 catch (XMLException ex) {
378 throw convertCastorException(ex, false);
379 }
380 }
381
382 protected final Object unmarshalReader(Reader reader) throws XmlMappingException, IOException {
383 try {
384 return createUnmarshaller().unmarshal(new InputSource(reader));
385 }
386 catch (XMLException ex) {
387 throw convertCastorException(ex, false);
388 }
389 }
390
391 protected final Object unmarshalXmlEventReader(XMLEventReader eventReader) {
392 XMLReader reader = new StaxEventXmlReader(eventReader);
393 try {
394 return unmarshalSaxReader(reader, new InputSource());
395 }
396 catch (IOException ex) {
397 throw new CastorUnmarshallingFailureException(new MarshalException(ex));
398 }
399 }
400
401 protected final Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
402 throws XmlMappingException, IOException {
403 UnmarshalHandler unmarshalHandler = createUnmarshaller().createHandler();
404 try {
405 ContentHandler contentHandler = Unmarshaller.getContentHandler(unmarshalHandler);
406 xmlReader.setContentHandler(contentHandler);
407 xmlReader.parse(inputSource);
408 return unmarshalHandler.getObject();
409 }
410 catch (SAXException ex) {
411 throw new CastorUnmarshallingFailureException(ex);
412 }
413 }
414
415 protected final Object unmarshalXmlStreamReader(XMLStreamReader streamReader) {
416 XMLReader reader = new StaxStreamXmlReader(streamReader);
417 try {
418 return unmarshalSaxReader(reader, new InputSource());
419 }
420 catch (IOException ex) {
421 throw new CastorUnmarshallingFailureException(new MarshalException(ex));
422 }
423 }
424
425 private Unmarshaller createUnmarshaller() {
426 Unmarshaller unmarshaller = xmlContext.createUnmarshaller();
427 if (targetClass != null) {
428 unmarshaller.setClass(targetClass);
429 unmarshaller.setClassLoader(targetClass.getClassLoader());
430 }
431 customizeUnmarshaller(unmarshaller);
432 return unmarshaller;
433 }
434
435
436
437
438
439
440
441
442 protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
443 unmarshaller.setValidation(isValidating());
444 unmarshaller.setWhitespacePreserve(getWhitespacePreserve());
445 unmarshaller.setIgnoreExtraAttributes(getIgnoreExtraAttributes());
446 unmarshaller.setIgnoreExtraElements(getIgnoreExtraElements());
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464 public XmlMappingException convertCastorException(XMLException ex, boolean marshalling) {
465 return CastorUtils.convertXmlException(ex, marshalling);
466 }
467 }