View Javadoc
1   /*
2    * Portions of this software was developed by employees of the National Institute
3    * of Standards and Technology (NIST), an agency of the Federal Government and is
4    * being made available as a public service. Pursuant to title 17 United States
5    * Code Section 105, works of NIST employees are not subject to copyright
6    * protection in the United States. This software may be subject to foreign
7    * copyright. Permission in the United States and in foreign countries, to the
8    * extent that NIST may hold copyright, to use, copy, modify, create derivative
9    * works, and distribute this software and its documentation without fee is hereby
10   * granted on a non-exclusive basis, provided that this notice and disclaimer
11   * of warranty appears in all copies.
12   *
13   * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14   * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15   * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17   * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18   * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
19   * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20   * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21   * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22   * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23   * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24   * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
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      // disable construction
94    }
95  
96    @SuppressWarnings({ "unused",
97        "PMD.OnlyOneReturn" // readability
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" // readability
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") // false positive
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 }