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 java.util.List; 030 031import edu.umd.cs.findbugs.annotations.NonNull; 032 033/** 034 * Used by implementations of this class to visit a sequence of node items in a 035 * directed graph, using depth-first ordering. 036 * 037 * @param <RESULT> 038 * the type of result produced by visitation 039 * @param <CONTEXT> 040 * the type of data to pass to each visited node 041 */ 042public abstract class AbstractNodeItemVisitor<RESULT, CONTEXT> implements INodeItemVisitor<RESULT, CONTEXT> { 043 /** 044 * Visit the provided {@code item}. 045 * 046 * @param item 047 * the item to visit 048 * @param context 049 * provides contextual information for use by the visitor 050 * @return the result produced by visiting the item 051 */ 052 public final RESULT visit(@NonNull INodeItemVisitable item, CONTEXT context) { 053 return item.accept(this, context); 054 } 055 056 /** 057 * Visit any child flags associated with the provided {@code item}. 058 * 059 * @param item 060 * the item to visit 061 * @param context 062 * provides contextual information for use by the visitor 063 * @return the result produced by visiting the item's flags 064 */ 065 protected RESULT visitFlags(@NonNull INodeItem item, CONTEXT context) { 066 RESULT result = defaultResult(); 067 for (IFlagNodeItem flag : item.getFlags()) { 068 assert flag != null; 069 if (!shouldVisitNextChild(item, flag, result, context)) { 070 break; 071 } 072 073 RESULT childResult = flag.accept(this, context); 074 result = aggregateResult(result, childResult, context); 075 } 076 return result; 077 } 078 079 /** 080 * Visit any child model items associated with the provided {@code item}. 081 * 082 * @param item 083 * the item to visit 084 * @param context 085 * provides contextual information for use by the visitor 086 * @return the result produced by visiting the item's child model items 087 */ 088 protected RESULT visitModelChildren(@NonNull INodeItem item, CONTEXT context) { 089 RESULT result = defaultResult(); 090 091 for (List<? extends IModelNodeItem<?, ?>> childItems : item.getModelItems()) { 092 for (IModelNodeItem<?, ?> childItem : childItems) { 093 assert childItem != null; 094 if (!shouldVisitNextChild(item, childItem, result, context)) { 095 break; 096 } 097 098 RESULT childResult = childItem.accept(this, context); 099 result = aggregateResult(result, childResult, context); 100 } 101 } 102 return result; 103 } 104 105 /** 106 * Determine if the child should be visited next, or skipped. 107 * 108 * @param parent 109 * the parent of the child to visit next 110 * @param child 111 * the next child to visit 112 * @param result 113 * the current visitation result 114 * @param context 115 * provides contextual information for use by the visitor 116 * @return {@code true} if the child should be visited, or {@code false} if the 117 * child should be skipped 118 */ 119 protected boolean shouldVisitNextChild( 120 @NonNull INodeItem parent, 121 @NonNull INodeItem child, 122 RESULT result, 123 CONTEXT context) { 124 // this is the default behavior, which can be overridden 125 return true; 126 } 127 128 /** 129 * Determine if the child should be visited next, or skipped. 130 * 131 * @param parent 132 * the parent of the child to visit next 133 * @param child 134 * the next child to visit 135 * @param result 136 * the current visitation result 137 * @param context 138 * provides contextual information for use by the visitor 139 * @return {@code true} if the child should be visited, or {@code false} if the 140 * child should be skipped 141 */ 142 protected boolean shouldVisitNextChild( 143 @NonNull INodeItem parent, 144 @NonNull IModelNodeItem<?, ?> child, 145 RESULT result, 146 CONTEXT context) { 147 // this is the default behavior, which can be overridden 148 return true; 149 } 150 151 /** 152 * The initial, default visitation result, which will be used as the basis for 153 * aggregating results produced when visiting. 154 * 155 * @return the default result 156 * @see #aggregateResult(Object, Object, Object) 157 */ 158 protected abstract RESULT defaultResult(); 159 160 /** 161 * Combine two results into a single, aggregate result. 162 * 163 * @param first 164 * the original result 165 * @param second 166 * the new result to combine with the original result 167 * @param context 168 * provides contextual information for use by the visitor 169 * @return the combined result 170 */ 171 protected RESULT aggregateResult(RESULT first, RESULT second, CONTEXT context) { 172 // this is the default behavior, which can be overridden 173 return second; 174 } 175 176 @Override 177 public RESULT visitDocument(IDocumentNodeItem item, CONTEXT context) { 178 // this is the default behavior, which can be overridden 179 return visitModelChildren(item, context); 180 // return visitAssembly(item.getRootAssemblyNodeItem(), context); 181 } 182 183 @Override 184 public RESULT visitFlag(IFlagNodeItem item, CONTEXT context) { 185 // this is the default behavior, which can be overridden 186 return defaultResult(); 187 } 188 189 @Override 190 public RESULT visitField(IFieldNodeItem item, CONTEXT context) { 191 // this is the default behavior, which can be overridden 192 return visitFlags(item, context); 193 } 194 195 @Override 196 public RESULT visitAssembly(IAssemblyNodeItem item, CONTEXT context) { 197 // this is the default behavior, which can be overridden 198 return aggregateResult(visitFlags(item, context), visitModelChildren(item, context), context); 199 } 200 201 @Override 202 public RESULT visitMetaschema(IModuleNodeItem item, CONTEXT context) { 203 // this is the default behavior, which can be overridden 204 return aggregateResult(visitFlags(item, context), visitModelChildren(item, context), context); 205 } 206}