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.datatype.IDataTypeAdapter;
30 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
31 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
32 import gov.nist.secauto.metaschema.core.model.IModule;
33 import gov.nist.secauto.metaschema.core.model.constraint.DefaultAllowedValuesConstraint;
34 import gov.nist.secauto.metaschema.core.model.constraint.DefaultCardinalityConstraint;
35 import gov.nist.secauto.metaschema.core.model.constraint.DefaultExpectConstraint;
36 import gov.nist.secauto.metaschema.core.model.constraint.DefaultIndexConstraint;
37 import gov.nist.secauto.metaschema.core.model.constraint.DefaultIndexHasKeyConstraint;
38 import gov.nist.secauto.metaschema.core.model.constraint.DefaultMatchesConstraint;
39 import gov.nist.secauto.metaschema.core.model.constraint.DefaultUniqueConstraint;
40 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
41 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
42 import gov.nist.secauto.metaschema.core.model.constraint.ICardinalityConstraint;
43 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint;
44 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint.ISource;
45 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintVisitor;
46 import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint;
47 import gov.nist.secauto.metaschema.core.model.constraint.IIndexConstraint;
48 import gov.nist.secauto.metaschema.core.model.constraint.IIndexHasKeyConstraint;
49 import gov.nist.secauto.metaschema.core.model.constraint.IKeyConstraint;
50 import gov.nist.secauto.metaschema.core.model.constraint.IKeyField;
51 import gov.nist.secauto.metaschema.core.model.constraint.IMatchesConstraint;
52 import gov.nist.secauto.metaschema.core.model.constraint.IModelConstrained;
53 import gov.nist.secauto.metaschema.core.model.constraint.IUniqueConstraint;
54 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ConstraintType;
55 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.DefineAssemblyConstraintsType;
56 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.EnumType;
57 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.GlobalAssemblyDefinitionType;
58 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.HasCardinalityConstraintType;
59 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.KeyConstraintType;
60 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.KeyConstraintType.KeyField;
61 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.PropertyType;
62 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.RemarksType;
63 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedAllowedValuesType;
64 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedExpectConstraintType;
65 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedIndexConstraintType;
66 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedIndexHasKeyConstraintType;
67 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedKeyConstraintType;
68 import gov.nist.secauto.metaschema.core.model.xml.xmlbeans.ScopedMatchesConstraintType;
69 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
70
71 import org.apache.xmlbeans.XmlCursor;
72 import org.apache.xmlbeans.XmlObject;
73
74 import java.math.BigInteger;
75 import java.util.LinkedList;
76 import java.util.List;
77 import java.util.Map;
78 import java.util.Set;
79 import java.util.regex.Pattern;
80
81 import javax.xml.namespace.QName;
82
83 import edu.umd.cs.findbugs.annotations.NonNull;
84
85
86
87
88
89 @SuppressWarnings("PMD.CouplingBetweenObjects")
90 class AssemblyConstraintSupport
91 extends ValueConstraintSupport
92 implements IModelConstrained {
93 @NonNull
94 private static final String PATH = "declare namespace m='http://csrc.nist.gov/ns/oscal/metaschema/1.0';"
95 + "$this/m:allowed-values|$this/m:index|$this/m:index-has-key|$this/m:is-unique|"
96 + "$this/m:has-cardinality|$this/m:matches|$this/m:expect";
97 @NonNull
98 private final List<IIndexConstraint> indexConstraints = new LinkedList<>();
99 @NonNull
100 private final List<IUniqueConstraint> uniqueConstraints = new LinkedList<>();
101 @NonNull
102 private final List<ICardinalityConstraint> cardinalityConstraints = new LinkedList<>();
103
104 public static AssemblyConstraintSupport newInstance(
105 @NonNull GlobalAssemblyDefinitionType definition,
106 @NonNull ISource source) {
107 AssemblyConstraintSupport retval;
108 if (definition.isSetConstraint()) {
109 retval = new AssemblyConstraintSupport(ObjectUtils.notNull(definition.getConstraint()), source);
110 } else {
111 retval = new AssemblyConstraintSupport();
112 }
113 return retval;
114 }
115
116 public AssemblyConstraintSupport() {
117
118 }
119
120
121
122
123
124
125
126
127
128 public AssemblyConstraintSupport(
129 @NonNull DefineAssemblyConstraintsType xmlConstraints,
130 @NonNull ISource source) {
131 try (XmlCursor cursor = xmlConstraints.newCursor()) {
132 assert cursor != null;
133 parse(source, cursor, PATH);
134 }
135 }
136
137 @Override
138 protected boolean parseXmlObject(
139 @NonNull ISource source,
140 @NonNull XmlObject obj) {
141 boolean handled = false;
142 if (obj instanceof ScopedAllowedValuesType) {
143 DefaultAllowedValuesConstraint constraint
144 = ModelFactory.newAllowedValuesConstraint((ScopedAllowedValuesType) obj, source);
145 addConstraint(constraint);
146 handled = true;
147 } else if (obj instanceof ScopedIndexConstraintType) {
148 DefaultIndexConstraint constraint
149 = ModelFactory.newIndexConstraint((ScopedIndexConstraintType) obj, source);
150 addConstraint(constraint);
151 handled = true;
152 } else if (obj instanceof ScopedIndexHasKeyConstraintType) {
153 DefaultIndexHasKeyConstraint constraint
154 = ModelFactory.newIndexHasKeyConstraint((ScopedIndexHasKeyConstraintType) obj, source);
155 addConstraint(constraint);
156 handled = true;
157 } else if (obj instanceof ScopedKeyConstraintType) {
158 DefaultUniqueConstraint constraint
159 = ModelFactory.newUniqueConstraint((ScopedKeyConstraintType) obj, source);
160 addConstraint(constraint);
161 handled = true;
162 } else if (obj instanceof HasCardinalityConstraintType) {
163 DefaultCardinalityConstraint constraint
164 = ModelFactory.newCardinalityConstraint((HasCardinalityConstraintType) obj, source);
165 addConstraint(constraint);
166 handled = true;
167 } else if (obj instanceof ScopedMatchesConstraintType) {
168 DefaultMatchesConstraint constraint
169 = ModelFactory.newMatchesConstraint((ScopedMatchesConstraintType) obj, source);
170 addConstraint(constraint);
171 handled = true;
172 } else if (obj instanceof ScopedExpectConstraintType) {
173 DefaultExpectConstraint constraint
174 = ModelFactory.newExpectConstraint((ScopedExpectConstraintType) obj, source);
175 addConstraint(constraint);
176 handled = true;
177 }
178 return handled;
179 }
180
181 @Override
182 public List<IIndexConstraint> getIndexConstraints() {
183 synchronized (this) {
184 return indexConstraints;
185 }
186 }
187
188 @Override
189 public List<IUniqueConstraint> getUniqueConstraints() {
190 synchronized (this) {
191 return uniqueConstraints;
192 }
193 }
194
195 @Override
196 public List<ICardinalityConstraint> getHasCardinalityConstraints() {
197 synchronized (this) {
198 return cardinalityConstraints;
199 }
200 }
201
202 @Override
203 public final void addConstraint(@NonNull IIndexConstraint constraint) {
204 synchronized (this) {
205 getConstraints().add(constraint);
206 indexConstraints.add(constraint);
207 }
208 }
209
210 @Override
211 public final void addConstraint(@NonNull IUniqueConstraint constraint) {
212 synchronized (this) {
213 getConstraints().add(constraint);
214 uniqueConstraints.add(constraint);
215 }
216 }
217
218 @Override
219 public final void addConstraint(@NonNull ICardinalityConstraint constraint) {
220 synchronized (this) {
221 getConstraints().add(constraint);
222 cardinalityConstraints.add(constraint);
223 }
224 }
225
226 public final DefineAssemblyConstraintsType generate() {
227 DefineAssemblyConstraintsType retval = DefineAssemblyConstraintsType.Factory.newInstance();
228
229 XmlbeanGeneratingVisitor visitor = new XmlbeanGeneratingVisitor();
230
231 for (IConstraint constraint : getConstraints()) {
232 constraint.accept(visitor, retval);
233 }
234 return retval;
235 }
236
237 private static final class XmlbeanGeneratingVisitor
238 implements IConstraintVisitor<DefineAssemblyConstraintsType, Void> {
239
240 private static void applyCommonValues(@NonNull IConstraint constraint, @NonNull ConstraintType bean) {
241 MarkupLine description = constraint.getDescription();
242 if (description != null) {
243 bean.setDescription(MarkupStringConverter.toMarkupLineDatatype(description));
244 }
245 String formalName = constraint.getFormalName();
246 if (formalName != null) {
247 bean.setFormalName(formalName);
248 }
249
250 String id = constraint.getId();
251 if (id != null) {
252 bean.setId(constraint.getId());
253 }
254
255 IConstraint.Level level = constraint.getLevel();
256 if (!IConstraint.DEFAULT_LEVEL.equals(level)) {
257 bean.setLevel(level);
258 }
259
260 for (Map.Entry<QName, Set<String>> entry : constraint.getProperties().entrySet()) {
261 QName qname = entry.getKey();
262 Set<String> values = entry.getValue();
263 for (String value : values) {
264 PropertyType prop = bean.addNewProp();
265 prop.setName(qname.getLocalPart());
266
267 String namespace = qname.getNamespaceURI();
268 if (namespace != null && !namespace.isEmpty()) {
269 prop.setNamespace(namespace);
270 }
271 prop.setValue(value);
272 }
273 }
274 }
275
276 @Override
277 public Void visitAllowedValues(IAllowedValuesConstraint constraint, DefineAssemblyConstraintsType state) {
278 ScopedAllowedValuesType bean = state.addNewAllowedValues();
279 assert bean != null;
280 applyCommonValues(constraint, bean);
281
282 if (Boolean.compare(IAllowedValuesConstraint.DEFAULT_ALLOW_OTHER, constraint.isAllowedOther()) != 0) {
283 bean.setAllowOther(constraint.isAllowedOther());
284 }
285 bean.setTarget(constraint.getTarget());
286 bean.setExtensible(constraint.getExtensible());
287
288 for (Map.Entry<String, ? extends IAllowedValue> entry : constraint.getAllowedValues().entrySet()) {
289 String value = entry.getKey();
290 IAllowedValue allowedValue = entry.getValue();
291
292 assert value.equals(allowedValue.getValue());
293
294 MarkupLine description = allowedValue.getDescription();
295 EnumType enumType = bean.addNewEnum();
296 enumType.setValue(value);
297
298 XmlbeansMarkupVisitor.visit(description, IModule.METASCHEMA_XML_NS, enumType);
299 }
300
301 MarkupMultiline remarks = constraint.getRemarks();
302 if (remarks != null) {
303 RemarksType remarksType = bean.addNewRemarks();
304 assert remarksType != null;
305 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
306 }
307 return null;
308 }
309
310 @Override
311 public Void visitCardinalityConstraint(ICardinalityConstraint constraint, DefineAssemblyConstraintsType state) {
312 HasCardinalityConstraintType bean = state.addNewHasCardinality();
313 assert bean != null;
314 applyCommonValues(constraint, bean);
315
316 Integer minOccurs = constraint.getMinOccurs();
317 if (minOccurs != null) {
318 bean.setMinOccurs(BigInteger.valueOf(minOccurs));
319 }
320
321 Integer maxOccurs = constraint.getMaxOccurs();
322 if (maxOccurs != null) {
323 bean.setMaxOccurs(BigInteger.valueOf(maxOccurs));
324 }
325
326 MarkupMultiline remarks = constraint.getRemarks();
327 if (remarks != null) {
328 RemarksType remarksType = bean.addNewRemarks();
329 assert remarksType != null;
330 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
331 }
332 return null;
333 }
334
335 @Override
336 public Void visitExpectConstraint(IExpectConstraint constraint, DefineAssemblyConstraintsType state) {
337 ScopedExpectConstraintType bean = state.addNewExpect();
338 assert bean != null;
339 applyCommonValues(constraint, bean);
340
341 bean.setTest(constraint.getTest());
342
343 String message = constraint.getMessage();
344 if (message != null) {
345 bean.setMessage(message);
346 }
347
348 MarkupMultiline remarks = constraint.getRemarks();
349 if (remarks != null) {
350 RemarksType remarksType = bean.addNewRemarks();
351 assert remarksType != null;
352 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
353 }
354 return null;
355 }
356
357 @Override
358 public Void visitMatchesConstraint(IMatchesConstraint constraint, DefineAssemblyConstraintsType state) {
359 ScopedMatchesConstraintType bean = state.addNewMatches();
360 assert bean != null;
361 applyCommonValues(constraint, bean);
362
363 Pattern pattern = constraint.getPattern();
364 if (pattern != null) {
365 bean.setRegex(pattern);
366 }
367
368 IDataTypeAdapter<?> dataType = constraint.getDataType();
369 if (dataType != null) {
370 bean.setDatatype(dataType);
371 }
372
373 MarkupMultiline remarks = constraint.getRemarks();
374 if (remarks != null) {
375 RemarksType remarksType = bean.addNewRemarks();
376 assert remarksType != null;
377 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
378 }
379 return null;
380 }
381
382 private static void applyKeyFields(@NonNull IKeyConstraint constraint, @NonNull KeyConstraintType bean) {
383 for (IKeyField keyField : constraint.getKeyFields()) {
384 KeyField keyFieldBean = bean.addNewKeyField();
385 assert keyField != null;
386 assert keyFieldBean != null;
387 applyKeyField(keyField, keyFieldBean);
388 }
389 }
390
391 private static void applyKeyField(@NonNull IKeyField keyField, @NonNull KeyField bean) {
392 Pattern pattern = keyField.getPattern();
393 if (pattern != null) {
394 bean.setPattern(pattern);
395 }
396
397 bean.setTarget(keyField.getTarget());
398
399 MarkupMultiline remarks = keyField.getRemarks();
400 if (remarks != null) {
401 RemarksType remarksType = bean.addNewRemarks();
402 assert remarksType != null;
403 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
404 }
405 }
406
407 @Override
408 public Void visitIndexConstraint(IIndexConstraint constraint, DefineAssemblyConstraintsType state) {
409 ScopedIndexConstraintType bean = state.addNewIndex();
410 assert bean != null;
411 applyCommonValues(constraint, bean);
412 applyKeyFields(constraint, bean);
413
414 bean.setName(constraint.getName());
415
416 MarkupMultiline remarks = constraint.getRemarks();
417 if (remarks != null) {
418 RemarksType remarksType = bean.addNewRemarks();
419 assert remarksType != null;
420 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
421 }
422 return null;
423 }
424
425 @Override
426 public Void visitIndexHasKeyConstraint(IIndexHasKeyConstraint constraint, DefineAssemblyConstraintsType state) {
427 ScopedIndexHasKeyConstraintType bean = state.addNewIndexHasKey();
428 assert bean != null;
429 applyCommonValues(constraint, bean);
430 applyKeyFields(constraint, bean);
431
432 bean.setName(constraint.getIndexName());
433
434 MarkupMultiline remarks = constraint.getRemarks();
435 if (remarks != null) {
436 RemarksType remarksType = bean.addNewRemarks();
437 assert remarksType != null;
438 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
439 }
440 return null;
441 }
442
443 @Override
444 public Void visitUniqueConstraint(IUniqueConstraint constraint, DefineAssemblyConstraintsType state) {
445 ScopedIndexHasKeyConstraintType bean = state.addNewIndexHasKey();
446 assert bean != null;
447 applyCommonValues(constraint, bean);
448 applyKeyFields(constraint, bean);
449
450 MarkupMultiline remarks = constraint.getRemarks();
451 if (remarks != null) {
452 RemarksType remarksType = bean.addNewRemarks();
453 assert remarksType != null;
454 XmlbeansMarkupVisitor.visit(remarks, IModule.METASCHEMA_XML_NS, remarksType);
455 }
456 return null;
457 }
458 }
459 }