Clover Coverage Report - perfectjpattern(Aggregated)
Coverage timestamp: Sat Feb 28 2009 14:35:07 CET
../../../../../img/srcFileCovDistChart10.png 0% of files have more coverage
59   435   31   3.93
20   212   0.53   7.5
15     2.07  
2    
3.1% of code in this file is excluded from these metrics.
 
  AbstractDelegator       Line # 49 44 1.4% 21 5 92.8% 0.92753625
  AbstractDelegator.DelegateProxy       Line # 299 15 7.4% 10 0 100% 1.0
 
  (13)
 
1    //----------------------------------------------------------------------
2    //
3    // PerfectJPattern: "Design patterns are good but components are better!"
4    // AbstractDelegator.java Copyright (c) 2009 Giovanni Azua Garcia
5    // bravegag@hotmail.com
6    //
7    // This program is free software; you can redistribute it and/or
8    // modify it under the terms of the GNU General Public License
9    // as published by the Free Software Foundation; either version 3
10    // of the License, or (at your option) any later version.
11    //
12    // This program is distributed in the hope that it will be useful,
13    // but WITHOUT ANY WARRANTY; without even the implied warranty of
14    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15    // GNU General Public License for more details.
16    //
17    // You should have received a copy of the GNU General Public License
18    // along with this program; if not, see <http://www.gnu.org/licenses/>.
19    //
20    //----------------------------------------------------------------------
21    package org.perfectjpattern.core.extras.delegate;
22   
23    import java.lang.reflect.*;
24    import java.util.*;
25   
26    import org.apache.commons.lang.*;
27    import org.perfectjpattern.core.api.extras.delegate.*;
28   
29   
30    /**
31    * Abstract base implementation of <code>IDelegator</code> interface.
32    * <br/><br/>
33    * <b>Notes</b>: Base source code implemented by Steve Lewis and Wilhelm
34    * Fitzpatrick and adapted to fit PerfectJPattern componentization
35    * criteria and code conventions.
36    *
37    * @see IDelegator
38    *
39    * @param <I> Interface type built by this <code>Delegator</code> instance.
40    *
41    * @author <a href="mailto:smlewis@lordjoe.com">Steve Lewis</a>
42    * @author <a href="mailto:wilhelmf@agileinformatics.com">Wilhelm
43    * Fitzpatrick</a>
44    * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
45    * @version $Revision: 1.0 $ $Date: Jun 25, 2007 7:01:04 AM $
46    */
47    @SuppressWarnings("unchecked")
48    public abstract
 
49    class AbstractDelegator<I>
50    implements IDelegator<I>
51    {
52    //------------------------------------------------------------------------
53    // protected
54    //------------------------------------------------------------------------
55    /**
56    * Constructs <code>Delegator</code> instance using a method
57    * signature. <br/><br/>
58    *
59    * @param aReturnClass Return class type.
60    * @param aParameters Parameter class types.
61    */
 
62  5 toggle protected
63    AbstractDelegator(Class aReturnClass, Class... aParameters)
64    {
65  5 theReturn = aReturnClass;
66  5 theArguments = aParameters;
67    }
68   
69    //------------------------------------------------------------------------
70    /**
71    * Constructs <code>Delegator</code> instance using an interface type
72    * that implements exactly one method.
73    *
74    * @param anInterface Interface with EXACTLY one method.
75    * @throws IllegalArgumentException DelegateTemplate must be constructed
76    * with an interface implementing exactly one method!
77    */
 
78  49 toggle protected
79    AbstractDelegator(Class<I> anInterface)
80    {
81  49 Method myMethod = findMethod(anInterface);
82   
83  47 theReturn = myMethod.getReturnType();
84  47 theArguments = myMethod.getParameterTypes();
85    }
86   
87    //------------------------------------------------------------------------
88    /**
89    * Returns true if the Method matches the given signature specified by
90    * Arguments and Return, false otherwise.
91    *
92    * @param aTestMethod
93    * @param anArguments
94    * @param aReturnClass
95    * @return true if the Method matches the given signature specified by
96    * Arguments and Return, false otherwise.
97    */
 
98  1 toggle @SuppressWarnings("unchecked")
99    protected boolean
100    isSuitableMethod(Method aTestMethod, Class aReturnClass,
101    Class... anArguments)
102    {
103  1 Class[] myMethodArgs = aTestMethod.getParameterTypes();
104   
105  2 for (int i = 0; i < myMethodArgs.length; i++)
106    {
107  1 Class myArgument = myMethodArgs[i];
108   
109  1 if (!myArgument.isAssignableFrom(anArguments[i]))
110    {
111  0 return false;
112    }
113    }
114   
115  1 return isValidReturn(aTestMethod, aReturnClass);
116    }
117   
118    //------------------------------------------------------------------------
119    /**
120    * Returns true if return type matches the expected type, false otherwise.
121    *
122    * @param aTestMethod
123    * @param aReturnClass
124    * @return true if return type matches the expected type, false otherwise.
125    */
 
126  14 toggle @SuppressWarnings("unchecked")
127    protected boolean
128    isValidReturn(Method aTestMethod, Class aReturnClass)
129    {
130  14 return (aReturnClass == null
131    || aTestMethod.getReturnType() == aReturnClass
132    || aTestMethod.getReturnType().equals(aReturnClass)
133    || aReturnClass.isAssignableFrom(aTestMethod.getReturnType()));
134    }
135   
136    //------------------------------------------------------------------------
137    /**
138    * Returns all candidate methods within a class that match the given
139    * signature.
140    *
141    * @param aTargetClass
142    * @param aMethodName
143    * @param aNumberOfArguments
144    * @return all candidate methods within a class that match the given
145    * signature.
146    */
 
147  37 toggle @SuppressWarnings("unchecked")
148    protected static Method[]
149    findMethod(Class aTargetClass, String aMethodName,
150    int aNumberOfArguments)
151    {
152  37 Method[] myPossibilities = aTargetClass.getMethods();
153  37 List myHolder = new ArrayList();
154   
155  579 for (int i = 0; i < myPossibilities.length; i++)
156    {
157  542 Method myPossibility = myPossibilities[i];
158   
159  542 if (myPossibility.getName().equals(aMethodName) &&
160    myPossibility.getParameterTypes().length ==
161    aNumberOfArguments && Modifier.isPublic(myPossibility.
162    getModifiers()))
163    {
164  37 myHolder.add(myPossibility);
165    }
166    }
167   
168  37 return (Method[]) myHolder.toArray(EMPTY_METHOD_ARRAY);
169    }
170   
171    //------------------------------------------------------------------------
172    /**
173    * Returns suitable Method within class type that matches the given
174    * Delegator signature.
175    *
176    * @param aTargetClass Class type to search for matching method.
177    * @param aMethodName Method name to search for.
178    * @param aDelegator Delegate specification.
179    * @return suitable Method within class type that matches the given
180    * Delegate specification.
181    * @throws IllegalArgumentException Requested method returns wrong type.
182    * @throws IllegalArgumentException Requested method is not public.
183    * @throws UnsupportedOperationException No suitable method found.
184    */
 
185  48 toggle @SuppressWarnings("unchecked")
186    protected Method
187    findMethod(Class aTargetClass, String aMethodName,
188    AbstractDelegator aDelegator)
189    throws IllegalArgumentException, UnsupportedOperationException
190    {
191  48 Class[] myArguments = aDelegator.getArguments();
192  48 Class myReturnClass = aDelegator.getReturn();
193   
194  48 try
195    {
196  48 Method myReturn = aTargetClass.getMethod(aMethodName, myArguments);
197   
198  13 Validate.isTrue(isValidReturn(myReturn, myReturnClass),
199    "Requested method returns wrong type.");
200   
201  13 Validate.isTrue(Modifier.isPublic(myReturn.getModifiers()),
202    "Requested method is not public.");
203   
204  13 return myReturn;
205    }
206    catch (SecurityException anException)
207    {
208    // try next possibility
209    }
210    catch (NoSuchMethodException anException)
211    {
212    // try next possibility
213    }
214   
215  35 Method[] myPossibilities = findMethod(aTargetClass, aMethodName,
216    myArguments.length);
217   
218  35 for (int i = 0; i < myPossibilities.length; i++)
219    {
220  35 Method myPossibility = myPossibilities[i];
221   
222  35 if (isSuitableMethod(myPossibility, myReturnClass, myArguments))
223    {
224  35 return myPossibility;
225    }
226    }
227   
228    throw new UnsupportedOperationException("No suitable method found.");
229    }
230   
231    //------------------------------------------------------------------------
232    /**
233    * Returns suitable <code>Method</code> found for the given interface type.
234    *
235    * @param anInterface
236    * @return The suitable <code>Method</code>
237    * @throws IllegalArgumentException 'anInterface' must not be null.
238    * @throws IllegalArgumentException DelegateTemplate must be constructed
239    * with an interface implementing exactly one method!
240    */
 
241  49 toggle protected static Method
242    findMethod(Class anInterface)
243    {
244  49 Validate.notNull(anInterface, "'anInterface' must not be null");
245  49 Validate.isTrue(anInterface.isInterface(),
246    "DelegateTemplate must be constructed with an interface");
247   
248  49 Method[] myMethods = anInterface.getMethods();
249  49 Method myReturn = null;
250   
251  97 for (int i = 0; i < myMethods.length; i++)
252    {
253  49 Method myTest = myMethods[i];
254   
255  49 if (Modifier.isAbstract(myTest.getModifiers()))
256    {
257  49 Validate.isTrue(myReturn == null, "DelegateTemplate must be " +
258    "constructed with an interface implementing exactly one " +
259    "method!");
260   
261  48 myReturn = myTest;
262    }
263    }
264   
265  48 Validate.notNull(myReturn, "DelegateTemplate must be constructed " +
266    "with an interface implementing exactly one method!");
267   
268  47 return myReturn;
269    }
270   
271    //------------------------------------------------------------------------
272    /**
273    * Returns the Return class type.
274    *
275    * @return the Return class type.
276    */
 
277  91 toggle protected Class
278    getReturn()
279    {
280  91 return theReturn;
281    }
282   
283    //------------------------------------------------------------------------
284    /**
285    * Returns the Arguments class types.
286    *
287    * @return Arguments class types.
288    */
 
289  30413 toggle protected Class[]
290    getArguments()
291    {
292  30413 return theArguments;
293    }
294   
295    //------------------------------------------------------------------------
296    // inner classes
297    //------------------------------------------------------------------------
298    protected
 
299    class DelegateProxy
300    implements IDelegate, InvocationHandler
301    {
302    //--------------------------------------------------------------------
303    /**
304    * Constructs a DelegateProxy supplying a Class passing in types not
305    * template.
306    *
307    * @param aTarget
308    * @param aTargetClass
309    * @param aMethodName
310    * @param aTemplate
311    * @throws UnsupportedOperationException
312    */
 
313  48 toggle public
314    DelegateProxy(Object aTarget, Class aTargetClass, String aMethodName,
315    AbstractDelegator aTemplate)
316    throws UnsupportedOperationException
317    {
318  48 theTarget = aTarget;
319   
320  48 Method myMethod =
321    findMethod(aTargetClass, aMethodName, aTemplate);
322  48 theMethod = myMethod;
323    }
324   
325    //--------------------------------------------------------------------
326    /**
327    * {@inheritDoc}
328    */
 
329  30357 toggle public Object
330    invoke(Object aProxy, Method aMethod, Object[] anArguments)
331    {
332  30357 return invoke(anArguments);
333    }
334   
335    //--------------------------------------------------------------------
336    /**
337    * {@inheritDoc}
338    */
 
339  30365 toggle public Object
340    invoke(Object... anArguments)
341    throws IllegalArgumentException, UnsupportedOperationException
342    {
343  30365 validateArgs(anArguments, getArguments());
344   
345  30365 try
346    {
347  30365 Object myReturn = getMethod().invoke(getTarget(), anArguments);
348   
349  30365 return myReturn;
350    }
351    catch (IllegalAccessException anException)
352    {
353    throw new UnsupportedOperationException(
354    anException.getMessage());
355    }
356    catch (InvocationTargetException anException)
357    {
358    throw new UnsupportedOperationException(anException.getCause());
359    }
360    }
361   
362    //--------------------------------------------------------------------
363    /**
364    * Validate actual arguments to match those expected from the Delegate
365    * type.
366    *
367    * @param anArguments Arguments to validate
368    * @param anExpectedArguments Expected arguments signature
369    * @throws IllegalArgumentException 'anExpectedArguments' must not be
370    * null
371    * @throws IllegalArgumentException Delegator required 'N' arguments
372    * @throws IllegalArgumentException Argument 'i' must be of type 'X'
373    */
 
374  30365 toggle protected void
375    validateArgs(Object[] anArguments, Class[] anExpectedArguments)
376    throws IllegalArgumentException
377    {
378  30365 Validate.notNull(anExpectedArguments,
379    "'anExpectedArguments' must not be null");
380   
381  30365 Validate.isTrue((anArguments == null && anExpectedArguments.length
382    == 0) || (anArguments != null && anArguments.length ==
383    anExpectedArguments.length), "Delegator required '" +
384    anExpectedArguments.length + "' arguments");
385   
386  30365 if (anArguments != null)
387    {
388  60724 for (int i = 0; i < anArguments.length; i++)
389    {
390  30362 Validate.isTrue(anExpectedArguments[i].isInstance(
391    anArguments[i]), "Argument '" + i + "' must be of " +
392    "type '" + anExpectedArguments[i].getName() + "'");
393    }
394    }
395    }
396   
397    //--------------------------------------------------------------------
398    /**
399    * Returns the method.
400    *
401    * @return Method.
402    */
 
403  30365 toggle protected Method
404    getMethod()
405    {
406  30365 return theMethod;
407    }
408   
409    //--------------------------------------------------------------------
410    /**
411    * Returns the target Object.
412    *
413    * @return Target Object.
414    */
 
415  30365 toggle protected Object
416    getTarget()
417    {
418  30365 return theTarget;
419    }
420   
421    //--------------------------------------------------------------------
422    // members
423    //--------------------------------------------------------------------
424    private final Method theMethod;
425    private final Object theTarget;
426    }
427   
428    //------------------------------------------------------------------------
429    // members
430    //------------------------------------------------------------------------
431    private static final Method[] EMPTY_METHOD_ARRAY = {};
432   
433    private final Class theReturn;
434    private final Class[] theArguments;
435    }