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.metapath.item.node;
28  
29  import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter;
30  import gov.nist.secauto.metaschema.core.metapath.format.IPathSegment;
31  import gov.nist.secauto.metaschema.core.metapath.item.IItem;
32  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
33  
34  import java.net.URI;
35  import java.util.Collection;
36  import java.util.List;
37  import java.util.stream.Stream;
38  
39  import edu.umd.cs.findbugs.annotations.NonNull;
40  import edu.umd.cs.findbugs.annotations.Nullable;
41  
42  /**
43   * Represents a queryable Metapath model node.
44   */
45  public interface INodeItem extends IItem, IPathSegment, INodeItemVisitable {
46  
47    /**
48     * Generate a path for this node in the directed node graph, using the provided
49     * path formatter.
50     */
51    @Override
52    String format(IPathFormatter formatter);
53  
54    /**
55     * Gets the value of the provided node item.
56     * <p>
57     * If the provided node item is a document, this method get the first child node
58     * item's value, since a document doesn't have a value.
59     *
60     * @param <CLASS>
61     *          the type of the bound object to return
62     * @param item
63     *          the node item to get the value of
64     * @return a bound object
65     * @throws NullPointerException
66     *           if the node item has no associated value
67     */
68    @SuppressWarnings("unchecked")
69    @NonNull
70    static <CLASS> CLASS toValue(@NonNull INodeItem item) {
71      INodeItem valuedItem;
72      if (item instanceof IDocumentNodeItem) {
73        // get first child item, since the document has no value
74        valuedItem = item.modelItems().findFirst().get();
75      } else {
76        valuedItem = item;
77      }
78      return ObjectUtils.requireNonNull((CLASS) valuedItem.getValue());
79    }
80  
81    /**
82     * Retrieve the parent node item if it exists.
83     *
84     * @return the parent node item, or {@code null} if this node item has no known
85     *         parent
86     */
87    INodeItem getParentNodeItem();
88  
89    /**
90     * Retrieve the parent content node item if it exists. A content node is a
91     * non-document node.
92     *
93     * @return the parent content node item, or {@code null} if this node item has
94     *         no known parent content node item
95     */
96    IModelNodeItem<?, ?> getParentContentNodeItem();
97  
98    /**
99     * Get the type of node item this is.
100    *
101    * @return the node item's type
102    */
103   @NonNull
104   NodeItemType getNodeItemType();
105 
106   /**
107    * Retrieve the base URI of this node.
108    * <p>
109    * The base URI of a node will be in order of preference:
110    * <ol>
111    * <li>the base URI defined on the node</li>
112    * <li>the base URI defined on the nearest ancestor node</li>
113    * <li>the base URI defined on the document node</li>
114    * <li>{@code null} if the document node is unknown</li>
115    * </ol>
116    *
117    * @return the base URI or {@code null} if it is unknown
118    */
119   URI getBaseUri();
120 
121   /**
122    * Get the path for this node item as a Metapath.
123    *
124    * @return the Metapath
125    */
126   @NonNull
127   default String getMetapath() {
128     return toPath(IPathFormatter.METAPATH_PATH_FORMATER);
129   }
130 
131   @Override
132   default Stream<? extends INodeItem> getPathStream() {
133     INodeItem parent = getParentNodeItem();
134     return ObjectUtils.notNull(
135         parent == null ? Stream.of(this) : Stream.concat(getParentNodeItem().getPathStream(), Stream.of(this)));
136   }
137 
138   /**
139    * Get a stream of all ancestors of this node item. The stream is ordered from
140    * closest to farthest ancestor.
141    *
142    * @return a stream of ancestor node items
143    */
144   @NonNull
145   default Stream<? extends INodeItem> ancestor() {
146     return ancestorsOf(this);
147   }
148 
149   /**
150    * Get a stream of this and all ancestors of this node item. The stream is
151    * ordered from self, then closest to farthest ancestor.
152    *
153    * @return a stream of this node followed by all ancestor node items
154    */
155   @NonNull
156   default Stream<? extends INodeItem> ancestorOrSelf() {
157     return ObjectUtils.notNull(Stream.concat(Stream.of(this), ancestor()));
158   }
159 
160   /**
161    * Get a stream of the ancestors of the provided {@code item}. The stream is
162    * ordered from the closest to farthest ancestor.
163    *
164    * @param item
165    *          the target item to get ancestors for
166    *
167    * @return a stream of all ancestor node items
168    */
169   @NonNull
170   static Stream<? extends INodeItem> ancestorsOf(@NonNull INodeItem item) {
171     INodeItem parent = item.getParentNodeItem();
172     return ObjectUtils.notNull(parent == null ? Stream.empty() : Stream.concat(Stream.of(parent), ancestorsOf(parent)));
173   }
174 
175   /**
176    * Get a stream of all descendant model items of this node item. The stream is
177    * ordered from closest to farthest descendants in a depth-first order.
178    *
179    * @return a stream of descendant node items
180    */
181   @NonNull
182   default Stream<? extends INodeItem> descendant() {
183     return decendantsOf(this);
184   }
185 
186   /**
187    * Get a stream of all descendant model items of the provided {@code item}. The
188    * stream is ordered from closest to farthest descendants in a depth-first
189    * order.
190    *
191    * @param item
192    *          the target item to get descendants for
193    *
194    * @return a stream of descendant node items
195    */
196   @NonNull
197   static Stream<? extends INodeItem> decendantsOf(@NonNull INodeItem item) {
198     Stream<? extends INodeItem> children = item.modelItems();
199 
200     return ObjectUtils.notNull(children.flatMap(child -> {
201       assert child != null;
202       return Stream.concat(Stream.of(child), decendantsOf(child));
203     }));
204   }
205 
206   /**
207    * Get a stream of this node, followed by all descendant model items of this
208    * node item. The stream is ordered from closest to farthest descendants in a
209    * depth-first order.
210    *
211    * @return a stream of this node and descendant node items
212    */
213   @NonNull
214   default Stream<? extends INodeItem> descendantOrSelf() {
215     return ObjectUtils.notNull(Stream.concat(Stream.of(this), descendant()));
216   }
217 
218   /**
219    * Get the flags and value data associated this node. The resulting collection
220    * is expected to be ordered, with the results in document order.
221    * <p>
222    * The resulting collection may be modified, but such modification is not thread
223    * safe
224    *
225    * @return a collection of flags
226    */
227   @NonNull
228   Collection<? extends IFlagNodeItem> getFlags();
229 
230   /**
231    * Lookup a flag and value data on this node by it's effective name.
232    *
233    * @param name
234    *          the effective name of the flag
235    * @return the flag with the matching effective name or {@code null} if no match
236    *         was found
237    */
238   @Nullable
239   IFlagNodeItem getFlagByName(@NonNull String name);
240 
241   /**
242    * Get the flags and value data associated with this node as a stream.
243    *
244    * @return the stream of flags or an empty stream if none exist
245    */
246   @SuppressWarnings("null")
247   @NonNull
248   default Stream<? extends IFlagNodeItem> flags() {
249     return getFlags().stream();
250   }
251 
252   /**
253    * Get the model items (i.e., fields, assemblies) and value data associated this
254    * node. A given model instance can be multi-valued, so the value of each
255    * instance will be a list. The resulting collection is expected to be ordered,
256    * with the results in document order.
257    * <p>
258    * The resulting collection may be modified, but such modification is not thread
259    * safe
260    *
261    * @return a collection of list(s), with each list containing the items for a
262    *         given model instance
263    */
264   @NonNull
265   Collection<? extends List<? extends IModelNodeItem<?, ?>>> getModelItems();
266 
267   /**
268    * Get the collection of model items associated with the instance having the
269    * provided {@code name}.
270    * <p>
271    * The resulting collection may be modified, but such modification is not thread
272    * safe
273    *
274    * @param name
275    *          the instance name to get model items for
276    * @return the sequence of items associated with the named model instance, or an
277    *         empty list if an instance with that name is not present
278    */
279   @NonNull
280   List<? extends IModelNodeItem<?, ?>> getModelItemsByName(@NonNull String name);
281 
282   /**
283    * Get the model items (i.e., fields, assemblies) and value data associated this
284    * node as a stream.
285    *
286    * @return the stream of model items or an empty stream if none exist
287    */
288   @SuppressWarnings("null")
289   @NonNull
290   default Stream<? extends IModelNodeItem<?, ?>> modelItems() {
291     return getModelItems().stream().flatMap(list -> list.stream());
292   }
293 }