View Javadoc

1   //----------------------------------------------------------------------
2   // 
3   // PerfectJPattern: "Design patterns are good but components are better!" 
4   // ExactMatchAdaptingStrategy.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.structural.adapter;
22  
23  import java.lang.reflect.Method;
24  import java.util.*;
25  
26  import org.apache.commons.lang.Validate;
27  import org.perfectjpattern.core.api.structural.adapter.IAdaptingStrategy;
28  
29  /**
30   * Concrete implementation of {@link IAdaptingStrategy}. Implements the exact 
31   * matching strategy. The Adaptee and Target methods (name and parameters) must 
32   * match or at least the Adaptee methods must be a subset of Target methods.
33   * 
34   * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
35   * @version $Revision: 1.0 $Date: Jan 28, 2009 2:20:39 PM $
36   */
37  public  
38  class ExactMatchAdaptingStrategy
39  implements IAdaptingStrategy
40  {
41      //------------------------------------------------------------------------
42      // public
43      //------------------------------------------------------------------------
44      /** 
45       * {@inheritDoc}
46       */
47      public void 
48      validate(Class<?> aTargetClass, Object anAdaptee, Object anAdapter)
49      throws NoSuchMethodError
50      {
51          Validate.notNull(aTargetClass, "'aTargetClass' must not be null");
52          Validate.notNull(anAdaptee, "'anAdaptee' must not be null");
53          Validate.notNull(anAdapter, "'anAdapter' must not be null");
54          
55          Class<?> myAdapteeClass = anAdaptee.getClass();
56          
57          Set<String> myTargetMethods = new HashSet<String>();
58          
59          // match all Adaptee publicly defined methods
60          for (Method myTargetMethod : aTargetClass.getMethods())
61          {
62              String myTargetMethodName = myTargetMethod.getName();
63              
64              try 
65              {
66                  // ensure the existance of Method in anAdaptee
67                  Method myAdapteeMethod = myAdapteeClass.getMethod(
68                      myTargetMethodName, myTargetMethod.getParameterTypes());
69                  
70                  assert myAdapteeMethod != null : 
71                      "'myAdapteeMethod' must not be null";                
72              }
73              catch (NoSuchMethodException anException)
74              {
75                  // not found, we can still look in the Adapter
76                  myTargetMethods.add(myTargetMethodName);                
77              }
78          }
79          
80          if (myTargetMethods.size() > 0)
81          {
82              validate(aTargetClass, anAdapter, myTargetMethods);
83              
84              // if still there are remaining then throw exception
85              if (myTargetMethods.size() > 0)
86              {
87                  throw new NoSuchMethodError("Not all target methods " +
88                      "are implemented: '" + Arrays.toString(myTargetMethods.
89                          toArray()) + "'");
90              }
91          }                
92      }
93  
94      //------------------------------------------------------------------------
95      /** 
96       * {@inheritDoc}
97       */
98      public Method 
99      resolve(Class<?> aTargetClass, Object anAdaptee, Object anAdapter, 
100         Method aTargetMethod)
101     throws IllegalArgumentException, NoSuchMethodError
102     {
103         Validate.notNull(aTargetClass, "'aTargetClass' must not be null");
104         Validate.notNull(anAdaptee, "'anAdaptee' must not be null");
105         Validate.notNull(anAdapter, "'anAdapter' must not be null");
106         Validate.notNull(aTargetMethod, "'aTargetMethod' must not be null");
107 
108         Method myMethod = null;
109         try
110         {
111             // first try with the Adapter
112             myMethod = resolve(anAdapter, aTargetMethod);            
113         }
114         catch (NoSuchMethodError anException)
115         {
116             // retry by looking into the Adaptee
117             myMethod = resolve(anAdaptee, aTargetMethod);
118         }
119         
120         return myMethod;
121     }
122     
123     //------------------------------------------------------------------------
124     // protected
125     //------------------------------------------------------------------------
126     /**
127      * Removes from aTargetMethods all methods found in anInterface that are
128      * actually implemented by anImplementor
129      * 
130      * @param anInterface The target interface
131      * @param anImplementor The underlying implementor
132      * @param aTargetMethods The methods to search for
133      */
134     protected void 
135     validate(Class<?> anInterface, Object anImplementor, 
136         Set<String> aTargetMethods)
137     { 
138         assert anInterface != null : "'anInterface' must not be null";
139         assert anImplementor != null : "'anImplementor' must not be null";
140         assert aTargetMethods != null : "'aTargetMethods' must not be null";
141         
142         for (Method myAdapterMethod : anImplementor.getClass().getMethods())
143         {
144             String myAdapterMethodName = myAdapterMethod.getName();
145             if (aTargetMethods.contains(myAdapterMethodName))
146             {
147                 Class<?>[] myParameterTypes = myAdapterMethod.
148                     getParameterTypes();
149                 
150                 try
151                 {
152                     anInterface.getMethod(myAdapterMethodName, 
153                         myParameterTypes);
154                     
155                     aTargetMethods.remove(myAdapterMethodName);
156                 }
157                 // CHECKSTYLE:OFF
158                 catch (Exception anException)
159                 // CHECKSTYLE:ON
160                 {
161                     // not found
162                 }
163             }                    
164         }
165     }
166     
167     //------------------------------------------------------------------------
168     /**
169      * Returns the found matching {@link Method} if exists, null or 
170      * {@link NoSuchMethodError} otherwise
171      * 
172      * @param anObject
173      * @param aMethodPrototype
174      * @param aMethodName
175      * @return found matching {@link Method} if exists, null or 
176      *         {@link NoSuchMethodError} otherwise
177      * @throws NoSuchMethodError
178      */
179     protected Method
180     resolve(Object anObject, Method aMethodPrototype, String aMethodName)
181     throws NoSuchMethodError
182     {   
183         assert anObject != null : "'anObject' must not be null";
184         assert aMethodPrototype != null : "'aMethod' must not be null";
185         
186         Method myMethod = null;
187         
188         try        
189         {
190             Class<?> myClass = anObject.getClass();
191 
192             // probe whether the Method exists in the Object
193             myMethod = myClass.getMethod(aMethodName, aMethodPrototype.
194                 getParameterTypes());
195             
196             assert myMethod != null : "'myMethod' must not be null";
197             
198             return myMethod;
199         }
200         catch (NoSuchMethodException anException)
201         {
202             throw new NoSuchMethodError("Method mismatch between Target " +
203                 "and Adaptee/Adapter '" + aMethodPrototype.getName() + "'");
204         }
205     }
206 
207     //------------------------------------------------------------------------
208     /**
209      * Returns the found matching {@link Method} if exists, null or 
210      * {@link NoSuchMethodError} otherwise
211      * 
212      * @param anObject
213      * @param aMethodPrototype
214      * @return found matching {@link Method} if exists, null or 
215      *         {@link NoSuchMethodError} otherwise
216      * @throws NoSuchMethodError
217      */
218     protected Method
219     resolve(Object anObject, Method aMethodPrototype)
220     throws NoSuchMethodError
221     {
222         String myMethodName = aMethodPrototype.getName();
223         
224         return resolve(anObject, aMethodPrototype, myMethodName);
225     }
226 }