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