1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.oscal.lib.metapath.function.library;
28
29 import gov.nist.secauto.metaschema.model.common.metapath.DynamicContext;
30 import gov.nist.secauto.metaschema.model.common.metapath.ISequence;
31 import gov.nist.secauto.metaschema.model.common.metapath.MetapathException;
32 import gov.nist.secauto.metaschema.model.common.metapath.function.FunctionUtils;
33 import gov.nist.secauto.metaschema.model.common.metapath.function.IArgument;
34 import gov.nist.secauto.metaschema.model.common.metapath.function.IFunction;
35 import gov.nist.secauto.metaschema.model.common.metapath.function.InvalidTypeFunctionException;
36 import gov.nist.secauto.metaschema.model.common.metapath.item.IBooleanItem;
37 import gov.nist.secauto.metaschema.model.common.metapath.item.IDefinitionNodeItem;
38 import gov.nist.secauto.metaschema.model.common.metapath.item.IItem;
39 import gov.nist.secauto.metaschema.model.common.metapath.item.INodeItem;
40 import gov.nist.secauto.metaschema.model.common.metapath.item.IStringItem;
41 import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
42 import gov.nist.secauto.oscal.lib.model.AssessmentPart;
43 import gov.nist.secauto.oscal.lib.model.ControlPart;
44 import gov.nist.secauto.oscal.lib.model.Property;
45 import gov.nist.secauto.oscal.lib.model.metadata.AbstractProperty;
46
47 import java.net.URI;
48 import java.util.List;
49
50 import edu.umd.cs.findbugs.annotations.NonNull;
51
52 public final class HasOscalNamespace {
53 @NonNull
54 static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
55 .name("has-oscal-namespace")
56 .argument(IArgument.newBuilder()
57 .name("namespace")
58 .type(IStringItem.class)
59 .oneOrMore()
60 .build())
61 .allowUnboundedArity(true)
62 .returnType(IBooleanItem.class)
63 .focusDependent()
64 .contextIndependent()
65 .deterministic()
66 .returnOne()
67 .functionHandler(HasOscalNamespace::executeOneArg)
68 .build();
69
70 @NonNull
71 static final IFunction SIGNATURE_TWO_ARGS = IFunction.builder()
72 .name("has-oscal-namespace")
73 .argument(IArgument.newBuilder()
74 .name("propOrPart")
75 .type(IDefinitionNodeItem.class)
76 .one()
77 .build())
78 .argument(IArgument.newBuilder()
79 .name("namespace")
80 .type(IStringItem.class)
81 .oneOrMore()
82 .build())
83 .allowUnboundedArity(true)
84 .focusIndependent()
85 .contextIndependent()
86 .deterministic()
87 .returnType(IBooleanItem.class)
88 .returnOne()
89 .functionHandler(HasOscalNamespace::executeTwoArg)
90 .build();
91
92 private HasOscalNamespace() {
93
94 }
95
96 @SuppressWarnings({ "unused",
97 "PMD.OnlyOneReturn"
98 })
99 @NonNull
100 public static ISequence<?> executeOneArg(
101 @NonNull IFunction function,
102 @NonNull List<ISequence<?>> arguments,
103 @NonNull DynamicContext dynamicContext,
104 INodeItem focus) {
105 INodeItem node = focus;
106 if (node == null) {
107 return ISequence.empty();
108 }
109
110 assert arguments.size() == 1;
111 ISequence<? extends IStringItem> namespaceArgs = FunctionUtils.asType(
112 ObjectUtils.notNull(arguments.get(0)));
113 if (namespaceArgs.isEmpty()) {
114 return ISequence.empty();
115 }
116
117 return ISequence.of(hasNamespace(FunctionUtils.asType(node), namespaceArgs));
118 }
119
120 @SuppressWarnings({ "unused",
121 "PMD.OnlyOneReturn"
122 })
123 @NonNull
124 public static ISequence<?> executeTwoArg(
125 @NonNull IFunction function,
126 @NonNull List<ISequence<?>> arguments,
127 @NonNull DynamicContext dynamicContext,
128 INodeItem focus) {
129 ISequence<? extends IDefinitionNodeItem> nodeSequence = FunctionUtils.asType(
130 ObjectUtils.notNull(arguments.get(0)));
131
132 IItem node = FunctionUtils.getFirstItem(nodeSequence, true);
133 if (node == null) {
134 return ISequence.empty();
135 }
136
137 assert arguments.size() == 2;
138 ISequence<? extends IStringItem> namespaceArgs = FunctionUtils.asType(
139 ObjectUtils.notNull(arguments.get(1)));
140 if (namespaceArgs.isEmpty()) {
141 return ISequence.empty();
142 }
143
144 return ISequence.of(hasNamespace(FunctionUtils.asType(node), namespaceArgs));
145 }
146
147 @SuppressWarnings("PMD.LinguisticNaming")
148 @NonNull
149 public static IBooleanItem hasNamespace(
150 @NonNull IDefinitionNodeItem propOrPart,
151 @NonNull ISequence<? extends IStringItem> namespaces)
152 throws MetapathException {
153 Object propOrPartObject = propOrPart.getValue();
154 if (propOrPartObject == null) {
155 throw new InvalidTypeFunctionException(InvalidTypeFunctionException.NODE_HAS_NO_TYPED_VALUE, propOrPart);
156 }
157
158 URI nodeNamespace;
159 if (propOrPartObject instanceof Property) {
160 nodeNamespace = ((Property) propOrPartObject).getNs();
161 } else if (propOrPartObject instanceof ControlPart) {
162 nodeNamespace = ((ControlPart) propOrPartObject).getNs();
163 } else if (propOrPartObject instanceof AssessmentPart) {
164 nodeNamespace = ((AssessmentPart) propOrPartObject).getNs();
165 } else {
166 throw new MetapathException(
167 String.format("Node of definition type '%s' has no OSCAL namespace", propOrPart.getDefinition().getName()));
168 }
169
170 String nodeNamespaceString = AbstractProperty.normalizeNamespace(nodeNamespace).toString();
171 return IBooleanItem.valueOf(namespaces.asStream()
172 .map(node -> nodeNamespaceString.equals(node.asString()))
173 .anyMatch(bool -> bool));
174 }
175 }