1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind;
7
8 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
9 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
10 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
11 import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem;
12 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
13 import gov.nist.secauto.metaschema.core.metapath.item.node.IRootAssemblyNodeItem;
14 import gov.nist.secauto.metaschema.core.model.IBoundObject;
15 import gov.nist.secauto.metaschema.core.model.IModule;
16 import gov.nist.secauto.metaschema.core.model.constraint.DefaultConstraintValidator;
17 import gov.nist.secauto.metaschema.core.model.constraint.FindingCollectingConstraintValidationHandler;
18 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintValidationHandler;
19 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintValidator;
20 import gov.nist.secauto.metaschema.core.model.constraint.ValidationFeature;
21 import gov.nist.secauto.metaschema.core.model.validation.AggregateValidationResult;
22 import gov.nist.secauto.metaschema.core.model.validation.IValidationResult;
23 import gov.nist.secauto.metaschema.core.model.validation.JsonSchemaContentValidator;
24 import gov.nist.secauto.metaschema.core.model.validation.XmlSchemaContentValidator;
25 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
26 import gov.nist.secauto.metaschema.databind.io.BindingException;
27 import gov.nist.secauto.metaschema.databind.io.DeserializationFeature;
28 import gov.nist.secauto.metaschema.databind.io.Format;
29 import gov.nist.secauto.metaschema.databind.io.IBoundLoader;
30 import gov.nist.secauto.metaschema.databind.io.IDeserializer;
31 import gov.nist.secauto.metaschema.databind.io.ISerializer;
32 import gov.nist.secauto.metaschema.databind.io.yaml.YamlOperations;
33 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModel;
34 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
35 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
36 import gov.nist.secauto.metaschema.databind.model.IBoundModule;
37 import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaAssembly;
38 import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaField;
39
40 import org.json.JSONObject;
41 import org.json.JSONTokener;
42 import org.xml.sax.SAXException;
43
44 import java.io.BufferedInputStream;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.math.BigInteger;
49 import java.net.URI;
50 import java.net.URL;
51 import java.nio.file.Path;
52 import java.time.ZonedDateTime;
53 import java.util.List;
54
55 import javax.xml.namespace.QName;
56 import javax.xml.transform.Source;
57
58 import edu.umd.cs.findbugs.annotations.NonNull;
59 import edu.umd.cs.findbugs.annotations.Nullable;
60
61
62
63
64
65 public interface IBindingContext {
66
67
68
69
70
71
72
73 @NonNull
74 static IBindingContext instance() {
75 return DefaultBindingContext.instance();
76 }
77
78
79
80
81
82
83
84
85
86 @NonNull
87 IBindingMatcher registerBindingMatcher(@NonNull IBoundDefinitionModelAssembly definition);
88
89
90
91
92
93
94
95
96
97
98 @NonNull
99 IBindingMatcher registerBindingMatcher(@NonNull Class<? extends IBoundObject> clazz);
100
101
102
103
104
105
106
107
108
109 @Nullable
110 IBoundDefinitionModelComplex registerClassBinding(@NonNull IBoundDefinitionModelComplex definition);
111
112
113
114
115
116
117
118
119
120
121
122
123
124 @Nullable
125 IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class<? extends IBoundObject> clazz);
126
127
128
129
130
131
132
133
134
135 @Nullable
136 Class<? extends IBoundObject> getBoundClassForRootXmlQName(@NonNull QName rootQName);
137
138
139
140
141
142
143
144
145
146
147 @Nullable
148 Class<? extends IBoundObject> getBoundClassForRootJsonName(@NonNull String rootName);
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 @Nullable
166 <TYPE extends IDataTypeAdapter<?>> TYPE getJavaTypeAdapterInstance(@NonNull Class<TYPE> clazz);
167
168
169
170
171
172
173
174
175
176
177
178
179
180 @NonNull
181 IBoundModule registerModule(@NonNull Class<? extends IBoundModule> clazz);
182
183
184
185
186
187
188
189
190
191
192
193
194
195 @NonNull
196 IBindingContext registerModule(
197 @NonNull IModule module,
198 @NonNull Path compilePath) throws IOException;
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 @NonNull
225 <CLASS extends IBoundObject> ISerializer<CLASS> newSerializer(
226 @NonNull Format format,
227 @NonNull Class<CLASS> clazz);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 @NonNull
254 <CLASS extends IBoundObject> IDeserializer<CLASS> newDeserializer(
255 @NonNull Format format,
256 @NonNull Class<CLASS> clazz);
257
258
259
260
261
262
263 @NonNull
264 IBoundLoader newBoundLoader();
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 @NonNull
284 <CLASS extends IBoundObject> CLASS deepCopy(@NonNull CLASS other, IBoundObject parentInstance)
285 throws BindingException;
286
287
288
289
290
291
292
293
294
295
296
297 default IConstraintValidator newValidator(
298 @NonNull IConstraintValidationHandler handler,
299 @Nullable IConfiguration<ValidationFeature<?>> config) {
300 IBoundLoader loader = newBoundLoader();
301 loader.disableFeature(DeserializationFeature.DESERIALIZE_VALIDATE_CONSTRAINTS);
302
303 DynamicContext context = new DynamicContext();
304 context.setDocumentLoader(loader);
305
306 DefaultConstraintValidator retval = new DefaultConstraintValidator(handler);
307 if (config != null) {
308 retval.applyConfiguration(config);
309 }
310 return retval;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 default IValidationResult validate(
328 @NonNull IDocumentNodeItem nodeItem,
329 @NonNull IBoundLoader loader,
330 @Nullable IConfiguration<ValidationFeature<?>> config) {
331 IRootAssemblyNodeItem root = nodeItem.getRootAssemblyNodeItem();
332 return validate(root, loader, config);
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349 default IValidationResult validate(
350 @NonNull IDefinitionNodeItem<?, ?> nodeItem,
351 @NonNull IBoundLoader loader,
352 @Nullable IConfiguration<ValidationFeature<?>> config) {
353
354 FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler();
355 IConstraintValidator validator = newValidator(handler, config);
356
357 DynamicContext dynamicContext = new DynamicContext(nodeItem.getStaticContext());
358 dynamicContext.setDocumentLoader(loader);
359
360 validator.validate(nodeItem, dynamicContext);
361 validator.finalizeValidation(dynamicContext);
362 return handler;
363 }
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 default IValidationResult validate(
382 @NonNull URI target,
383 @NonNull Format asFormat,
384 @NonNull ISchemaValidationProvider schemaProvider,
385 @Nullable IConfiguration<ValidationFeature<?>> config) throws IOException {
386
387 IValidationResult retval = schemaProvider.validateWithSchema(target, asFormat);
388
389 if (retval.isPassing()) {
390 IValidationResult constraintValidationResult = validateWithConstraints(target, config);
391 retval = AggregateValidationResult.aggregate(retval, constraintValidationResult);
392 }
393 return retval;
394 }
395
396
397
398
399
400
401
402
403
404
405
406
407
408 default IValidationResult validateWithConstraints(
409 @NonNull URI target,
410 @Nullable IConfiguration<ValidationFeature<?>> config)
411 throws IOException {
412 IBoundLoader loader = newBoundLoader();
413 loader.disableFeature(DeserializationFeature.DESERIALIZE_VALIDATE_CONSTRAINTS);
414 IDocumentNodeItem nodeItem = loader.loadAsNodeItem(target);
415
416 return validate(nodeItem, loader, config);
417 }
418
419 interface IModuleLoaderStrategy {
420
421
422
423
424
425
426
427
428
429
430
431
432
433 @NonNull
434 IBoundModule loadModule(@NonNull Class<? extends IBoundModule> clazz);
435
436
437
438
439
440
441
442
443
444
445
446
447
448 @Nullable
449 IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class<? extends IBoundObject> clazz);
450 }
451
452 interface ISchemaValidationProvider {
453
454 @NonNull
455 default IValidationResult validateWithSchema(@NonNull URI target, @NonNull Format asFormat)
456 throws FileNotFoundException, IOException {
457 URL targetResource = ObjectUtils.notNull(target.toURL());
458
459 IValidationResult retval;
460 switch (asFormat) {
461 case JSON: {
462 JSONObject json;
463 try (@SuppressWarnings("resource") InputStream is
464 = new BufferedInputStream(ObjectUtils.notNull(targetResource.openStream()))) {
465 json = new JSONObject(new JSONTokener(is));
466 }
467 retval = new JsonSchemaContentValidator(getJsonSchema(json)).validate(json, target);
468 break;
469 }
470 case XML:
471 try {
472 List<Source> schemaSources = getXmlSchemas(targetResource);
473 retval = new XmlSchemaContentValidator(schemaSources).validate(target);
474 } catch (SAXException ex) {
475 throw new IOException(ex);
476 }
477 break;
478 case YAML: {
479 JSONObject json = YamlOperations.yamlToJson(YamlOperations.parseYaml(target));
480 assert json != null;
481 retval = new JsonSchemaContentValidator(getJsonSchema(json)).validate(json, ObjectUtils.notNull(target));
482 break;
483 }
484 default:
485 throw new UnsupportedOperationException("Unsupported format: " + asFormat.name());
486 }
487 return retval;
488 }
489
490
491
492
493
494
495
496
497
498
499
500 @NonNull
501 JSONObject getJsonSchema(@NonNull JSONObject json) throws IOException;
502
503
504
505
506
507
508
509
510
511
512
513 @NonNull
514 List<Source> getXmlSchemas(@NonNull URL targetResource) throws IOException;
515 }
516
517
518
519
520
521
522 interface IBindingMatcher {
523 @SuppressWarnings("PMD.ShortMethodName")
524 @NonNull
525 static IBindingMatcher of(IBoundDefinitionModelAssembly assembly) {
526 if (!assembly.isRoot()) {
527 throw new IllegalArgumentException(
528 String.format("The provided class '%s' is not a root assembly.", assembly.getBoundClass().getName()));
529 }
530 return new RootAssemblyBindingMatcher(assembly);
531 }
532
533
534
535
536
537
538
539
540
541 Class<? extends IBoundObject> getBoundClassForXmlQName(QName rootQName);
542
543
544
545
546
547
548
549
550
551 Class<? extends IBoundObject> getBoundClassForJsonName(String rootName);
552 }
553 }