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 }