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.core.model.xml;
28
29 import gov.nist.secauto.metaschema.core.model.IAssemblyInstance;
30 import gov.nist.secauto.metaschema.core.model.IFieldInstance;
31 import gov.nist.secauto.metaschema.core.model.IModelContainer;
32 import gov.nist.secauto.metaschema.core.model.IModelInstance;
33 import gov.nist.secauto.metaschema.core.model.INamedModelInstance;
34 import gov.nist.secauto.metaschema.core.model.JsonGroupAsBehavior;
35 import gov.nist.secauto.metaschema.core.model.MetaschemaModelConstants;
36 import gov.nist.secauto.metaschema.core.model.XmlGroupAsBehavior;
37 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.AssemblyReferenceType;
38 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ChoiceType;
39 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.FieldReferenceType;
40 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.GroupAsType;
41 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.InlineAssemblyDefinitionType;
42 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.InlineFieldDefinitionType;
43 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
44 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
45
46 import org.apache.xmlbeans.XmlCursor;
47 import org.apache.xmlbeans.XmlObject;
48
49 import java.math.BigInteger;
50 import java.util.Collections;
51 import java.util.LinkedHashMap;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.function.Function;
55 import java.util.stream.Collectors;
56 import java.util.stream.Stream;
57
58 import edu.umd.cs.findbugs.annotations.NonNull;
59 import edu.umd.cs.findbugs.annotations.Nullable;
60
61 @SuppressWarnings("PMD.CouplingBetweenObjects")
62 class XmlModelParser {
63 private Map<String, INamedModelInstance> namedModelInstances;
64 private Map<String, IFieldInstance> fieldInstances;
65 private Map<String, IAssemblyInstance> assemblyInstances;
66 private List<IModelInstance> modelInstances;
67
68
69 void parseChoice(XmlObject xmlObject, @NonNull IModelContainer container) {
70 try (XmlCursor cursor = xmlObject.newCursor()) {
71 cursor.selectPath("declare namespace m='http://csrc.nist.gov/ns/oscal/metaschema/1.0';"
72 + "$this/m:assembly|$this/m:define-assembly|$this/m:field"
73 + "|$this/m:define-field");
74 parseInternal(cursor, container);
75 }
76 }
77
78
79 void parseModel(XmlObject xmlObject, @NonNull IModelContainer container) {
80
81 try (XmlCursor cursor = xmlObject.newCursor()) {
82 cursor.selectPath("declare namespace m='http://csrc.nist.gov/ns/oscal/metaschema/1.0';"
83 + "$this/m:model/m:assembly|$this/m:model/m:define-assembly|$this/m:model/m:field"
84 + "|$this/m:model/m:define-field|$this/m:model/m:choice");
85
86 parseInternal(cursor, container);
87 }
88 }
89
90 @SuppressWarnings("null")
91 @NonNull
92 protected <S> Stream<S> append(@NonNull Stream<S> original, @NonNull S item) {
93 Stream<S> newStream = Stream.of(item).sequential();
94 return Stream.concat(original, newStream);
95 }
96
97 @SuppressWarnings("null")
98 private void parseInternal(XmlCursor cursor, @NonNull IModelContainer container) {
99
100
101
102
103 Stream<IFieldInstance> fieldInstances = Stream.empty();
104 fieldInstances = fieldInstances.sequential();
105 Stream<IAssemblyInstance> assemblyInstances = Stream.empty();
106 assemblyInstances = assemblyInstances.sequential();
107 Stream<INamedModelInstance> namedModelInstances = Stream.empty();
108 namedModelInstances = namedModelInstances.sequential();
109 Stream<IModelInstance> modelInstances = Stream.empty();
110 modelInstances = modelInstances.sequential();
111
112 while (cursor.toNextSelection()) {
113 XmlObject obj = cursor.getObject();
114 if (obj instanceof FieldReferenceType) {
115 XmlFieldInstance field
116 = new XmlFieldInstance((FieldReferenceType) obj, container);
117 fieldInstances = append(fieldInstances, field);
118 namedModelInstances = append(namedModelInstances, field);
119 modelInstances = append(modelInstances, field);
120 } else if (obj instanceof InlineFieldDefinitionType) {
121 XmlInlineFieldDefinition field
122 = new XmlInlineFieldDefinition((InlineFieldDefinitionType) obj, container);
123 fieldInstances = append(fieldInstances, field);
124 namedModelInstances = append(namedModelInstances, field);
125 modelInstances = append(modelInstances, field);
126 } else if (obj instanceof AssemblyReferenceType) {
127 XmlAssemblyInstance assembly
128 = new XmlAssemblyInstance((AssemblyReferenceType) obj, container);
129 assemblyInstances = append(assemblyInstances, assembly);
130 namedModelInstances = append(namedModelInstances, assembly);
131 modelInstances = append(modelInstances, assembly);
132 } else if (obj instanceof InlineAssemblyDefinitionType) {
133 XmlInlineAssemblyDefinition assembly
134 = new XmlInlineAssemblyDefinition((InlineAssemblyDefinitionType) obj, container);
135 assemblyInstances = append(assemblyInstances, assembly);
136 namedModelInstances = append(namedModelInstances, assembly);
137 modelInstances = append(modelInstances, assembly);
138 } else if (obj instanceof ChoiceType) {
139 XmlChoiceInstance choice
140 = new XmlChoiceInstance((ChoiceType) obj, container);
141
142
143 modelInstances = append(modelInstances, choice);
144 }
145 }
146
147 this.fieldInstances = fieldInstances
148 .collect(Collectors.toMap(IFieldInstance::getEffectiveName, Function.identity(),
149 CustomCollectors.useFirstMapper(), LinkedHashMap::new));
150 this.assemblyInstances = assemblyInstances
151 .collect(Collectors.toMap(IAssemblyInstance::getEffectiveName, Function.identity(),
152 CustomCollectors.useFirstMapper(), LinkedHashMap::new));
153 this.modelInstances = modelInstances
154 .collect(Collectors.toUnmodifiableList());
155 this.namedModelInstances = namedModelInstances
156 .collect(Collectors.toMap(INamedModelInstance::getEffectiveName, Function.identity(),
157 CustomCollectors.useFirstMapper(), LinkedHashMap::new));
158 }
159
160 @SuppressWarnings("null")
161 @NonNull
162 public Map<String, IFieldInstance> getFieldInstances() {
163 return fieldInstances == null ? Collections.emptyMap() : fieldInstances;
164 }
165
166 @SuppressWarnings("null")
167 @NonNull
168 public Map<String, IAssemblyInstance> getAssemblyInstances() {
169 return assemblyInstances == null ? Collections.emptyMap() : assemblyInstances;
170 }
171
172 @SuppressWarnings("null")
173 @NonNull
174 public Map<String, INamedModelInstance> getNamedModelInstances() {
175 return namedModelInstances == null ? Collections.emptyMap() : namedModelInstances;
176 }
177
178 @SuppressWarnings("null")
179 @NonNull
180 protected List<IModelInstance> getModelInstances() {
181 return modelInstances == null ? Collections.emptyList() : modelInstances;
182 }
183
184 @NonNull
185 public static JsonGroupAsBehavior getJsonGroupAsBehavior(@Nullable GroupAsType groupAs) {
186 JsonGroupAsBehavior retval = MetaschemaModelConstants.DEFAULT_JSON_GROUP_AS_BEHAVIOR;
187 if (groupAs != null && groupAs.isSetInJson()) {
188 retval = ObjectUtils.notNull(groupAs.getInJson());
189 }
190 return retval;
191 }
192
193 @NonNull
194 public static XmlGroupAsBehavior getXmlGroupAsBehavior(@Nullable GroupAsType groupAs) {
195 XmlGroupAsBehavior retval = MetaschemaModelConstants.DEFAULT_XML_GROUP_AS_BEHAVIOR;
196 if (groupAs != null && groupAs.isSetInXml()) {
197 retval = ObjectUtils.notNull(groupAs.getInXml());
198 }
199 return retval;
200 }
201
202 public static int getMinOccurs(@Nullable BigInteger value) {
203 int retval = MetaschemaModelConstants.DEFAULT_GROUP_AS_MIN_OCCURS;
204 if (value != null) {
205 retval = value.intValueExact();
206 }
207 return retval;
208 }
209
210 public static int getMaxOccurs(@Nullable Object value) {
211 int retval = MetaschemaModelConstants.DEFAULT_GROUP_AS_MAX_OCCURS;
212 if (value != null) {
213 if (value instanceof String) {
214
215 retval = -1;
216 } else if (value instanceof BigInteger) {
217 retval = ((BigInteger) value).intValueExact();
218 } else {
219 throw new IllegalStateException("Invalid type: " + value.getClass().getName());
220 }
221 }
222 return retval;
223 }
224 }