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.defaults;
009    
010    import org.picocontainer.PicoVisitor;
011    
012    import java.lang.reflect.InvocationTargetException;
013    import java.lang.reflect.Method;
014    import java.security.AccessController;
015    import java.security.PrivilegedAction;
016    
017    /**
018     * Abstract PicoVisitor implementation. A generic traverse method is implemented, that 
019     * accepts any object with a method named "accept", that takes a 
020     * {@link PicoVisitor}  as argument and and invokes it. Additionally it provides the 
021     * {@link #checkTraversal()} method, that throws a {@link PicoVisitorTraversalException},
022     * if currently no traversal is running.
023     * 
024     * @author Jörg Schaible
025     * @since 1.1
026     */
027    public abstract class AbstractPicoVisitor implements PicoVisitor {
028        private boolean traversal;
029    
030        public Object traverse(final Object node) {
031            traversal = true;
032            Object retval =
033                    AccessController.doPrivileged(new PrivilegedAction() {
034                        public Object run() {
035                            try {
036                                Method method = node.getClass().getMethod("accept", new Class[]{PicoVisitor.class});
037                                return method;
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, new Object[]{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    }