001/* 002 * Configurate 003 * Copyright (C) zml and Configurate contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.spongepowered.configurate; 018 019/** 020 * A visitor to traverse node hierarchies in a depth-first order. 021 * 022 * <p>Instances of stateful implementations may be reusable by taking advantage 023 * of the state object. During each visitation, a visitor will experience the 024 * node tree as a sequence of events, described by the following 025 * pseudo-grammar:</p> 026 * 027 * <pre> 028 * mappingNode: enterMappingNode node* exitMappingNode 029 * listNode: enterListNode node* exitListNode 030 * 031 * node: enterNode 032 * (mappingNode 033 * | listNode 034 * | enterScalarNode) 035 * 036 * visit: newState? 037 * beginVisit 038 * node* 039 * endVisit 040 * </pre> 041 * 042 * <p>If the starting node has no value, no node events will be received. 043 * Otherwise, the first event received will be for the starting node itself, and 044 * will continue from there.</p> 045 * 046 * <p>The children to visit for list and mapping nodes will only be collected 047 * after both the {@code enterNode} and {@code enter(List|Mapping)Node} methods 048 * have been executed for the node, and changes to the node values may be made 049 * to control which nodes will be visited.</p> 050 * 051 * <p>Any exceptions thrown within the visitor will result in the visitation 052 * ending immediately and the exception being rethrown within the visit 053 * method.</p> 054 * 055 * <p>There are a few specializations of the visitor interface available: 056 * {@link Stateless} carries no state and can act as a functional interface 057 * type, and {@link Safe} which throws no checked exceptions and therefore can 058 * be visited without having to handle any exceptions.</p> 059 * 060 * @param <S> a state object that will be used for one visit 061 * @param <T> the terminal value, that can be returned at the end of the visit 062 * @param <E> exception type that may be thrown 063 * @see ScopedConfigurationNode#visit(ConfigurationVisitor) to execute this 064 * configuration visitation 065 * @since 4.0.0 066 */ 067public interface ConfigurationVisitor<S, T, E extends Exception> { 068 069 /** 070 * Called to provide a state object if a visit is initiated without one 071 * already existing. 072 * 073 * @return a new state object to be passed through the rest of this visit 074 * @throws E when thrown by implementation 075 * @since 4.0.0 076 */ 077 S newState() throws E; 078 079 /** 080 * Called at the beginning of the visit with a state object created. 081 * 082 * @param node the root node 083 * @param state the state 084 * @throws E when thrown by implementation 085 * @since 4.0.0 086 */ 087 void beginVisit(ConfigurationNode node, S state) throws E; 088 089 /** 090 * Called once per node, for every node. 091 * 092 * @param node the current node 093 * @param state provided state 094 * @throws E when thrown by implementation 095 * @since 4.0.0 096 */ 097 void enterNode(ConfigurationNode node, S state) throws E; 098 099 /** 100 * Called after {@link #enterNode(ConfigurationNode, Object)} for mapping 101 * nodes. 102 * 103 * @param node current node 104 * @param state provided state 105 * @throws E when thrown by implementation 106 * @since 4.0.0 107 */ 108 void enterMappingNode(ConfigurationNode node, S state) throws E; 109 110 /** 111 * Called after {@link #enterNode(ConfigurationNode, Object)} for list nodes. 112 * 113 * @param node current node 114 * @param state provided state 115 * @throws E when thrown by implementation 116 * @since 4.0.0 117 */ 118 void enterListNode(ConfigurationNode node, S state) throws E; 119 120 /** 121 * Called after {@link #enterNode(ConfigurationNode, Object)} for scalar nodes. 122 * 123 * @param node current node 124 * @param state provided state 125 * @throws E when thrown by implementation 126 * @since 4.0.0 127 */ 128 void enterScalarNode(ConfigurationNode node, S state) throws E; 129 130 /** 131 * Called for a list node after the node and any of its children have 132 * been visited. 133 * 134 * @param node the node that has been visited 135 * @param state provided state 136 * @throws E when thrown by implementation 137 * @since 4.0.0 138 */ 139 void exitMappingNode(ConfigurationNode node, S state) throws E; 140 141 /** 142 * Called for a list node after the node and any of its children have 143 * been visited. 144 * 145 * @param node the node that has been visited 146 * @param state provided state 147 * @throws E when thrown by implementation 148 * @since 4.0.0 149 */ 150 void exitListNode(ConfigurationNode node, S state) throws E; 151 152 /** 153 * Called after every node has been visited, to allow for cleanup 154 * and validation. 155 * 156 * @param state provided state 157 * @return a terminal value 158 * @throws E when thrown by implementation 159 * @since 4.0.0 160 */ 161 T endVisit(S state) throws E; 162 163 /** 164 * Stateless specialization of visitors, where both the state and terminal 165 * type are Void. 166 * 167 * @since 4.0.0 168 */ 169 @FunctionalInterface 170 interface Stateless<E extends Exception> extends ConfigurationVisitor<Void, Void, E> { 171 @Override 172 default Void newState() { 173 return null; 174 } 175 176 @Override 177 default void beginVisit(ConfigurationNode node, Void state) throws E { 178 beginVisit(node); 179 } 180 181 /** 182 * Called at the beginning of the visit with a state object created. 183 * 184 * @param node the root node 185 * @throws E as required by implementation 186 * @since 4.0.0 187 */ 188 default void beginVisit(ConfigurationNode node) throws E {} 189 190 @Override 191 default void enterNode(ConfigurationNode node, Void state) throws E { 192 enterNode(node); 193 } 194 195 /** 196 * Called once per node, for every node. 197 * 198 * @param node the current node 199 * @throws E as required by implementation 200 * @since 4.0.0 201 */ 202 void enterNode(ConfigurationNode node) throws E; 203 204 @Override 205 default void enterMappingNode(ConfigurationNode node, Void state) throws E { 206 enterMappingNode(node); 207 } 208 209 /** 210 * Called after {@link #enterNode(ConfigurationNode, Object)} for 211 * mapping nodes. 212 * 213 * @param node current node 214 * @throws E when thrown by implementation 215 * @since 4.0.0 216 */ 217 default void enterMappingNode(ConfigurationNode node) throws E {} 218 219 @Override 220 default void enterListNode(ConfigurationNode node, Void state) throws E { 221 enterListNode(node); 222 } 223 224 /** 225 * Called after {@link #enterNode(ConfigurationNode, Object)} for list 226 * nodes. 227 * 228 * @param node current node 229 * @throws E when thrown by implementation 230 * @since 4.0.0 231 */ 232 default void enterListNode(ConfigurationNode node) throws E { 233 } 234 235 @Override 236 default void enterScalarNode(ConfigurationNode node, Void state) throws E { 237 enterScalarNode(node); 238 } 239 240 /** 241 * Called after {@link #enterNode(ConfigurationNode, Object)} for scalar 242 * nodes. 243 * 244 * @param node current node 245 * @throws E when thrown by implementation 246 * @since 4.0.0 247 */ 248 default void enterScalarNode(ConfigurationNode node) throws E { 249 } 250 251 @Override 252 default void exitMappingNode(ConfigurationNode node, Void state) throws E { 253 exitMappingNode(node); 254 } 255 256 /** 257 * Called for a mapping node after the node and any of its children have 258 * been visited. 259 * 260 * @param node the node that has been visited 261 * @throws E when thrown by implementation 262 * @since 4.0.0 263 */ 264 default void exitMappingNode(ConfigurationNode node) throws E {} 265 266 @Override 267 default void exitListNode(ConfigurationNode node, Void state) throws E { 268 exitListNode(node); 269 } 270 271 /** 272 * Called for a list node after the node and any of its children have 273 * been visited. 274 * 275 * @param node the node that has been visited 276 * @throws E when thrown by implementation 277 * @since 4.0.0 278 */ 279 default void exitListNode(ConfigurationNode node) throws E {} 280 281 @Override 282 default Void endVisit(Void state) throws E { 283 endVisit(); 284 return null; 285 } 286 287 /** 288 * Called after every node has been visited, to allow for cleanup 289 * and validation. 290 * 291 * @throws E when thrown by implementation 292 * @since 4.0.0 293 */ 294 default void endVisit() throws E {} 295 } 296 297 /** 298 * A subinterface for visitors that do not throw any checked exceptions 299 * during their execution. 300 * 301 * @param <S> state type 302 * @param <T> terminal value type 303 * @since 4.0.0 304 */ 305 interface Safe<S, T> extends ConfigurationVisitor<S, T, VisitorSafeNoopException> { 306 307 @Override 308 S newState(); 309 310 @Override 311 void beginVisit(ConfigurationNode node, S state); 312 313 @Override 314 void enterNode(ConfigurationNode node, S state); 315 316 @Override 317 void enterMappingNode(ConfigurationNode node, S state); 318 319 @Override 320 void enterListNode(ConfigurationNode node, S state); 321 322 @Override 323 void enterScalarNode(ConfigurationNode node, S state); 324 325 @Override 326 void exitMappingNode(ConfigurationNode node, S state); 327 328 @Override 329 void exitListNode(ConfigurationNode node, S state); 330 331 @Override 332 T endVisit(S state); 333 334 } 335 336}