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 }