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.PicoContainer; 011 import org.picocontainer.PicoIntrospectionException; 012 013 import java.io.Serializable; 014 import java.lang.reflect.InvocationTargetException; 015 import java.lang.reflect.Method; 016 import java.util.ArrayList; 017 import java.util.Collections; 018 import java.util.Iterator; 019 import java.util.List; 020 021 022 /** 023 * A PicoVisitor implementation, that calls methods on the components of a specific type. 024 * 025 * @author Aslak Hellesøy 026 * @author Jörg Schaible 027 * @since 1.2 028 */ 029 public class MethodCallingVisitor extends TraversalCheckingVisitor implements Serializable { 030 031 // TODO: we must serialize method with read/writeObject ... and are our parent serializable ??? 032 private transient Method method; 033 private final Object[] arguments; 034 private final Class type; 035 private final boolean visitInInstantiationOrder; 036 private final List componentInstances; 037 038 /** 039 * Construct a MethodCallingVisitor for a method with arguments. 040 * 041 * @param method the {@link Method} to invoke 042 * @param ofType the type of the components, that will be invoked 043 * @param visitInInstantiationOrder <code>true</code> if components are visited in instantiation order 044 * @param arguments the arguments for the method invocation (may be <code>null</code>) 045 * @throws NullPointerException if <tt>method</tt>, or <tt>ofType</tt> is <code>null</code> 046 * @since 1.2 047 */ 048 public MethodCallingVisitor(Method method, Class ofType, Object[] arguments, boolean visitInInstantiationOrder) { 049 if (method == null) { 050 throw new NullPointerException(); 051 } 052 this.method = method; 053 this.arguments = arguments; 054 this.type = ofType; 055 this.visitInInstantiationOrder = visitInInstantiationOrder; 056 this.componentInstances = new ArrayList(); 057 } 058 059 /** 060 * Construct a MethodCallingVisitor for standard methods visiting the component in instantiation order. 061 * 062 * @param method the method to invoke 063 * @param ofType the type of the components, that will be invoked 064 * @param arguments the arguments for the method invocation (may be <code>null</code>) 065 * @throws NullPointerException if <tt>method</tt>, or <tt>ofType</tt> is <code>null</code> 066 * @since 1.2 067 */ 068 public MethodCallingVisitor(Method method, Class ofType, Object[] arguments) { 069 this(method, ofType, arguments, true); 070 } 071 072 public Object traverse(Object node) { 073 componentInstances.clear(); 074 try { 075 super.traverse(node); 076 if (!visitInInstantiationOrder) { 077 Collections.reverse(componentInstances); 078 } 079 for (Iterator iterator = componentInstances.iterator(); iterator.hasNext();) { 080 invoke(iterator.next()); 081 } 082 } finally { 083 componentInstances.clear(); 084 } 085 return Void.TYPE; 086 } 087 088 public void visitContainer(PicoContainer pico) { 089 super.visitContainer(pico); 090 componentInstances.addAll(pico.getComponentInstancesOfType(type)); 091 } 092 093 protected Method getMethod() { 094 return method; 095 } 096 097 protected Object[] getArguments() { 098 return arguments; 099 } 100 101 protected void invoke(final Object[] targets) { 102 for (int i = 0; i < targets.length; i++) { 103 invoke(targets[i]); 104 } 105 } 106 107 protected Object invoke(final Object target) { 108 final Method method = getMethod(); 109 try { 110 method.invoke(target, getArguments()); 111 } catch (IllegalArgumentException e) { 112 throw new PicoIntrospectionException("Can't call " + method.getName() + " on " + target, e); 113 } catch (IllegalAccessException e) { 114 throw new PicoIntrospectionException("Can't call " + method.getName() + " on " + target, e); 115 } catch (InvocationTargetException e) { 116 throw new PicoIntrospectionException("Failed when calling " + method.getName() + " on " + target, e 117 .getTargetException()); 118 } 119 return Void.TYPE; 120 } 121 }