org.apache.wicket.util.visit.Visits.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.util.visit.Visits.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.util.visit;

import java.util.Collections;
import java.util.Iterator;

import org.apache.wicket.util.lang.Args;

/**
 * Utility class that contains visitor/traversal related code
 */
public class Visits {
    /** Constructor */
    private Visits() {
    }

    private static class SingletonIterable<T> implements Iterable<T> {
        private final T singleton;

        public SingletonIterable(final T singleton) {
            this.singleton = singleton;
        }

        @Override
        public Iterator<T> iterator() {
            return Collections.singleton(singleton).iterator();
        }
    }

    /**
     * Visits container and its children pre-order (parent first). Children are determined by
     * calling {@link Iterable#iterator()}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param container
     *            object whose children will be visited
     * @param visitor
     *            the visitor
     * @return return value from the {@code visitor} or {@code null} if none
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <S, R> R visit(final Iterable<? super S> container, final IVisitor<S, R> visitor) {
        return (R) visitChildren(new SingletonIterable(container), visitor, IVisitFilter.ANY);
    }

    /**
     * Visits container and its children pre-order (parent first). Children are determined by
     * calling {@link Iterable#iterator()}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param container
     *            object whose children will be visited
     * @param visitor
     *            the visitor
     * @param filter
     *            filter used to limit the types of objects that will be visited
     * @return return value from the {@code visitor} or {@code null} if none
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <S, R> R visit(final Iterable<? super S> container, final IVisitor<S, R> visitor,
            final IVisitFilter filter) {
        return (R) visitChildren(new SingletonIterable(container), visitor, filter);
    }

    /**
     * Visits children of the specified {@link Iterable} pre-order (parent first). Children are
     * determined by calling {@link Iterable#iterator()}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param container
     *            object whose children will be visited
     * @param visitor
     *            the visitor
     * @param filter
     *            filter used to limit the types of objects that will be visited
     * @return return value from the {@code visitor} or {@code null} if none
     */
    public static <S, R> R visitChildren(final Iterable<? super S> container, final IVisitor<S, R> visitor,
            final IVisitFilter filter) {
        Visit<R> visit = new Visit<>();
        visitChildren(container, visitor, filter, visit);
        return visit.getResult();
    }

    @SuppressWarnings("unchecked")
    private static <S, R> void visitChildren(final Iterable<? super S> container, final IVisitor<S, R> visitor,
            final IVisitFilter filter, final Visit<R> visit) {
        Args.notNull(visitor, "visitor");

        // Iterate through children of this container
        for (final Object child : container) {
            // Get next child component
            // Is the child of the correct class (or was no class specified)?
            if (filter.visitObject(child)) {
                Visit<R> childTraversal = new Visit<>();

                // Call visitor
                S s = (S) child;
                visitor.component(s, childTraversal);

                if (childTraversal.isStopped()) {
                    visit.stop(childTraversal.getResult());
                    return;
                } else if (childTraversal.isDontGoDeeper()) {
                    continue;
                }
            }

            // If child is a container
            if (!visit.isDontGoDeeper() && (child instanceof Iterable<?>) && filter.visitChildren(child)) {
                // visit the children in the container
                visitChildren((Iterable<? super S>) child, visitor, filter, visit);

                if (visit.isStopped()) {
                    return;
                }
            }
        }
    }

    /**
     * Visits children of the specified {@link Iterable} pre-order (parent first). Children are
     * determined by calling {@link Iterable#iterator()}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param container
     *            object whose children will be visited
     * @param visitor
     *            the visitor
     * @return return value from the {@code visitor} or {@code null} if none
     */
    public static <S, R> R visitChildren(final Iterable<? super S> container, final IVisitor<S, R> visitor) {
        return visitChildren(container, visitor, IVisitFilter.ANY);
    }

    /**
     * Visits the specified object and any of its children using a post-order (child first)
     * traversal. Children are determined by calling {@link Iterable#iterator()} if the object
     * implements {@link Iterable}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param root
     *            root object that will be visited
     * @param visitor
     *            the visitor
     * @return return value from the {@code visitor} or {@code null} if none
     */
    public static <S, R> R visitPostOrder(final S root, final org.apache.wicket.util.visit.IVisitor<S, R> visitor) {
        return visitPostOrder(root, visitor, IVisitFilter.ANY);
    }

    /**
     * Visits the specified object and any of its children using a post-order (child first)
     * traversal. Children are determined by calling {@link Iterable#iterator()} if the object
     * implements {@link Iterable}.
     * 
     * @param <S>
     *            the type of object that will be visited, notice that {@code container} is not
     *            declared as {@code Iterable<S>} because it may return a generalization of
     *            {@code S}
     * @param <R>
     *            the type of object that should be returned from the visitor, use {@link Void} if
     *            no return value is needed
     * @param root
     *            root object that will be visited
     * @param visitor
     *            the visitor
     * @param filter
     *            filter used to limit the types of objects that will be visited
     * @return return value from the {@code visitor} or {@code null} if none
     */
    public static <S, R> R visitPostOrder(final Object root,
            final org.apache.wicket.util.visit.IVisitor<S, R> visitor, final IVisitFilter filter) {
        Args.notNull(visitor, "visitor");

        Visit<R> visit = new Visit<>();
        visitPostOrderHelper(root, visitor, filter, visit);
        return visit.getResult();
    }

    @SuppressWarnings("unchecked")
    private static <S, R> void visitPostOrderHelper(final Object component,
            final org.apache.wicket.util.visit.IVisitor<S, R> visitor, final IVisitFilter filter,
            final Visit<R> visit) {
        if (component instanceof Iterable<?>) {
            final Iterable<?> container = (Iterable<?>) component;
            if (filter.visitChildren(container)) {
                Visit<R> childTraversal = new Visit<>();
                for (final Object child : ((Iterable<?>) component)) {
                    visitPostOrderHelper(child, visitor, filter, childTraversal);
                    if (childTraversal.isStopped()) {
                        visit.stop(childTraversal.getResult());
                        return;
                    }
                }
            }
        }

        if (filter.visitObject(component)) {
            visitor.component((S) component, visit);
        }
    }
}