1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.betwixt.expression;
17
18 import java.lang.reflect.Method;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23 /*** <p><code>MapEntryAdder</code> is used to add entries to a map.</p>
24 *
25 * <p>
26 * <code>MapEntryAdder</code> supplies two updaters:
27 * <ul>
28 * <li>{@link #getKeyUpdater()} which allows the entry key to be updated</li>
29 * <li>{@link #getValueUpdater()} which allows the entry value to be updated</li>
30 * </ul>
31 * When both of these updaters have been called, the entry adder method is called.
32 * Once this has happened then the values can be updated again.
33 * Note that only the <code>Context</code> passed by the last update will be used.
34 * </p>
35 *
36 * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
37 * @since 0.5
38 */
39 public class MapEntryAdder {
40
41
42
43
44
45 /*** Log used by this class */
46 private static Log log = LogFactory.getLog( MapEntryAdder.class );
47
48
49
50
51
52 /***
53 * Sets the logger used by this class.
54 *
55 * @param newLog log to this
56 */
57 public static void setLog(Log newLog) {
58 log = newLog;
59 }
60
61
62
63
64 /*** The method to be called to add a new map entry */
65 private Method adderMethod;
66
67 /*** Has the entry key been updated? */
68 private boolean keyUpdated = false;
69 /*** The entry key */
70 private Object key;
71
72 /*** Has the entry value been updated? */
73 private boolean valueUpdated = false;
74 /*** The entry value */
75 private Object value;
76
77
78
79
80
81 /***
82 * Construct a <code>MapEntryAdder</code> which adds entries to given method.
83 *
84 * @param method the <code>Method</code> called to add a key-value entry
85 * @throws IllegalArgumentException if the given method does not take two parameters
86 */
87 public MapEntryAdder(Method method) {
88
89 Class[] types = method.getParameterTypes();
90 if ( types == null || types.length != 2) {
91 throw new IllegalArgumentException(
92 "Method used to add entries to maps must have two parameter.");
93 }
94 this.adderMethod = method;
95 }
96
97
98
99
100 /***
101 * Gets the entry key <code>Updater</code>.
102 * This is used to update the entry key value to the read value.
103 * If {@link #getValueUpdater} has been called previously,
104 * then this trigger the updating of the adder method.
105 *
106 * @return the <code>Updater</code> which should be used to populate the entry key
107 */
108 public Updater getKeyUpdater() {
109
110 return new Updater() {
111 public void update( Context context, Object keyValue ) {
112
113 if ( !keyUpdated ) {
114 keyUpdated = true;
115 key = keyValue;
116 if ( log.isTraceEnabled() ) {
117 log.trace( "Setting entry key to " + key );
118 log.trace( "Current entry value is " + value );
119 }
120 if ( valueUpdated ) {
121 callAdderMethod( context );
122 }
123 }
124 }
125 };
126 }
127
128 /***
129 * Gets the entry value <code>Updater</code>.
130 * This is used to update the entry key value to the read value.
131 * If {@link #getKeyUpdater} has been called previously,
132 * then this trigger the updating of the adder method.
133 *
134 * @return the <code>Updater</code> which should be used to populate the entry value
135 */
136 public Updater getValueUpdater() {
137
138 return new Updater() {
139 public void update( Context context, Object valueValue ) {
140
141 if ( !valueUpdated ) {
142 valueUpdated = true;
143 value = valueValue;
144 if ( log.isTraceEnabled() ) {
145 log.trace( "Setting entry value to " + value);
146 log.trace( "Current entry key is " + key );
147 }
148 if ( keyUpdated ) {
149 callAdderMethod( context );
150 }
151 }
152 }
153 };
154 }
155
156
157
158
159
160
161 /***
162 * Call the adder method on the bean associated with the <code>Context</code>
163 * with the key, value entry values stored previously.
164 *
165 * @param context the Context against whose bean the adder method will be invoked
166 */
167 private void callAdderMethod(Context context) {
168 log.trace("Calling adder method");
169
170
171 keyUpdated = false;
172 valueUpdated = false;
173
174
175
176
177
178
179
180
181
182 Class[] types = adderMethod.getParameterTypes();
183
184 Class keyType = types[0];
185
186 Class valueType = types[1];
187
188 Object bean = context.getBean();
189 if ( bean != null ) {
190 if ( key instanceof String ) {
191
192 key = context.getObjectStringConverter()
193 .stringToObject( (String) key, valueType, null, context );
194 }
195
196 if ( value instanceof String ) {
197
198 value = context.getObjectStringConverter()
199 .stringToObject( (String) value, keyType, null, context );
200 }
201
202 Object[] arguments = { key, value };
203 try {
204 if ( log.isTraceEnabled() ) {
205 log.trace(
206 "Calling adder method: " + adderMethod.getName() + " on bean: " + bean
207 + " with key: " + key + " and value: " + value
208 );
209 }
210 adderMethod.invoke( bean, arguments );
211
212 } catch (Exception e) {
213 log.warn(
214 "Cannot evaluate adder method: " + adderMethod.getName() + " on bean: " + bean
215 + " of type: " + bean.getClass().getName() + " with value: " + value
216 + " of type: " + valueType + " and key: " + key
217 + " of type: " + keyType
218 );
219 log.debug(e);
220 }
221 }
222 }
223 }