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.oscal.lib.profile.resolver.support; 028 029import gov.nist.secauto.metaschema.model.common.metapath.MetapathExpression; 030import gov.nist.secauto.metaschema.model.common.metapath.item.IDocumentNodeItem; 031import gov.nist.secauto.metaschema.model.common.metapath.item.IRequiredValueModelNodeItem; 032import gov.nist.secauto.metaschema.model.common.metapath.item.IRootAssemblyNodeItem; 033import gov.nist.secauto.metaschema.model.common.util.CollectionUtil; 034import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; 035 036import java.util.Collections; 037import java.util.EnumSet; 038import java.util.Set; 039 040import edu.umd.cs.findbugs.annotations.NonNull; 041 042/** 043 * Visits a catalog document and its children as designated. 044 * <p> 045 * This implementation is stateless. The {@code T} parameter can be used to 046 * convey state as needed. 047 * 048 * @param <T> 049 * the state type 050 * @param <R> 051 * the result type 052 */ 053public abstract class AbstractCatalogEntityVisitor<T, R> 054 extends AbstractCatalogVisitor<T, R> { 055 @NonNull 056 public static final MetapathExpression CHILD_PART_METAPATH 057 = MetapathExpression.compile("part|part//part"); 058 @NonNull 059 private static final MetapathExpression BACK_MATTER_RESOURCES_METAPATH 060 = MetapathExpression.compile("back-matter/resource"); 061 @NonNull 062 private static final Set<IEntityItem.ItemType> GROUP_CONTAINER_TYPES 063 = ObjectUtils.notNull(EnumSet.of( 064 IEntityItem.ItemType.GROUP, 065 IEntityItem.ItemType.CONTROL, 066 IEntityItem.ItemType.PARAMETER, 067 IEntityItem.ItemType.PART)); 068 @NonNull 069 private static final Set<IEntityItem.ItemType> CONTROL_CONTAINER_TYPES 070 = ObjectUtils.notNull(EnumSet.of( 071 IEntityItem.ItemType.CONTROL, 072 IEntityItem.ItemType.PARAMETER, 073 IEntityItem.ItemType.PART)); 074 @NonNull 075 private final Set<IEntityItem.ItemType> itemTypesToVisit; 076 077 /** 078 * Create a new visitor that will visit the item types identified by 079 * {@code itemTypesToVisit}. 080 * 081 * @param itemTypesToVisit 082 * the item type the visitor will visit 083 */ 084 public AbstractCatalogEntityVisitor(@NonNull Set<IEntityItem.ItemType> itemTypesToVisit) { 085 this.itemTypesToVisit = CollectionUtil.unmodifiableSet(itemTypesToVisit); 086 } 087 088 public Set<IEntityItem.ItemType> getItemTypesToVisit() { 089 return CollectionUtil.unmodifiableSet(itemTypesToVisit); 090 } 091 092 protected boolean isVisitedItemType(@NonNull IEntityItem.ItemType type) { 093 return itemTypesToVisit.contains(type); 094 } 095 096 @Override 097 public R visitCatalog(IDocumentNodeItem catalogDocument, T state) { 098 R result = super.visitCatalog(catalogDocument, state); 099 100 IRootAssemblyNodeItem root = catalogDocument.getRootAssemblyNodeItem(); 101 visitMetadata(root, state); 102 visitBackMatter(root, state); 103 return result; 104 } 105 106 @Override 107 protected R visitGroupContainer(IRequiredValueModelNodeItem catalogOrGroup, R initialResult, T state) { 108 R retval; 109 if (Collections.disjoint(getItemTypesToVisit(), GROUP_CONTAINER_TYPES)) { 110 retval = initialResult; 111 } else { 112 retval = super.visitGroupContainer(catalogOrGroup, initialResult, state); 113 } 114 return retval; 115 } 116 117 @Override 118 protected R visitControlContainer(IRequiredValueModelNodeItem catalogOrGroupOrControl, R initialResult, T state) { 119 R retval; 120 if (Collections.disjoint(getItemTypesToVisit(), CONTROL_CONTAINER_TYPES)) { 121 retval = initialResult; 122 } else { 123 // first descend to all control container children 124 retval = super.visitControlContainer(catalogOrGroupOrControl, initialResult, state); 125 126 // handle parameters 127 if (isVisitedItemType(IEntityItem.ItemType.PARAMETER)) { 128 retval = catalogOrGroupOrControl.getModelItemsByName("param").stream() 129 .map(paramItem -> { 130 return visitParameter(ObjectUtils.requireNonNull(paramItem), catalogOrGroupOrControl, state); 131 }) 132 .reduce(retval, (first, second) -> aggregateResults(first, second, state)); 133 } // TODO Auto-generated method stub 134 } 135 return retval; 136 } 137 138 protected void visitParts(@NonNull IRequiredValueModelNodeItem groupOrControlItem, T state) { 139 // handle parts 140 if (isVisitedItemType(IEntityItem.ItemType.PART)) { 141 CHILD_PART_METAPATH.evaluate(groupOrControlItem).asStream() 142 .map(item -> (IRequiredValueModelNodeItem) item) 143 .forEachOrdered(partItem -> { 144 visitPart(ObjectUtils.requireNonNull(partItem), groupOrControlItem, state); 145 }); 146 } 147 } 148 149 @Override 150 protected R visitGroupInternal(@NonNull IRequiredValueModelNodeItem item, R childResult, T state) { 151 if (isVisitedItemType(IEntityItem.ItemType.PART)) { 152 visitParts(item, state); 153 } 154 155 R retval = childResult; 156 if (isVisitedItemType(IEntityItem.ItemType.GROUP)) { 157 retval = visitGroup(item, retval, state); 158 } 159 return retval; 160 } 161 162 @Override 163 protected R visitControlInternal(IRequiredValueModelNodeItem item, R childResult, T state) { 164 if (isVisitedItemType(IEntityItem.ItemType.PART)) { 165 visitParts(item, state); 166 } 167 168 R retval = childResult; 169 if (isVisitedItemType(IEntityItem.ItemType.CONTROL)) { 170 retval = visitControl(item, retval, state); 171 } 172 return retval; 173 } 174 175 /** 176 * Called when visiting a parameter. 177 * <p> 178 * Can be overridden by classes extending this interface to support processing 179 * of the visited object. 180 * 181 * @param item 182 * the Metapath item for the parameter 183 * @param catalogOrGroupOrControl 184 * the parameter's parent Metapath item 185 * @param state 186 * the calling context information 187 * @return a meaningful result of the given type 188 */ 189 protected R visitParameter( 190 @NonNull IRequiredValueModelNodeItem item, 191 @NonNull IRequiredValueModelNodeItem catalogOrGroupOrControl, 192 T state) { 193 // do nothing 194 return newDefaultResult(state); 195 } 196 197 /** 198 * Called when visiting a part. 199 * <p> 200 * Can be overridden by classes extending this interface to support processing 201 * of the visited object. 202 * 203 * @param item 204 * the Metapath item for the part 205 * @param groupOrControl 206 * the part's parent Metapath item 207 * @param state 208 * the calling context information 209 */ 210 protected void visitPart( // NOPMD noop default 211 @NonNull IRequiredValueModelNodeItem item, 212 @NonNull IRequiredValueModelNodeItem groupOrControl, 213 T state) { 214 // do nothing 215 } 216 217 /** 218 * Called when visiting the "metadata" section of an OSCAL document. 219 * <p> 220 * Visits each contained role, location, and party. 221 * 222 * @param rootItem 223 * the root Metaschema node item containing the "metadata" node 224 * @param state 225 * the calling context information 226 */ 227 protected void visitMetadata(@NonNull IRootAssemblyNodeItem rootItem, T state) { 228 rootItem.getModelItemsByName("metadata").forEach(metadataItem -> { 229 if (isVisitedItemType(IEntityItem.ItemType.ROLE)) { 230 metadataItem.getModelItemsByName("role").forEach(roleItem -> { 231 visitRole(ObjectUtils.requireNonNull(roleItem), metadataItem, state); 232 }); 233 } 234 235 if (isVisitedItemType(IEntityItem.ItemType.LOCATION)) { 236 metadataItem.getModelItemsByName("location").forEach(locationItem -> { 237 visitLocation(ObjectUtils.requireNonNull(locationItem), metadataItem, state); 238 }); 239 } 240 241 if (isVisitedItemType(IEntityItem.ItemType.PARTY)) { 242 metadataItem.getModelItemsByName("party").forEach(partyItem -> { 243 visitParty(ObjectUtils.requireNonNull(partyItem), metadataItem, state); 244 }); 245 } 246 }); 247 } 248 249 /** 250 * Called when visiting a role in the "metadata" section of an OSCAL document. 251 * <p> 252 * Can be overridden by classes extending this interface to support processing 253 * of the visited object. 254 * 255 * @param item 256 * the role Metaschema node item which is a child of the "metadata" 257 * node 258 * @param metadataItem 259 * the "metadata" Metaschema node item containing the role 260 * @param state 261 * the calling context information 262 */ 263 protected void visitRole( // NOPMD noop default 264 @NonNull IRequiredValueModelNodeItem item, 265 @NonNull IRequiredValueModelNodeItem metadataItem, 266 T state) { 267 // do nothing 268 } 269 270 /** 271 * Called when visiting a location in the "metadata" section of an OSCAL 272 * document. 273 * <p> 274 * Can be overridden by classes extending this interface to support processing 275 * of the visited object. 276 * 277 * @param item 278 * the location Metaschema node item which is a child of the "metadata" 279 * node 280 * @param metadataItem 281 * the "metadata" Metaschema node item containing the location 282 * @param state 283 * the calling context information 284 */ 285 protected void visitLocation( // NOPMD noop default 286 @NonNull IRequiredValueModelNodeItem item, 287 @NonNull IRequiredValueModelNodeItem metadataItem, 288 T state) { 289 // do nothing 290 } 291 292 /** 293 * Called when visiting a party in the "metadata" section of an OSCAL document. 294 * <p> 295 * Can be overridden by classes extending this interface to support processing 296 * of the visited object. 297 * 298 * @param item 299 * the party Metaschema node item which is a child of the "metadata" 300 * node 301 * @param metadataItem 302 * the "metadata" Metaschema node item containing the party 303 * @param state 304 * the calling context information 305 */ 306 protected void visitParty( // NOPMD noop default 307 @NonNull IRequiredValueModelNodeItem item, 308 @NonNull IRequiredValueModelNodeItem metadataItem, 309 T state) { 310 // do nothing 311 } 312 313 /** 314 * Called when visiting the "back-matter" section of an OSCAL document. 315 * <p> 316 * Visits each contained resource. 317 * 318 * @param rootItem 319 * the root Metaschema node item containing the "back-matter" node 320 * @param state 321 * the calling context information 322 */ 323 protected void visitBackMatter(@NonNull IRootAssemblyNodeItem rootItem, T state) { 324 if (isVisitedItemType(IEntityItem.ItemType.RESOURCE)) { 325 BACK_MATTER_RESOURCES_METAPATH.evaluate(rootItem).asStream() 326 .map(item -> (IRequiredValueModelNodeItem) item) 327 .forEachOrdered(resourceItem -> { 328 visitResource(ObjectUtils.requireNonNull(resourceItem), rootItem, state); 329 }); 330 } 331 } 332 333 /** 334 * Called when visiting a resource in the "back-matter" section of an OSCAL 335 * document. 336 * <p> 337 * Can be overridden by classes extending this interface to support processing 338 * of the visited object. 339 * 340 * @param item 341 * the resource Metaschema node item which is a child of the "metadata" 342 * node 343 * @param backMatterItem 344 * the resource Metaschema node item containing the party 345 * @param state 346 * the calling context information 347 */ 348 protected void visitResource( // NOPMD noop default 349 @NonNull IRequiredValueModelNodeItem item, 350 @NonNull IRootAssemblyNodeItem backMatterItem, 351 T state) { 352 // do nothing 353 } 354}