2 * Copyright 2008 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.system.adapters;
18 import org.wamblee.collections.CollectionFilter;
20 import org.wamblee.conditions.Condition;
21 import org.wamblee.conditions.FixedCondition;
23 import org.wamblee.general.Pair;
25 import org.wamblee.reflection.ReflectionUtils;
27 import org.wamblee.system.core.DefaultProvidedInterface;
28 import org.wamblee.system.core.DefaultRequiredInterface;
29 import org.wamblee.system.core.ProvidedInterface;
30 import org.wamblee.system.core.RequiredInterface;
31 import org.wamblee.system.core.Scope;
32 import org.wamblee.system.core.SystemAssemblyException;
34 import java.awt.CompositeContext;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.HashMap;
43 import java.util.List;
49 * Represents the configuration for exposing the setters of a class as
50 * required interfaces.
52 * @author Erik Brakkee
54 public class SetterConfiguration {
63 private boolean publicOnly;
68 private Map<Method, ParameterValues> setters;
71 * Constructs the setter configuration. By default no setters are added.
74 * Class which is being configured.
76 public SetterConfiguration(Class aClass) {
79 setters = new HashMap<Method, ParameterValues>();
83 * Makes sure that all available setters are used.
85 * @return DOCUMENT ME!
87 public SetterConfiguration initAllSetters() {
90 for (Method method : getAllSetters(_class, publicOnly)) {
91 setters.put(method, createParameterValues(method));
98 * Called to set whether non-public setters are also used. By
99 * default only public setters are used. The currently selected setters
102 * @param aIsNonPublic Non public flag.
104 * @return DOCUMENT ME!
106 public SetterConfiguration setNonPublic(boolean aIsNonPublic) {
107 publicOnly = !aIsNonPublic;
113 * Removes all setters.
115 * @return Reference to the current object to allow call chaining.
117 public SetterConfiguration clear() {
124 * Removes a setter from the set of methods.
126 * @param aName Name of the setter to remove.
128 * @return Reference to the current object to allow call chaining.
130 * @throws IllegalArgumentException DOCUMENT ME!
132 public SetterConfiguration remove(String aName) {
133 for (Method method : setters.keySet()) {
134 if (method.getName().equals(aName)) {
135 setters.remove(method);
141 throw new IllegalArgumentException(
142 "No method configured by the name of '" + aName + "'");
146 * Removes the method from the set of methods.
148 * @param aMethod Method to remove.
152 * @throws RuntimeException DOCUMENT ME!
153 * @throws IllegalArgumentException DOCUMENT ME!
155 public SetterConfiguration remove(Method aMethod) {
156 if (!aMethod.getDeclaringClass().isAssignableFrom(_class)) {
157 throw new RuntimeException("Method " + aMethod
158 + " not found in class " + _class + " or its superclasses");
161 for (Method method : setters.keySet()) {
162 if (method.equals(aMethod)) {
163 setters.remove(method);
169 throw new IllegalArgumentException("Method '" + aMethod
170 + "' was not configured. ");
174 * Adds a given setter name to the setters.
176 * @param aName Name of a setter method.
178 * @return Reference to the current object to allow call chaining.
180 * @throws IllegalArgumentException DOCUMENT ME!
182 public SetterConfiguration add(final String aName) {
183 int oldlen = setters.size();
184 List<Method> methods = new ArrayList<Method>();
185 CollectionFilter.filter(getAllSetters(_class, publicOnly), methods,
186 new Condition<Method>() {
188 public boolean matches(Method aObject) {
189 return aObject.getName().equals(aName);
193 if (methods.size() == 0) {
194 throw new IllegalArgumentException("Method '" + aName
195 + "' not found in " + _class.getName());
198 // TODO is it possible to get more than one setter here in case the subclass overrides
199 // the baseclass method?
200 setters.put(methods.get(0), createParameterValues(methods.get(0)));
206 * Adds a given setter identified by the type it accepts to the
209 * @param aType Type to look for. Note that this must be the exact type as
210 * autoboxing and autounboxing is not used.
212 * @return Reference to the current object to allow call chaining.
214 * @throws IllegalArgumentException In case no setter is found or multiple
217 public SetterConfiguration addSetter(final Class aType) {
218 List<Method> result = new ArrayList<Method>();
219 CollectionFilter.filter(getAllSetters(_class, publicOnly), result,
220 new Condition<Method>() {
222 public boolean matches(Method aObject) {
223 Class type = aObject.getParameterTypes()[0];
225 return type.equals(aType);
229 if (result.size() == 0) {
230 throw new IllegalArgumentException("No setter found in class '"
231 + _class.getName() + "' that has a setter with argument type '"
232 + aType.getName() + "'");
235 if (result.size() > 1) {
238 for (Method method : result) {
239 setters += (method.getName() + " ");
242 throw new IllegalArgumentException(
243 "Multiple setters found in class '" + _class.getName()
244 + " that accept type '" + aType.getName() + "': " + setters);
247 Method method = result.get(0);
248 setters.put(method, createParameterValues(method));
254 * Gets all setters for the current class.
256 * @param aClass DOCUMENT ME!
257 * @param aPublicOnly DOCUMENT ME!
259 * @return List of all setters.
261 public static List<Method> getAllSetters(Class aClass, boolean aPublicOnly) {
262 List<Method> result = new ArrayList<Method>();
264 for (Method method : getAllMethods(aClass)) {
265 if (!aPublicOnly || Modifier.isPublic(method.getModifiers())) {
266 if (method.getName().startsWith("set")
267 && (method.getParameterTypes().length == 1)) {
268 method.setAccessible(true);
280 * @param aMethod DOCUMENT ME!
282 * @return DOCUMENT ME!
284 private static ParameterValues createParameterValues(Method aMethod) {
285 Class[] paramTypes = aMethod.getParameterTypes();
286 String[] paramNames = new String[paramTypes.length];
288 for (int i = 0; i < paramTypes.length; i++) {
289 paramNames[i] = aMethod.getName() + "." + i;
292 return new ParameterValues(paramNames, paramTypes);
298 * @param aClass DOCUMENT ME!
300 * @return DOCUMENT ME!
302 private static final List<Method> getAllMethods(Class aClass) {
303 return ReflectionUtils.getAllMethods(aClass);
307 * Gets the required interfaces based on the configured setteres.
309 * @return List of required interfaces.
311 public List<RequiredInterface> getRequiredInterfaces() {
312 List<RequiredInterface> result = new ArrayList<RequiredInterface>();
314 for (Method method : setters.keySet()) {
315 result.addAll(setters.get(method).getRequiredInterfaces());
322 * Invokes all configured setters with the appropriate values.
324 * @param aScope Scope within which invocation takes place.
325 * @param aObject Object on which the invocation takes place.
327 * @throws IllegalArgumentException DOCUMENT ME!
328 * @throws SystemAssemblyException DOCUMENT ME!
330 public void inject(Scope aScope, Object aObject) {
331 if (!_class.isInstance(aObject)) {
332 throw new IllegalArgumentException("Object '" + aObject
333 + "' is not an instance of " + _class.getName());
336 for (Method method : setters.keySet()) {
337 ParameterValues values = setters.get(method);
340 method.invoke(aObject, values.values(aScope));
341 } catch (IllegalAccessException e) {
342 throw new SystemAssemblyException("Problem invoking " + method
343 + " with " + values, e);
344 } catch (InvocationTargetException e) {
345 throw new SystemAssemblyException("Problem invoking " + method
346 + " with " + values, e);
352 * Returns the parameter values for allowing detailed configuration
353 * of how parameter values are set.
355 * @param aMethod Setter name without the "set" prefix with the first
356 * character converted to lower case.
358 * @return Parameter values.
360 * @throws IllegalArgumentException DOCUMENT ME!
362 public ParameterValues values(String aMethod) {
363 for (Method method : setters.keySet()) {
364 if (method.getName().equals(aMethod)) {
365 return setters.get(method);
369 throw new IllegalArgumentException("No setter method '" + aMethod
376 * @return DOCUMENT ME!
378 public List<Method> getSetters() {
379 return new ArrayList<Method>(setters.keySet());