001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.metaschema.core.model;
028
029import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
030import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
031import gov.nist.secauto.metaschema.core.util.ObjectUtils;
032
033import java.net.URI;
034import java.util.Collection;
035import java.util.List;
036import java.util.function.Predicate;
037import java.util.stream.Collectors;
038import java.util.stream.Stream;
039
040import javax.xml.namespace.QName;
041
042import edu.umd.cs.findbugs.annotations.NonNull;
043import edu.umd.cs.findbugs.annotations.Nullable;
044
045/**
046 * The API for accessing information about a given Metaschema.
047 * <p>
048 * A Metaschem module may import another Metaschema module. This import graph
049 * can be accessed using {@link #getImportedModules()}.
050 * <p>
051 * Global scoped Metaschema definitions can be accessed using
052 * {@link #getScopedAssemblyDefinitionByName(String)},
053 * {@link #getScopedFieldDefinitionByName(String)}, and
054 * {@link #getScopedFlagDefinitionByName(String)}. These methods take into
055 * consideration the import order to provide the global definitions that are in
056 * scope within the given Metschema module.
057 * <p>
058 * Global scoped definitions exported by this Metaschema module, available for
059 * use by importing Metaschema modules, can be accessed using
060 * {@link #getExportedAssemblyDefinitions()},
061 * {@link #getExportedFieldDefinitions()}, and
062 * {@link #getExportedFlagDefinitions()}.
063 * <p>
064 * Global scoped definitions defined directly within the given Metaschema module
065 * can be accessed using {@link #getAssemblyDefinitions()},
066 * {@link #getFieldDefinitions()}, and {@link #getFlagDefinitions()}, along with
067 * similarly named access methods.
068 */
069// REFACTOR: rename to IModule
070public interface IModule {
071  String METASCHEMA_XML_NS = "http://csrc.nist.gov/ns/oscal/metaschema/1.0";
072
073  /**
074   * Get a filter that will match all definitions that are not locally defined.
075   *
076   * @param <DEF>
077   *          the type of definition
078   * @return a predicate implementing the filter
079   */
080  static <DEF extends IDefinition> Predicate<DEF> allNonLocalDefinitions() {
081    return definition -> {
082      return ModuleScopeEnum.INHERITED.equals(definition.getModuleScope())
083          || ModelType.ASSEMBLY.equals(definition.getModelType()) && ((IAssemblyDefinition) definition).isRoot();
084    };
085  }
086
087  /**
088   * Get a filter that will match all definitions that are root assemblies.
089   *
090   * @param <DEF>
091   *          the type of definition
092   * @return a predicate implementing the filter
093   */
094  static <DEF extends IDefinition> Predicate<DEF> allRootAssemblyDefinitions() {
095    return definition -> {
096      return ModelType.ASSEMBLY.equals(definition.getModelType()) && ((IAssemblyDefinition) definition).isRoot();
097    };
098  }
099
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}