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