001 package com.sptci.echo2;
002
003 import java.io.Serializable;
004
005 import java.lang.reflect.Field;
006 import java.lang.reflect.InvocationTargetException;
007 import java.lang.reflect.Method;
008
009 import java.util.ArrayList;
010 import java.util.HashMap;
011 import java.util.HashSet;
012 import java.util.Iterator;
013 import java.util.List;
014 import java.util.Map;
015 import java.util.TreeMap;
016 import java.util.logging.Logger;
017
018 import nextapp.echo2.app.ListBox;
019 import nextapp.echo2.app.SelectField;
020 import nextapp.echo2.app.button.ToggleButton;
021 import nextapp.echo2.app.list.ListModel;
022 import nextapp.echo2.app.text.TextComponent;
023
024 import com.sptci.ReflectionUtility;
025
026 /**
027 * An abstract <code>updater</code> used to update UI containers or
028 * JavaBean objects from one another.
029 *
030 * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
031 * @author Rakesh Vidyadharan 2006-02-07
032 * @version $Id: Updater.java,v 1.3 2006/02/09 21:27:31 rakesh Exp $
033 */
034 public abstract class Updater implements Serializable
035 {
036 /**
037 * The logger used to log errors/warnings to.
038 */
039 private static transient final Logger logger =
040 Logger.getLogger( "com.sptci.echo2.Updater" );
041
042 /**
043 * The UI container that is to be updated.
044 */
045 protected Object uiContainer;
046
047 /**
048 * The java bean that contains the data to use to update the
049 * {@link #uiContainer}.
050 */
051 protected Object bean;
052
053 /**
054 * Default constructor. Cannot be instantiated.
055 */
056 protected Updater() {}
057
058 /**
059 * Create a new instance with the specified UI container and java
060 * bean.
061 *
062 * @param uiContainer The {@link #uiContainer} to use.
063 * @param bean The {@link #bean} to use.
064 */
065 protected Updater( Object uiContainer, Object bean )
066 {
067 setUiContainer( uiContainer );
068 setBean( bean );
069 }
070
071 /**
072 * Fetch the values of all the fields in {@link #bean} that have
073 * an <code>accessor</code> method conforming to JavaBean naming
074 * convention.
075 *
076 * @see ReflectionUtility#fetchFields
077 * @see ReflectionUtility#fetchMethod( Object, String, Class[] )
078 * @return Map A map with the field name as <code>key</code> and
079 * the field value as <code>value</code>.
080 * @throws IllegalAccessException If a custom security policy
081 * restricts access to the bean fields.
082 * @throws InvocationTargetException If the accessor method for
083 * the field could not be invoked successfully.
084 */
085 protected Map<String, Object> beanValues()
086 throws IllegalAccessException, InvocationTargetException
087 {
088 Map<String, Object> values = new HashMap<String, Object>();
089 for ( Map.Entry<String, Field> entry :
090 ReflectionUtility.fetchFields( bean ).entrySet() )
091 {
092 Field field = entry.getValue();
093 String methodName = "get" +
094 field.getName().substring( 0, 1 ).toUpperCase() +
095 field.getName().substring( 1 );
096 Method method = ReflectionUtility.fetchMethod( bean,
097 methodName, new Class[0] );
098 if ( method != null )
099 {
100 Object value = method.invoke( bean );
101 values.put( field.getName(), value );
102 }
103 else
104 {
105 logger.fine( "No accessor method in bean: " + bean.getClass() +
106 " for field: " + field.getName() );
107 }
108 }
109
110 return values;
111 }
112
113 /**
114 * Fetch the values of all the fields in {@link #uiContainer}.
115 * Convert the values of the UI components to the mapping scheme
116 * used in bean generation.
117 *
118 * @see ReflectionUtility#fetchFields
119 * @see ReflectionUtility#fetchMethod( Object, String, Class[] )
120 * @return Map A map with the field name as <code>key</code> and
121 * the field value as <code>value</code>.
122 * @throws IllegalAccessException If a custom security policy
123 * restricts access to the bean fields.
124 * @throws InvocationTargetException If the accessor method for
125 * the field could not be invoked successfully.
126 */
127 protected Map<String, Object> uiValues()
128 throws IllegalAccessException, InvocationTargetException
129 {
130 Map<String, Object> values = new HashMap<String, Object>();
131
132 for ( Map.Entry<String, Field> entry :
133 ReflectionUtility.fetchFields( uiContainer ).entrySet() )
134 {
135 Field field = entry.getValue();
136 Object object = field.get( uiContainer );
137 Object value = null;
138
139 if ( object instanceof nextapp.echo2.app.text.TextComponent )
140 {
141 value = ( (TextComponent) object ).getText();
142 }
143 else if ( object instanceof nextapp.echo2.app.ListBox )
144 {
145 List<ListItem> list = new ArrayList<ListItem>();
146 ListBox box = (ListBox) object;
147 ListModel model = box.getModel();
148 int[] selected = box.getSelectedIndices();
149 HashSet<Integer> set = new HashSet<Integer>( selected.length );
150 for ( int i : selected )
151 {
152 set.add( i );
153 }
154
155 for ( int i = 0; i < model.size(); ++i )
156 {
157 if ( set.contains( i ) )
158 {
159 list.add( new ListItem( (String) model.get( i ), true ) );
160 }
161 else
162 {
163 list.add( new ListItem( (String) model.get( i ), false ) );
164 }
165 }
166
167 value = list;
168 }
169 else if ( object instanceof nextapp.echo2.app.SelectField )
170 {
171 List<ListItem> list = new ArrayList<ListItem>();
172 SelectField select = (SelectField) object;
173 ListModel model = select.getModel();
174 int index = select.getSelectedIndex();
175
176 for ( int i = 0; i < model.size(); ++i )
177 {
178 if ( i == index )
179 {
180 list.add( new ListItem( (String) model.get( i ), true ) );
181 }
182 else
183 {
184 list.add( new ListItem( (String) model.get( i ), false ) );
185 }
186 }
187
188 value = list;
189 }
190 else if ( object instanceof java.util.Map )
191 {
192 Map<String, Boolean> map = new TreeMap<String, Boolean>();
193
194 for ( Iterator iterator = ( (Map) object ).entrySet().iterator();
195 iterator.hasNext(); )
196 {
197 Map.Entry mapEntry = (Map.Entry) iterator.next();
198 if ( mapEntry.getValue() instanceof
199 nextapp.echo2.app.button.ToggleButton )
200 {
201 ToggleButton button = (ToggleButton) mapEntry.getValue();
202 String key = (String) mapEntry.getKey();
203 int index = 0;
204 if ( ( index = key.lastIndexOf( ">" ) ) != -1 )
205 {
206 key = key.substring( index + 1 );
207 }
208
209 map.put( key, button.isSelected() );
210 }
211 }
212
213 value = map;
214 }
215
216 values.put( entry.getKey(), value );
217 }
218
219 return values;
220 }
221
222 /**
223 * Update the fields of the desired component with the data contained
224 * in similarly named fields in the other component.
225 */
226 public abstract void update();
227
228 /**
229 * Returns {@link #uiContainer}.
230 *
231 * @return Object The value/reference of/to uiContainer.
232 */
233 public final Object getUiContainer()
234 {
235 return uiContainer;
236 }
237
238 /**
239 * Set {@link #uiContainer}.
240 *
241 * @param uiContainer The value to set.
242 */
243 public final void setUiContainer( Object uiContainer )
244 {
245 this.uiContainer = uiContainer;
246 }
247
248 /**
249 * Returns {@link #bean}.
250 *
251 * @return Object The value/reference of/to bean.
252 */
253 public final Object getBean()
254 {
255 return bean;
256 }
257
258 /**
259 * Set {@link #bean}.
260 *
261 * @param bean The value to set.
262 */
263 public final void setBean( Object bean )
264 {
265 this.bean = bean;
266 }
267 }