1
2
3
4
5
6 package gov.nist.secauto.metaschema.core.metapath;
7
8 import gov.nist.secauto.metaschema.core.datatype.DataTypeService;
9 import gov.nist.secauto.metaschema.core.metapath.function.FunctionService;
10 import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
11 import gov.nist.secauto.metaschema.core.metapath.function.IFunctionResolver;
12 import gov.nist.secauto.metaschema.core.metapath.item.IItem;
13 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
14 import gov.nist.secauto.metaschema.core.metapath.type.IAtomicOrUnionType;
15 import gov.nist.secauto.metaschema.core.metapath.type.IItemType;
16 import gov.nist.secauto.metaschema.core.qname.EQNameFactory;
17 import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
18 import gov.nist.secauto.metaschema.core.qname.NamespaceCache;
19 import gov.nist.secauto.metaschema.core.qname.WellKnown;
20 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
21 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
22 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
23
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.stream.Collectors;
30
31 import javax.xml.XMLConstants;
32
33 import edu.umd.cs.findbugs.annotations.NonNull;
34 import edu.umd.cs.findbugs.annotations.Nullable;
35
36
37
38
39
40
41
42 public final class StaticContext {
43 @Nullable
44 private final URI baseUri;
45 @NonNull
46 private final Map<String, String> knownPrefixToNamespace;
47 @NonNull
48 private final Map<String, String> knownNamespacesToPrefix;
49 @Nullable
50 private final String defaultModelNamespace;
51 @Nullable
52 private final String defaultFunctionNamespace;
53 private final boolean useWildcardWhenNamespaceNotDefaulted;
54 @NonNull
55 private final IFunctionResolver functionResolver;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 @NonNull
72 @Deprecated(since = "2.2.0", forRemoval = true)
73 public static Map<String, String> getWellKnownNamespacesMap() {
74 return WellKnown.getWellKnownPrefixesToNamespaces();
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88 @NonNull
89 @Deprecated(since = "2.2.0", forRemoval = true)
90 public static Map<String, String> getWellKnownURIToPrefixMap() {
91 return WellKnown.getWellKnownURIsToPrefixes();
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106 @Deprecated(since = "2.2.0", forRemoval = true)
107 @Nullable
108 public static String getWellKnownPrefixForUri(@NonNull String uri) {
109 return WellKnown.getWellKnownPrefixForUri(uri);
110 }
111
112
113
114
115
116
117 @NonNull
118 public static StaticContext instance() {
119 return builder().build();
120 }
121
122 private StaticContext(Builder builder) {
123 this.baseUri = builder.baseUri;
124 this.knownPrefixToNamespace = CollectionUtil.unmodifiableMap(ObjectUtils.notNull(Map.copyOf(builder.namespaces)));
125 this.knownNamespacesToPrefix = ObjectUtils.notNull(builder.namespaces.entrySet().stream()
126 .map(entry -> Map.entry(entry.getValue(), entry.getKey()))
127 .collect(Collectors.toUnmodifiableMap(
128 Map.Entry::getKey,
129 Map.Entry::getValue,
130 CustomCollectors.useFirstMapper())));
131 this.defaultModelNamespace = builder.defaultModelNamespace;
132 this.defaultFunctionNamespace = builder.defaultFunctionNamespace;
133 this.useWildcardWhenNamespaceNotDefaulted = builder.useWildcardWhenNamespaceNotDefaulted;
134 this.functionResolver = builder.functionResolver;
135 }
136
137
138
139
140
141
142
143
144 @Nullable
145 public URI getBaseUri() {
146 return baseUri;
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 @Nullable
168 private String lookupNamespaceURIForPrefix(@NonNull String prefix) {
169 String retval = knownPrefixToNamespace.get(prefix);
170 if (retval == null) {
171
172 retval = WellKnown.getWellKnownUriForPrefix(prefix);
173 }
174 return retval;
175 }
176
177 @Nullable
178 private String lookupPrefixForNamespaceURI(@NonNull String namespace) {
179 String retval = knownNamespacesToPrefix.get(namespace);
180 if (retval == null) {
181
182 retval = WellKnown.getWellKnownPrefixForUri(namespace);
183 }
184 return retval;
185 }
186
187
188
189
190
191
192
193
194
195
196 @Nullable
197 public String lookupNamespaceForPrefix(@NonNull String prefix) {
198 String result = lookupNamespaceURIForPrefix(prefix);
199 return result == null ? null : result;
200 }
201
202
203
204
205
206
207
208
209
210
211 @Nullable
212 public String lookupPrefixForNamespace(@NonNull String namespace) {
213 return lookupPrefixForNamespaceURI(namespace);
214 }
215
216
217
218
219
220
221
222 @Nullable
223 private String getDefaultModelNamespace() {
224 return defaultModelNamespace;
225 }
226
227
228
229
230
231
232
233 @Nullable
234 private String getDefaultFunctionNamespace() {
235 return defaultFunctionNamespace;
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262 @NonNull
263 public IEnhancedQName parseAtomicTypeName(@NonNull String name) {
264 return EQNameFactory.instance().parseName(
265 name,
266 this::resolveAtomicTypePrefix);
267 }
268
269 private String resolveAtomicTypePrefix(@NonNull String prefix) {
270 String ns = lookupNamespaceForPrefix(prefix);
271 if (ns == null) {
272 checkForUnknownPrefix(prefix);
273
274 ns = MetapathConstants.NS_METAPATH;
275 }
276 return ns;
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 @NonNull
303 public IAtomicOrUnionType<?> lookupAtomicType(@NonNull String name) {
304 IEnhancedQName qname = parseAtomicTypeName(name);
305 return lookupAtomicType(qname);
306 }
307
308
309
310
311
312
313
314
315
316
317
318 @NonNull
319 public static IAtomicOrUnionType<?> lookupAtomicType(@NonNull IEnhancedQName qname) {
320 IAtomicOrUnionType<?> retval = DataTypeService.instance().getAtomicTypeByQNameIndex(qname.getIndexPosition());
321 if (retval == null) {
322 throw new StaticMetapathException(
323 StaticMetapathException.UNKNOWN_TYPE,
324 String.format("The atomic type named '%s' was not found.", qname));
325 }
326 return retval;
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340
341 @NonNull
342 public static <T extends IAnyAtomicItem> IAtomicOrUnionType<T> lookupAtomicType(Class<T> clazz) {
343 IAtomicOrUnionType<T> retval = DataTypeService.instance().getAtomicTypeByItemClass(clazz);
344 if (retval == null) {
345 throw new StaticMetapathException(
346 StaticMetapathException.UNKNOWN_TYPE,
347 String.format("The atomic type for item class '%s' was not found.", clazz.getName()));
348 }
349 return retval;
350 }
351
352
353
354
355
356
357
358
359
360
361
362 @NonNull
363 public static IItemType lookupItemType(Class<? extends IItem> clazz) {
364 IItemType retval = DataTypeService.instance().getItemTypeByItemClass(clazz);
365 if (retval == null) {
366 throw new StaticMetapathException(
367 StaticMetapathException.UNKNOWN_TYPE,
368 String.format("The item type for item class '%s' was not found.", clazz.getName()));
369 }
370 return retval;
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 @NonNull
394 public IEnhancedQName parseFunctionName(@NonNull String name) {
395 return EQNameFactory.instance().parseName(
396 name,
397 this::resolveFunctionPrefix);
398 }
399
400 @NonNull
401 private String resolveFunctionPrefix(@NonNull String prefix) {
402 String ns = lookupNamespaceForPrefix(prefix);
403 if (ns == null) {
404 checkForUnknownPrefix(prefix);
405
406 ns = getDefaultFunctionNamespace();
407 }
408 return ns == null ? XMLConstants.NULL_NS_URI : ns;
409 }
410
411
412
413
414
415
416
417
418
419
420
421 private static void checkForUnknownPrefix(@NonNull String prefix) {
422 if (!prefix.isEmpty()) {
423 throw new StaticMetapathException(
424 StaticMetapathException.PREFIX_NOT_EXPANDABLE,
425 String.format("The namespace prefix '%s' is not expandable.",
426 prefix));
427 }
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455 @NonNull
456 public IFunction lookupFunction(@NonNull String name, int arity) {
457 IEnhancedQName qname = parseFunctionName(name);
458 return functionResolver.getFunction(qname, arity);
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473 @NonNull
474 public static IFunction lookupFunction(@NonNull IEnhancedQName qname, int arity) {
475 return FunctionService.getInstance().getFunction(
476 Objects.requireNonNull(qname, "name"),
477 arity);
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503 @NonNull
504 public IEnhancedQName parseFlagName(@NonNull String name) {
505 return EQNameFactory.instance().parseName(
506 name,
507 this::resolveBasicPrefix);
508 }
509
510 private String resolveBasicPrefix(@NonNull String prefix) {
511 String ns = lookupNamespaceForPrefix(prefix);
512 if (ns == null) {
513 checkForUnknownPrefix(prefix);
514 }
515 return ns == null ? XMLConstants.NULL_NS_URI : ns;
516 }
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538 @NonNull
539 public IEnhancedQName parseModelName(@NonNull String name) {
540 return EQNameFactory.instance().parseName(
541 name,
542 this::resolveModelReferencePrefix);
543 }
544
545 @NonNull
546 private String resolveModelReferencePrefix(@NonNull String prefix) {
547 String ns = lookupNamespaceForPrefix(prefix);
548 if (ns == null) {
549 checkForUnknownPrefix(prefix);
550 ns = getDefaultModelNamespace();
551 }
552 return ns == null ? XMLConstants.NULL_NS_URI : ns;
553 }
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575 @NonNull
576 public IEnhancedQName parseVariableName(@NonNull String name) {
577 return EQNameFactory.instance().parseName(
578 name,
579 this::resolveBasicPrefix);
580 }
581
582
583
584
585
586
587
588 @NonNull
589 public Builder buildFrom() {
590 Builder builder = builder();
591 builder.baseUri = this.baseUri;
592 builder.namespaces.putAll(this.knownPrefixToNamespace);
593 builder.defaultModelNamespace = this.defaultModelNamespace;
594 builder.defaultFunctionNamespace = this.defaultFunctionNamespace;
595 return builder;
596 }
597
598
599
600
601
602
603
604
605
606 public boolean isUseWildcardWhenNamespaceNotDefaulted() {
607 return useWildcardWhenNamespaceNotDefaulted && getDefaultModelNamespace() == null;
608 }
609
610
611
612
613
614
615
616 @NonNull
617 public static Builder builder() {
618 return new Builder();
619 }
620
621
622
623
624 public static final class Builder {
625 private boolean useWildcardWhenNamespaceNotDefaulted;
626 @Nullable
627 private URI baseUri;
628 @NonNull
629 private final Map<String, String> namespaces = new ConcurrentHashMap<>();
630 @Nullable
631 private String defaultModelNamespace;
632 @Nullable
633 private String defaultFunctionNamespace = MetapathConstants.NS_METAPATH_FUNCTIONS;
634 @NonNull
635 private IFunctionResolver functionResolver = FunctionService.getInstance();
636
637 private Builder() {
638
639 }
640
641
642
643
644
645
646
647
648
649
650 @NonNull
651 public Builder baseUri(@NonNull URI uri) {
652 this.baseUri = uri;
653 return this;
654 }
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674 @NonNull
675 public Builder namespace(@NonNull String prefix, @NonNull URI uri) {
676 return namespace(prefix, ObjectUtils.notNull(uri.toASCIIString()));
677 }
678
679
680
681
682
683
684
685
686
687
688
689
690
691 @NonNull
692 public Builder namespace(@NonNull String prefix, @NonNull String uri) {
693 if (MetapathConstants.PREFIX_METAPATH.equals(prefix)) {
694
695 throw new IllegalArgumentException(
696 "Redefining the prefix '" + MetapathConstants.PREFIX_METAPATH + "' is not allowed.");
697 }
698 this.namespaces.put(prefix, uri);
699 NamespaceCache.instance().indexOf(uri);
700 return this;
701 }
702
703
704
705
706
707
708
709
710
711 @NonNull
712 public Builder defaultModelNamespace(@NonNull URI namespace) {
713 String uri = ObjectUtils.notNull(namespace.toASCIIString());
714 this.defaultModelNamespace = uri;
715 NamespaceCache.instance().indexOf(uri);
716 return this;
717 }
718
719
720
721
722
723
724
725
726
727
728 @NonNull
729 public Builder defaultModelNamespace(@NonNull String uri) {
730 try {
731 this.defaultModelNamespace = new URI(uri).toASCIIString();
732 } catch (URISyntaxException ex) {
733 throw new IllegalArgumentException(ex);
734 }
735 NamespaceCache.instance().indexOf(uri);
736 return this;
737 }
738
739
740
741
742
743
744
745
746
747 @NonNull
748 public Builder defaultFunctionNamespace(@NonNull URI namespace) {
749 String uri = ObjectUtils.notNull(namespace.toASCIIString());
750 this.defaultFunctionNamespace = uri;
751 NamespaceCache.instance().indexOf(uri);
752 return this;
753 }
754
755
756
757
758
759
760
761
762
763
764 @NonNull
765 public Builder defaultFunctionNamespace(@NonNull String uri) {
766 try {
767 this.defaultFunctionNamespace = new URI(uri).toASCIIString();
768 } catch (URISyntaxException ex) {
769 throw new IllegalArgumentException(ex);
770 }
771 NamespaceCache.instance().indexOf(uri);
772 return this;
773 }
774
775
776
777
778
779
780
781
782 public Builder useWildcardWhenNamespaceNotDefaulted(boolean value) {
783 this.useWildcardWhenNamespaceNotDefaulted = value;
784 return this;
785 }
786
787
788
789
790
791
792
793
794
795
796
797 public Builder functionResolver(@NonNull IFunctionResolver resolver) {
798 this.functionResolver = resolver;
799 return this;
800 }
801
802
803
804
805
806
807 @NonNull
808 public StaticContext build() {
809 return new StaticContext(this);
810 }
811 }
812 }