EMMA Coverage Report (generated Tue Apr 17 08:51:20 BST 2007)
[all classes][org.jtoolkit.essence.app.pojo]

COVERAGE SUMMARY FOR SOURCE FILE [DatableUtils.java]

nameclass, %method, %block, %line, %
DatableUtils.java100% (5/5)92%  (44/48)82%  (1600/1949)86%  (310/359)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DatableUtils$InStreamStatus100% (1/1)100% (4/4)76%  (125/164)89%  (26.8/30)
DatableUtils$InStreamStatus (DataInput): void 100% (1/1)48%  (24/50)78%  (7/9)
get (int): Object 100% (1/1)70%  (28/40)83%  (5/6)
pruneTo (int): void 100% (1/1)98%  (39/40)98%  (7.8/8)
set (int, Object): void 100% (1/1)100% (34/34)100% (7/7)
     
class DatableUtils100% (1/1)88%  (28/32)79%  (1086/1378)84%  (246.4/292)
DatableUtils (): void 0%   (0/1)0%   (0/3)0%   (0/2)
readDataValue (DatableUtils$InStreamStatus, DataInput): Object 0%   (0/1)0%   (0/27)0%   (0/5)
readSet (DataInput): Object 0%   (0/1)0%   (0/12)0%   (0/2)
readSortedMap (DatableUtils$InStreamStatus, DataInput): Object 0%   (0/1)0%   (0/21)0%   (0/5)
readLen (DataInput, int, int): int 100% (1/1)38%  (12/32)75%  (3/4)
readBaseObject (DataInput): Object 100% (1/1)46%  (16/35)80%  (4/5)
readObject0 (DatableUtils$InStreamStatus, DataInput): Object 100% (1/1)47%  (66/140)56%  (18/32)
readObject (DatableUtils$InStreamStatus, DataInput): Object 100% (1/1)71%  (39/55)92%  (11/12)
writeByteString (DataOutput, String): void 100% (1/1)78%  (42/54)92%  (11/12)
writeObject (DatableUtils$OutStreamStatus, DataOutput, Object): void 100% (1/1)80%  (332/415)87%  (86.4/99)
readDatable (DatableUtils$InStreamStatus, DataInput): Object 100% (1/1)92%  (57/62)93%  (14/15)
<static initializer> 100% (1/1)100% (121/121)100% (9/9)
acquireStreamStatus (DataInput): DatableUtils$InStreamStatus 100% (1/1)100% (22/22)100% (5/5)
acquireStreamStatus (DataOutput): DatableUtils$OutStreamStatus 100% (1/1)100% (22/22)100% (5/5)
close (Closeable): void 100% (1/1)100% (9/9)100% (3/3)
fromBytes (byte [], int, int): Object [] 100% (1/1)100% (17/17)100% (4/4)
prune (DataOutput): void 100% (1/1)100% (10/10)100% (3/3)
readBER (DataInput): long 100% (1/1)100% (37/37)100% (7/7)
readByteString (DataInput): String 100% (1/1)100% (7/7)100% (1/1)
readBytesArray (DataInput): byte [] 100% (1/1)100% (12/12)100% (4/4)
readList (DataInput): Object 100% (1/1)100% (9/9)100% (2/2)
readMap (DataInput): Object 100% (1/1)100% (9/9)100% (2/2)
readObject (DataInput): Object 100% (1/1)100% (7/7)100% (2/2)
readObjects (DataInput, int, int): Object [] 100% (1/1)100% (26/26)100% (6/6)
readSerializable (DataInput): Object 100% (1/1)100% (12/12)100% (2/2)
readSortedSet (DatableUtils$InStreamStatus, DataInput): Object 100% (1/1)100% (21/21)100% (4/4)
readStringArray (DataInput): Object 100% (1/1)100% (18/18)100% (4/4)
registerBuilder (Class, Mapping): void 100% (1/1)100% (6/6)100% (2/2)
toBytes (Object []): byte [] 100% (1/1)100% (17/17)100% (5/5)
writeBER (DataOutput, long): void 100% (1/1)100% (103/103)100% (21/21)
writeObject (DataOutput, Object): void 100% (1/1)100% (8/8)100% (3/3)
writeObjects (DataOutput, Object []): void 100% (1/1)100% (29/29)100% (5/5)
     
class DatableUtils$1100% (1/1)100% (1/1)86%  (113/131)86%  (0.9/1)
<static initializer> 100% (1/1)86%  (113/131)86%  (0.9/1)
     
class DatableUtils$Formats100% (1/1)100% (4/4)100% (198/198)100% (19/19)
<static initializer> 100% (1/1)100% (184/184)100% (19/19)
DatableUtils$Formats (String, int): void 100% (1/1)100% (5/5)100% (1/1)
valueOf (String): DatableUtils$Formats 100% (1/1)100% (5/5)100% (1/1)
values (): DatableUtils$Formats [] 100% (1/1)100% (4/4)100% (1/1)
     
class DatableUtils$OutStreamStatus100% (1/1)100% (7/7)100% (78/78)100% (18/18)
DatableUtils$OutStreamStatus (DataOutput): void 100% (1/1)100% (34/34)100% (8/8)
allocateNumber (Object): int 100% (1/1)100% (15/15)100% (2/2)
getAndClearPrune (): boolean 100% (1/1)100% (8/8)100% (3/3)
getNumber (Object): Integer 100% (1/1)100% (6/6)100% (1/1)
prune (int): int 100% (1/1)100% (7/7)100% (1/1)
setPruneTrue (): void 100% (1/1)100% (4/4)100% (2/2)
size (): int 100% (1/1)100% (4/4)100% (1/1)

1package org.jtoolkit.essence.app.pojo;
2 
3import org.apache.commons.logging.Log;
4import static org.apache.commons.logging.LogFactory.getLog;
5import org.jetbrains.annotations.NotNull;
6import org.jetbrains.annotations.Nullable;
7import org.jtoolkit.essence.app.pojo.impl.DataValueClass;
8import static org.jtoolkit.essence.app.pojo.impl.DataValueClass.build;
9import org.jtoolkit.essence.app.pojo.impl.PojoContext;
10import org.jtoolkit.essence.concurrency.NotThreadSafe;
11import org.jtoolkit.essence.data.Mapping;
12import org.jtoolkit.essence.utils.IOUtils;
13import org.jtoolkit.essence.utils.ImmutableUtils;
14import static org.jtoolkit.essence.utils.ImmutableUtils.immutableWrap;
15import static org.jtoolkit.essence.utils.ImmutableUtils.tryImmutableCopy;
16import org.jtoolkit.essence.utils.impl.MapArray;
17import static org.jtoolkit.essence.utils.impl.MapArray.*;
18import org.jtoolkit.essence.utils.impl.SameHashMap;
19 
20import java.io.*;
21import java.lang.reflect.Constructor;
22import java.math.BigDecimal;
23import java.math.BigInteger;
24import java.util.*;
25import java.util.concurrent.ConcurrentHashMap;
26import java.util.concurrent.ConcurrentMap;
27 
28/*
29   Copyright 2006 Peter Lawrey
30 
31   Licensed under the Apache License, Version 2.0 (the "License");
32   you may not use this file except in compliance with the License.
33   You may obtain a copy of the License at
34 
35       http://www.apache.org/licenses/LICENSE-2.0
36 
37   Unless required by applicable law or agreed to in writing, software
38   distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
39   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40   See the License for the specific language governing permissions and
41   limitations under the License.
42*/
43 
44/**
45 * @author Peter Lawrey
46 */
47@NotThreadSafe
48@SuppressWarnings({"unchecked", "OverlyCoupledClass"})
49public class DatableUtils {
50    private static final int PROTOCOL_VERSION = 0xDa4ab1e1;
51    private static final long BER_MASK = 0x7F;
52    private static final int BYTE_HIGH_BIT = 0x80;
53    private static final int LONG_BER_SIZE = 11;
54    public static final Class[] BASE_CLASSES = {
55            Boolean.class, Byte.class, Character.class, Short.class, Integer.class, Float.class, Double.class, Long.class,
56            Class.class, BigInteger.class, BigDecimal.class, Boolean.class, String.class
57    };
58    private static final Map<Class, Integer> IS_BASE_CLASS = asKeys(BASE_CLASSES);
59 
60    private static final Class[] DATA_INPUT_CLASS = {DataInput.class};
61    private static final Log LOG = getLog(DatableUtils.class);
62    private static final Map<Class, Mapping<DataInput, Object>> BUILDERS = new ConcurrentHashMap<Class, Mapping<DataInput, Object>>(256, 0.5f, 16);
63    private static final ConcurrentMap<DataInput, InStreamStatus> IN_STREAM_STATUS =
64            new ConcurrentHashMap<DataInput, InStreamStatus>(256, 0.5f, 16);
65    private static final ConcurrentMap<DataOutput, OutStreamStatus> OUT_STREAM_STATUS =
66            new ConcurrentHashMap<DataOutput, OutStreamStatus>(256, 0.5f, 16);
67    private static final int PRUNE_SIZE = 512;
68 
69    private static final int PRUNE = 'p';
70    private static final int OLD_OBJECT = 'o';
71    private static final int NEW_OBJECT = 'n';
72    private static final Formats[] FORMATS = Formats.values();
73 
74    @SuppressWarnings({"SuspiciousMethodCalls"})
75    public static void close(Closeable closeable) {
76        IN_STREAM_STATUS.remove(closeable);
77        OUT_STREAM_STATUS.remove(closeable);
78    }
79 
80    enum Formats {
81        NULL,
82        BASE,
83        BYTES_ARRAY,
84        CHARACTER,
85        DATE,
86        DATABLE,
87        DATA_VALUE,
88        INTEGER,
89        LIST,
90        LONG,
91        MAP,
92        OBJECT_ARRAY,
93        SERIALIZABLE,
94        SET,
95        SORTED_MAP,
96        SORTED_SET,
97        STRING,
98        STRING_ARRAY,
99    }
100 
101    private DatableUtils() {
102    }
103 
104    /**
105     * Convert byte[] to a number of Object.  Limits on the number of expected objects can be given.
106     */
107    public static Object[] fromBytes(byte[] bytes, int min, int max) throws IOException {
108        DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
109        Object[] ret = readObjects(in, min, max);
110        IOUtils.close(in);
111        return ret;
112    }
113 
114    public static void prune(DataOutput out) {
115        OutStreamStatus streamStatus = OUT_STREAM_STATUS.get(out);
116        if (streamStatus != null) streamStatus.setPruneTrue();
117    }
118 
119    public static long readBER(DataInput in) throws IOException {
120        long num = 0;
121        // long values should not be more than 11 bytes long.
122        for (int i = 0; i < LONG_BER_SIZE; i++) {
123            int b = in.readUnsignedByte();
124            // negative number.
125            if (i > 0 && b == 0) return ~num;
126            num |= (b & BER_MASK) << 7 * i;
127            if (b < BYTE_HIGH_BIT) break;
128        }
129        return num;
130    }
131 
132    @Nullable
133    private static Object readBaseObject(DataInput in) throws IOException {
134        int type = in.readUnsignedByte();
135        if (type >= BASE_CLASSES.length)
136            throw new StreamCorruptedException("Unknown base type " + type + " last is " + (BASE_CLASSES.length - 1));
137        String text = readByteString(in);
138        return DataValueClass.cast(BASE_CLASSES[type], text);
139    }
140 
141    @SuppressWarnings("deprecation")
142    private static String readByteString(DataInput in) throws IOException {
143        return new String(readBytesArray(in), 0);
144    }
145 
146    private static Object readDataValue(InStreamStatus iss, DataInput in) throws Exception {
147        Class clazz = (Class) readObject(iss, in);
148        Mapping<DataInput, Object> builder = BUILDERS.get(clazz);
149        if (builder != null) return builder.convert(in);
150 
151        Object[] objs = readObjects(in, 0, Integer.MAX_VALUE);
152        return build(clazz, MapArray.<String, Object>toMap(objs), PojoContext.EMPTY);
153    }
154 
155    private static Object readList(DataInput in) throws IOException {
156        List list = Arrays.asList(readObjects(in, 0, Integer.MAX_VALUE));
157        return immutableWrap(list);
158    }
159 
160    private static Object readMap(DataInput in) throws IOException {
161        Map map = toMap(readObjects(in, 0, Integer.MAX_VALUE));
162        return immutableWrap(map);
163    }
164 
165    /**
166     * Read a number of objects from in.  Limits on the number of expected objects can be given. min and max can be 0 and Integer.MAX_INT respectly.
167     */
168    @NotNull
169    public static Object[] readObjects(@NotNull DataInput in, int min, int max) throws IOException {
170        InStreamStatus iss = acquireStreamStatus(in);
171        int objectCount = readLen(in, min, max);
172 
173        Object[] objects = new Object[objectCount];
174        for (int i = 0; i < objectCount; i++) {
175            objects[i] = readObject(iss, in);
176        }
177        return objects;
178    }
179 
180    public static Object readObject(DataInput in) throws IOException {
181        InStreamStatus iss = acquireStreamStatus(in);
182        return readObject(iss, in);
183    }
184 
185    private static Object readObject(InStreamStatus iss, DataInput in) throws IOException {
186        int type = in.readUnsignedByte();
187        if (type == PRUNE) {
188            iss.pruneTo((int) readBER(in));
189            type = (int) readBER(in);
190        }
191        int objNum = (int) readBER(in);
192        if (type == OLD_OBJECT) {
193            return iss.get(objNum);
194        } else if (type == NEW_OBJECT) {
195            Object obj = readObject0(iss, in);
196            iss.set(objNum, obj);
197            return obj;
198        }
199        throw new StreamCorruptedException("Unknown type " + type + " object num=" + objNum);
200    }
201 
202    @SuppressWarnings({"MethodWithMultipleReturnPoints", "OverlyComplexMethod"})
203    private static Object readObject0(InStreamStatus iss, DataInput in) throws IOException {
204        int formatByte = in.readUnsignedByte();
205        if (formatByte >= FORMATS.length)
206            throw new StreamCorruptedException("Illegal format " + formatByte + " last format is " + (FORMATS.length - 1));
207        Formats format = FORMATS[formatByte];
208        // if a builder has been defined.
209        try {
210            switch (format) {
211                case BASE:
212                    return readBaseObject(in);
213 
214                case BYTES_ARRAY:
215                    return readBytesArray(in);
216 
217                case CHARACTER:
218                    return in.readChar();
219 
220                case DATABLE:
221                    return readDatable(iss, in);
222 
223                case DATA_VALUE:
224                    return readDataValue(iss, in);
225 
226                case DATE:
227                    return new Date(in.readLong());
228 
229                case INTEGER:
230                    return (int) readBER(in);
231 
232                case LIST:
233                    return readList(in);
234 
235                case LONG:
236                    return readBER(in);
237 
238                case MAP:
239                    return readMap(in);
240 
241                case SORTED_MAP:
242                    return readSortedMap(iss, in);
243 
244                case NULL:
245                    return null;
246 
247                case OBJECT_ARRAY:
248                    return readObjects(in, 0, Integer.MAX_VALUE);
249 
250                case STRING_ARRAY:
251                    return readStringArray(in);
252 
253                case SERIALIZABLE:
254                    return readSerializable(in);
255 
256                case SET:
257                    return readSet(in);
258 
259                case SORTED_SET:
260                    return readSortedSet(iss, in);
261 
262                case STRING:
263                    return in.readUTF();
264            }
265            throw new NotSerializableException(format.toString());
266        } catch (IOException ie) {
267            throw ie;
268        } catch (Throwable e) {
269            Throwable e2 = e;
270            if (e2 instanceof InstantiationException) e2 = e2.getCause();
271            NotSerializableException se = new NotSerializableException(format.toString() + ' ' + e2);
272            se.initCause(e2);
273            throw se;
274        }
275    }
276 
277    private static Object readSet(DataInput in) throws IOException {
278        Set set = new LinkedHashSet(Arrays.asList(readObjects(in, 0, Integer.MAX_VALUE)));
279        return immutableWrap(set);
280    }
281 
282    private static Object readSerializable(DataInput in) throws IOException, ClassNotFoundException {
283        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(readBytesArray(in)));
284        return ois.readObject();
285    }
286 
287    private static Object readSortedMap(InStreamStatus iss, DataInput in) throws IOException {
288        Comparator comparator = (Comparator) readObject(iss, in);
289        SortedMap smap = new TreeMap(comparator);
290        Map map = toMap(readObjects(in, 0, Integer.MAX_VALUE));
291        smap.putAll(map);
292        return smap;
293    }
294 
295    private static Object readSortedSet(InStreamStatus iss, DataInput in) throws IOException {
296        Comparator comparator = (Comparator) readObject(iss, in);
297        SortedSet set = new TreeSet(comparator);
298        set.addAll(Arrays.asList(readObjects(in, 0, Integer.MAX_VALUE)));
299        return immutableWrap(set);
300    }
301 
302    private static Object readStringArray(DataInput in) throws IOException {
303        Object[] objects = readObjects(in, 0, Integer.MAX_VALUE);
304        String[] strings = new String[objects.length];
305        //noinspection SuspiciousSystemArraycopy
306        System.arraycopy(objects, 0, strings, 0, objects.length);
307        return objects;
308    }
309 
310    private static byte[] readBytesArray(DataInput in) throws IOException {
311        int len = (int) readBER(in);
312        byte[] bytes = new byte[len];
313        in.readFully(bytes);
314        return bytes;
315    }
316 
317    private static Object readDatable(InStreamStatus iss, DataInput in) throws Exception {
318        Class clazz = (Class) readObject(iss, in);
319        if (clazz == null)
320            throw new NotSerializableException("Cannot read null datable");
321        byte[] bytes = readBytesArray(in);
322        DataInputStream in2 = new DataInputStream(new ByteArrayInputStream(bytes));
323        IN_STREAM_STATUS.put(in2, iss);
324        Mapping<DataInput, Object> builder = BUILDERS.get(clazz);
325        Object ret;
326        if (builder == null) {
327            Constructor cons = clazz.getDeclaredConstructor(DATA_INPUT_CLASS);
328            cons.setAccessible(true);
329            ret = cons.newInstance(in2);
330        } else {
331            ret = builder.convert(in2);
332        }
333        IN_STREAM_STATUS.remove(in2);
334        return ret;
335    }
336 
337    public static <T> void registerBuilder(Class<T> clazz, Mapping<DataInput, T> builder) {
338        BUILDERS.put(clazz, (Mapping) builder);
339    }
340 
341    /**
342     * Convert a number of object (collectively) to a byte[]. Can be decoded with fromBytes()
343     */
344    @NotNull
345    public static byte[] toBytes(Object... object) throws IOException {
346        ByteArrayOutputStream baos = new ByteArrayOutputStream();
347        DataOutputStream out = new DataOutputStream(baos);
348        writeObjects(out, object);
349        IOUtils.close(out);
350        return baos.toByteArray();
351    }
352 
353    public static void writeBER(DataOutput out, long v) throws IOException {
354        if (v >= 0) {
355            if (v < 1 << 7) {
356                out.write((int) v);
357                return;
358            }
359            if (v < 1 << 14) {
360                out.write((int) v | BYTE_HIGH_BIT);
361                out.write((int) v >>> 7);
362                return;
363            }
364        }
365 
366        long num = v < 0 ? ~v : v;
367 
368        // always write at least one byte.
369        byte[] buffer = new byte[LONG_BER_SIZE];
370        buffer[0] = (byte) (num & BER_MASK);
371        int ptr = 1;
372        while (num > BER_MASK) {
373            num >>>= 7;
374            buffer[ptr++] = (byte) (num & BER_MASK);
375        }
376        // a number with more than 1 byte would never normaly end with a 0.
377        // This is used to signifiy the number was negative.
378        if (v < 0)
379            buffer[ptr++] = 0;
380 
381        // set the top bit for all but the last byte.
382        for (int i = 0; i < ptr - 1; i++) {
383            buffer[i] |= BYTE_HIGH_BIT;
384        }
385        out.write(buffer, 0, ptr);
386    }
387 
388    private static void writeByteString(DataOutput out, String s) throws IOException {
389        int len = s.length();
390        char[] chars = new char[len];
391        s.getChars(0, len, chars, 0);
392        byte[] bytes = new byte[len];
393        for (int i = 0; i < len; i++) {
394            char ch = chars[i];
395            if (ch > 255)
396                throw new NotSerializableException("Cannot write byte string with char > 255, was " + s);
397            bytes[i] = (byte) ch;
398        }
399        writeBER(out, len);
400        out.write(bytes);
401    }
402 
403    /**
404     * Write a number of objects to the output stream.
405     */
406    public static void writeObjects(@NotNull DataOutput out, Object... datables) throws IOException {
407        OutStreamStatus oss = acquireStreamStatus(out);
408        writeBER(out, datables.length);
409        for (Object datable : datables)
410            writeObject(oss, out, datable);
411    }
412 
413    public static void writeObject(DataOutput out, Object datable) throws IOException {
414        OutStreamStatus oss = acquireStreamStatus(out);
415        writeObject(oss, out, datable);
416    }
417 
418    @SuppressWarnings({"OverlyComplexMethod", "OverlyCoupledMethod", "OverlyLongMethod"})
419    private static void writeObject(OutStreamStatus oss, DataOutput out, Object datable) throws IOException {
420        datable = tryImmutableCopy(datable);
421        if (datable != null && !ImmutableUtils.isImmutable(datable.getClass()) && !(datable instanceof Serializable))
422            throw new NotSerializableException("Unable to make not @Immutable and is not Serializable " + datable.getClass());
423        Integer num = oss.getNumber(datable);
424        if (num != null) {
425            out.writeByte(OLD_OBJECT);
426            writeBER(out, num);
427            return;
428        }
429        if (oss.getAndClearPrune() && oss.size() > PRUNE_SIZE * 2) {
430            out.writeByte(PRUNE);
431            int pruneTo = oss.prune(PRUNE_SIZE);
432            writeBER(out, pruneTo);
433        }
434        // negative means this is a new object!
435        out.writeByte(NEW_OBJECT);
436        writeBER(out, oss.allocateNumber(datable));
437        if (datable == null) {
438            out.writeByte(Formats.NULL.ordinal());
439            return;
440        }
441 
442        Class clazz = datable.getClass();
443        if (clazz == Character.class) {
444            out.writeByte(Formats.CHARACTER.ordinal());
445            out.writeChar((Character) datable);
446            return;
447        }
448        if (clazz == Date.class) {
449            out.writeByte(Formats.DATE.ordinal());
450            out.writeLong(((Date) datable).getTime());
451            return;
452        }
453        if (clazz == Integer.class) {
454            out.writeByte(Formats.INTEGER.ordinal());
455            writeBER(out, (Integer) datable);
456            return;
457        }
458        if (clazz == Long.class) {
459            out.writeByte(Formats.LONG.ordinal());
460            writeBER(out, (Long) datable);
461            return;
462        }
463        if (clazz == String.class) {
464            out.writeByte(Formats.STRING.ordinal());
465            out.writeUTF((String) datable);
466            return;
467        }
468        if (IS_BASE_CLASS.containsKey(clazz)) {
469            out.writeByte(Formats.BASE.ordinal());
470 
471            int type = IS_BASE_CLASS.get(clazz);
472            out.writeByte(type);
473            writeByteString(out, clazz == Class.class ? ((Class) datable).getName() : datable.toString());
474        } else if (datable instanceof SortedMap) {
475            out.writeByte(Formats.SORTED_MAP.ordinal());
476 
477            writeObject(oss, out, ((SortedMap) datable).comparator());
478            writeObjects(out, asArray((Map) datable));
479        } else if (datable instanceof Map) {
480            out.writeByte(Formats.MAP.ordinal());
481 
482            writeObjects(out, asArray((Map) datable));
483        } else if (datable instanceof SortedSet) {
484            out.writeByte(Formats.SORTED_SET.ordinal());
485 
486            writeObject(oss, out, ((SortedSet) datable).comparator());
487            writeObjects(out, ((Collection) datable).toArray());
488        } else if (datable instanceof List) {
489            out.writeByte(Formats.LIST.ordinal());
490 
491            writeObjects(out, ((Collection) datable).toArray());
492        } else if (datable instanceof Set) {
493            out.writeByte(Formats.SET.ordinal());
494 
495            writeObjects(out, ((Collection) datable).toArray());
496        } else if (datable instanceof Datable) {
497            out.writeByte(Formats.DATABLE.ordinal());
498 
499            writeObject(oss, out, clazz);
500            ByteArrayOutputStream baos = new ByteArrayOutputStream();
501            DataOutputStream out2 = new DataOutputStream(baos);
502            OUT_STREAM_STATUS.put(out2, OUT_STREAM_STATUS.get(out));
503            ((Datable) datable).writeData(out2);
504            OUT_STREAM_STATUS.remove(out2);
505            byte[] bytes = baos.toByteArray();
506 
507            writeBER(out, bytes.length);
508            out.write(bytes);
509 
510        } else if (datable instanceof DataValue) {
511            out.writeByte(Formats.DATA_VALUE.ordinal());
512 
513            writeObject(oss, out, clazz);
514            writeObjects(out, asArray(((DataValue) datable).asMap()));
515        } else if (clazz == Object[].class) {
516            out.writeByte(Formats.OBJECT_ARRAY.ordinal());
517 
518            writeObjects(out, (Object[]) datable);
519        } else if (clazz == String[].class) {
520            out.writeByte(Formats.STRING_ARRAY.ordinal());
521 
522            writeObjects(out, (Object[]) datable);
523        } else if (clazz == byte[].class) {
524            out.writeByte(Formats.BYTES_ARRAY.ordinal());
525 
526            byte[] bytes = (byte[]) datable;
527            writeBER(out, bytes.length);
528            out.write(bytes);
529        } else if (datable instanceof Serializable) {
530            out.writeByte(Formats.SERIALIZABLE.ordinal());
531 
532            if (LOG.isDebugEnabled()) LOG.debug(Thread.currentThread().getName() + ": Serializing " + clazz);
533            ByteArrayOutputStream baos = new ByteArrayOutputStream();
534            ObjectOutputStream oos = new ObjectOutputStream(baos);
535            oos.writeObject(datable);
536            oos.close();
537            byte[] bytes = baos.toByteArray();
538            writeBER(out, bytes.length);
539            out.write(bytes);
540        } else {
541            throw new NotSerializableException(clazz.getName());
542        }
543    }
544 
545    private static int readLen(DataInput in, int min, int max) throws IOException {
546        int objectCount = (int) readBER(in);
547        if (objectCount < min || objectCount > max)
548            throw new IllegalArgumentException("Expected [" + min + ',' + max + "] arguments, got " + objectCount);
549        return objectCount;
550    }
551 
552//    private static long last = System.currentTimeMillis();
553 
554    private static InStreamStatus acquireStreamStatus(DataInput stream) throws IOException {
555        InStreamStatus streamStatus = IN_STREAM_STATUS.get(stream);
556        if (streamStatus == null) {
557            IN_STREAM_STATUS.putIfAbsent(stream, new InStreamStatus(stream));
558            streamStatus = IN_STREAM_STATUS.get(stream);
559        }
560        return streamStatus;
561    }
562 
563    static class InStreamStatus {
564        private final List<Object> objects = new ArrayList<Object>(Arrays.asList(OBJECT_DICT));
565        private int offset = 0;
566 
567        InStreamStatus(DataInput in) throws IOException {
568            int protocolVersion = in.readInt();
569            if (protocolVersion >>> 4 != PROTOCOL_VERSION >>> 4)
570                throw new StreamCorruptedException("Not a Datable protocol " + Integer.toHexString(protocolVersion));
571            if (protocolVersion != PROTOCOL_VERSION)
572                throw new StreamCorruptedException("Unsupported Datable protocol " + Integer.toHexString(protocolVersion));
573        }
574 
575        public Object get(int objNum) throws StreamCorruptedException {
576            if (objNum < 0)
577                throw new StreamCorruptedException("Cannot reference a negative object " + objNum);
578            if (objNum < offset)
579                throw new StreamCorruptedException("Cannot reference a pruned object " + objNum);
580            objNum -= offset;
581            return objects.get(objNum);
582        }
583 
584        public void set(int objNum, Object obj) {
585            objNum -= offset;
586            while (objects.size() < objNum)
587                objects.add(null);
588            if (objects.size() == objNum)
589                objects.add(obj);
590            else
591                objects.set(objNum, obj);
592        }
593 
594        public void pruneTo(int pruneTo) {
595            if (pruneTo < offset) return;
596            Object[] objectsArr = objects.toArray();
597            objects.clear();
598            int toRemove = pruneTo - offset;
599            for (int i = toRemove + 1; i < objectsArr.length; i++)
600                objects.add(objectsArr[i]);
601            offset = pruneTo + 1;
602        }
603    }
604 
605    private static OutStreamStatus acquireStreamStatus(DataOutput stream) throws IOException {
606        OutStreamStatus streamStatus = OUT_STREAM_STATUS.get(stream);
607        if (streamStatus == null) {
608            OUT_STREAM_STATUS.putIfAbsent(stream, new OutStreamStatus(stream));
609            streamStatus = OUT_STREAM_STATUS.get(stream);
610        }
611        return streamStatus;
612    }
613 
614    public static final Object[] OBJECT_DICT = {null, true, false, "", LinkedHashMap.class, HashMap.class};
615 
616    static class OutStreamStatus {
617        private final SameHashMap<Object, Integer> objectToNumber = new SameHashMap<Object, Integer>();
618        private boolean prune = false;
619        private int counter;
620 
621        OutStreamStatus(DataOutput out) throws IOException {
622            out.writeInt(PROTOCOL_VERSION);
623            for (int i = 0; i < OBJECT_DICT.length; i++)
624                objectToNumber.put(OBJECT_DICT[i], i);
625            counter = OBJECT_DICT.length;
626        }
627 
628        public Integer getNumber(Object datable) {
629            return objectToNumber.get(datable);
630        }
631 
632        public int size() {
633            return objectToNumber.size();
634        }
635 
636        public int prune(int pruneSize) {
637            return objectToNumber.prune(pruneSize);
638        }
639 
640        public int allocateNumber(Object datable) {
641            objectToNumber.put(datable, counter);
642            return counter++;
643        }
644 
645        public boolean getAndClearPrune() {
646            boolean prune = this.prune;
647            this.prune = false;
648            return prune;
649        }
650 
651        public void setPruneTrue() {
652            prune = true;
653        }
654    }
655}

[all classes][org.jtoolkit.essence.app.pojo]
EMMA 2.0.5312 (C) Vladimir Roubtsov