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 gov.nist.secauto.metaschema.databind.io.json.DefaultJsonProblemHandler;
30 import gov.nist.secauto.metaschema.databind.model.IAssemblyClassBinding;
31 import gov.nist.secauto.metaschema.databind.model.IBoundAssemblyInstance;
32 import gov.nist.secauto.metaschema.databind.model.IBoundFieldInstance;
33 import gov.nist.secauto.metaschema.databind.model.IBoundFieldValueInstance;
34 import gov.nist.secauto.metaschema.databind.model.IBoundFlagInstance;
35 import gov.nist.secauto.metaschema.databind.model.IBoundNamedModelInstance;
36 import gov.nist.secauto.metaschema.databind.model.IClassBinding;
37 import gov.nist.secauto.metaschema.databind.model.IFieldClassBinding;
38 import gov.nist.secauto.metaschema.databind.model.info.IDataTypeHandler;
39 import gov.nist.secauto.metaschema.databind.model.info.IModelPropertyInfo;
40
41 import org.codehaus.stax2.XMLStreamWriter2;
42
43 import java.io.IOException;
44
45 import javax.xml.namespace.NamespaceContext;
46 import javax.xml.namespace.QName;
47 import javax.xml.stream.XMLStreamException;
48
49 import edu.umd.cs.findbugs.annotations.NonNull;
50
51 public class MetaschemaXmlWriter implements IXmlWritingContext {
52 @NonNull
53 private final XMLStreamWriter2 writer;
54
55
56
57
58
59
60
61
62 public MetaschemaXmlWriter(
63 @NonNull XMLStreamWriter2 writer) {
64 this.writer = writer;
65 }
66
67 @Override
68 public XMLStreamWriter2 getWriter() {
69 return writer;
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public void write(
87 @NonNull IAssemblyClassBinding targetDefinition,
88 @NonNull Object targetObject) throws XMLStreamException, IOException {
89 writer.writeStartDocument("UTF-8", "1.0");
90
91 QName rootQName = targetDefinition.getRootXmlQName();
92
93 NamespaceContext nsContext = writer.getNamespaceContext();
94 String prefix = nsContext.getPrefix(rootQName.getNamespaceURI());
95 if (prefix == null) {
96 prefix = "";
97 }
98
99 writer.writeStartElement(prefix, rootQName.getLocalPart(), rootQName.getNamespaceURI());
100
101 writeDefinitionValue(targetDefinition, targetObject, rootQName);
102
103 writer.writeEndElement();
104 }
105
106 @Override
107 public void writeDefinitionValue(
108 @NonNull IClassBinding targetDefinition,
109 @NonNull Object targetObject,
110 @NonNull QName parentName) throws IOException {
111
112 for (IBoundFlagInstance flag : targetDefinition.getFlagInstances()) {
113 assert flag != null;
114 writeFlagInstance(flag, targetObject);
115 }
116
117 if (targetDefinition instanceof IAssemblyClassBinding) {
118 for (IBoundNamedModelInstance modelProperty : ((IAssemblyClassBinding) targetDefinition).getModelInstances()) {
119 assert modelProperty != null;
120 writeModelInstanceValues(modelProperty, targetObject, parentName);
121 }
122 } else if (targetDefinition instanceof IFieldClassBinding) {
123 IBoundFieldValueInstance fieldValueInstance = ((IFieldClassBinding) targetDefinition).getFieldValueInstance();
124
125 Object value = fieldValueInstance.getValue(targetObject);
126 if (value != null) {
127 try {
128 fieldValueInstance.getJavaTypeAdapter().writeXmlValue(value, parentName, writer);
129 } catch (XMLStreamException ex) {
130 throw new IOException(ex);
131 }
132 }
133 } else {
134 throw new UnsupportedOperationException(
135 String.format("Unsupported class binding type: %s", targetDefinition.getClass().getName()));
136 }
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150 protected void writeFlagInstance(
151 @NonNull IBoundFlagInstance targetInstance,
152 @NonNull Object parentObject)
153 throws IOException {
154 Object objectValue = targetInstance.getValue(parentObject);
155 String value
156 = objectValue == null ? null : targetInstance.getDefinition().getJavaTypeAdapter().asString(objectValue);
157
158 if (value != null) {
159 QName name = targetInstance.getXmlQName();
160 try {
161 if (name.getNamespaceURI().isEmpty()) {
162 writer.writeAttribute(name.getLocalPart(), value);
163 } else {
164 writer.writeAttribute(name.getNamespaceURI(), name.getLocalPart(), value);
165 }
166 } catch (XMLStreamException ex) {
167 throw new IOException(ex);
168 }
169 }
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 protected boolean writeModelInstanceValues(
187 @NonNull IBoundNamedModelInstance targetInstance,
188 @NonNull Object parentObject,
189 @NonNull QName parentName)
190 throws IOException {
191 Object value = targetInstance.getValue(parentObject);
192 if (value == null) {
193 return false;
194 }
195
196 IModelPropertyInfo propertyInfo = targetInstance.getPropertyInfo();
197 if (targetInstance.getMinOccurs() > 0 || propertyInfo.getItemCount(value) > 0) {
198
199 QName currentStart = parentName;
200
201 try {
202 QName groupQName = targetInstance.getXmlGroupAsQName();
203 if (groupQName != null) {
204
205 writer.writeStartElement(groupQName.getNamespaceURI(), groupQName.getLocalPart());
206 currentStart = groupQName;
207 }
208
209
210 propertyInfo.writeValues(value, currentStart, this);
211
212 if (groupQName != null) {
213 writer.writeEndElement();
214 }
215 } catch (XMLStreamException ex) {
216 throw new IOException(ex);
217 }
218 }
219 return true;
220 }
221
222 @Override
223 public void writeInstanceValue(
224 @NonNull IBoundNamedModelInstance targetInstance,
225 @NonNull Object targetObject,
226 @NonNull QName parentName) throws IOException {
227
228 IDataTypeHandler handler = targetInstance.getDataTypeHandler();
229
230
231 boolean writeWrapper = targetInstance instanceof IBoundAssemblyInstance
232 || ((IBoundFieldInstance) targetInstance).isInXmlWrapped()
233 || !handler.isUnwrappedValueAllowedInXml();
234
235 try {
236 QName currentParentName;
237 if (writeWrapper) {
238 currentParentName = targetInstance.getXmlQName();
239 writer.writeStartElement(currentParentName.getNamespaceURI(), currentParentName.getLocalPart());
240 } else {
241 currentParentName = parentName;
242 }
243
244
245 handler.writeItem(targetObject, currentParentName, this);
246
247 if (writeWrapper) {
248 writer.writeEndElement();
249 }
250 } catch (XMLStreamException ex) {
251 throw new IOException(ex);
252 }
253 }
254 }