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.metapath.item.node; 028 029import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter; 030import gov.nist.secauto.metaschema.core.metapath.format.IPathSegment; 031import gov.nist.secauto.metaschema.core.metapath.item.IItem; 032import gov.nist.secauto.metaschema.core.util.ObjectUtils; 033 034import java.net.URI; 035import java.util.Collection; 036import java.util.List; 037import java.util.stream.Stream; 038 039import edu.umd.cs.findbugs.annotations.NonNull; 040import edu.umd.cs.findbugs.annotations.Nullable; 041 042/** 043 * Represents a queryable Metapath model node. 044 */ 045public interface INodeItem extends IItem, IPathSegment, INodeItemVisitable { 046 047 /** 048 * Generate a path for this node in the directed node graph, using the provided 049 * path formatter. 050 */ 051 @Override 052 String format(IPathFormatter formatter); 053 054 /** 055 * Gets the value of the provided node item. 056 * <p> 057 * If the provided node item is a document, this method get the first child node 058 * item's value, since a document doesn't have a value. 059 * 060 * @param <CLASS> 061 * the type of the bound object to return 062 * @param item 063 * the node item to get the value of 064 * @return a bound object 065 * @throws NullPointerException 066 * if the node item has no associated value 067 */ 068 @SuppressWarnings("unchecked") 069 @NonNull 070 static <CLASS> CLASS toValue(@NonNull INodeItem item) { 071 INodeItem valuedItem; 072 if (item instanceof IDocumentNodeItem) { 073 // get first child item, since the document has no value 074 valuedItem = item.modelItems().findFirst().get(); 075 } else { 076 valuedItem = item; 077 } 078 return ObjectUtils.requireNonNull((CLASS) valuedItem.getValue()); 079 } 080 081 /** 082 * Retrieve the parent node item if it exists. 083 * 084 * @return the parent node item, or {@code null} if this node item has no known 085 * parent 086 */ 087 INodeItem getParentNodeItem(); 088 089 /** 090 * Retrieve the parent content node item if it exists. A content node is a 091 * non-document node. 092 * 093 * @return the parent content node item, or {@code null} if this node item has 094 * no known parent content node item 095 */ 096 IModelNodeItem<?, ?> getParentContentNodeItem(); 097 098 /** 099 * 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}