Clover Coverage Report - perfectjpattern(Aggregated)
Coverage timestamp: Sat Feb 28 2009 14:35:07 CET
../../../../../img/srcFileCovDistChart10.png 0% of files have more coverage
38   257   19   5.43
14   125   0.5   3.5
7     2.71  
2    
 
  AbstractVisitor       Line # 43 28 0% 13 2 95.1% 0.9512195
  AbstractVisitor.VisitorDelegator       Line # 140 10 0% 6 2 88.9% 0.8888889
 
  (5)
 
1    //----------------------------------------------------------------------
2    //
3    // PerfectJPattern: "Design patterns are good but components are better!"
4    // AbstractVisitor.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.behavioral.visitor;
22   
23    import java.lang.reflect.*;
24    import java.util.*;
25   
26    import org.apache.commons.lang.*;
27    import org.perfectjpattern.core.api.behavioral.visitor.*;
28    import org.perfectjpattern.core.extras.delegate.*;
29   
30   
31    /**
32    * Reusable abstract base implementation of <code>IVisitor</code> interface.
33    * <br/>
34    *
35    * @see IVisitor
36    *
37    * @param <E> Element type that this <code>IVisitor</code> can visit.
38    *
39    * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
40    * @version $Revision: 1.0 $ $Date: Jul 1, 2007 7:02:55 AM $
41    */
42    public abstract
 
43    class AbstractVisitor<E>
44    implements IVisitor<E>
45    {
46    //------------------------------------------------------------------------
47    // public
48    //------------------------------------------------------------------------
49    /**
50    * {@inheritDoc}
51    */
 
52  28 toggle @SuppressWarnings("unchecked")
53    public final void
54    visit(E anElement)
55    {
56  28 Validate.notNull(anElement, "'anElement' must not be null");
57   
58  28 String myElementClassName = anElement.getClass().getName();
59   
60    // do we have it already?
61  28 if (!theLookup.containsKey(myElementClassName))
62    {
63    // lookup the right implementation
64  12 Class myElementType = anElement.getClass();
65  12 Class myVisitorType = this.getClass();
66   
67  12 Method myMethod = findVisitorMethod(myElementType,
68    myVisitorType, theDelegator);
69   
70    // any matching methods found?
71  12 if (myMethod != null)
72    {
73  12 theLookup.put(myElementClassName, theDelegator.build(
74    this, myMethod.getName()));
75    }
76    }
77   
78    // if a matching visit method was found then visit
79  28 if (theLookup.containsKey(myElementClassName))
80    {
81    // do the visiting
82  28 theLookup.get(myElementClassName).visit(anElement);
83    }
84    }
85   
86    //------------------------------------------------------------------------
87    /**
88    * Reusable implementation of the visit method that may be reused by
89    * implementors of <code>IVisitor</code> that for any reason can not
90    * subclass <code>AbstractVisitor</code>.
91    *
92    * @param <E> Type of Element to visit.
93    *
94    * @param aVisitor Concrete IVisitor instance.
95    * @param anElements Concrete IElement instances to visit.
96    * @throws IllegalArgumentException 'aVisitor' must not be null.
97    * @throws IllegalArgumentException 'anElements' must not be null.
98    * @throws IllegalArgumentException 'anElements' must not be empty.
99    */
 
100  23 toggle @SuppressWarnings("unchecked")
101    public static <E> void
102    reusableVisit(IVisitor<E> aVisitor, E... anElements)
103    throws IllegalArgumentException
104    {
105  23 Validate.notNull(aVisitor, "'aVisitor' must not be null");
106  23 Validate.notNull(anElements, "'anElements' must not be null");
107  23 Validate.notEmpty(anElements, "'anElements' must not be empty.");
108   
109  23 for (E myElement : anElements)
110    {
111    // lookup the right implementation
112  31 Class myElementType = myElement.getClass();
113  31 Class myVisitorType = aVisitor.getClass();
114   
115  31 VisitorDelegator myDelegator = new VisitorDelegator(IVisitor.class);
116   
117  31 Method myMethod = findVisitorMethod(myElementType, myVisitorType,
118    myDelegator);
119   
120    // any matching methods found?
121  31 if (myMethod != null)
122    {
123  23 IVisitor<E> myRealVisitor =
124    (IVisitor) myDelegator.build(aVisitor, myMethod.getName());
125   
126    // do the visiting
127  23 myRealVisitor.visit(myElement);
128    }
129    }
130    }
131   
132    //------------------------------------------------------------------------
133    // inner classes
134    //------------------------------------------------------------------------
135    /**
136    * Subclass implementation of Delegator redefining specific methods.
137    */
138    @SuppressWarnings("unchecked")
139    private static
 
140    class VisitorDelegator<E>
141    extends Delegator<IVisitor<E>>
142    {
143    //--------------------------------------------------------------------
144    /**
145    * Constructs a <code>VisitorDelegator</code> instance from a Visitor
146    * that visits Elements of Type E.
147    *
148    * @param aClass Class type of Visitor.
149    */
 
150  44 toggle public
151    VisitorDelegator(Class<IVisitor<E>> aClass)
152    {
153  44 super(aClass);
154    }
155   
156    //--------------------------------------------------------------------
157    /**
158    * {@inheritDoc}
159    */
 
160  35 toggle @Override
161    protected boolean
162    isSuitableMethod(Method aTestMethod, Class aReturnClass,
163    Class... anArguments)
164    {
165  35 Class[] myMethodArguments = aTestMethod.getParameterTypes();
166  70 for (int i = 0; i < myMethodArguments.length; i++)
167    {
168  35 Class myArgument = myMethodArguments[i];
169   
170  35 if (!anArguments[i].isAssignableFrom(myArgument))
171    {
172  0 return false;
173    }
174   
175    }
176   
177  35 isValidReturn(aTestMethod, aReturnClass);
178   
179  35 return true;
180    }
181   
182    //--------------------------------------------------------------------
183    /**
184    * {@inheritDoc}
185    */
 
186  294 toggle @Override
187    protected boolean
188    isValidReturn(Method aTestMethod, Class aReturnClass)
189    {
190  294 return (aReturnClass == null
191    || aTestMethod.getReturnType() == aReturnClass
192    || aTestMethod.getReturnType().equals(aReturnClass)
193    || aTestMethod.getReturnType().isAssignableFrom(aReturnClass));
194    }
195   
196    //--------------------------------------------------------------------
 
197  78 toggle @Override
198    public Class
199    getReturn()
200    {
201  78 return super.getReturn();
202    }
203    }
204   
205    //------------------------------------------------------------------------
206    // private
207    //------------------------------------------------------------------------
208    /**
209    * Returns Visitor method matching the specified Element argument type,
210    * null if the requested Method is not found.
211    *
212    * @param anElementType Class that corresponds to the concrete Element type.
213    * @param aVisitorType Class that corresponds to the concrete Visitor type.
214    * @param aDelegator Delegator implementation.
215    * @return Visitor method matching the specified Element argument type,
216    * null if the requested Method is not found.
217    */
 
218  43 toggle @SuppressWarnings("unchecked")
219    private static Method
220    findVisitorMethod(Class anElementType, Class aVisitorType,
221    VisitorDelegator aDelegator)
222    {
223  43 Class myReturnClass = aDelegator.getReturn();
224  43 Method myResult = null;
225  43 for (Method myMethod : aVisitorType.getMethods())
226    {
227  259 if (aDelegator.isValidReturn(myMethod, myReturnClass)
228    && Modifier.isPublic(myMethod.getModifiers())
229    && myMethod.getParameterTypes().length == 1
230    && myMethod.getParameterTypes()[0].equals(anElementType))
231    {
232  35 myResult = myMethod;
233  35 break;
234    }
235    }
236   
237  43 return myResult;
238    }
239   
240    //------------------------------------------------------------------------
241    // members
242    //------------------------------------------------------------------------
243    /**
244    * <code>Map</code> of <code>IVisitor</code> instances keyed by
245    * <code>IElement</code>-based Class names.
246    */
247    private final Map<String, IVisitor<E>> theLookup = new HashMap<String,
248    IVisitor<E>>();
249   
250    /**
251    * Special subtype of <code>Delegator<code> that delegates only to
252    * subtypes of the <code>IVisitor</code> interface.
253    */
254    @SuppressWarnings("unchecked")
255    private final VisitorDelegator<E> theDelegator = new VisitorDelegator(
256    IVisitor.class);
257    }