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 }