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 }