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.ISequence;
10 import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
11 import gov.nist.secauto.metaschema.core.metapath.MetapathException;
12 import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
13 import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
14 import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
15 import gov.nist.secauto.metaschema.core.metapath.function.InvalidTypeFunctionException;
16 import gov.nist.secauto.metaschema.core.metapath.function.library.FnData;
17 import gov.nist.secauto.metaschema.core.metapath.item.IItem;
18 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem;
19 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
20 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
21 import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem;
22 import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem;
23 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
24 import gov.nist.secauto.metaschema.core.model.IFlagInstance;
25 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
26 import gov.nist.secauto.oscal.lib.OscalModelConstants;
27 import gov.nist.secauto.oscal.lib.model.metadata.AbstractProperty;
28
29 import java.net.URI;
30 import java.util.List;
31
32 import javax.xml.namespace.QName;
33
34 import edu.umd.cs.findbugs.annotations.NonNull;
35
36 public final class HasOscalNamespace {
37 @NonNull
38 private static final QName NS_FLAG_QNAME = new QName("ns");
39 @NonNull
40 static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
41 .name("has-oscal-namespace")
42 .namespace(OscalModelConstants.NS_OSCAL)
43 .argument(IArgument.builder()
44 .name("namespace")
45 .type(IStringItem.class)
46 .oneOrMore()
47 .build())
48 .allowUnboundedArity(true)
49 .returnType(IBooleanItem.class)
50 .focusDependent()
51 .contextIndependent()
52 .deterministic()
53 .returnOne()
54 .functionHandler(HasOscalNamespace::executeOneArg)
55 .build();
56
57 @NonNull
58 static final IFunction SIGNATURE_TWO_ARGS = IFunction.builder()
59 .name("has-oscal-namespace")
60 .namespace(OscalModelConstants.NS_OSCAL)
61 .argument(IArgument.builder()
62 .name("propOrPart")
63 .type(IAssemblyNodeItem.class)
64 .one()
65 .build())
66 .argument(IArgument.builder()
67 .name("namespace")
68 .type(IStringItem.class)
69 .oneOrMore()
70 .build())
71 .allowUnboundedArity(true)
72 .focusIndependent()
73 .contextIndependent()
74 .deterministic()
75 .returnType(IBooleanItem.class)
76 .returnOne()
77 .functionHandler(HasOscalNamespace::executeTwoArg)
78 .build();
79
80 @NonNull
81 static final IFunction SIGNATURE_ONE_ARG_METAPATH = IFunction.builder()
82 .name("has-oscal-namespace")
83 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
84 .argument(IArgument.builder()
85 .name("namespace")
86 .type(IStringItem.class)
87 .oneOrMore()
88 .build())
89 .allowUnboundedArity(true)
90 .returnType(IBooleanItem.class)
91 .focusDependent()
92 .contextIndependent()
93 .deterministic()
94 .returnOne()
95 .functionHandler(HasOscalNamespace::executeOneArg)
96 .build();
97
98 @NonNull
99 static final IFunction SIGNATURE_TWO_ARGS_METAPATH = IFunction.builder()
100 .name("has-oscal-namespace")
101 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
102 .argument(IArgument.builder()
103 .name("propOrPart")
104 .type(IAssemblyNodeItem.class)
105 .one()
106 .build())
107 .argument(IArgument.builder()
108 .name("namespace")
109 .type(IStringItem.class)
110 .oneOrMore()
111 .build())
112 .allowUnboundedArity(true)
113 .focusIndependent()
114 .contextIndependent()
115 .deterministic()
116 .returnType(IBooleanItem.class)
117 .returnOne()
118 .functionHandler(HasOscalNamespace::executeTwoArg)
119 .build();
120
121 private HasOscalNamespace() {
122
123 }
124
125 @SuppressWarnings({ "unused",
126 "PMD.OnlyOneReturn"
127 })
128 @NonNull
129 public static ISequence<?> executeOneArg(
130 @NonNull IFunction function,
131 @NonNull List<ISequence<?>> arguments,
132 @NonNull DynamicContext dynamicContext,
133 IItem focus) {
134 assert arguments.size() == 1;
135 ISequence<? extends IStringItem> namespaceArgs = FunctionUtils.asType(
136 ObjectUtils.notNull(arguments.get(0)));
137
138 if (namespaceArgs.isEmpty()) {
139 return ISequence.empty();
140 }
141
142 IAssemblyNodeItem node = FunctionUtils.requireType(IAssemblyNodeItem.class, focus);
143 return ISequence.of(hasNamespace(FunctionUtils.asType(node), namespaceArgs));
144 }
145
146 @SuppressWarnings({ "unused",
147 "PMD.OnlyOneReturn"
148 })
149 @NonNull
150 public static ISequence<?> executeTwoArg(
151 @NonNull IFunction function,
152 @NonNull List<ISequence<?>> arguments,
153 @NonNull DynamicContext dynamicContext,
154 IItem focus) {
155 assert arguments.size() == 2;
156
157 ISequence<? extends IStringItem> namespaceArgs = FunctionUtils.asType(
158 ObjectUtils.notNull(arguments.get(1)));
159 if (namespaceArgs.isEmpty()) {
160 return ISequence.empty();
161 }
162
163 ISequence<? extends IAssemblyNodeItem> nodeSequence = FunctionUtils.asType(
164 ObjectUtils.notNull(arguments.get(0)));
165
166
167 IAssemblyNodeItem node = FunctionUtils.asType(ObjectUtils.requireNonNull(nodeSequence.getFirstItem(true)));
168 return ISequence.of(hasNamespace(node, namespaceArgs));
169 }
170
171 @SuppressWarnings("PMD.LinguisticNaming")
172 @NonNull
173 public static IBooleanItem hasNamespace(
174 @NonNull IAssemblyNodeItem propOrPart,
175 @NonNull ISequence<? extends IStringItem> namespaces) {
176 Object propOrPartObject = propOrPart.getValue();
177 if (propOrPartObject == null) {
178 throw new InvalidTypeFunctionException(InvalidTypeFunctionException.NODE_HAS_NO_TYPED_VALUE, propOrPart);
179 }
180
181 URI nodeNamespace = null;
182
183 IFlagNodeItem ns = propOrPart.getFlagByName(NS_FLAG_QNAME);
184 if (ns == null) {
185
186 IAssemblyDefinition definition = propOrPart.getDefinition();
187 IFlagInstance flag = definition.getFlagInstanceByName(NS_FLAG_QNAME);
188 if (flag == null) {
189 throw new MetapathException(
190 String.format(
191 "Node at path '%s' bound to '%s' based on the assembly definition '%s' has no OSCAL namespace",
192 propOrPart.getMetapath(),
193 propOrPart.getClass().getName(),
194 propOrPart.getDefinition().getName()));
195
196 }
197
198 Object defaultValue = flag.getDefinition().getDefaultValue();
199 if (defaultValue != null) {
200 nodeNamespace = IAnyUriItem.valueOf(ObjectUtils.notNull(defaultValue.toString())).asUri();
201 }
202 } else {
203 nodeNamespace = IAnyUriItem.cast(FnData.fnDataItem(ns)).asUri();
204 }
205
206 String nodeNamespaceString = AbstractProperty.normalizeNamespace(nodeNamespace).toString();
207 return IBooleanItem.valueOf(namespaces.stream()
208 .map(node -> nodeNamespaceString.equals(node.asString()))
209 .anyMatch(bool -> bool));
210 }
211 }