View Javadoc

    1
    2   package st.ata.util;
    3
    4   import java.io.IOException;
    5   import java.io.InputStream;
    6   import java.io.Serializable;
    7   import java.util.Arrays;
    8   import java.util.Date;
    9   import java.util.Hashtable;
    10  import java.util.Iterator;
    11  import java.util.NoSuchElementException;
    12
    13
    14  // Tested by TestHashtableAList
    15
    16  /*** Implementation of {@link AList} using simple hashtable. */
    17  @SuppressWarnings({"unchecked"})
    18  public class HashtableAList implements MutableAList, Serializable {
    19      private static final long serialVersionUID = 3670660167336648644L;
    20
    21      private final Hashtable mTable = new Hashtable();
    22
    23      private static class DateArray {
    24          public Date[] values;
    25          public DateArray(Date[] v) { values = v; }
    26          public boolean equals(Object obj) {
    27              if (! (obj instanceof DateArray)) return false;
    28              return Arrays.equals(values, ((DateArray)obj).values);
    29          }
    30      }
    31
    32
    33      /*** Remove all key-value mappings. */
    34      public void clear() {
    35          close();
    36          mTable.clear();
    37      }
    38
    39      public boolean containsKey(String key) {
    40          return mTable.containsKey(key);
    41      }
    42
    43      /***
    44       * Deep Clone.
    45       *
    46       * Limited implementation
    47       * @return The cloned object.
    48       */
    49      public Object clone() {
    50          HashtableAList copy = new HashtableAList();
    51          String[] keys = getKeyArray();
    52          for (int i=0; i<keys.length; i++) {
    53              Object me=getObject(keys[i]);
    54              if (me instanceof AList)
    55                  copy.putObject(keys[i], ((AList)me).clone());
    56              else  if (me instanceof AList[]) {
    57                  AList[] from = (AList[])me;
    58                  int count=from.length;
    59                  for (int j=0; j<from.length; j++) {
    60                      if (from[j]==null) {
    61                          count--;
    62                      }
    63                  }
    64
    65                  AList[] copyAList = new AList[count];
    66                  for (int j=0; j<count; j++) {
    67                      if (from[j]==null) continue;
    68                      copyAList[j]=(AList)from[j].clone();
    69                  }
    70                  copy.putObject(keys[i], copyAList);
    71              } else  if (me instanceof String[]) {
    72                  String[] from = (String[])me;
    73                  String[] copyA = new String[from.length];
    74                  for (int j=0; j<from.length; j++)
    75                      copyA[j]=from[j];
    76                  copy.putObject(keys[i], copyA);
    77              }
    78              else if (me instanceof Long) {
    79                  copy.putObject(keys[i], new Long(((Long)me).longValue()));
    80              } else if (me instanceof String) {
    81                  copy.putObject(keys[i], me);
    82              } else
    83                  X.noimpl();
    84          }
    85          return copy;
    86      }
    87
    88      /***
    89       * Shallow copy of fields of <code>other</code> into <code>this</code>.
    90       * @param other AList to copy from.
    91       */
    92      public void copyFrom(AList other) {
    93          Iterator keys = other.getKeys();
    94          while (keys.hasNext()) {
    95              String key = (String)keys.next();
    96              switch (other.getType(key)) {
    97              case T_ALIST:
    98                  putAList(key, other.getAList(key));
    99                  break;
    100             case T_DATE:
    101                 putDate(key, other.getDate(key));
    102                 break;
    103             case T_INT:
    104                 putInt(key, other.getInt(key));
    105                 break;
    106             case T_LONG:
    107                 putLong(key, other.getLong(key));
    108                 break;
    109             case T_STRING:
    110                 putString(key, other.getString(key));
    111                 break;
    112             case T_INPUTSTREAM:
    113                 putInputStream(key, other.getInputStream(key));
    114                 break;
    115             case F_ARRAY | T_ALIST:
    116                 putAListArray(key, other.getAListArray(key));
    117                 break;
    118             case F_ARRAY | T_DATE:
    119                 putDateArray(key, other.getDateArray(key));
    120                 break;
    121             case F_ARRAY | T_INT:
    122                 putIntArray(key, other.getIntArray(key));
    123                 break;
    124             case F_ARRAY | T_LONG:
    125                 putLongArray(key, other.getLongArray(key));
    126                 break;
    127             case F_ARRAY | T_STRING:
    128                 putStringArray(key, other.getStringArray(key));
    129                 break;
    130             case F_ARRAY_ARRAY | T_STRING:
    131                 putStringArrayArray(key, other.getStringArrayArray(key));
    132                 break;
    133             case F_ARRAY | T_INPUTSTREAM:
    134                 putInputStreamArray(key, other.getInputStreamArray(key));
    135                 break;
    136             default:
    137                 X.fail("Unexpected case");
    138             }
    139         }
    140     }
    141
    142     public void copyKeysFrom(Iterator keys, AList other) {
    143         for (; keys.hasNext();) {
    144             String key = (String)keys.next();
    145             Object value = other.getObject(key);
    146             // TODO: consider shallow or deep copy in some cases?
    147             // perhaps controlled by a third parameter?
    148             if(value!=null) {
    149                 putObject(key,value);
    150             }
    151         }
    152     }
    153
    154     public Object getObject(String key) {
    155         return mTable.get(key);
    156     }
    157
    158     public void putObject(String key, Object val) {
    159         mTable.put(key, val);
    160     }
    161     public void remove(String key) {
    162         mTable.remove(key);
    163     }
    164     public Iterator getKeys() {
    165         return mTable.keySet().iterator();
    166     }
    167
    168     public String[] getKeyArray() {
    169         int i = 0;
    170         String keys[] = new String[mTable.size()];
    171         for(Iterator it = getKeys(); it.hasNext(); ++i)
    172             keys[i] = (String)it.next();
    173         return keys;
    174     }
    175
    176     public int getInt(String key) {
    177         Integer v = (Integer)mTable.get(key);
    178         if (v == null) throw new NoSuchElementException(key);
    179         return v.intValue();
    180     }
    181
    182     public long getLong(String key) {
    183         Long v = (Long)mTable.get(key);
    184         if (v == null) throw new NoSuchElementException(key);
    185         return v.longValue();
    186     }
    187
    188     public String getString(String key) {
    189         String v = (String)mTable.get(key);
    190         if (v == null) throw new NoSuchElementException(key);
    191         return v;
    192     }
    193
    194     public AList getAList(String key) {
    195         AList a = (AList) mTable.get(key);
    196         if (a == null) throw new NoSuchElementException(key);
    197         return a;
    198     }
    199
    200     public Date getDate(String key) {
    201         Date v = (Date)mTable.get(key);
    202         if (v == null) throw new NoSuchElementException(key);
    203         return v;
    204     }
    205
    206     public InputStream getInputStream(String key) {
    207         InputStream v = (InputStream)mTable.get(key);
    208         if (v == null) throw new NoSuchElementException(key);
    209         return v;
    210     }
    211
    212     public int[] getIntArray(String key) {
    213         int[] a = (int[]) mTable.get(key);
    214         if (a == null) throw new NoSuchElementException(key);
    215         return a;
    216     }
    217
    218     public long[] getLongArray(String key) {
    219         long[] a = (long[]) mTable.get(key);
    220         if (a == null) throw new NoSuchElementException(key);
    221         return a;
    222     }
    223
    224     public String[] getStringArray(String key) {
    225         String[] a = (String[]) mTable.get(key);
    226         if (a == null) throw new NoSuchElementException(key);
    227         return a;
    228     }
    229
    230     public AList[] getAListArray(String key) {
    231         AList[] a = (AList[]) mTable.get(key);
    232         if (a == null) throw new NoSuchElementException(key);
    233         return a;
    234     }
    235
    236     public Date[] getDateArray(String key) {
    237         DateArray a = (DateArray) mTable.get(key);
    238         if (a == null) throw new NoSuchElementException(key);
    239         return a.values;
    240     }
    241
    242     public InputStream[] getInputStreamArray(String key) {
    243         InputStream v[] = (InputStream [])mTable.get(key);
    244         if (v == null) throw new NoSuchElementException(key);
    245         return v;
    246     }
    247
    248     public String[][] getStringArrayArray(String key) {
    249         String[][] a = (String[][]) mTable.get(key);
    250         if (a == null) throw new NoSuchElementException(key);
    251         return a;
    252     }
    253
    254
    255     public void putInt(String key, int value) {
    256         mTable.put(key, new Integer(value));
    257     }
    258
    259     public void putLong(String key, long value) {
    260         mTable.put(key, new Long(value));
    261     }
    262
    263     public void putString(String key, String value) {
    264         mTable.put(key, value);
    265     }
    266
    267     public void putAList(String key, AList value) {
    268         mTable.put(key, value);
    269     }
    270
    271     public void putDate(String key, Date value) {
    272         mTable.put(key, value);
    273     }
    274
    275     public void putInputStream(String key, InputStream value) {
    276         mTable.put(key, value);
    277     }
    278
    279     public void putIntArray(String key, int[] value) {
    280         mTable.put(key, value);
    281     }
    282
    283     public void putLongArray(String key, long[] value) {
    284         mTable.put(key, value);
    285     }
    286
    287     public void putStringArray(String key, String[] value) {
    288         mTable.put(key, value);
    289     }
    290
    291     public void putAListArray(String key, AList[] value) {
    292         mTable.put(key, value);
    293     }
    294
    295     public void putDateArray(String key, Date[] value) {
    296         mTable.put(key, new DateArray(value));
    297     }
    298
    299     public void putInputStreamArray(String key, InputStream[] value) {
    300         mTable.put(key, value);
    301     }
    302
    303     public void putStringArrayArray(String key, String[][] value) {
    304         mTable.put(key, value);
    305     }
    306
    307
    308     /*** Deep equals.  Arrays need to have same values in same order to
    309      *  be considered equal.
    310      * @param obj
    311      * @return True if equals.
    312      */
    313     public boolean equals(Object obj) {
    314         if (! (obj instanceof HashtableAList)) return false;
    315         HashtableAList o = (HashtableAList)obj;
    316         for (Iterator i = o.getKeys(); i.hasNext(); ) {
    317             if (mTable.get(i.next()) == null) return false;
    318         }
    319         for (Iterator i = getKeys(); i.hasNext(); ) {
    320             Object k = i.next();
    321             Object v1 = mTable.get(k);
    322             Object v2 = o.mTable.get(k);
    323             if (! v1.equals(v2)) {
    324                 if (v1 instanceof AList[]) {
    325                     if (! (v2 instanceof AList[])) return false;
    326                     if (! Arrays.equals((Object[])v1, (Object[])v2))
    327                         return false;
    328                 } else if (v1 instanceof int[]) {
    329                     if (! (v2 instanceof int[])) return false;
    330                     if (! Arrays.equals((int[])v1, (int[])v2)) return false;
    331                 } else if (v1 instanceof long[]) {
    332                     if (! (v2 instanceof long[])) return false;
    333                     if (! Arrays.equals((long[])v1, (long[])v2)) return false;
    334                 } else if (v1 instanceof String[]) {
    335                     if (! (v2 instanceof String[])) return false;
    336                     if (! Arrays.equals((String[])v1, (String[])v2))
    337                         return false;
    338                 } else return false;
    339             }
    340         }
    341         return true;
    342     }
    343
    344     public int getType(String key) {
    345         Object o = mTable.get(key);
    346         if (o == null) return T_UNDEFINED;
    347         else if (o instanceof AList) return T_ALIST;
    348         else if (o instanceof Date) return T_DATE;
    349         else if (o instanceof Integer) return T_INT;
    350         else if (o instanceof Long) return T_LONG;
    351         else if (o instanceof String) return T_STRING;
    352         else if (o instanceof InputStream) return T_INPUTSTREAM;
    353         else if (o instanceof AList[]) return T_ALIST | F_ARRAY;
    354         else if (o instanceof DateArray) return T_DATE | F_ARRAY;
    355         else if (o instanceof int[]) return T_INT | F_ARRAY;
    356         else if (o instanceof long[]) return T_LONG | F_ARRAY;
    357         else if (o instanceof String[]) return T_STRING | F_ARRAY;
    358         else if (o instanceof InputStream[]) return T_INPUTSTREAM | F_ARRAY;
    359         else if (o instanceof String[][]) return T_STRING | F_ARRAY_ARRAY;
    360         else if (o instanceof Object[]) return T_OBJECT | F_ARRAY;
    361         else if (o instanceof Object) return T_OBJECT;
    362         else X.fail("Should not get here " + o);
    363         return -1;
    364     }
    365
    366     /*** Useful for creating test-tables for debugging.  The object
    367         should be one of an {@link AList}, {@link Date}, {@link
    368         Integer}, {@link Long}, {@link String}, {@link AList}[],
    369         {@link Date}[], <code>int[]</code>, <code>long[]</code>,
    370         <code>{@link String}[]</code>, <code>ZE[]</code>
    371         or <code>ZE[][]</code>.  In the case of <code>ZE[]</code>,
    372         the entry is treated as an {@link AList}. Similaryly
    373         if the entry is <code>ZE[][]</code> it is treated as
    374         {@link AList}[]. */
    375     public static class ZE {
    376         public final String key;
    377         public final Object val;
    378         public ZE(String k, Object v) { key = k; val = v; }
    379     }
    380
    381     public void zInsert(ZE[] entries) {
    382         for (int i = 0; i < entries.length; i++) {
    383             zInsert(entries[i]);
    384         }
    385     }
    386
    387     public void zInsert(ZE entry) {
    388         if (entry.val instanceof Date[]) {
    389             mTable.put(entry.key, new DateArray((Date[])entry.val));
    390         } else if (entry.val instanceof ZE[]) {
    391             HashtableAList v = new HashtableAList();
    392             v.zInsert((ZE[])entry.val);
    393             mTable.put(entry.key, v);
    394         } else if (entry.val instanceof ZE[][]) {
    395             AList v[] = new AList[((ZE[][])entry.val).length];
    396             for(int j = 0; j < v.length; ++j) {
    397                 HashtableAList h = new HashtableAList();
    398                 h.zInsert(((ZE[][])entry.val)[j]);
    399                 v[j] = h;
    400             }
    401             mTable.put(entry.key, v);
    402         } else {
    403             mTable.put(entry.key, entry.val);
    404         }
    405     }
    406
    407     public void close() {
    408         String[] keys = getKeyArray();
    409         try {
    410             for (int i = 0; i < keys.length; i++) {
    411                 if (getType(keys[i]) == T_INPUTSTREAM) {
    412                     getInputStream(keys[i]).close();
    413                 } else if (getType(keys[i]) == (T_INPUTSTREAM | F_ARRAY)) {
    414                     InputStream[] ins = getInputStreamArray(keys[i]);
    415                     for (int j = 0; j < ins.length; j++) {
    416                         ins[j].close();
    417                     }
    418                 } else if (getType(keys[i]) == T_ALIST) {
    419                     getAList(keys[i]).close();
    420                 } else if (getType(keys[i]) == (T_ALIST | F_ARRAY)) {
    421                     AList[] als = getAListArray(keys[i]);
    422                     for (int j = 0; j < als.length; j++) {
    423                         als[j].close();
    424                     }
    425                 }
    426             }
    427         } catch (IOException e) {
    428             throw X.toRTE(e);
    429         }
    430     }
    431
    432     public AList newAList() {
    433         return new HashtableAList();
    434     }
    435
    436     public String toString() {
    437         return mTable.toString();
    438     }
    439
    440     /***
    441      * Enhance given object's default String display for appearing
    442      * nested in a pretty AList String.
    443      *
    444      * @param obj Object to prettify
    445      * @return prettified String
    446      */
    447     protected String prettyString(Object obj) {
    448         if (obj instanceof AList) return ((AList)obj).toPrettyString();
    449         else if (obj instanceof AList[]) return prettyString((AList[])obj);
    450         else return "<"+obj+">";
    451     }
    452
    453     /* (non-Javadoc)
    454      * @see st.ata.util.AList#toPrettyString()
    455      */
    456     public String toPrettyString() {
    457         StringBuilder builder = new StringBuilder();
    458         builder.append("{ ");
    459         boolean needsComma = false;
    460         for( String key : getKeyArray()) {
    461             if(needsComma) {
    462                 builder.append(", ");
    463             }
    464             builder.append(key);
    465             builder.append(": ");
    466             builder.append(prettyString(mTable.get(key)));
    467             needsComma = true;
    468         }
    469         builder.append(" }");
    470         return builder.toString();
    471     }
    472
    473     /***
    474      * Provide a slightly-improved String of AList[]
    475      *
    476      * @param alists
    477      * @return prettified (in square brackets) of AList[]
    478      */
    479     protected String prettyString(AList[] alists) {
    480         StringBuilder builder = new StringBuilder();
    481         builder.append("[ ");
    482         boolean needsComma = false;
    483         for( AList alist : alists) {
    484             if(alist==null) continue;
    485             if(needsComma) {
    486                 builder.append(", ");
    487             }
    488             builder.append(alist.toPrettyString());
    489             needsComma = true;
    490         }
    491         builder.append(" ]");
    492         return builder.toString();
    493     }
    494 }