1
2
3
4
5
6 package gov.nist.secauto.oscal.lib.metapath.function.library;
7
8 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
9 import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
10 import gov.nist.secauto.metaschema.core.metapath.MetapathException;
11 import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
12 import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
13 import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
14 import gov.nist.secauto.metaschema.core.metapath.function.library.FnDoc;
15 import gov.nist.secauto.metaschema.core.metapath.function.library.FnResolveUri;
16 import gov.nist.secauto.metaschema.core.metapath.item.IItem;
17 import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
18 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem;
19 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
20 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
21 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
22 import gov.nist.secauto.oscal.lib.OscalModelConstants;
23 import gov.nist.secauto.oscal.lib.model.Catalog;
24 import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolutionException;
25 import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolver;
26
27 import java.io.IOException;
28 import java.net.URI;
29 import java.util.List;
30
31 import edu.umd.cs.findbugs.annotations.NonNull;
32
33 public final class ResolveProfile {
34
35 @NonNull
36 static final IFunction SIGNATURE_NO_ARG = IFunction.builder()
37 .name("resolve-profile")
38 .namespace(OscalModelConstants.NS_OSCAL)
39 .returnType(INodeItem.type())
40 .focusDependent()
41 .contextDependent()
42 .deterministic()
43 .returnOne()
44 .functionHandler(ResolveProfile::executeNoArg)
45 .build();
46
47 @NonNull
48 static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
49 .name("resolve-profile")
50 .namespace(OscalModelConstants.NS_OSCAL)
51 .argument(IArgument.builder()
52 .name("profile")
53 .type(INodeItem.type())
54 .zeroOrOne()
55 .build())
56 .focusIndependent()
57 .contextDependent()
58 .deterministic()
59 .returnType(INodeItem.type())
60 .returnOne()
61 .functionHandler(ResolveProfile::executeOneArg)
62 .build();
63
64 @NonNull
65 static final IFunction SIGNATURE_NO_ARG_METAPATH = IFunction.builder()
66 .name("resolve-profile")
67 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
68 .returnType(INodeItem.type())
69 .focusDependent()
70 .contextDependent()
71 .deterministic()
72 .returnOne()
73 .functionHandler(ResolveProfile::executeNoArg)
74 .build();
75
76 @NonNull
77 static final IFunction SIGNATURE_ONE_ARG_METAPATH = IFunction.builder()
78 .name("resolve-profile")
79 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
80 .argument(IArgument.builder()
81 .name("profile")
82 .type(INodeItem.type())
83 .zeroOrOne()
84 .build())
85 .focusIndependent()
86 .contextDependent()
87 .deterministic()
88 .returnType(INodeItem.type())
89 .returnOne()
90 .functionHandler(ResolveProfile::executeOneArg)
91 .build();
92
93 private ResolveProfile() {
94
95 }
96
97 @SuppressWarnings({ "unused",
98 "PMD.OnlyOneReturn"
99 })
100 @NonNull
101 public static ISequence<?> executeNoArg(
102 @NonNull IFunction function,
103 @NonNull List<ISequence<?>> arguments,
104 @NonNull DynamicContext dynamicContext,
105 IItem focus) {
106
107 if (focus == null) {
108 return ISequence.empty();
109 }
110 return ISequence.of(resolveProfile(FunctionUtils.asType(focus), dynamicContext));
111 }
112
113 @SuppressWarnings({ "unused",
114 "PMD.OnlyOneReturn"
115 })
116 @NonNull
117 public static ISequence<?> executeOneArg(
118 @NonNull IFunction function,
119 @NonNull List<ISequence<?>> arguments,
120 @NonNull DynamicContext dynamicContext,
121 IItem focus) {
122 ISequence<? extends IDocumentNodeItem> arg = FunctionUtils.asType(
123 ObjectUtils.notNull(arguments.get(0)));
124
125 IItem item = arg.getFirstItem(true);
126 if (item == null) {
127 return ISequence.empty();
128 }
129
130 return ISequence.of(resolveProfile(FunctionUtils.asType(item), dynamicContext));
131 }
132
133 @NonNull
134 public static IDocumentNodeItem resolveProfile(
135 @NonNull IDocumentNodeItem document,
136 @NonNull DynamicContext dynamicContext) {
137
138
139 URI documentUri = document.getBaseUri();
140 String fragment = documentUri.getFragment();
141
142 IDocumentNodeItem profile;
143 if (fragment == null) {
144 profile = document;
145 } else {
146 IAnyUriItem referenceUri = ResolveReference.resolveReference(IAnyUriItem.valueOf(documentUri), null, document);
147 IAnyUriItem resolvedUri = FnResolveUri.fnResolveUri(referenceUri, null, dynamicContext);
148 profile = FnDoc.fnDoc(resolvedUri, dynamicContext);
149 }
150
151 Object profileObject = INodeItem.toValue(profile);
152
153 IDocumentNodeItem retval;
154 if (profileObject instanceof Catalog) {
155 retval = profile;
156 } else {
157
158 ProfileResolver resolver
159 = new ProfileResolver(dynamicContext, (uri, source) -> profile.getDocumentUri().resolve(uri));
160 try {
161 retval = resolver.resolve(profile);
162 } catch (IOException | ProfileResolutionException ex) {
163 throw new MetapathException(
164 String.format("Unable to resolve profile '%s'. %s",
165 profile.getBaseUri(),
166 ex.getLocalizedMessage()),
167 ex);
168 }
169 }
170 return retval;
171 }
172 }