1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.oxm.xmlbeans;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.io.Reader;
23 import java.io.Writer;
24 import java.lang.ref.WeakReference;
25 import java.nio.CharBuffer;
26 import java.util.ArrayList;
27 import java.util.List;
28 import javax.xml.stream.XMLEventReader;
29 import javax.xml.stream.XMLEventWriter;
30 import javax.xml.stream.XMLStreamReader;
31 import javax.xml.stream.XMLStreamWriter;
32
33 import org.apache.xmlbeans.XMLStreamValidationException;
34 import org.apache.xmlbeans.XmlError;
35 import org.apache.xmlbeans.XmlException;
36 import org.apache.xmlbeans.XmlObject;
37 import org.apache.xmlbeans.XmlOptions;
38 import org.apache.xmlbeans.XmlSaxHandler;
39 import org.apache.xmlbeans.XmlValidationError;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.ContentHandler;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.SAXNotRecognizedException;
47 import org.xml.sax.SAXNotSupportedException;
48 import org.xml.sax.XMLReader;
49 import org.xml.sax.ext.LexicalHandler;
50
51 import org.springframework.oxm.Marshaller;
52 import org.springframework.oxm.MarshallingFailureException;
53 import org.springframework.oxm.UncategorizedMappingException;
54 import org.springframework.oxm.UnmarshallingFailureException;
55 import org.springframework.oxm.ValidationFailureException;
56 import org.springframework.oxm.XmlMappingException;
57 import org.springframework.oxm.support.AbstractMarshaller;
58 import org.springframework.util.xml.StaxUtils;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public class XmlBeansMarshaller extends AbstractMarshaller {
80
81 private XmlOptions xmlOptions;
82
83 private boolean validating = false;
84
85
86
87
88
89
90 public void setXmlOptions(XmlOptions xmlOptions) {
91 this.xmlOptions = xmlOptions;
92 }
93
94
95
96
97 public XmlOptions getXmlOptions() {
98 return this.xmlOptions;
99 }
100
101
102
103
104
105 public void setValidating(boolean validating) {
106 this.validating = validating;
107 }
108
109
110
111
112 public boolean isValidating() {
113 return this.validating;
114 }
115
116
117
118
119
120 @Override
121 public boolean supports(Class<?> clazz) {
122 return XmlObject.class.isAssignableFrom(clazz);
123 }
124
125
126 @Override
127 protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
128 Document document = (node.getNodeType() == Node.DOCUMENT_NODE ? (Document) node : node.getOwnerDocument());
129 Node xmlBeansNode = ((XmlObject) graph).newDomNode(getXmlOptions());
130 NodeList xmlBeansChildNodes = xmlBeansNode.getChildNodes();
131 for (int i = 0; i < xmlBeansChildNodes.getLength(); i++) {
132 Node xmlBeansChildNode = xmlBeansChildNodes.item(i);
133 Node importedNode = document.importNode(xmlBeansChildNode, true);
134 node.appendChild(importedNode);
135 }
136 }
137
138 @Override
139 protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) {
140 ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
141 LexicalHandler lexicalHandler = null;
142 if (contentHandler instanceof LexicalHandler) {
143 lexicalHandler = (LexicalHandler) contentHandler;
144 }
145 marshalSaxHandlers(graph, contentHandler, lexicalHandler);
146 }
147
148 @Override
149 protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
150 ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter);
151 LexicalHandler lexicalHandler = null;
152 if (contentHandler instanceof LexicalHandler) {
153 lexicalHandler = (LexicalHandler) contentHandler;
154 }
155 marshalSaxHandlers(graph, contentHandler, lexicalHandler);
156 }
157
158 @Override
159 protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler)
160 throws XmlMappingException {
161 try {
162 ((XmlObject) graph).save(contentHandler, lexicalHandler, getXmlOptions());
163 }
164 catch (SAXException ex) {
165 throw convertXmlBeansException(ex, true);
166 }
167 }
168
169 @Override
170 protected void marshalOutputStream(Object graph, OutputStream outputStream)
171 throws XmlMappingException, IOException {
172
173 ((XmlObject) graph).save(outputStream, getXmlOptions());
174 }
175
176 @Override
177 protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
178 ((XmlObject) graph).save(writer, getXmlOptions());
179 }
180
181
182 @Override
183 protected Object unmarshalDomNode(Node node) throws XmlMappingException {
184 try {
185 XmlObject object = XmlObject.Factory.parse(node, getXmlOptions());
186 validate(object);
187 return object;
188 }
189 catch (XmlException ex) {
190 throw convertXmlBeansException(ex, false);
191 }
192 }
193
194 @Override
195 protected Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException {
196 XMLReader reader = StaxUtils.createXMLReader(eventReader);
197 try {
198 return unmarshalSaxReader(reader, new InputSource());
199 }
200 catch (IOException ex) {
201 throw convertXmlBeansException(ex, false);
202 }
203 }
204
205 @Override
206 protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException {
207 try {
208 XmlObject object = XmlObject.Factory.parse(streamReader, getXmlOptions());
209 validate(object);
210 return object;
211 }
212 catch (XmlException ex) {
213 throw convertXmlBeansException(ex, false);
214 }
215 }
216
217 @Override
218 protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
219 throws XmlMappingException, IOException {
220
221 XmlSaxHandler saxHandler = XmlObject.Factory.newXmlSaxHandler(getXmlOptions());
222 xmlReader.setContentHandler(saxHandler.getContentHandler());
223 try {
224 xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", saxHandler.getLexicalHandler());
225 }
226 catch (SAXNotRecognizedException ex) {
227
228 }
229 catch (SAXNotSupportedException ex) {
230
231 }
232 try {
233 xmlReader.parse(inputSource);
234 XmlObject object = saxHandler.getObject();
235 validate(object);
236 return object;
237 }
238 catch (SAXException ex) {
239 throw convertXmlBeansException(ex, false);
240 }
241 catch (XmlException ex) {
242 throw convertXmlBeansException(ex, false);
243 }
244 }
245
246 @Override
247 protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException {
248 try {
249 InputStream nonClosingInputStream = new NonClosingInputStream(inputStream);
250 XmlObject object = XmlObject.Factory.parse(nonClosingInputStream, getXmlOptions());
251 validate(object);
252 return object;
253 }
254 catch (XmlException ex) {
255 throw convertXmlBeansException(ex, false);
256 }
257 }
258
259 @Override
260 protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException {
261 try {
262 Reader nonClosingReader = new NonClosingReader(reader);
263 XmlObject object = XmlObject.Factory.parse(nonClosingReader, getXmlOptions());
264 validate(object);
265 return object;
266 }
267 catch (XmlException ex) {
268 throw convertXmlBeansException(ex, false);
269 }
270 }
271
272
273
274
275
276
277
278 protected void validate(XmlObject object) throws ValidationFailureException {
279 if (isValidating() && object != null) {
280 XmlOptions validateOptions = getXmlOptions();
281 if (validateOptions == null) {
282
283 validateOptions = new XmlOptions();
284 }
285 List<XmlError> errorsList = new ArrayList<XmlError>();
286 validateOptions.setErrorListener(errorsList);
287 if (!object.validate(validateOptions)) {
288 StringBuilder sb = new StringBuilder("Failed to validate XmlObject: ");
289 boolean first = true;
290 for (XmlError error : errorsList) {
291 if (error instanceof XmlValidationError) {
292 if (!first) {
293 sb.append("; ");
294 }
295 sb.append(error.toString());
296 first = false;
297 }
298 }
299 throw new ValidationFailureException("XMLBeans validation failure",
300 new XmlException(sb.toString(), null, errorsList));
301 }
302 }
303 }
304
305
306
307
308
309
310
311
312
313
314
315 protected XmlMappingException convertXmlBeansException(Exception ex, boolean marshalling) {
316 if (ex instanceof XMLStreamValidationException) {
317 return new ValidationFailureException("XMLBeans validation exception", ex);
318 }
319 else if (ex instanceof XmlException || ex instanceof SAXException) {
320 if (marshalling) {
321 return new MarshallingFailureException("XMLBeans marshalling exception", ex);
322 }
323 else {
324 return new UnmarshallingFailureException("XMLBeans unmarshalling exception", ex);
325 }
326 }
327 else {
328
329 return new UncategorizedMappingException("Unknown XMLBeans exception", ex);
330 }
331 }
332
333
334 private static class NonClosingInputStream extends InputStream {
335
336 private final WeakReference<InputStream> in;
337
338 public NonClosingInputStream(InputStream in) {
339 this.in = new WeakReference<InputStream>(in);
340 }
341
342 private InputStream getInputStream() {
343 return this.in.get();
344 }
345
346 @Override
347 public int read() throws IOException {
348 InputStream in = getInputStream();
349 return (in != null ? in.read() : -1);
350 }
351
352 @Override
353 public int read(byte[] b) throws IOException {
354 InputStream in = getInputStream();
355 return (in != null ? in.read(b) : -1);
356 }
357
358 @Override
359 public int read(byte[] b, int off, int len) throws IOException {
360 InputStream in = getInputStream();
361 return (in != null ? in.read(b, off, len) : -1);
362 }
363
364 @Override
365 public long skip(long n) throws IOException {
366 InputStream in = getInputStream();
367 return (in != null ? in.skip(n) : 0);
368 }
369
370 @Override
371 public boolean markSupported() {
372 InputStream in = getInputStream();
373 return (in != null && in.markSupported());
374 }
375
376 @Override
377 public void mark(int readlimit) {
378 InputStream in = getInputStream();
379 if (in != null) {
380 in.mark(readlimit);
381 }
382 }
383
384 @Override
385 public void reset() throws IOException {
386 InputStream in = getInputStream();
387 if (in != null) {
388 in.reset();
389 }
390 }
391
392 @Override
393 public int available() throws IOException {
394 InputStream in = getInputStream();
395 return (in != null ? in.available() : 0);
396 }
397
398 @Override
399 public void close() throws IOException {
400 InputStream in = getInputStream();
401 if (in != null) {
402 this.in.clear();
403 }
404 }
405 }
406
407
408 private static class NonClosingReader extends Reader {
409
410 private final WeakReference<Reader> reader;
411
412 public NonClosingReader(Reader reader) {
413 this.reader = new WeakReference<Reader>(reader);
414 }
415
416 private Reader getReader() {
417 return this.reader.get();
418 }
419
420 @Override
421 public int read(CharBuffer target) throws IOException {
422 Reader rdr = getReader();
423 return (rdr != null ? rdr.read(target) : -1);
424 }
425
426 @Override
427 public int read() throws IOException {
428 Reader rdr = getReader();
429 return (rdr != null ? rdr.read() : -1);
430 }
431
432 @Override
433 public int read(char[] cbuf) throws IOException {
434 Reader rdr = getReader();
435 return (rdr != null ? rdr.read(cbuf) : -1);
436 }
437
438 @Override
439 public int read(char[] cbuf, int off, int len) throws IOException {
440 Reader rdr = getReader();
441 return (rdr != null ? rdr.read(cbuf, off, len) : -1);
442 }
443
444 @Override
445 public long skip(long n) throws IOException {
446 Reader rdr = getReader();
447 return (rdr != null ? rdr.skip(n) : 0);
448 }
449
450 @Override
451 public boolean ready() throws IOException {
452 Reader rdr = getReader();
453 return (rdr != null && rdr.ready());
454 }
455
456 @Override
457 public boolean markSupported() {
458 Reader rdr = getReader();
459 return (rdr != null && rdr.markSupported());
460 }
461
462 @Override
463 public void mark(int readAheadLimit) throws IOException {
464 Reader rdr = getReader();
465 if (rdr != null) {
466 rdr.mark(readAheadLimit);
467 }
468 }
469
470 @Override
471 public void reset() throws IOException {
472 Reader rdr = getReader();
473 if (rdr != null) {
474 rdr.reset();
475 }
476 }
477
478 @Override
479 public void close() throws IOException {
480 Reader rdr = getReader();
481 if (rdr != null) {
482 this.reader.clear();
483 }
484 }
485 }
486
487 }