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