View Javadoc

1   //----------------------------------------------------------------------
2   // 
3   // PerfectJPattern: "Design patterns are good but components are better!" 
4   // NameMatchAdaptingStrategy.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.*;
24  import java.util.*;
25  
26  import org.apache.commons.lang.*;
27  import org.perfectjpattern.core.api.structural.adapter.*;
28  
29  /**
30   * Concrete implementation of {@link IAdaptingStrategy}. Implements the name
31   * matching strategy. The <code>Adaptee</code> and <code>Target</code> methods 
32   * are matched by name. The method correspondence is provided by the user as 
33   * a {@link Map} of <code>Target</code> method names keyed by <code>
34   * Adaptee</code> method names. The mapping does not have to be exhaustive, 
35   * those methods not explicitly mapped will be resolved against the Adaptee 
36   * and Adapter using exact match.
37   * 
38   * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
39   * @version $Revision: 1.0 $Date: Jan 28, 2009 3:42:25 PM $
40   */
41  public final 
42  class NameMatchAdaptingStrategy
43  extends ExactMatchAdaptingStrategy
44  implements IAdaptingStrategy
45  {
46      //------------------------------------------------------------------------
47      // public
48      //------------------------------------------------------------------------
49      /**
50       * Constructs a {@link NameMatchAdaptingStrategy} from a map that defines
51       * the correspondence between Target and Adaptee i.e. Adaptee method names
52       * keyed by Target method names.
53       * 
54       * @param aMethodsMapping Map of Target method names keyed by Target 
55       *        method names
56       * @throws IllegalArgumentException 'aMethodsMap' must not be null
57       */
58      public 
59      NameMatchAdaptingStrategy(Map<String, String> aMethodsMapping)
60      {
61          Validate.notNull(aMethodsMapping, "'aMethodsMap' must not be null");
62          
63          theMethodsMapping = aMethodsMapping;
64      }
65      
66      //------------------------------------------------------------------------
67      /** 
68       * {@inheritDoc}
69       */
70      @Override
71      public void 
72      validate(Class<?> aTargetClass, Object anAdaptee, Object anAdapter)
73      throws NoSuchMethodError
74      {
75          Validate.notNull(aTargetClass, "'aTargetClass' must not be null");
76          Validate.notNull(anAdaptee, "'anAdaptee' must not be null");
77          Validate.notNull(anAdapter, "'anAdapter' must not be null");
78          
79          Class<?> myAdapteeClass = anAdaptee.getClass();
80          
81          // check that all aMethodsMap keys exist in the Target interface and 
82          // that they match the corresponding definitions in the Adaptee 
83          // interface                
84          Set<String> myTargetMethods = new HashSet<String>();
85          for (Method myTargetMethod : aTargetClass.getMethods())
86          {
87              myTargetMethods.add(myTargetMethod.getName());
88          }
89          
90          for (Map.Entry<String, String> myEntry : theMethodsMapping.entrySet())
91          {
92              String myTargetMethodName = myEntry.getKey();
93              String myAdapteeMethodName = myEntry.getValue();
94              
95              boolean myFound = false;
96              for (Method myAdapteeMethod : myAdapteeClass.getMethods())
97              {
98                  if (myAdapteeMethodName.equals(myAdapteeMethod.getName()))
99                  {
100                     Class<?>[] myParameterTypes = myAdapteeMethod.
101                         getParameterTypes();
102                     
103                     try
104                     {
105                         aTargetClass.getMethod(myTargetMethodName, 
106                             myParameterTypes);
107                         
108                         myTargetMethods.remove(myTargetMethodName);
109                         
110                         myFound = true;
111                         
112                         break;
113                     }
114                     // CHECKSTYLE:OFF
115                     catch (Exception anException)
116                     // CHECKSTYLE:ON
117                     {
118                         // not found
119                     }
120                 }                    
121             }
122             
123             if (!myFound)
124             {
125                 throw new NoSuchMethodError("Method mismatch between Target " +
126                     "and Adaptee '" + myTargetMethodName + "'");
127             }
128         }        
129         
130         // check that if the mapping is not exhaustive then the adapter 
131         // implements the remaining methods 
132         if (myTargetMethods.size() > 0)
133         {
134             validate(aTargetClass, anAdaptee, myTargetMethods);
135             validate(aTargetClass, anAdapter, myTargetMethods);
136             
137             // if still there are remaining then throw exception
138             if (myTargetMethods.size() > 0)
139             {
140                 throw new NoSuchMethodError("Not all target methods " +
141                     "are implemented: '" + Arrays.toString(myTargetMethods.
142                         toArray()) + "'");
143             }
144         }
145     }
146     
147     //------------------------------------------------------------------------
148     /** 
149      * {@inheritDoc}
150      */
151     @Override
152     public Method 
153     resolve(Class<?> aTargetClass, Object anAdaptee, Object anAdapter, 
154         Method aTargetMethod)
155     throws IllegalArgumentException, NoSuchMethodError
156     {
157         Validate.notNull(aTargetClass, "'aTargetClass' must not be null");
158         Validate.notNull(anAdaptee, "'anAdaptee' must not be null");
159         Validate.notNull(anAdapter, "'anAdapter' must not be null");
160         Validate.notNull(aTargetMethod, "'aTargetMethod' must not be null");
161         
162         String myAdapteeMethodName = theMethodsMapping.get(aTargetMethod.
163             getName());
164         
165         Method myResultMethod = null; 
166         if (myAdapteeMethodName != null)
167         {
168             myResultMethod = super.resolve(anAdaptee, aTargetMethod, 
169                 myAdapteeMethodName);
170         }
171         else
172         {
173             myResultMethod = super.resolve(aTargetClass, anAdaptee, anAdapter, 
174                 aTargetMethod);
175         }
176         
177         return myResultMethod;
178     }
179     
180     //------------------------------------------------------------------------
181     // members
182     //------------------------------------------------------------------------
183     private final Map<String, String> theMethodsMapping;
184 }