    001    /*****************************************************************************
    002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
    003     * ------------------------------------------------------------------------- *
    004     * The software in this package is published under the terms of the BSD      *
    005     * style license a copy of which has been included with this distribution in *
    006     * the LICENSE.txt file.                                                     *
    007     *****************************************************************************/
    008    package org.picocontainer.visitors;
    009
    010    import org.picocontainer.PicoVisitor;
    011    import org.picocontainer.PicoException;
    012
    013    import java.lang.reflect.InvocationTargetException;
    014    import java.lang.reflect.Method;
    015    import java.security.AccessController;
    016    import java.security.PrivilegedAction;
    017
    018    /**
    019     * Abstract PicoVisitor implementation. A generic traverse method is implemented, that
    020     * accepts any object with a method named &quot;accept&quot;, that takes a
    021     * {@link PicoVisitor}  as argument and and invokes it. Additionally it provides the
    022     * {@link #checkTraversal()} method, that throws a {@link PicoVisitorTraversalException},
    023     * if currently no traversal is running.
    024     *
    025     * @author J&ouml;rg Schaible
    026     */
    027    @SuppressWarnings("serial")
    028    public abstract class AbstractPicoVisitor implements PicoVisitor {
    029        private boolean traversal;
    030
    031        public Object traverse(final Object node) {
    032            traversal = true;
    033            Object retval =
    034                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
    035                        public Object run() {
    036                            try {
    037                                return node.getClass().getMethod("accept", PicoVisitor.class);
    038                            } catch (NoSuchMethodException e) {
    039                                return e;
    040                            }
    041                        }
    042                    });
    043            try {
    044                if (retval instanceof NoSuchMethodException) {
    045                    throw (NoSuchMethodException) retval;
    046                }
    047                Method accept = (Method) retval;
    048                accept.invoke(node, this);
    049                return Void.TYPE;
    050            } catch (NoSuchMethodException e) {
    051            } catch (IllegalAccessException e) {
    052            } catch (InvocationTargetException e) {
    053                Throwable cause = e.getTargetException();
    054                if (cause instanceof RuntimeException) {
    055                    throw (RuntimeException)cause;
    056                } else if (cause instanceof Error) {
    057                    throw (Error)cause;
    058                }
    059            } finally {
    060                traversal = false;
    061            }
    062            throw new IllegalArgumentException(node.getClass().getName() + " is not a valid type for traversal");
    063        }
    064
    065        /**
    066         * Checks the traversal flag, indicating a currently running traversal of the visitor.
    067         * @throws PicoVisitorTraversalException if no traversal is active.
    068         */
    069        protected void checkTraversal() {
    070            if (!traversal) {
    071                throw new PicoVisitorTraversalException(this);
    072            }
    073        }
    074
    075        /**
    076         * Exception for a PicoVisitor, that is dependent on a defined starting point of the traversal.
    077         * If the traversal is not initiated with a call of {@link PicoVisitor#traverse}
    078         *
    079         * @author joehni
    080         */
    081        public static class PicoVisitorTraversalException
    082                extends PicoException {
    083
    084            /**
    085             * Construct the PicoVisitorTraversalException.
    086             *
    087             * @param visitor The visitor casing the exception.
    088             */
    089            public PicoVisitorTraversalException(PicoVisitor visitor) {
    090                super("Traversal for PicoVisitor of type " + visitor.getClass().getName() + " must start with the visitor's traverse method");
    091            }
    092        }
    093
    094    }