source: trunk/LogicMail/src/org/logicprobe/LogicMail/util/SerializableHashtable.java @ 858

Revision 858, 9.8 KB checked in by octorian, 13 months ago (diff)

Support for data refresh on startup, and periodic folder polling (refs #79)

Line 
1/*-
2 * Copyright (c) 2007, Derek Konigsberg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its
15 *    contributors may be used to endorse or promote products derived
16 *    from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.logicprobe.LogicMail.util;
33
34import java.io.DataInput;
35import java.io.DataOutput;
36import java.io.IOException;
37import java.util.Date;
38import java.util.Enumeration;
39import java.util.Hashtable;
40
41/**
42 * Provides an implementation of java.util.Hashtable that implements
43 * the LogicMail.util.Serializable interface.
44 * The maximum number of items that can be stored is 1000.
45 * This limit exists so that the deserialization code can quickly
46 * handle data corruption that could result in a bad size value.
47 */
48public class SerializableHashtable extends Hashtable implements Serializable {
49    private int hashcode = -1;
50
51    final private static int TYPE_NULL    = 0;
52    final private static int TYPE_BOOLEAN = 1;
53    final private static int TYPE_BYTE    = 2;
54    final private static int TYPE_BYTE_ARRAY   = 102;
55    final private static int TYPE_CHAR    = 3;
56    final private static int TYPE_STRING  = 4;
57    final private static int TYPE_STRING_ARRAY = 104;
58    final private static int TYPE_DOUBLE  = 5;
59    final private static int TYPE_FLOAT   = 6;
60    final private static int TYPE_INT     = 7;
61    final private static int TYPE_LONG    = 8;
62    final private static int TYPE_LONG_ARRAY   = 108;
63    final private static int TYPE_SHORT   = 9;
64    final private static int TYPE_DATE    = 10;
65
66    final private static int MAX_ITEMS = 1000;
67
68    private long uniqueId;
69
70    /**
71     * Creates a new instance of SerializableHashtable.
72     * This class only supports hash tables containing objects which
73     * wrap the various primitive types supported by {@link DataOutput}
74     * and {@link DataInput}.
75     */
76    public SerializableHashtable() {
77        super();
78        uniqueId = UniqueIdGenerator.getInstance().getUniqueId();
79    }
80
81    /**
82     * Creates a new instance of SerializableHashtable.
83     * This class only supports hash tables containing objects which
84     * wrap the various primitive types supported by {@link DataOutput}
85     * and {@link DataInput}.
86     *
87     * @param initialCapacity Initial capacity of the hashtable.
88     */
89    public SerializableHashtable(int initialCapacity) {
90        super(initialCapacity);
91        uniqueId = UniqueIdGenerator.getInstance().getUniqueId();
92    }
93
94    private static void writeObject(DataOutput output, Object item) throws IOException {
95        if(item instanceof Boolean) {
96            output.writeInt(TYPE_BOOLEAN);
97            output.writeBoolean(((Boolean)item).booleanValue());
98        }
99        else if(item instanceof Byte) {
100            output.writeInt(TYPE_BYTE);
101            output.writeByte(((Byte)item).byteValue());
102        }
103        else if(item instanceof byte[]) {
104            output.writeInt(TYPE_BYTE_ARRAY);
105            byte[] byteArray = (byte[])item;
106            output.writeInt(byteArray.length);
107            output.write(byteArray);
108        }
109        else if(item instanceof Character) {
110            output.writeInt(TYPE_CHAR);
111            output.writeChar(((Character)item).charValue());
112        }
113        else if(item instanceof String) {
114            output.writeInt(TYPE_STRING);
115            output.writeUTF(((String)item));
116        }
117        else if(item instanceof String[]) {
118            output.writeInt(TYPE_STRING_ARRAY);
119            String[] stringArray = (String[])item;
120            output.writeInt(stringArray.length);
121            for(int i = 0; i < stringArray.length; i++) {
122                output.writeUTF(stringArray[i]);
123            }
124        }
125        else if(item instanceof Double) {
126            output.writeInt(TYPE_DOUBLE);
127            output.writeDouble(((Double)item).doubleValue());
128        }
129        else if(item instanceof Float) {
130            output.writeInt(TYPE_FLOAT);
131            output.writeFloat(((Float)item).floatValue());
132        }
133        else if(item instanceof Integer) {
134            output.writeInt(TYPE_INT);
135            output.writeInt(((Integer)item).intValue());
136        }
137        else if(item instanceof Long) {
138            output.writeInt(TYPE_LONG);
139            output.writeLong(((Long)item).longValue());
140        }
141        else if(item instanceof long[]) {
142            output.writeInt(TYPE_LONG_ARRAY);
143            long[] longArray = (long[])item;
144            output.writeInt(longArray.length);
145            for(int i = 0; i < longArray.length; i++) {
146                output.writeLong(longArray[i]);
147            }
148        }
149        else if(item instanceof Short) {
150            output.writeInt(TYPE_SHORT);
151            output.writeShort(((Short)item).shortValue());
152        }
153        else if(item instanceof Date) {
154            output.writeInt(TYPE_DATE);
155            output.writeLong(((Date)item).getTime());
156        }
157        else {
158            output.writeInt(TYPE_NULL);
159            output.write(0);
160        }
161    }
162
163    private static Object readObject(DataInput input) throws IOException {
164        int type = input.readInt();
165        int len;
166        switch(type) {
167        case TYPE_BOOLEAN:
168            return new Boolean(input.readBoolean());
169        case TYPE_BYTE:
170            return new Byte(input.readByte());
171        case TYPE_BYTE_ARRAY:
172            len = input.readInt();
173            byte[] byteArray = new byte[len];
174            input.readFully(byteArray);
175            return byteArray;
176        case TYPE_CHAR:
177            return new Character(input.readChar());
178        case TYPE_STRING:
179            return input.readUTF();
180        case TYPE_STRING_ARRAY:
181            len = input.readInt();
182            String[] stringArray = new String[len];
183            for(int i=0; i<len; i++) {
184                stringArray[i] = input.readUTF();
185            }
186            return stringArray;
187        case TYPE_DOUBLE:
188            return new Double(input.readDouble());
189        case TYPE_FLOAT:
190            return new Float(input.readFloat());
191        case TYPE_INT:
192            return new Integer(input.readInt());
193        case TYPE_LONG:
194            return new Long(input.readLong());
195        case TYPE_LONG_ARRAY:
196            len = input.readInt();
197            long[] longArray = new long[len];
198            for(int i=0; i<len; i++) {
199                longArray[i] = input.readLong();
200            }
201            return longArray;
202        case TYPE_SHORT:
203            return new Short(input.readShort());
204        case TYPE_DATE:
205            return new Date(input.readLong());
206        case TYPE_NULL:
207            return null;
208        default:
209            return null;
210        }
211    }
212
213    public void serialize(DataOutput output) throws IOException {
214        output.writeLong(uniqueId);
215        output.writeInt(this.size());
216        Enumeration e = this.keys();
217        Object key;
218        while(e.hasMoreElements()) {
219            key = e.nextElement();
220            writeObject(output, key);
221            writeObject(output, this.get(key));
222        }
223    }
224
225    public void deserialize(DataInput input) throws IOException {
226        this.clear();
227        uniqueId = input.readLong();
228        int size = input.readInt();
229        if(size > MAX_ITEMS) {
230            throw new IOException();
231        }
232        Object key;
233        Object value;
234        for(int i=0; i<size; i++) {
235            key = readObject(input);
236            value = readObject(input);
237            if(key != null && value != null) {
238                this.put(key, value);
239            }
240        }
241    }   
242
243    public long getUniqueId() {
244        return uniqueId;
245    }
246
247    /* (non-Javadoc)
248     * @see java.lang.Object#hashCode()
249     */
250    public int hashCode() {
251        if(hashcode == -1) {
252            hashcode = 31 * 1 + (int) (uniqueId ^ (uniqueId >>> 32));
253        }
254        return hashcode;
255    }
256
257    /* (non-Javadoc)
258     * @see java.lang.Object#equals(java.lang.Object)
259     */
260    public boolean equals(Object obj) {
261        if (this == obj) {
262            return true;
263        }
264        if (obj == null) {
265            return false;
266        }
267        if (getClass() != obj.getClass()) {
268            return false;
269        }
270        SerializableHashtable other = (SerializableHashtable) obj;
271        if (uniqueId != other.uniqueId) {
272            return false;
273        }
274        return true;
275    }
276}
Note: See TracBrowser for help on using the repository browser.