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.metaschema.core.model;
28  
29  import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
30  import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
31  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
32  
33  import java.net.URI;
34  import java.util.Collection;
35  import java.util.List;
36  import java.util.function.Predicate;
37  import java.util.stream.Collectors;
38  import java.util.stream.Stream;
39  
40  import javax.xml.namespace.QName;
41  
42  import edu.umd.cs.findbugs.annotations.NonNull;
43  import edu.umd.cs.findbugs.annotations.Nullable;
44  
45  /**
46   * The API for accessing information about a given Metaschema.
47   * <p>
48   * A Metaschem module may import another Metaschema module. This import graph
49   * can be accessed using {@link #getImportedModules()}.
50   * <p>
51   * Global scoped Metaschema definitions can be accessed using
52   * {@link #getScopedAssemblyDefinitionByName(String)},
53   * {@link #getScopedFieldDefinitionByName(String)}, and
54   * {@link #getScopedFlagDefinitionByName(String)}. These methods take into
55   * consideration the import order to provide the global definitions that are in
56   * scope within the given Metschema module.
57   * <p>
58   * Global scoped definitions exported by this Metaschema module, available for
59   * use by importing Metaschema modules, can be accessed using
60   * {@link #getExportedAssemblyDefinitions()},
61   * {@link #getExportedFieldDefinitions()}, and
62   * {@link #getExportedFlagDefinitions()}.
63   * <p>
64   * Global scoped definitions defined directly within the given Metaschema module
65   * can be accessed using {@link #getAssemblyDefinitions()},
66   * {@link #getFieldDefinitions()}, and {@link #getFlagDefinitions()}, along with
67   * similarly named access methods.
68   */
69  // REFACTOR: rename to IModule
70  public interface IModule {
71    String METASCHEMA_XML_NS = "http://csrc.nist.gov/ns/oscal/metaschema/1.0";
72  
73    /**
74     * Get a filter that will match all definitions that are not locally defined.
75     *
76     * @param <DEF>
77     *          the type of definition
78     * @return a predicate implementing the filter
79     */
80    static <DEF extends IDefinition> Predicate<DEF> allNonLocalDefinitions() {
81      return definition -> {
82        return ModuleScopeEnum.INHERITED.equals(definition.getModuleScope())
83            || ModelType.ASSEMBLY.equals(definition.getModelType()) && ((IAssemblyDefinition) definition).isRoot();
84      };
85    }
86  
87    /**
88     * Get a filter that will match all definitions that are root assemblies.
89     *
90     * @param <DEF>
91     *          the type of definition
92     * @return a predicate implementing the filter
93     */
94    static <DEF extends IDefinition> Predicate<DEF> allRootAssemblyDefinitions() {
95      return definition -> {
96        return ModelType.ASSEMBLY.equals(definition.getModelType()) && ((IAssemblyDefinition) definition).isRoot();
97      };
98    }
99  
100   /**
101    * Retrieves the location where the Metaschema module was loaded from.
102    *
103    * @return the location, or {@code null} if this information is not available
104    */
105   URI getLocation();
106 
107   /**
108    * Get the long name for the Metaschema module.
109    *
110    * @return the name
111    */
112   @NonNull
113   MarkupLine getName();
114 
115   /**
116    * Get the revision of the Metaschema module.
117    *
118    * @return the revision
119    */
120   @NonNull
121   String getVersion();
122 
123   /**
124    * Retrieve the remarks associated with this Metaschema module, if any.
125    *
126    * @return the remarks or {@code null} if no remarks are defined
127    */
128   @Nullable
129   MarkupMultiline getRemarks();
130 
131   /**
132    * Retrieves the unique short name for the Metaschema module, which provides a
133    * textual identifier for the Metaschema module.
134    *
135    * @return the short name
136    */
137   @NonNull
138   String getShortName();
139 
140   /**
141    * Retrieves the XML namespace associated with the Metaschema module.
142    *
143    * @return a namespace
144    */
145   @NonNull
146   URI getXmlNamespace();
147 
148   /**
149    * Retrieve the JSON schema base URI associated with the Metaschema module.
150    *
151    * @return the base URI
152    */
153   @NonNull
154   URI getJsonBaseUri();
155 
156   /**
157    * Get the qualified name associated with the Metaschema module.
158    *
159    * @return the qualified name
160    */
161   default QName getQName() {
162     return new QName(getXmlNamespace().toString(), getShortName());
163   }
164 
165   /**
166    * Retrieves all Metaschema modules imported by this Metaschema module.
167    *
168    * @return a list of imported Metaschema modules
169    */
170   @NonNull
171   List<? extends IModule> getImportedModules();
172 
173   /**
174    * Retrieve the imported Metaschema module with the specified name, if it
175    * exists.
176    *
177    * @param name
178    *          the short name of the Metschema module to retrieve
179    * @return the imported Metaschema module or {@code null} if it doesn't exist
180    */
181   @Nullable
182   IModule getImportedModuleByShortName(String name);
183 
184   /**
185    * Retrieves the top-level assembly definitions in this Metaschema module.
186    *
187    * @return the collection of assembly definitions
188    */
189   @NonNull
190   Collection<? extends IAssemblyDefinition> getAssemblyDefinitions();
191 
192   /**
193    * Retrieves the top-level assembly definition in this Metaschema module with
194    * the matching name, if it exists.
195    *
196    * @param name
197    *          the definition name
198    *
199    * @return the matching assembly definition, or {@code null} if none match
200    */
201   @Nullable
202   IAssemblyDefinition getAssemblyDefinitionByName(@NonNull String name);
203 
204   /**
205    * Retrieves the top-level field definitions in this Metaschema module.
206    *
207    * @return the collection of field definitions
208    */
209   @NonNull
210   Collection<? extends IFieldDefinition> getFieldDefinitions();
211 
212   /**
213    * Retrieves the top-level field definition in this Metaschema module with the
214    * matching name, if it exists.
215    *
216    * @param name
217    *          the definition name
218    *
219    * @return the matching field definition, or {@code null} if none match
220    */
221   @Nullable
222   IFieldDefinition getFieldDefinitionByName(@NonNull String name);
223 
224   /**
225    * Retrieves the top-level assembly and field definitions in this Metaschema
226    * module.
227    *
228    * @return a listing of assembly and field definitions
229    */
230   @NonNull
231   default List<? extends IFlagContainer> getAssemblyAndFieldDefinitions() {
232     return ObjectUtils.notNull(
233         Stream.concat(getAssemblyDefinitions().stream(), getFieldDefinitions().stream())
234             .collect(Collectors.toList()));
235   }
236 
237   /**
238    * Retrieves the top-level flag definitions in this Metaschema module.
239    *
240    * @return the collection of flag definitions
241    */
242   @NonNull
243   Collection<? extends IFlagDefinition> getFlagDefinitions();
244 
245   /**
246    * Retrieves the top-level flag definition in this Metaschema module with the
247    * matching name, if it exists.
248    *
249    * @param name
250    *          the definition name
251    *
252    * @return the matching flag definition, or {@code null} if none match
253    */
254   @Nullable
255   IFlagDefinition getFlagDefinitionByName(@NonNull String name);
256 
257   // /**
258   // * Retrieves the information elements matching the path.
259   // *
260   // * @param path
261   // * a MetaPath expression
262   // * @return the matching information elements or an empty collection
263   // */
264   // @NonNull
265   // Collection<@NonNull ? extends IModelElement>
266   // getInfoElementsByMetapath(@NonNull String path);
267 
268   /**
269    * Retrieves the assembly definition with a matching name from either: 1) the
270    * top-level assembly definitions from this Metaschema module, or 2) global
271    * assembly definitions from each imported Metaschema module in reverse order of
272    * import.
273    *
274    * @param name
275    *          the name of the assembly to find
276    * @return the assembly definition
277    */
278   @Nullable
279   default IAssemblyDefinition getScopedAssemblyDefinitionByName(@NonNull String name) {
280     // first try local/global top-level definitions from current metaschema module
281     IAssemblyDefinition retval = getAssemblyDefinitionByName(name);
282     if (retval == null) {
283       // try global definitions from imported Metaschema modules
284       retval = getExportedAssemblyDefinitionByName(name);
285     }
286     return retval;
287   }
288 
289   /**
290    * Retrieves the field definition with a matching name from either: 1) the
291    * top-level field definitions from this Metaschema module, or 2) global field
292    * definitions from each imported Metaschema module in reverse order of import.
293    *
294    * @param name
295    *          the name of the field definition to find
296    * @return the field definition
297    */
298   @Nullable
299   default IFieldDefinition getScopedFieldDefinitionByName(@NonNull String name) {
300     // first try local/global top-level definitions from current metaschema module
301     IFieldDefinition retval = getFieldDefinitionByName(name);
302     if (retval == null) {
303       // try global definitions from imported metaschema modules
304       retval = getExportedFieldDefinitionByName(name);
305     }
306     return retval;
307   }
308 
309   /**
310    * Retrieves the flag definition with a matching name from either: 1) the
311    * top-level flag definitions from this Metaschema module, or 2) global flag
312    * definitions from each imported Metaschema module in reverse order of import.
313    *
314    * @param name
315    *          the name of the flag definition to find
316    * @return the flag definition
317    */
318   @Nullable
319   default IFlagDefinition getScopedFlagDefinitionByName(@NonNull String name) {
320     // first try local/global top-level definitions from current metaschema module
321     IFlagDefinition retval = getFlagDefinitionByName(name);
322     if (retval == null) {
323       // try global definitions from imported metaschema modules
324       retval = getExportedFlagDefinitionByName(name);
325     }
326     return retval;
327   }
328 
329   /**
330    * Retrieves the top-level assembly definitions that are marked as roots from
331    * the current Metaschema module and any imported Metaschema modules.
332    *
333    * @return a listing of assembly definitions marked as root
334    */
335   @NonNull
336   default Collection<? extends IAssemblyDefinition> getExportedRootAssemblyDefinitions() {
337     return ObjectUtils.notNull(getExportedAssemblyDefinitions().stream()
338         .filter(allRootAssemblyDefinitions())
339         .collect(Collectors.toList()));
340   }
341 
342   /**
343    * Retrieves the top-level assembly definitions that are marked as roots from
344    * the current Metaschema module.
345    *
346    * @return a listing of assembly definitions marked as root
347    */
348   @NonNull
349   default Collection<? extends IAssemblyDefinition> getRootAssemblyDefinitions() {
350     return ObjectUtils.notNull(getAssemblyDefinitions().stream()
351         .filter(allRootAssemblyDefinitions())
352         .collect(Collectors.toList()));
353   }
354 
355   /**
356    * Retrieve the top-level flag definitions that are marked global in this
357    * Metaschema module or in any imported Metaschema modules. The resulting
358    * collection is built by adding global definitions from each imported
359    * Metaschema module in order of import, then adding global definitions from the
360    * current Metaschema module. Such a map is built in this way for each imported
361    * Metaschema module in the chain. Values for clashing keys will be replaced in
362    * this order, giving preference to the "closest" definition.
363    *
364    * @return the collection of exported flag definitions
365    */
366   @NonNull
367   Collection<? extends IFlagDefinition> getExportedFlagDefinitions();
368 
369   /**
370    * Retrieves the exported named flag definition, if it exists.
371    * <p>
372    * For information about how flag definitions are exported see
373    * {@link #getExportedFlagDefinitions()}.
374    *
375    * @param name
376    *          the definition name
377    * @return the flag definition, or {@code null} if it doesn't exist.
378    */
379   @Nullable
380   IFlagDefinition getExportedFlagDefinitionByName(String name);
381 
382   /**
383    * Retrieve the top-level field definitions that are marked global in this
384    * Metaschema module or in any imported Metaschema module. The resulting
385    * collection is built by adding global definitions from each imported
386    * Metaschema module in order of import, then adding global definitions from the
387    * current Metaschema module. Such a map is built in this way for each imported
388    * Metaschema module in the chain. Values for clashing keys will be replaced in
389    * this order, giving preference to the "closest" definition
390    *
391    * @return the collection of exported field definitions
392    */
393   @NonNull
394   Collection<? extends IFieldDefinition> getExportedFieldDefinitions();
395 
396   /**
397    * Retrieves the exported named field definition, if it exists.
398    * <p>
399    * For information about how field definitions are exported see
400    * {@link #getExportedFieldDefinitions()}.
401    *
402    * @param name
403    *          the definition name
404    * @return the field definition, or {@code null} if it doesn't exist.
405    */
406   @Nullable
407   IFieldDefinition getExportedFieldDefinitionByName(String name);
408 
409   /**
410    * Retrieve the top-level assembly definitions that are marked global in this
411    * Metaschema module or in any imported Metaschema module. The resulting
412    * collection is built by adding global definitions from each imported
413    * Metaschema module in order of import, then adding global definitions from the
414    * current Metaschema module. This collection is built in this way for each
415    * imported Metaschema module in the chain. Items with duplicate names will be
416    * replaced in this order, giving preference to the "closest" definition
417    *
418    * @return the collection of exported assembly definitions
419    */
420   @NonNull
421   Collection<? extends IAssemblyDefinition> getExportedAssemblyDefinitions();
422 
423   /**
424    * Retrieves the exported named assembly definition, if it exists.
425    * <p>
426    * For information about how assembly definitions are exported see
427    * {@link #getExportedFieldDefinitions()}.
428    *
429    * @param name
430    *          the definition name
431    * @return the assembly definition, or {@code null} if it doesn't exist.
432    */
433   @Nullable
434   IAssemblyDefinition getExportedAssemblyDefinitionByName(String name);
435 }