Implemented the ObjectAdapter for adapting existing objects to a component.
[utils] / system / general / src / main / java / org / wamblee / system / adapters / SetterConfiguration.java
1 /*
2  * Copyright 2008 the original author or authors.
3  * 
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
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */
16 package org.wamblee.system.adapters;
17
18 import java.awt.CompositeContext;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import org.wamblee.collections.CollectionFilter;
25 import org.wamblee.conditions.Condition;
26 import org.wamblee.conditions.FixedCondition;
27 import org.wamblee.general.Pair;
28 import org.wamblee.system.core.DefaultProvidedInterface;
29 import org.wamblee.system.core.DefaultRequiredInterface;
30 import org.wamblee.system.core.ProvidedInterface;
31 import org.wamblee.system.core.RequiredInterface;
32 import org.wamblee.system.core.Scope;
33 import org.wamblee.system.core.SystemAssemblyException;
34
35 /**
36  * Represents the configuration for exposing the setters of a class as required
37  * interfaces.
38  * 
39  * @author Erik Brakkee
40  */
41 public class SetterConfiguration {
42
43     private Class _class;
44
45     private List<Pair<Method, ParameterValues>> _setters;
46
47     /**
48      * Constructs the setter configuration. By default all setters are added.
49      * 
50      * @param aClass
51      *            Class which is being configured.
52      */
53     public SetterConfiguration(Class aClass) {
54         _class = aClass;
55         _setters = getAllSetters();
56     }
57
58     /**
59      * Removes all setters.
60      * 
61      * @return Reference to the current object to allow call chaining.
62      */
63     public SetterConfiguration clear() {
64         _setters.clear();
65         return this;
66     }
67
68     /**
69      * Removes a setter from the set of methods.
70      * 
71      * @param aName
72      *            Name of the setter to remove (without the "set" prefix).
73      * @return Reference to the current object to allow call chaining.
74      */
75     public SetterConfiguration remove(String aName) {
76         final String name = createSetterName(aName);
77         List<Pair<Method,ParameterValues>> setters = 
78             new ArrayList<Pair<Method,ParameterValues>>();
79         CollectionFilter.filter(_setters, setters, new Condition<Pair<Method,ParameterValues>>() {
80             @Override
81             public boolean matches(Pair<Method,ParameterValues> aObject) {
82                 return !aObject.getFirst().getName().equals(name);
83             }
84
85         });
86         if ( _setters.size() == setters.size()) { 
87             throw new IllegalArgumentException("No setter configured by the name of '" + aName + "'");
88         }
89         _setters = setters;
90         return this;
91     }
92
93     /**
94      * Creates the name of a setter based on the name of the setter without
95      * the "set" prefix. 
96      * @param aName Setter name. 
97      * @return Setter name. 
98      */
99     private String createSetterName(String aName) {
100         return "set" + aName.substring(0, 1).toUpperCase()
101                 + aName.substring(1);
102     }
103
104     /**
105      * Adds a given setter name to the setters. 
106      * @param aName
107      * @return Reference to the current object to allow call chaining. 
108      */
109     public SetterConfiguration add(String aName) {
110         final String name = createSetterName(aName);
111         int oldlen = _setters.size(); 
112         CollectionFilter.filter(getAllSetters(), _setters,
113                 new Condition<Pair<Method,ParameterValues>>() {
114                     @Override
115                     public boolean matches(Pair<Method,ParameterValues> aObject) {
116                         return aObject.getFirst().getName().equals(name);
117                     }
118
119                 });
120         if ( _setters.size() == oldlen) { 
121             throw new IllegalArgumentException("No setter found for '" + aName + "'");
122         }
123         return this;
124     }
125
126     /**
127      * Gets all setters for the current class. 
128      * @return List of all setters. 
129      */
130     private List<Pair<Method, ParameterValues>> getAllSetters() {
131         List<Pair<Method,ParameterValues>> result = 
132             new ArrayList<Pair<Method, ParameterValues>>();
133         for (Method method : _class.getMethods()) {
134             if (method.getName().startsWith("set")
135                     && method.getParameterTypes().length == 1) {
136                 String name = getSetterName(method);
137                 result.add(new Pair<Method,ParameterValues>(method,
138                         new ParameterValues(
139                                 new String[] { name }, new Class[] { method.getParameterTypes()[0] })));
140             }
141         }
142         return result;
143     }
144     
145     /**
146      * Gets the required interfaces based on the configured setteres.
147      * @return List of required interfaces. 
148      */
149     public List<RequiredInterface> getRequiredInterfaces() { 
150         List<RequiredInterface> result = new ArrayList<RequiredInterface>();
151         for (Pair<Method,ParameterValues> method: _setters) {
152             result.addAll(method.getSecond().getRequiredInterfaces());
153         }
154         return result; 
155     }
156     
157     
158     /**
159      * Invokes all configured setters with the appropriate values. 
160      * @param aScope Scope within which invocation takes place. 
161      * @param aObject Object on which the invocation takes place. 
162      */
163     public void inject(Scope aScope, Object aObject) {
164         if ( !_class.isInstance(aObject)) { 
165             throw new IllegalArgumentException("Object '" + aObject + "' is not an instance of " 
166                     + _class.getName());
167         }
168         for (Pair<Method,ParameterValues> setter: _setters) {
169             Method method = setter.getFirst();
170             ParameterValues values = setter.getSecond(); 
171             
172             try {
173                 method.invoke(aObject, values.values(aScope));
174             } catch (IllegalAccessException e) {
175                 throw new SystemAssemblyException("Problem invoking " + method + " with " + values, e);
176             } catch (InvocationTargetException e) { 
177                 throw new SystemAssemblyException("Problem invoking " + method + " with " + values, e);
178             }
179         }
180     }
181     
182     /**
183      * Returns the parameter values for allowing detailed configuration of how
184      * parameter values are set.
185      * @param aSetter Setter name without the "set" prefix with the first
186      *  character converted to lower case.  
187      * @return Parameter values. 
188      */
189     public ParameterValues values(String aMethod) { 
190         String name = createSetterName(aMethod); 
191         for (Pair<Method,ParameterValues> method: _setters) { 
192             if ( method.getFirst().getName().equals(name) ) { 
193                 return method.getSecond();
194             }
195         }
196         throw new IllegalArgumentException("No setter method '" + name + "' found");
197     }
198
199     /**
200      * Gets the setter name for a given setter method. This is the name of the
201      * setter without the "set" prefix and with the first character converted to
202      * lowercase.  
203      * @param aMethod Method. 
204      * @return Setter name. 
205      */
206     private String getSetterName(Method aMethod) {
207         String result = aMethod.getName().substring(3);
208         return result.substring(0,1).toLowerCase() +  result.substring(1);
209     }
210     
211 }