1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.databind.io.xml;
28
29 import com.ctc.wstx.stax.WstxInputFactory;
30
31 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
32 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory;
33 import gov.nist.secauto.metaschema.core.util.AutoCloser;
34 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
35 import gov.nist.secauto.metaschema.databind.io.AbstractDeserializer;
36 import gov.nist.secauto.metaschema.databind.model.IAssemblyClassBinding;
37
38 import org.codehaus.stax2.XMLEventReader2;
39 import org.codehaus.stax2.XMLInputFactory2;
40
41 import java.io.IOException;
42 import java.io.Reader;
43 import java.net.URI;
44
45 import javax.xml.stream.EventFilter;
46 import javax.xml.stream.XMLEventReader;
47 import javax.xml.stream.XMLInputFactory;
48 import javax.xml.stream.XMLStreamException;
49
50 import edu.umd.cs.findbugs.annotations.NonNull;
51
52 public class DefaultXmlDeserializer<CLASS>
53 extends AbstractDeserializer<CLASS> {
54 private XMLInputFactory2 xmlInputFactory;
55
56 @NonNull
57 private final IAssemblyClassBinding rootDefinition;
58
59
60
61
62
63
64
65
66
67 public DefaultXmlDeserializer(@NonNull IAssemblyClassBinding classBinding) {
68 super(classBinding);
69 if (!classBinding.isRoot()) {
70 throw new UnsupportedOperationException(
71 String.format("The assembly '%s' is not a root assembly.", classBinding.getBoundClass().getName()));
72 }
73 this.rootDefinition = classBinding;
74 }
75
76
77
78
79
80
81
82
83
84 @NonNull
85 private XMLInputFactory2 getXMLInputFactory() {
86 synchronized (this) {
87 if (xmlInputFactory == null) {
88 xmlInputFactory = (XMLInputFactory2) XMLInputFactory.newInstance();
89 assert xmlInputFactory instanceof WstxInputFactory;
90 xmlInputFactory.configureForXmlConformance();
91 xmlInputFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
92
93 }
94 return ObjectUtils.notNull(xmlInputFactory);
95 }
96 }
97
98
99
100
101
102
103
104
105 protected void setXMLInputFactory(@NonNull XMLInputFactory2 factory) {
106 synchronized (this) {
107 this.xmlInputFactory = factory;
108 }
109 }
110
111 @NonNull
112 private XMLEventReader2 newXMLEventReader2(@NonNull Reader reader) throws XMLStreamException {
113 XMLEventReader eventReader = getXMLInputFactory().createXMLEventReader(reader);
114 EventFilter filter = new CommentFilter();
115 return ObjectUtils.notNull((XMLEventReader2) getXMLInputFactory().createFilteredReader(eventReader, filter));
116 }
117
118 @Override
119 protected final IDocumentNodeItem deserializeToNodeItemInternal(Reader reader, URI documentUri) throws IOException {
120 Object value = deserializeToValue(reader, documentUri);
121 return INodeItemFactory.instance().newDocumentNodeItem(rootDefinition, documentUri, value);
122 }
123
124 @Override
125 public final CLASS deserializeToValue(Reader reader, URI documentUri) throws IOException {
126
127 try (AutoCloser<XMLEventReader2, XMLStreamException> closer = new AutoCloser<>(
128 newXMLEventReader2(reader), event -> event.close())) {
129 return parseXmlInternal(closer.getResource());
130 } catch (XMLStreamException ex) {
131 throw new IOException("Unable to create a new XMLEventReader2 instance.", ex);
132 }
133 }
134
135 @NonNull
136 private CLASS parseXmlInternal(@NonNull XMLEventReader2 reader)
137 throws IOException {
138
139 MetaschemaXmlReader parser = new MetaschemaXmlReader(reader, new DefaultXmlProblemHandler());
140
141 try {
142 return parser.read(rootDefinition);
143 } catch (IOException | XMLStreamException | AssertionError ex) {
144 throw new IOException(
145 String.format("An unexpected error occured during parsing: %s", ex.getMessage()),
146 ex);
147 }
148 }
149 }