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}