KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > betwixt > expression > MapEntryAdder


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
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.apache.commons.betwixt.expression;
17
18 import java.lang.reflect.Array JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.util.Collection JavaDoc;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 /** <p><code>MapEntryAdder</code> is used to add entries to a map.</p>
26   *
27   * <p>
28   * <code>MapEntryAdder</code> supplies two updaters:
29   * <ul>
30   * <li>{@link #getKeyUpdater()} which allows the entry key to be updated</li>
31   * <li>{@link #getValueUpdater()} which allows the entry value to be updated</li>
32   * </ul>
33   * When both of these updaters have been called, the entry adder method is called.
34   * Once this has happened then the values can be updated again.
35   * Note that only the <code>Context</code> passed by the last update will be used.
36   * </p>
37   *
38   * @author <a HREF="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
39   * @since 0.5
40   */

41 public class MapEntryAdder {
42
43     
44     // Class Attributes
45
//-------------------------------------------------------------------------
46

47     /** Log used by this class */
48     private static Log log = LogFactory.getLog( MapEntryAdder.class );
49     
50     
51     // Class Methods
52
//-------------------------------------------------------------------------
53

54     /**
55      * Sets the logger used by this class.
56      *
57      * @param newLog log to this
58      */

59     public static void setLog(Log newLog) {
60         log = newLog;
61     }
62     
63     // Attributes
64
//-------------------------------------------------------------------------
65

66     /** The method to be called to add a new map entry */
67     private Method JavaDoc adderMethod;
68     
69     /** Has the entry key been updated? */
70     private boolean keyUpdated = false;
71     /** The entry key */
72     private Object JavaDoc key;
73     
74     /** Has the entry value been updated? */
75     private boolean valueUpdated = false;
76     /** The entry value */
77     private Object JavaDoc value;
78     
79         
80     // Constructors
81
//-------------------------------------------------------------------------
82

83     /**
84      * Construct a <code>MapEntryAdder</code> which adds entries to given method.
85      *
86      * @param method the <code>Method</code> called to add a key-value entry
87      * @throws IllegalArgumentException if the given method does not take two parameters
88      */

89     public MapEntryAdder(Method JavaDoc method) {
90         
91         Class JavaDoc[] types = method.getParameterTypes();
92         if ( types == null || types.length != 2) {
93             throw new IllegalArgumentException JavaDoc(
94                 "Method used to add entries to maps must have two parameter.");
95         }
96         this.adderMethod = method;
97     }
98     
99     // Properties
100
//-------------------------------------------------------------------------
101

102     /**
103      * Gets the entry key <code>Updater</code>.
104      * This is used to update the entry key value to the read value.
105      * If {@link #getValueUpdater} has been called previously,
106      * then this trigger the updating of the adder method.
107      *
108      * @return the <code>Updater</code> which should be used to populate the entry key
109      */

110     public Updater getKeyUpdater() {
111         
112         return new Updater() {
113             public void update( Context context, Object JavaDoc keyValue ) {
114                 // might as well make sure that his can only be set once
115
if ( !keyUpdated ) {
116                     keyUpdated = true;
117                     key = keyValue;
118                     if ( log.isTraceEnabled() ) {
119                         log.trace( "Setting entry key to " + key );
120                         log.trace( "Current entry value is " + value );
121                     }
122                     if ( valueUpdated ) {
123                         callAdderMethod( context );
124                     }
125                 }
126             }
127         };
128     }
129     
130     /**
131      * Gets the entry value <code>Updater</code>.
132      * This is used to update the entry key value to the read value.
133      * If {@link #getKeyUpdater} has been called previously,
134      * then this trigger the updating of the adder method.
135      *
136      * @return the <code>Updater</code> which should be used to populate the entry value
137      */

138     public Updater getValueUpdater() {
139         
140         return new Updater() {
141             public void update( Context context, Object JavaDoc valueValue ) {
142                 // might as well make sure that his can only be set once
143
if ( !valueUpdated ) {
144                     valueUpdated = true;
145                     value = valueValue;
146                     if ( log.isTraceEnabled() ) {
147                         log.trace( "Setting entry value to " + value);
148                         log.trace( "Current entry key is " + key );
149                     }
150                     if ( keyUpdated ) {
151                         callAdderMethod( context );
152                     }
153                 }
154             }
155         };
156     }
157     
158     
159     
160     // Implementation methods
161
//-------------------------------------------------------------------------
162

163     /**
164      * Call the adder method on the bean associated with the <code>Context</code>
165      * with the key, value entry values stored previously.
166      *
167      * @param context the Context against whose bean the adder method will be invoked
168      */

169     private void callAdderMethod(Context context) {
170         log.trace("Calling adder method");
171         
172         // this allows the same instance to be used multiple times.
173
keyUpdated = false;
174         valueUpdated = false;
175         
176         //
177
// XXX This is (basically) cut and pasted from the MethodUpdater code
178
// I haven't abstracted this code just yet since I think that adding
179
// handling for non-beans will mean adding quite a lot more structure
180
// and only once this is added will the proper position for this method
181
// become clear.
182
//
183

184         Class JavaDoc[] types = adderMethod.getParameterTypes();
185         // key is first parameter
186
Class JavaDoc keyType = types[0];
187         // value is the second
188
Class JavaDoc valueType = types[1];
189         
190         Object JavaDoc bean = context.getBean();
191         if ( bean != null ) {
192             if ( key instanceof String JavaDoc ) {
193                 // try to convert into primitive types
194
key = context.getObjectStringConverter()
195                         .stringToObject( (String JavaDoc) key, keyType, null, context );
196             }
197             
198             if ( value instanceof String JavaDoc ) {
199                 // try to convert into primitive types
200
value = context.getObjectStringConverter()
201                         .stringToObject( (String JavaDoc) value, valueType, null, context );
202             }
203             
204             // special case for collection objects into arrays
205
if (value instanceof Collection JavaDoc && valueType.isArray()) {
206                 Collection JavaDoc valuesAsCollection = (Collection JavaDoc) value;
207                 Class JavaDoc componentType = valueType.getComponentType();
208                 if (componentType != null) {
209                     Object JavaDoc[] valuesAsArray =
210                         (Object JavaDoc[]) Array.newInstance(componentType, valuesAsCollection.size());
211                     value = valuesAsCollection.toArray(valuesAsArray);
212                 }
213             }
214             
215                  
216             Object JavaDoc[] arguments = { key, value };
217             try {
218                 if ( log.isTraceEnabled() ) {
219                     log.trace(
220                         "Calling adder method: " + adderMethod.getName() + " on bean: " + bean
221                         + " with key: " + key + " and value: " + value
222                     );
223                 }
224                 adderMethod.invoke( bean, arguments );
225                 
226             } catch (Exception JavaDoc e) {
227                 log.warn(
228                     "Cannot evaluate adder method: " + adderMethod.getName() + " on bean: " + bean
229                     + " of type: " + bean.getClass().getName() + " with value: " + value
230                     + " of type: " + valueType + " and key: " + key
231                     + " of type: " + keyType
232                 );
233                 log.debug(e);
234             }
235         }
236     }
237 }
238
Popular Tags