Clover coverage report - Code Coverage for tapestry release 4.0-beta-8
Coverage timestamp: Sat Sep 24 2005 11:50:34 EDT
file stats: LOC: 291   Methods: 14
NCLOC: 114   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ListEditMap.java 100% 100% 100% 100%
coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.tapestry.form;
 16   
 17    import java.util.ArrayList;
 18    import java.util.Collections;
 19    import java.util.HashMap;
 20    import java.util.HashSet;
 21    import java.util.List;
 22    import java.util.Map;
 23    import java.util.Set;
 24   
 25    import org.apache.tapestry.Tapestry;
 26   
 27    /**
 28    * A utility class often used with the {@link org.apache.tapestry.form.ListEdit} component. A
 29    * ListEditMap is loaded with data objects before the ListEdit renders, and again before the
 30    * ListEdit rewinds. This streamlines the synchronization of the form against data on the server. It
 31    * is most useful when the set of objects is of a manageable size (say, no more than a few hundred
 32    * objects).
 33    * <p>
 34    * The map stores a list of keys, and relates each key to a value. It also tracks a deleted flag for
 35    * each key.
 36    * <p>
 37    * Usage: <br>
 38    * The page or component should implement {@link org.apache.tapestry.event.PageBeginRenderListener}
 39    * and implement
 40    * {@link org.apache.tapestry.event.PageBeginRenderListener#pageBeginRender(org.apache.tapestry.event.PageEvent)}
 41    * to initialize the map.
 42    * <p>
 43    * The external data (from which keys and values are obtained) is queried, and each key/value pair
 44    * is {@link #add(Object, Object) added} to the map, in the order that items should be presented.
 45    * <p>
 46    * The {@link org.apache.tapestry.form.ListEdit}'s source parameter should be bound to the map's
 47    * {@link #getKeys() keys} property. The value parameter should be bound to the map's
 48    * {@link #setKey(Object) key} property.
 49    * <p>
 50    * The {@link org.apache.tapestry.form.ListEdit}'s listener parameter should be bound to a listener
 51    * method to synchronize a property of the component from the map. <code>
 52    * public void synchronize()
 53    * {
 54    * ListEditMap map = ...;
 55    * <i>Type</i> object = (<i>Type</i>)map.getValue();
 56    *
 57    * if (object == null)
 58    * ...
 59    *
 60    * set<i>Property</i>(object);
 61    * }
 62    * </code>
 63    * <p>
 64    * You may also connect a {@link org.apache.tapestry.form.Checkbox}'s selected parameter to the
 65    * map's {@link #isDeleted() deleted} property.
 66    * <p>
 67    * You may track inclusion in other sets by subclassing ListEditMap and implementing new boolean
 68    * properties. The accessor method should be a call to {@link #checkSet(Set)} and the mutator method
 69    * should be a call to {@link #updateSet(Set, boolean)}.
 70    *
 71    * @author Howard Lewis Ship
 72    * @since 3.0
 73    */
 74   
 75    public class ListEditMap
 76    {
 77    private Map _map = new HashMap();
 78   
 79    private List _keys = new ArrayList();
 80   
 81    private Set _deletedKeys;
 82   
 83    private Object _currentKey;
 84   
 85    /**
 86    * Records the key and value into this map. The keys may be obtained, in the order in which they
 87    * are added, using {@link #getKeys()}. This also sets the current key (so that you may invoke
 88    * {@link #setDeleted(boolean)}, for example).
 89    */
 90   
 91  24 public void add(Object key, Object value)
 92    {
 93  24 _currentKey = key;
 94   
 95  24 _keys.add(_currentKey);
 96  24 _map.put(_currentKey, value);
 97    }
 98   
 99    /**
 100    * Returns a List of keys, in the order that keys were added to the map (using
 101    * {@link #add(Object, Object)}. The caller must not modify the List.
 102    */
 103   
 104  3 public List getKeys()
 105    {
 106  3 return _keys;
 107    }
 108   
 109    /**
 110    * Sets the key for the map. This defines the key used with the other methods:
 111    * {@link #getValue()}, {@link #isDeleted()}, {@link #setDeleted(boolean)}.
 112    */
 113   
 114  9 public void setKey(Object key)
 115    {
 116  9 _currentKey = key;
 117    }
 118   
 119    /**
 120    * Returns the current key within the map.
 121    */
 122   
 123  2 public Object getKey()
 124    {
 125  2 return _currentKey;
 126    }
 127   
 128    /**
 129    * Returns the value for the key (set using {@link #setKey(Object)}). May return null if no
 130    * such key has been added (this can occur if a data object is deleted between the time a form
 131    * is rendered and the time a form is submitted).
 132    */
 133   
 134  2 public Object getValue()
 135    {
 136  2 return _map.get(_currentKey);
 137    }
 138   
 139    /**
 140    * Returns true if the {@link #setKey(Object) current key} is in the set of deleted keys.
 141    */
 142   
 143  6 public boolean isDeleted()
 144    {
 145  6 return checkSet(_deletedKeys);
 146    }
 147   
 148    /**
 149    * Returns true if the set contains the {@link #getKey() current key}. Returns false is the set
 150    * is null, or doesn't contain the current key.
 151    */
 152   
 153  6 protected boolean checkSet(Set set)
 154    {
 155  6 if (set == null)
 156  3 return false;
 157   
 158  3 return set.contains(_currentKey);
 159    }
 160   
 161    /**
 162    * Adds or removes the {@link #setKey(Object) current key} from the set of deleted keys.
 163    */
 164   
 165  8 public void setDeleted(boolean value)
 166    {
 167  8 _deletedKeys = updateSet(_deletedKeys, value);
 168    }
 169   
 170    /**
 171    * Updates the set, adding or removing the {@link #getKey() current key} from it. Returns the
 172    * set passed in. If the value is true and the set is null, an new instance of {@link HashSet}
 173    * is created and returned.
 174    */
 175   
 176  8 protected Set updateSet(Set set, boolean value)
 177    {
 178  8 if (value)
 179    {
 180  6 if (set == null)
 181  4 set = new HashSet();
 182   
 183  6 set.add(_currentKey);
 184    }
 185    else
 186    {
 187  2 if (set != null)
 188  1 set.remove(_currentKey);
 189    }
 190   
 191  8 return set;
 192    }
 193   
 194    /**
 195    * Returns the deleted keys in an unspecified order. Returns a List, which may be empty if no
 196    * keys have been deleted.
 197    */
 198   
 199  4 public List getDeletedKeys()
 200    {
 201  4 return convertSetToList(_deletedKeys);
 202    }
 203   
 204    /**
 205    * Removes keys and values that are in the set of deleted keys, then clears the set of deleted
 206    * keys. After invoking this method, {@link #getValues()} and {@link #getAllValues()} will
 207    * return equivalent lists and {@link #getKeys()} will no longer show any of the deleted keys.
 208    * Note that this method <em>does not</em> change the current key. Subclasses that track
 209    * additional key sets may want to override this method to remove deleted keys from those key
 210    * sets.
 211    */
 212   
 213  2 public void purgeDeletedKeys()
 214    {
 215  2 if (_deletedKeys == null)
 216  1 return;
 217   
 218  1 _map.keySet().removeAll(_deletedKeys);
 219  1 _keys.removeAll(_deletedKeys);
 220   
 221  1 _deletedKeys = null;
 222    }
 223   
 224    /**
 225    * Invoked to convert a set into a List.
 226    *
 227    * @param set
 228    * a set (which may be empty or null)
 229    * @return a list (possibly empty) of the items in the set
 230    */
 231   
 232  4 protected List convertSetToList(Set set)
 233    {
 234  4 if (Tapestry.isEmpty(set))
 235  2 return Collections.EMPTY_LIST;
 236   
 237  2 return new ArrayList(set);
 238    }
 239   
 240    /**
 241    * Returns all the values stored in the map, in the order in which values were added to the map
 242    * using {@link #add(Object, Object)}.
 243    */
 244   
 245  5 public List getAllValues()
 246    {
 247  5 int count = _keys.size();
 248  5 List result = new ArrayList(count);
 249   
 250  5 for (int i = 0; i < count; i++)
 251    {
 252  13 Object key = _keys.get(i);
 253  13 Object value = _map.get(key);
 254   
 255  13 result.add(value);
 256    }
 257   
 258  5 return result;
 259    }
 260   
 261    /**
 262    * Returns all the values stored in the map, excluding those whose id has been marked deleted,
 263    * in the order in which values were added to the map using {@link #add(Object, Object)}.
 264    */
 265   
 266  4 public List getValues()
 267    {
 268  4 int deletedCount = Tapestry.size(_deletedKeys);
 269   
 270  4 if (deletedCount == 0)
 271  1 return getAllValues();
 272   
 273  3 int count = _keys.size();
 274   
 275  3 List result = new ArrayList(count - deletedCount);
 276   
 277  3 for (int i = 0; i < count; i++)
 278    {
 279  9 Object key = _keys.get(i);
 280   
 281  9 if (_deletedKeys.contains(key))
 282  4 continue;
 283   
 284  5 Object value = _map.get(key);
 285  5 result.add(value);
 286    }
 287   
 288  3 return result;
 289    }
 290   
 291    }