1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.model.metaschema.impl;
7
8 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
9 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
10 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
11 import gov.nist.secauto.metaschema.core.model.ISource;
12 import gov.nist.secauto.metaschema.core.model.constraint.AbstractConfigurableMessageConstraintBuilder;
13 import gov.nist.secauto.metaschema.core.model.constraint.AbstractConstraintBuilder;
14 import gov.nist.secauto.metaschema.core.model.constraint.AbstractKeyConstraintBuilder;
15 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
16 import gov.nist.secauto.metaschema.core.model.constraint.ICardinalityConstraint;
17 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint;
18 import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint;
19 import gov.nist.secauto.metaschema.core.model.constraint.IIndexConstraint;
20 import gov.nist.secauto.metaschema.core.model.constraint.IIndexHasKeyConstraint;
21 import gov.nist.secauto.metaschema.core.model.constraint.IKeyField;
22 import gov.nist.secauto.metaschema.core.model.constraint.ILet;
23 import gov.nist.secauto.metaschema.core.model.constraint.IMatchesConstraint;
24 import gov.nist.secauto.metaschema.core.model.constraint.IModelConstrained;
25 import gov.nist.secauto.metaschema.core.model.constraint.IUniqueConstraint;
26 import gov.nist.secauto.metaschema.core.model.constraint.IValueConstrained;
27 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
28 import gov.nist.secauto.metaschema.databind.model.metaschema.IConfigurableMessageConstraintBase;
29 import gov.nist.secauto.metaschema.databind.model.metaschema.IConstraintBase;
30 import gov.nist.secauto.metaschema.databind.model.metaschema.IModelConstraintsBase;
31 import gov.nist.secauto.metaschema.databind.model.metaschema.IValueConstraintsBase;
32 import gov.nist.secauto.metaschema.databind.model.metaschema.IValueTargetedConstraintsBase;
33 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.ConstraintValueEnum;
34 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagAllowedValues;
35 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagExpect;
36 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagIndexHasKey;
37 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagMatches;
38 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.KeyConstraintField;
39 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.Property;
40 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.Remarks;
41 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedAllowedValuesConstraint;
42 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedExpectConstraint;
43 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedHasCardinalityConstraint;
44 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIndexConstraint;
45 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIndexHasKeyConstraint;
46 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIsUniqueConstraint;
47 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedMatchesConstraint;
48
49 import java.math.BigInteger;
50 import java.util.List;
51 import java.util.regex.Pattern;
52
53 import javax.xml.namespace.QName;
54
55 import edu.umd.cs.findbugs.annotations.NonNull;
56 import edu.umd.cs.findbugs.annotations.Nullable;
57
58
59
60
61 @SuppressWarnings("PMD.CouplingBetweenObjects")
62 public final class ConstraintBindingSupport {
63 private ConstraintBindingSupport() {
64
65 }
66
67
68
69
70
71
72
73
74
75
76
77 public static void parse(
78 @NonNull IValueConstrained constraintSet,
79 @NonNull IValueConstraintsBase constraints,
80 @NonNull ISource source) {
81 parseLet(constraintSet, constraints, source);
82
83
84 for (IConstraintBase ruleObj : constraints.getRules()) {
85 if (ruleObj instanceof FlagAllowedValues) {
86 IAllowedValuesConstraint constraint = newAllowedValues((FlagAllowedValues) ruleObj, source);
87 constraintSet.addConstraint(constraint);
88 } else if (ruleObj instanceof FlagExpect) {
89 IExpectConstraint constraint = newExpect((FlagExpect) ruleObj, source);
90 constraintSet.addConstraint(constraint);
91 } else if (ruleObj instanceof FlagIndexHasKey) {
92 IIndexHasKeyConstraint constraint = newIndexHasKey((FlagIndexHasKey) ruleObj, source);
93 constraintSet.addConstraint(constraint);
94 } else if (ruleObj instanceof FlagMatches) {
95 IMatchesConstraint constraint = newMatches((FlagMatches) ruleObj, source);
96 constraintSet.addConstraint(constraint);
97 }
98 }
99 }
100
101
102
103
104
105
106
107
108
109
110
111 public static void parse(
112 @NonNull IValueConstrained constraintSet,
113 @NonNull IValueTargetedConstraintsBase constraints,
114 @NonNull ISource source) {
115 parseLet(constraintSet, constraints, source);
116
117
118 for (IConstraintBase ruleObj : constraints.getRules()) {
119 if (ruleObj instanceof TargetedAllowedValuesConstraint) {
120 IAllowedValuesConstraint constraint = newAllowedValues((TargetedAllowedValuesConstraint) ruleObj, source);
121 constraintSet.addConstraint(constraint);
122 } else if (ruleObj instanceof TargetedExpectConstraint) {
123 IExpectConstraint constraint = newExpect((TargetedExpectConstraint) ruleObj, source);
124 constraintSet.addConstraint(constraint);
125 } else if (ruleObj instanceof TargetedIndexHasKeyConstraint) {
126 IIndexHasKeyConstraint constraint = newIndexHasKey((TargetedIndexHasKeyConstraint) ruleObj, source);
127 constraintSet.addConstraint(constraint);
128 } else if (ruleObj instanceof TargetedMatchesConstraint) {
129 IMatchesConstraint constraint = newMatches((TargetedMatchesConstraint) ruleObj, source);
130 constraintSet.addConstraint(constraint);
131 }
132 }
133 }
134
135
136
137
138
139
140
141
142
143
144
145 public static void parse(
146 @NonNull IModelConstrained constraintSet,
147 @NonNull IModelConstraintsBase constraints,
148 @NonNull ISource source) {
149 parseLet(constraintSet, constraints, source);
150
151
152 for (IConstraintBase ruleObj : constraints.getRules()) {
153 if (ruleObj instanceof TargetedAllowedValuesConstraint) {
154 IAllowedValuesConstraint constraint = newAllowedValues((TargetedAllowedValuesConstraint) ruleObj, source);
155 constraintSet.addConstraint(constraint);
156 } else if (ruleObj instanceof TargetedExpectConstraint) {
157 IExpectConstraint constraint = newExpect((TargetedExpectConstraint) ruleObj, source);
158 constraintSet.addConstraint(constraint);
159 } else if (ruleObj instanceof TargetedIndexHasKeyConstraint) {
160 IIndexHasKeyConstraint constraint = newIndexHasKey((TargetedIndexHasKeyConstraint) ruleObj, source);
161 constraintSet.addConstraint(constraint);
162 } else if (ruleObj instanceof TargetedMatchesConstraint) {
163 IMatchesConstraint constraint = newMatches((TargetedMatchesConstraint) ruleObj, source);
164 constraintSet.addConstraint(constraint);
165 } else if (ruleObj instanceof TargetedIndexConstraint) {
166 IIndexConstraint constraint = newIndex((TargetedIndexConstraint) ruleObj, source);
167 constraintSet.addConstraint(constraint);
168 } else if (ruleObj instanceof TargetedHasCardinalityConstraint) {
169 ICardinalityConstraint constraint = newHasCardinality((TargetedHasCardinalityConstraint) ruleObj, source);
170 constraintSet.addConstraint(constraint);
171 } else if (ruleObj instanceof TargetedIsUniqueConstraint) {
172 IUniqueConstraint constraint = newUnique((TargetedIsUniqueConstraint) ruleObj, source);
173 constraintSet.addConstraint(constraint);
174 }
175 }
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public static void parseLet(
189 @NonNull IValueConstrained constraintSet,
190 @NonNull IValueConstraintsBase constraints,
191 @NonNull ISource source) {
192
193 constraints.getLets().stream()
194 .map(letObj -> {
195 MarkupMultiline remarks = null;
196 Remarks remarkObj = letObj.getRemarks();
197 if (remarkObj != null) {
198 remarks = remarkObj.getRemark();
199 }
200
201 return ILet.of(
202 ObjectUtils.requireNonNull(new QName(letObj.getVar())),
203 ObjectUtils.requireNonNull(letObj.getExpression()),
204 source,
205 remarks);
206 })
207 .forEachOrdered(constraintSet::addLetExpression);
208 }
209
210 @NonNull
211 private static IAllowedValuesConstraint newAllowedValues(
212 @NonNull FlagAllowedValues obj,
213 @NonNull ISource source) {
214 IAllowedValuesConstraint.Builder builder = IAllowedValuesConstraint.builder()
215 .allowsOther(ModelSupport.yesOrNo(obj.getAllowOther()))
216 .extensible(extensible(obj.getExtensible()));
217 applyCommonValues(obj, null, source, builder);
218
219 for (ConstraintValueEnum value : ObjectUtils.requireNonNull(obj.getEnums())) {
220 builder.allowedValue(ObjectUtils.requireNonNull(value));
221 }
222 return builder.build();
223 }
224
225 @NonNull
226 private static IAllowedValuesConstraint newAllowedValues(
227 @NonNull TargetedAllowedValuesConstraint obj,
228 @NonNull ISource source) {
229 IAllowedValuesConstraint.Builder builder = IAllowedValuesConstraint.builder()
230 .allowsOther(ModelSupport.yesOrNo(obj.getAllowOther()))
231 .extensible(extensible(ObjectUtils.requireNonNull(obj.getExtensible())));
232 applyCommonValues(obj, obj.getTarget(), source, builder);
233
234 for (ConstraintValueEnum value : ObjectUtils.requireNonNull(obj.getEnums())) {
235 builder.allowedValue(ObjectUtils.requireNonNull(value));
236 }
237 return builder.build();
238 }
239
240 @NonNull
241 private static IExpectConstraint newExpect(
242 @NonNull FlagExpect obj,
243 @NonNull ISource source) {
244 IExpectConstraint.Builder builder = IExpectConstraint.builder()
245 .test(target(ObjectUtils.requireNonNull(obj.getTest())));
246 applyConfigurableCommonValues(obj, null, source, builder);
247
248 String message = obj.getMessage();
249 if (message != null) {
250 builder.message(message);
251 }
252
253 return builder.build();
254 }
255
256 @NonNull
257 private static IExpectConstraint newExpect(
258 @NonNull TargetedExpectConstraint obj,
259 @NonNull ISource source) {
260 IExpectConstraint.Builder builder = IExpectConstraint.builder()
261 .test(target(ObjectUtils.requireNonNull(obj.getTest())));
262 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
263
264 return builder.build();
265 }
266
267 @NonNull
268 private static <T extends AbstractKeyConstraintBuilder<T, ?>> T handleKeyConstraints(
269 @NonNull List<KeyConstraintField> keys,
270 @NonNull T builder,
271 @NonNull ISource source) {
272 for (KeyConstraintField value : keys) {
273 assert value != null;
274
275 IKeyField keyField = IKeyField.of(
276 target(ObjectUtils.requireNonNull(value.getTarget())),
277 pattern(value.getPattern()),
278 ModelSupport.remarks(value.getRemarks()),
279 source);
280 builder.keyField(keyField);
281 }
282 return builder;
283 }
284
285 @NonNull
286 private static IIndexHasKeyConstraint newIndexHasKey(
287 @NonNull FlagIndexHasKey obj,
288 @NonNull ISource source) {
289 IIndexHasKeyConstraint.Builder builder = IIndexHasKeyConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
290 applyConfigurableCommonValues(obj, null, source, builder);
291 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
292 return builder.build();
293 }
294
295 @NonNull
296 private static IIndexHasKeyConstraint newIndexHasKey(
297 @NonNull TargetedIndexHasKeyConstraint obj,
298 @NonNull ISource source) {
299 IIndexHasKeyConstraint.Builder builder = IIndexHasKeyConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
300 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
301 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
302 return builder.build();
303 }
304
305 @NonNull
306 private static IMatchesConstraint newMatches(
307 @NonNull FlagMatches obj,
308 @NonNull ISource source) {
309 IMatchesConstraint.Builder builder = IMatchesConstraint.builder();
310 applyConfigurableCommonValues(obj, null, source, builder);
311
312 Pattern regex = pattern(obj.getRegex());
313 if (regex != null) {
314 builder.regex(regex);
315 }
316
317 String dataType = obj.getDatatype();
318 if (dataType != null) {
319 IDataTypeAdapter<?> javaTypeAdapter = ModelSupport.dataType(obj.getDatatype());
320 builder.datatype(javaTypeAdapter);
321 }
322
323 return builder.build();
324 }
325
326 @NonNull
327 private static IMatchesConstraint newMatches(
328 @NonNull TargetedMatchesConstraint obj,
329 @NonNull ISource source) {
330 IMatchesConstraint.Builder builder = IMatchesConstraint.builder();
331 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
332
333 Pattern regex = pattern(obj.getRegex());
334 if (regex != null) {
335 builder.regex(regex);
336 }
337
338 String dataType = obj.getDatatype();
339 if (dataType != null) {
340 IDataTypeAdapter<?> javaTypeAdapter = ModelSupport.dataType(obj.getDatatype());
341 builder.datatype(javaTypeAdapter);
342 }
343
344 return builder.build();
345 }
346
347 @NonNull
348 private static IIndexConstraint newIndex(
349 @NonNull TargetedIndexConstraint obj,
350 @NonNull ISource source) {
351 IIndexConstraint.Builder builder = IIndexConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
352 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
353 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
354
355 return builder.build();
356 }
357
358 @NonNull
359 private static ICardinalityConstraint newHasCardinality(
360 @NonNull TargetedHasCardinalityConstraint obj,
361 @NonNull ISource source) {
362 ICardinalityConstraint.Builder builder = ICardinalityConstraint.builder();
363 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
364
365 BigInteger minOccurs = obj.getMinOccurs();
366 if (minOccurs != null) {
367 builder.minOccurs(minOccurs.intValueExact());
368 }
369 String maxOccurs = obj.getMaxOccurs();
370 if (maxOccurs != null) {
371 int occurance = ModelSupport.maxOccurs(maxOccurs);
372 builder.maxOccurs(occurance);
373 }
374
375 return builder.build();
376 }
377
378 @NonNull
379 private static IUniqueConstraint newUnique(
380 @NonNull TargetedIsUniqueConstraint obj,
381 @NonNull ISource source) {
382 IUniqueConstraint.Builder builder = IUniqueConstraint.builder();
383 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
384 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
385
386 return builder.build();
387 }
388
389 @NonNull
390 private static <T extends AbstractConfigurableMessageConstraintBuilder<T, ?>> T applyConfigurableCommonValues(
391 @NonNull IConfigurableMessageConstraintBase constraint,
392 @Nullable String target,
393 @NonNull ISource source,
394 @NonNull T builder) {
395 applyCommonValues(constraint, target, source, builder);
396
397 String message = constraint.getMessage();
398 if (message != null) {
399 builder.message(message);
400 }
401 return builder;
402 }
403
404 @NonNull
405 private static <T extends AbstractConstraintBuilder<T, ?>> T applyCommonValues(
406 @NonNull IConstraintBase constraint,
407 @Nullable String target,
408 @NonNull ISource source,
409 @NonNull T builder) {
410
411 String id = constraint.getId();
412
413 if (id != null) {
414 builder.identifier(id);
415 }
416
417 String formalName = constraint.getFormalName();
418 if (formalName != null) {
419 builder.formalName(formalName);
420 }
421
422 MarkupLine description = constraint.getDescription();
423 if (description != null) {
424 builder.description(description);
425 }
426
427 List<Property> props = ObjectUtils.requireNonNull(constraint.getProps());
428 builder.properties(ModelSupport.parseProperties(props));
429
430 Remarks remarks = constraint.getRemarks();
431 if (remarks != null) {
432 builder.remarks(ObjectUtils.notNull(remarks.getRemark()));
433 }
434
435 builder.target(target(target));
436 builder.level(level(constraint.getLevel()));
437 builder.source(source);
438 return builder;
439 }
440
441 @NonNull
442 private static String target(@Nullable String target) {
443 return target == null
444 ? IConstraint.DEFAULT_TARGET_METAPATH
445 : target;
446 }
447
448 @NonNull
449 private static IConstraint.Level level(@Nullable String level) {
450 IConstraint.Level retval = IConstraint.DEFAULT_LEVEL;
451 if (level != null) {
452 switch (level) {
453 case "CRITICAL":
454 retval = IConstraint.Level.CRITICAL;
455 break;
456 case "ERROR":
457 retval = IConstraint.Level.ERROR;
458 break;
459 case "WARNING":
460 retval = IConstraint.Level.WARNING;
461 break;
462 case "INFORMATIONAL":
463 retval = IConstraint.Level.INFORMATIONAL;
464 break;
465 case "DEBUG":
466 retval = IConstraint.Level.DEBUG;
467 break;
468 default:
469 throw new UnsupportedOperationException(level);
470 }
471 }
472 return retval;
473 }
474
475 @NonNull
476 private static IAllowedValuesConstraint.Extensible extensible(@Nullable String extensible) {
477 IAllowedValuesConstraint.Extensible retval = IAllowedValuesConstraint.EXTENSIBLE_DEFAULT;
478 if (extensible != null) {
479 switch (extensible) {
480 case "model":
481 retval = IAllowedValuesConstraint.Extensible.MODEL;
482 break;
483 case "external":
484 retval = IAllowedValuesConstraint.Extensible.EXTERNAL;
485 break;
486 case "none":
487 retval = IAllowedValuesConstraint.Extensible.NONE;
488 break;
489 default:
490 throw new UnsupportedOperationException(extensible);
491 }
492 }
493 return retval;
494 }
495
496 @Nullable
497 private static Pattern pattern(@Nullable String pattern) {
498 return pattern == null ? null : Pattern.compile(pattern);
499 }
500
501 }