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