1
2
3
4
5
6 package gov.nist.secauto.metaschema.schemagen.xml.impl;
7
8 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
9 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
10 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
11 import gov.nist.secauto.metaschema.core.model.IDefinition;
12 import gov.nist.secauto.metaschema.core.model.IFieldDefinition;
13 import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
14 import gov.nist.secauto.metaschema.core.model.IModelElement;
15 import gov.nist.secauto.metaschema.core.model.IModule;
16 import gov.nist.secauto.metaschema.core.model.IValuedDefinition;
17 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
18 import gov.nist.secauto.metaschema.core.util.AutoCloser;
19 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
20 import gov.nist.secauto.metaschema.schemagen.AbstractGenerationState;
21 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationException;
22 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
23 import gov.nist.secauto.metaschema.schemagen.xml.datatype.XmlDatatypeManager;
24 import gov.nist.secauto.metaschema.schemagen.xml.schematype.IXmlComplexType;
25 import gov.nist.secauto.metaschema.schemagen.xml.schematype.IXmlSimpleType;
26 import gov.nist.secauto.metaschema.schemagen.xml.schematype.IXmlType;
27 import gov.nist.secauto.metaschema.schemagen.xml.schematype.XmlComplexTypeAssemblyDefinition;
28 import gov.nist.secauto.metaschema.schemagen.xml.schematype.XmlComplexTypeFieldDefinition;
29 import gov.nist.secauto.metaschema.schemagen.xml.schematype.XmlSimpleTypeDataTypeReference;
30 import gov.nist.secauto.metaschema.schemagen.xml.schematype.XmlSimpleTypeDataTypeRestriction;
31 import gov.nist.secauto.metaschema.schemagen.xml.schematype.XmlSimpleTypeUnion;
32
33 import org.codehaus.stax2.XMLStreamWriter2;
34
35 import java.io.IOException;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.concurrent.ConcurrentHashMap;
39
40 import javax.xml.namespace.QName;
41 import javax.xml.stream.XMLStreamException;
42
43 import edu.umd.cs.findbugs.annotations.NonNull;
44 import edu.umd.cs.findbugs.annotations.Nullable;
45
46 public class XmlGenerationState
47 extends AbstractGenerationState<AutoCloser<XMLStreamWriter2, SchemaGenerationException>, XmlDatatypeManager> {
48 @NonNull
49 private final String defaultNS;
50 @NonNull
51 private final Map<String, String> namespaceToPrefixMap = new ConcurrentHashMap<>();
52 @NonNull
53 private final Map<IDataTypeAdapter<?>, IXmlSimpleType> dataTypeToSimpleTypeMap = new ConcurrentHashMap<>();
54 @NonNull
55 private final Map<IValuedDefinition, IXmlSimpleType> definitionToSimpleTypeMap = new ConcurrentHashMap<>();
56 @NonNull
57 private final Map<IDefinition, IXmlType> definitionToTypeMap = new ConcurrentHashMap<>();
58
59 private int prefixNum;
60
61 public XmlGenerationState(
62 @NonNull IModule module,
63 @NonNull AutoCloser<XMLStreamWriter2, SchemaGenerationException> writer,
64 @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration) {
65 super(module, writer, configuration, new XmlDatatypeManager());
66 this.defaultNS = ObjectUtils.notNull(module.getXmlNamespace().toASCIIString());
67 }
68
69 @SuppressWarnings("resource")
70 @NonNull
71 public XMLStreamWriter2 getXMLStreamWriter() {
72 return getWriter().getResource();
73 }
74
75 @NonNull
76 public String getDefaultNS() {
77 return defaultNS;
78 }
79
80 @NonNull
81 public String getDatatypeNS() {
82 return getDefaultNS();
83 }
84
85 @SuppressWarnings("null")
86 @NonNull
87 public String getNS(@NonNull IModelElement modelElement) {
88 return modelElement.getContainingModule().getXmlNamespace().toASCIIString();
89 }
90
91 public String getNSPrefix(String namespace) {
92 String retval = null;
93 if (!getDefaultNS().equals(namespace)) {
94 synchronized (this) {
95 retval = namespaceToPrefixMap.get(namespace);
96 if (retval == null) {
97 retval = String.format("ns%d", ++prefixNum);
98 namespaceToPrefixMap.put(namespace, retval);
99 }
100 }
101 }
102 return retval;
103 }
104
105 @NonNull
106 protected QName newQName(
107 @NonNull String localName,
108 @NonNull String namespace) {
109 String prefix = null;
110 if (!getDefaultNS().equals(namespace)) {
111 prefix = getNSPrefix(namespace);
112 }
113
114 return ObjectUtils.notNull(
115 prefix == null ? new QName(namespace, localName) : new QName(namespace, localName, prefix));
116 }
117
118 @NonNull
119 protected QName newQName(
120 @NonNull IDefinition definition,
121 @Nullable String suffix) {
122 return newQName(
123 getTypeNameForDefinition(definition, suffix),
124 getNS(definition));
125 }
126
127 public IXmlType getXmlForDefinition(@NonNull IDefinition definition) {
128 IXmlType retval = definitionToTypeMap.get(definition);
129 if (retval == null) {
130 switch (definition.getModelType()) {
131 case FIELD: {
132 IFieldDefinition field = (IFieldDefinition) definition;
133 if (field.getFlagInstances().isEmpty()) {
134 retval = getSimpleType(field);
135 } else {
136 retval = newComplexType(field);
137 }
138 break;
139 }
140 case ASSEMBLY: {
141 retval = newComplexType((IAssemblyDefinition) definition);
142 break;
143 }
144 case FLAG:
145 retval = getSimpleType((IFlagDefinition) definition);
146 break;
147 case CHOICE_GROUP:
148 case CHOICE:
149 default:
150 throw new UnsupportedOperationException(definition.getModelType().toString());
151 }
152 definitionToTypeMap.put(definition, retval);
153 }
154 return retval;
155 }
156
157 @NonNull
158 public IXmlSimpleType getSimpleType(@NonNull IDataTypeAdapter<?> dataType) {
159 IXmlSimpleType type = dataTypeToSimpleTypeMap.get(dataType);
160 if (type == null) {
161
162 QName qname = newQName(
163 getDatatypeManager().getTypeNameForDatatype(dataType),
164 getDatatypeNS());
165 type = new XmlSimpleTypeDataTypeReference(qname, dataType);
166 dataTypeToSimpleTypeMap.put(dataType, type);
167 }
168 return type;
169 }
170
171 @NonNull
172 public IXmlSimpleType getSimpleType(@NonNull IValuedDefinition definition) {
173 IXmlSimpleType simpleType = definitionToSimpleTypeMap.get(definition);
174 if (simpleType == null) {
175 AllowedValueCollection allowedValuesCollection = getContextIndependentEnumeratedValues(definition);
176 List<IAllowedValue> allowedValues = allowedValuesCollection.getValues();
177
178 IDataTypeAdapter<?> dataType = definition.getJavaTypeAdapter();
179 if (allowedValues.isEmpty()) {
180
181 simpleType = getSimpleType(dataType);
182 } else {
183
184
185 simpleType = new XmlSimpleTypeDataTypeRestriction(
186 newQName(definition, null),
187 definition,
188 allowedValuesCollection);
189
190 if (!allowedValuesCollection.isClosed()) {
191
192
193
194 simpleType = new XmlSimpleTypeUnion(
195 newQName(definition, "Union"),
196 definition,
197 getSimpleType(dataType),
198 simpleType);
199 }
200 }
201
202 definitionToSimpleTypeMap.put(definition, simpleType);
203 }
204 return simpleType;
205 }
206
207 @NonNull
208 protected IXmlComplexType newComplexType(@NonNull IFieldDefinition definition) {
209 QName qname = newQName(definition, null);
210 return new XmlComplexTypeFieldDefinition(qname, definition);
211 }
212
213 @NonNull
214 protected IXmlComplexType newComplexType(@NonNull IAssemblyDefinition definition) {
215 QName qname = newQName(definition, null);
216 return new XmlComplexTypeAssemblyDefinition(qname, definition);
217 }
218
219 public void generateXmlTypes() throws XMLStreamException {
220
221 for (IXmlType type : definitionToTypeMap.values()) {
222 if (!type.isInline(this) && type.isGeneratedType(this) && type.isReferenced(this)) {
223 type.generate(this);
224 } else {
225 assert !type.isGeneratedType(this) || type.isInline(this) || !type.isReferenced(this);
226 }
227 }
228 getDatatypeManager().generateDatatypes(getXMLStreamWriter());
229 }
230
231 public void writeAttribute(@NonNull String localName, @NonNull String value) throws XMLStreamException {
232 getXMLStreamWriter().writeAttribute(localName, value);
233 }
234
235 public void writeStartElement(@NonNull String namespaceUri, @NonNull String localName) throws XMLStreamException {
236 getXMLStreamWriter().writeStartElement(namespaceUri, localName);
237 }
238
239 public void writeStartElement(
240 @NonNull String prefix,
241 @NonNull String localName,
242 @NonNull String namespaceUri) throws XMLStreamException {
243 getXMLStreamWriter().writeStartElement(prefix, localName, namespaceUri);
244
245 }
246
247 public void writeEndElement() throws XMLStreamException {
248 getXMLStreamWriter().writeEndElement();
249 }
250
251 public void writeCharacters(@NonNull String text) throws XMLStreamException {
252 getXMLStreamWriter().writeCharacters(text);
253 }
254
255 public void writeNamespace(String prefix, String namespaceUri) throws XMLStreamException {
256 getXMLStreamWriter().writeNamespace(prefix, namespaceUri);
257 }
258
259 @Override
260 public void flushWriter() throws IOException {
261 try {
262 getWriter().getResource().flush();
263 } catch (XMLStreamException ex) {
264 throw new IOException(ex);
265 }
266 }
267 }