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 "accept", 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ö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 }