View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.di.impl.providers;
17  
18  import java.util.HashSet;
19  import java.util.Set;
20  
21  import net.sf.jguiraffe.di.Dependency;
22  import net.sf.jguiraffe.di.DependencyProvider;
23  import net.sf.jguiraffe.di.impl.ClassDescription;
24  import net.sf.jguiraffe.di.impl.MethodInvocation;
25  
26  /**
27   * <p>
28   * A specialized <code>BeanProvider</code> that creates beans by invoking a
29   * method.
30   * </p>
31   * <p>
32   * This <code>BeanProvider</code> implementation is initialized with a
33   * {@link MethodInvocation} object describing the method to be invoked. Optional
34   * a {@link Dependency} can be provided for the instance, on which the method is
35   * to be invoked (if no such dependency is specified, the method to be invoked
36   * must be static). This class is intended for the following use cases:
37   * <ul>
38   * <li>It can be used for obtaining instances that are not created using a
39   * constructor, but by invoking a static factory method. In this case the passed
40   * in <code>MethodInvocation</code> must refer to this factory method and must
41   * provide the parameters for this invocation.</li>
42   * <li>Another use case is the handling of <em>factory classes</em>: Some
43   * objects are not directly created, but a method on a specific factory class is
44   * used for this purpose. An example could be a <code>Connection</code> object
45   * that is obtained from a <code>DataSource</code>. In this case the factory is
46   * defined as a separate bean, and a dependency to this bean is specified to
47   * this bean provider class. The <code>MethodInvocation</code> defines the
48   * method of this factory bean that has to be called for obtaining an instance.</li>
49   * </ul>
50   * </p>
51   * <p>
52   * As is true for other <code>SimpleBeanProvider</code>s, this provider is
53   * intended to be used together with a life-cycle-aware
54   * <code>BeanProvider</code>. It does not provide any life-cycle support on its
55   * own.
56   * </p>
57   *
58   * @author Oliver Heger
59   * @version $Id: MethodInvocationBeanProvider.java 205 2012-01-29 18:29:57Z oheger $
60   */
61  public class MethodInvocationBeanProvider extends SimpleBeanProvider
62  {
63      /** Stores the method invocation object. */
64      private MethodInvocation invocation;
65  
66      /** Stores the target dependency. */
67      private Dependency targetDependency;
68  
69      /** Stores a class description for the managed bean. */
70      private ClassDescription beanClassDescription;
71  
72      /**
73       * Creates a new instance of <code>MethodInvocationBeanProvider</code> and
74       * initializes it with the dependency to the target object (on which the
75       * method is to be invoked) and the description of the method invocation.
76       *
77       * @param targetBean the dependency to the target bean (can be <b>null</b>)
78       * @param methodInv the description of the method to invoke (must not be
79       * <b>null</b>)
80       * @throws IllegalArgumentException if the <code>MethodInvocation</code>
81       * is undefined
82       */
83      public MethodInvocationBeanProvider(Dependency targetBean,
84              MethodInvocation methodInv)
85      {
86          this(targetBean, methodInv, null);
87      }
88  
89      /**
90       * Creates a new instance of <code>MethodInvocationBeanProvider</code> and
91       * initializes it with the description of the method to invoke. No
92       * dependency for the target instance is provided, so a static method must
93       * be specified.
94       *
95       * @param methodInv the description of the method to invoke (must not be
96       * <b>null</b>)
97       * @throws IllegalArgumentException if the <code>MethodInvocation</code>
98       * is undefined
99       */
100     public MethodInvocationBeanProvider(MethodInvocation methodInv)
101     {
102         this(null, methodInv);
103     }
104 
105     /**
106      * Creates a new instance of <code>MethodInvocationBeanProvider</code> and
107      * initializes it with the dependency to the target object (on which the
108      * method is to be invoked), the description of the method invocation, and
109      * the class of the managed bean. Depending on the used dependency and/or
110      * the method invocation, it is not always possible to determine the class
111      * of the managed bean. With this constructor it can be explicitly set.
112      *
113      * @param targetBean the dependency to the target bean (can be <b>null</b>)
114      * @param methodInv the description of the method to invoke (must not be
115      * <b>null</b>)
116      * @param beanClsDsc a description of the class of the managed bean (can be
117      * <b>null</b>)
118      * @throws IllegalArgumentException if the <code>MethodInvocation</code>
119      * is undefined
120      */
121     public MethodInvocationBeanProvider(Dependency targetBean,
122             MethodInvocation methodInv, ClassDescription beanClsDsc)
123     {
124         if (methodInv == null)
125         {
126             throw new IllegalArgumentException(
127                     "Method invocation must not be null!");
128         }
129         invocation = methodInv;
130         targetDependency = targetBean;
131         beanClassDescription = beanClsDsc;
132     }
133 
134     /**
135      * Returns the dependency to the target bean. This can be <b>null</b> if
136      * none is provided.
137      *
138      * @return the dependency to the target bean
139      */
140     public Dependency getTargetDependency()
141     {
142         return targetDependency;
143     }
144 
145     /**
146      * Returns the <code>MethodInvocation</code> for the method to be invoked.
147      *
148      * @return the method invocation
149      */
150     public MethodInvocation getInvocation()
151     {
152         return invocation;
153     }
154 
155     /**
156      * Returns the description of the class of the managed bean. If a class
157      * description was explicitly set in the constructor, this description is
158      * returned. Otherwise this implementation tries to obtain the bean class
159      * from the {@link MethodInvocation} object owned by this provider. Because
160      * a class is optional for a method invocation, result can be <b>null</b>.
161      * To avoid this, a valid {@link ClassDescription} should always be set
162      * either on the <code>MethodInvocation</code> or when an instance of this
163      * class is constructed.
164      *
165      * @return a class description of the managed bean
166      */
167     public ClassDescription getBeanClassDescription()
168     {
169         return (beanClassDescription != null) ? beanClassDescription
170                 : getInvocation().getTargetClass();
171     }
172 
173     /**
174      * Returns the bean managed by this provider. If a target dependency is set,
175      * the corresponding bean will be fetched from the specified dependency
176      * provider and used as target instance for the method invocation. Otherwise
177      * the method is invoked on a <b>null</b> instance, so this has to be a
178      * static method.
179      *
180      * @param dependencyProvider the dependency provider
181      * @return the bean managed by this provider
182      */
183     public Object getBean(DependencyProvider dependencyProvider)
184     {
185         Object target = (getTargetDependency() != null) ? dependencyProvider
186                 .getDependentBean(getTargetDependency()) : null;
187         Object result = getInvocation().invoke(dependencyProvider, target);
188         return (target != null) ? target : result;
189     }
190 
191     /**
192      * Returns the bean class of the bean managed by this provider. This
193      * implementation delegates to <code>getBeanClassDescription()</code> for
194      * obtaining the description of the bean class. If this is successful, the
195      * class is resolved; otherwise result is <b>null</b>.
196      *
197      * @param dependencyProvider the dependency provider
198      * @return the class of the managed bean
199      * @see #getBeanClassDescription()
200      */
201     public Class<?> getBeanClass(DependencyProvider dependencyProvider)
202     {
203         ClassDescription cdesc = getBeanClassDescription();
204         return (cdesc != null) ? cdesc.getTargetClass(dependencyProvider)
205                 : null;
206     }
207 
208     /**
209      * Returns the dependencies of this bean provider. These are the parameter
210      * dependencies of the <code>MethodInvocation</code> object. If a
211      * dependency for the target instance is provided, it will also be contained
212      * in the returned set.
213      *
214      * @return a set with the dependencies of this provider
215      */
216     @Override
217     public Set<Dependency> getDependencies()
218     {
219         Set<Dependency> result = new HashSet<Dependency>(getInvocation()
220                 .getParameterDependencies());
221         if (getTargetDependency() != null)
222         {
223             result.add(getTargetDependency());
224         }
225         return result;
226     }
227 
228     /**
229      * Returns a string representation for this object. This string will contain
230      * information about the method invoked by this bean provider. If a target
231      * dependency is provided, it will also be output.
232      *
233      * @return a string for this object
234      */
235     @Override
236     public String toString()
237     {
238         StringBuilder buf = new StringBuilder(getClass().getName());
239         buf.append('@').append(System.identityHashCode(this));
240         buf.append("[ method = ").append(getInvocation());
241         if (getTargetDependency() != null)
242         {
243             buf.append(" target = ").append(getTargetDependency());
244         }
245         return buf.toString();
246     }
247 }