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 }