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.metapath.IMetapathExpression;
12 import gov.nist.secauto.metaschema.core.metapath.StaticContext;
13 import gov.nist.secauto.metaschema.core.model.ISource;
14 import gov.nist.secauto.metaschema.core.model.constraint.AbstractConfigurableMessageConstraintBuilder;
15 import gov.nist.secauto.metaschema.core.model.constraint.AbstractConstraintBuilder;
16 import gov.nist.secauto.metaschema.core.model.constraint.AbstractKeyConstraintBuilder;
17 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
18 import gov.nist.secauto.metaschema.core.model.constraint.ICardinalityConstraint;
19 import gov.nist.secauto.metaschema.core.model.constraint.IConstraint;
20 import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint;
21 import gov.nist.secauto.metaschema.core.model.constraint.IIndexConstraint;
22 import gov.nist.secauto.metaschema.core.model.constraint.IIndexHasKeyConstraint;
23 import gov.nist.secauto.metaschema.core.model.constraint.IKeyField;
24 import gov.nist.secauto.metaschema.core.model.constraint.ILet;
25 import gov.nist.secauto.metaschema.core.model.constraint.IMatchesConstraint;
26 import gov.nist.secauto.metaschema.core.model.constraint.IModelConstrained;
27 import gov.nist.secauto.metaschema.core.model.constraint.IUniqueConstraint;
28 import gov.nist.secauto.metaschema.core.model.constraint.IValueConstrained;
29 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
30 import gov.nist.secauto.metaschema.databind.model.metaschema.IConfigurableMessageConstraintBase;
31 import gov.nist.secauto.metaschema.databind.model.metaschema.IConstraintBase;
32 import gov.nist.secauto.metaschema.databind.model.metaschema.IModelConstraintsBase;
33 import gov.nist.secauto.metaschema.databind.model.metaschema.IValueConstraintsBase;
34 import gov.nist.secauto.metaschema.databind.model.metaschema.IValueTargetedConstraintsBase;
35 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.ConstraintValueEnum;
36 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagAllowedValues;
37 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagExpect;
38 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagIndexHasKey;
39 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.FlagMatches;
40 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.KeyConstraintField;
41 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.Property;
42 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.Remarks;
43 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedAllowedValuesConstraint;
44 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedExpectConstraint;
45 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedHasCardinalityConstraint;
46 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIndexConstraint;
47 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIndexHasKeyConstraint;
48 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedIsUniqueConstraint;
49 import gov.nist.secauto.metaschema.databind.model.metaschema.binding.TargetedMatchesConstraint;
50
51 import java.math.BigInteger;
52 import java.util.List;
53 import java.util.regex.Pattern;
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 StaticContext staticContext = source.getStaticContext();
193
194
195 constraints.getLets().stream()
196 .map(letObj -> {
197 MarkupMultiline remarks = null;
198 Remarks remarkObj = letObj.getRemarks();
199 if (remarkObj != null) {
200 remarks = remarkObj.getRemark();
201 }
202
203 return ILet.of(
204 staticContext.parseVariableName(ObjectUtils.requireNonNull(letObj.getVar())),
205 IMetapathExpression.lazyCompile(
206 ObjectUtils.requireNonNull(letObj.getExpression()),
207 source.getStaticContext()),
208 source,
209 remarks);
210 })
211 .forEachOrdered(constraintSet::addLetExpression);
212 }
213
214 @NonNull
215 private static IAllowedValuesConstraint newAllowedValues(
216 @NonNull FlagAllowedValues obj,
217 @NonNull ISource source) {
218 IAllowedValuesConstraint.Builder builder = IAllowedValuesConstraint.builder()
219 .allowsOther(ModelSupport.yesOrNo(obj.getAllowOther()))
220 .extensible(extensible(obj.getExtensible()));
221 applyCommonValues(obj, null, source, builder);
222
223 for (ConstraintValueEnum value : ObjectUtils.requireNonNull(obj.getEnums())) {
224 builder.allowedValue(ObjectUtils.requireNonNull(value));
225 }
226 return builder.build();
227 }
228
229 @NonNull
230 private static IAllowedValuesConstraint newAllowedValues(
231 @NonNull TargetedAllowedValuesConstraint obj,
232 @NonNull ISource source) {
233 IAllowedValuesConstraint.Builder builder = IAllowedValuesConstraint.builder()
234 .allowsOther(ModelSupport.yesOrNo(obj.getAllowOther()))
235 .extensible(extensible(ObjectUtils.requireNonNull(obj.getExtensible())));
236 applyCommonValues(obj, obj.getTarget(), source, builder);
237
238 for (ConstraintValueEnum value : ObjectUtils.requireNonNull(obj.getEnums())) {
239 builder.allowedValue(ObjectUtils.requireNonNull(value));
240 }
241 return builder.build();
242 }
243
244 @NonNull
245 private static IExpectConstraint newExpect(
246 @NonNull FlagExpect obj,
247 @NonNull ISource source) {
248 IExpectConstraint.Builder builder = IExpectConstraint.builder()
249 .test(metapath(ObjectUtils.requireNonNull(obj.getTest()), source));
250 applyConfigurableCommonValues(obj, null, source, builder);
251
252 String message = obj.getMessage();
253 if (message != null) {
254 builder.message(message);
255 }
256
257 return builder.build();
258 }
259
260 @NonNull
261 private static IExpectConstraint newExpect(
262 @NonNull TargetedExpectConstraint obj,
263 @NonNull ISource source) {
264 IExpectConstraint.Builder builder = IExpectConstraint.builder()
265 .test(metapath(ObjectUtils.requireNonNull(obj.getTest()), source));
266 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
267
268 return builder.build();
269 }
270
271 @NonNull
272 private static <T extends AbstractKeyConstraintBuilder<T, ?>> T handleKeyConstraints(
273 @NonNull List<KeyConstraintField> keys,
274 @NonNull T builder,
275 @NonNull ISource source) {
276 for (KeyConstraintField value : keys) {
277 assert value != null;
278
279 IKeyField keyField = IKeyField.of(
280 metapath(ObjectUtils.requireNonNull(value.getTarget()), source),
281 pattern(value.getPattern()),
282 ModelSupport.remarks(value.getRemarks()));
283 builder.keyField(keyField);
284 }
285 return builder;
286 }
287
288 @NonNull
289 private static IIndexHasKeyConstraint newIndexHasKey(
290 @NonNull FlagIndexHasKey obj,
291 @NonNull ISource source) {
292 IIndexHasKeyConstraint.Builder builder = IIndexHasKeyConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
293 applyConfigurableCommonValues(obj, null, source, builder);
294 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
295 return builder.build();
296 }
297
298 @NonNull
299 private static IIndexHasKeyConstraint newIndexHasKey(
300 @NonNull TargetedIndexHasKeyConstraint obj,
301 @NonNull ISource source) {
302 IIndexHasKeyConstraint.Builder builder = IIndexHasKeyConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
303 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
304 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
305 return builder.build();
306 }
307
308 @NonNull
309 private static IMatchesConstraint newMatches(
310 @NonNull FlagMatches obj,
311 @NonNull ISource source) {
312 IMatchesConstraint.Builder builder = IMatchesConstraint.builder();
313 applyConfigurableCommonValues(obj, null, source, builder);
314
315 Pattern regex = pattern(obj.getRegex());
316 if (regex != null) {
317 builder.regex(regex);
318 }
319
320 String dataType = obj.getDatatype();
321 if (dataType != null) {
322 IDataTypeAdapter<?> javaTypeAdapter = ModelSupport.dataType(
323 obj.getDatatype(),
324 source);
325 builder.datatype(javaTypeAdapter);
326 }
327
328 return builder.build();
329 }
330
331 @NonNull
332 private static IMatchesConstraint newMatches(
333 @NonNull TargetedMatchesConstraint obj,
334 @NonNull ISource source) {
335 IMatchesConstraint.Builder builder = IMatchesConstraint.builder();
336 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
337
338 Pattern regex = pattern(obj.getRegex());
339 if (regex != null) {
340 builder.regex(regex);
341 }
342
343 String dataType = obj.getDatatype();
344 if (dataType != null) {
345 IDataTypeAdapter<?> javaTypeAdapter = ModelSupport.dataType(
346 obj.getDatatype(),
347 source);
348 builder.datatype(javaTypeAdapter);
349 }
350
351 return builder.build();
352 }
353
354 @NonNull
355 private static IIndexConstraint newIndex(
356 @NonNull TargetedIndexConstraint obj,
357 @NonNull ISource source) {
358 IIndexConstraint.Builder builder = IIndexConstraint.builder(ObjectUtils.requireNonNull(obj.getName()));
359 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
360 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
361
362 return builder.build();
363 }
364
365 @NonNull
366 private static ICardinalityConstraint newHasCardinality(
367 @NonNull TargetedHasCardinalityConstraint obj,
368 @NonNull ISource source) {
369 ICardinalityConstraint.Builder builder = ICardinalityConstraint.builder();
370 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
371
372 BigInteger minOccurs = obj.getMinOccurs();
373 if (minOccurs != null) {
374 builder.minOccurs(minOccurs.intValueExact());
375 }
376 String maxOccurs = obj.getMaxOccurs();
377 if (maxOccurs != null) {
378 int occurance = ModelSupport.maxOccurs(maxOccurs);
379 builder.maxOccurs(occurance);
380 }
381
382 return builder.build();
383 }
384
385 @NonNull
386 private static IUniqueConstraint newUnique(
387 @NonNull TargetedIsUniqueConstraint obj,
388 @NonNull ISource source) {
389 IUniqueConstraint.Builder builder = IUniqueConstraint.builder();
390 applyConfigurableCommonValues(obj, obj.getTarget(), source, builder);
391 handleKeyConstraints(ObjectUtils.requireNonNull(obj.getKeyFields()), builder, source);
392
393 return builder.build();
394 }
395
396 @NonNull
397 private static <T extends AbstractConfigurableMessageConstraintBuilder<T, ?>> T applyConfigurableCommonValues(
398 @NonNull IConfigurableMessageConstraintBase constraint,
399 @Nullable String target,
400 @NonNull ISource source,
401 @NonNull T builder) {
402 applyCommonValues(constraint, target, source, builder);
403
404 String message = constraint.getMessage();
405 if (message != null) {
406 builder.message(message);
407 }
408 return builder;
409 }
410
411 @NonNull
412 private static <T extends AbstractConstraintBuilder<T, ?>> T applyCommonValues(
413 @NonNull IConstraintBase constraint,
414 @Nullable String target,
415 @NonNull ISource source,
416 @NonNull T builder) {
417
418 String id = constraint.getId();
419
420 if (id != null) {
421 builder.identifier(id);
422 }
423
424 String formalName = constraint.getFormalName();
425 if (formalName != null) {
426 builder.formalName(formalName);
427 }
428
429 MarkupLine description = constraint.getDescription();
430 if (description != null) {
431 builder.description(description);
432 }
433
434 List<Property> props = ObjectUtils.requireNonNull(constraint.getProps());
435 builder.properties(ModelSupport.parseProperties(props));
436
437 Remarks remarks = constraint.getRemarks();
438 if (remarks != null) {
439 builder.remarks(ObjectUtils.notNull(remarks.getRemark()));
440 }
441
442 builder.target(metapath(target, source));
443 builder.level(level(constraint.getLevel()));
444 builder.source(source);
445 return builder;
446 }
447
448 @NonNull
449 private static IMetapathExpression metapath(
450 @Nullable String metapath,
451 @NonNull ISource source) {
452 return metapath == null
453 ? IConstraint.defaultTarget()
454 : IMetapathExpression.lazyCompile(
455 metapath,
456 source.getStaticContext());
457 }
458
459 @NonNull
460 private static IConstraint.Level level(@Nullable String level) {
461 IConstraint.Level retval = IConstraint.defaultLevel();
462 if (level != null) {
463 switch (level) {
464 case "CRITICAL":
465 retval = IConstraint.Level.CRITICAL;
466 break;
467 case "ERROR":
468 retval = IConstraint.Level.ERROR;
469 break;
470 case "WARNING":
471 retval = IConstraint.Level.WARNING;
472 break;
473 case "INFORMATIONAL":
474 retval = IConstraint.Level.INFORMATIONAL;
475 break;
476 case "DEBUG":
477 retval = IConstraint.Level.DEBUG;
478 break;
479 default:
480 throw new UnsupportedOperationException(level);
481 }
482 }
483 return retval;
484 }
485
486 @NonNull
487 private static IAllowedValuesConstraint.Extensible extensible(@Nullable String extensible) {
488 IAllowedValuesConstraint.Extensible retval = IAllowedValuesConstraint.EXTENSIBLE_DEFAULT;
489 if (extensible != null) {
490 switch (extensible) {
491 case "model":
492 retval = IAllowedValuesConstraint.Extensible.MODEL;
493 break;
494 case "external":
495 retval = IAllowedValuesConstraint.Extensible.EXTERNAL;
496 break;
497 case "none":
498 retval = IAllowedValuesConstraint.Extensible.NONE;
499 break;
500 default:
501 throw new UnsupportedOperationException(extensible);
502 }
503 }
504 return retval;
505 }
506
507 @Nullable
508 private static Pattern pattern(@Nullable String pattern) {
509 return pattern == null ? null : Pattern.compile(pattern);
510 }
511
512 }