KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > DataCellSerialization


1 /**
2  * com.mckoi.database.DataCellSerialization 07 Dec 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import com.mckoi.database.global.*;
28 import com.mckoi.util.BigNumber;
29 import java.util.zip.*;
30 import java.util.Date JavaDoc;
31 import java.math.*;
32 import java.io.*;
33
34 /**
35  * An object that manages the serialization and deserialization of objects
36  * to the database file system. This object maintains a buffer that stores
37  * intermediate serialization information as objects are written.
38  *
39  * @author Tobias Downer
40  */

41
42 final class DataCellSerialization extends ByteArrayOutputStream
43                                                         implements CellInput {
44
45   /**
46    * A Deflater and Inflater used to compress and uncompress the size of data
47    * fields put into the store.
48    */

49   private Deflater deflater;
50   private Inflater inflater;
51   private byte[] compress_buf;
52   private int compress_length;
53
54   /**
55    * If true, when writing out use the compressed form.
56    */

57   private boolean use_compressed;
58
59   /**
60    * The type of object.
61    */

62   private short type;
63
64   /**
65    * Set to true if null.
66    */

67   private boolean is_null;
68
69   /**
70    * Constructor.
71    */

72   DataCellSerialization() {
73     super(1024);
74   }
75
76
77   /**
78    * Returns the number of bytes to skip on the stream to go past the
79    * next serialization.
80    */

81   int skipSerialization(CellInput din) throws IOException {
82     int len = din.readInt();
83     return len - 4;
84   }
85
86   /**
87    * Reads input from the given CellInput object.
88    */

89   Object JavaDoc readSerialization(CellInput din) throws IOException {
90
91     count = 0;
92
93     // Read the length first,
94
int len = din.readInt();
95     short s = din.readShort();
96     type = (short) (s & 0x0FFF);
97     is_null = (s & 0x02000) != 0;
98     use_compressed = (s & 0x04000) != 0;
99
100     // If we are compressed...
101
if (use_compressed) {
102       // Uncompress it,
103
int uncompressed_len = din.readInt();
104       if (buf.length < uncompressed_len) {
105         buf = new byte[uncompressed_len];
106       }
107
108       // Write data to the compressed buffer
109
compress_length = len - 4 - 2 - 4;
110       if (compress_buf == null || compress_buf.length < compress_length) {
111         compress_buf = new byte[compress_length];
112       }
113       din.readFully(compress_buf, 0, compress_length);
114
115       if (inflater == null) {
116         inflater = new Inflater();
117       }
118       inflater.reset();
119       inflater.setInput(compress_buf, 0, compress_length);
120       int inflate_count;
121       try {
122         inflate_count = inflater.inflate(buf, 0, uncompressed_len);
123       }
124       catch (DataFormatException e) {
125         throw new RuntimeException JavaDoc(e.getMessage());
126       }
127
128       din = this;
129
130     }
131
132     return readFromCellInput(din);
133   }
134
135   /**
136    * Creates a BigNumber object used to store a numeric value in the database.
137    */

138   private BigNumber createBigNumber(byte[] buf, int scale, byte state) {
139     // Otherwise generate the number from the data given.
140
return BigNumber.fromData(buf, scale, state);
141   }
142
143   /**
144    * Reads an object from the given CellInput. No type information is included
145    * with the returned object so it must be wrapped in a TObject. Returns
146    * null if the object stored was null.
147    */

148   private Object JavaDoc readFromCellInput(CellInput din) throws IOException {
149
150     // If null byte is 1 then return null data cell.
151
if (is_null) {
152       return null;
153     }
154     else {
155       // This type isn't actually serialized anymore, but we must understand
156
// how to deserialize it because of older database formats.
157
if (type == Types.DB_NUMERIC) {
158         int scale = din.readShort();
159         int num_len = din.readInt();
160         byte[] buf = new byte[num_len];
161         din.readFully(buf, 0, num_len);
162
163         return createBigNumber(buf, scale, (byte) 0);
164       }
165       else if (type == Types.DB_NUMERIC_EXTENDED) {
166         byte state = din.readByte();
167         int scale = din.readShort();
168         int num_len = din.readInt();
169         byte[] buf = new byte[num_len];
170         din.readFully(buf, 0, num_len);
171
172         return createBigNumber(buf, scale, state);
173       }
174       else if (type == Types.DB_STRING) {
175         int str_length = din.readInt();
176         // No length string is a static to save memory.
177
if (str_length == 0) {
178           return "";
179         }
180
181         String JavaDoc dastr = din.readChars(str_length);
182         // NOTE: We intern the string to save memory.
183
return dastr.intern();
184       }
185       else if (type == Types.DB_BOOLEAN) {
186         if (din.readByte() == 0) {
187           return Boolean.FALSE;
188         }
189         else {
190           return Boolean.TRUE;
191         }
192       }
193       else if (type == Types.DB_TIME) {
194         return new java.util.Date JavaDoc(din.readLong());
195       }
196       else if (type == Types.DB_BLOB) {
197         int blob_length = din.readInt();
198         // Intern to save memory
199
if (blob_length == 0) {
200           return EMPTY_BYTE_LONG_OBJECT;
201         }
202
203         byte[] buf = new byte[blob_length];
204         din.readFully(buf, 0, blob_length);
205
206         return new ByteLongObject(buf);
207       }
208       else if (type == Types.DB_OBJECT) {
209         int blob_length = din.readInt();
210
211         byte[] buf = new byte[blob_length];
212         din.readFully(buf, 0, blob_length);
213         
214         return new ByteLongObject(buf);
215       }
216       else {
217         throw new Error JavaDoc("Don't understand type: " + type);
218       }
219
220     }
221
222   }
223
224   /**
225    * Writes the current serialized data buffer to the output stream.
226    */

227   void writeSerialization(DataOutputStream out) throws IOException {
228     int len = use_compressed ? (compress_length + 4) : count;
229     // size + (type | null | compressed)
230
len += 4 + 2;
231     out.writeInt(len);
232     short s = type;
233     if (is_null) {
234       s |= 0x02000;
235     }
236     if (use_compressed) {
237       s |= 0x04000;
238     }
239     out.writeShort(s);
240
241     // Write out the data.
242
if (use_compressed) {
243       // If compressed, must write out uncompressed size first.
244
out.writeInt(count);
245       out.write(compress_buf, 0, compress_length);
246     }
247     else {
248       out.write(buf, 0, count);
249     }
250
251     // And that's it!
252
}
253
254   /**
255    * Sets this up with a TObject to serialize.
256    */

257   void setToSerialize(TObject cell) throws IOException {
258
259     is_null = false;
260     count = 0;
261     use_compressed = false;
262
263     TType ttype = cell.getTType();
264     if (ttype instanceof TStringType) {
265       type = Types.DB_STRING;
266     }
267     else if (ttype instanceof TNumericType) {
268       // NOTE: We set type to DB_NUMERIC_EXTENDED which includes support for
269
// NaN, negative infinity and positive infinity.
270
type = Types.DB_NUMERIC_EXTENDED;
271     }
272     else if (ttype instanceof TBooleanType) {
273       type = Types.DB_BOOLEAN;
274     }
275     else if (ttype instanceof TDateType) {
276       type = Types.DB_TIME;
277     }
278     else if (ttype instanceof TBinaryType) {
279       type = Types.DB_BLOB;
280     }
281     else if (ttype instanceof TJavaObjectType) {
282       type = Types.DB_OBJECT;
283     }
284     else {
285       throw new Error JavaDoc("Couldn't handle type: " + ttype.getClass());
286     }
287
288     if (cell.isNull()) {
289       is_null = true;
290       return;
291     }
292
293     Object JavaDoc ob = cell.getObject();
294
295     // Write the serialized form to the buffer,
296
writeToBuffer(cell);
297
298     // Should we compress?
299

300     // If it's a string, blob or serialized object, we may want to compress it,
301
TType type = cell.getTType();
302     if (type instanceof TStringType ||
303         type instanceof TBinaryType ||
304         type instanceof TJavaObjectType) {
305       int length = count;
306       // Any strings > 150 are compressed
307
if (length > 150) {
308
309         if (deflater == null) {
310           deflater = new Deflater();
311         }
312
313         deflater.setInput(buf, 0, length);
314         deflater.finish();
315
316         if (compress_buf == null || compress_buf.length < length) {
317           compress_buf = new byte[length];
318         }
319         compress_length = deflater.deflate(compress_buf);
320         deflater.reset();
321
322         if (compress_length < length) {
323           use_compressed = true;
324         }
325       }
326     }
327
328   }
329
330   /**
331    * Writes the TObject to the data buffer in this object.
332    */

333   private void writeToBuffer(TObject cell) throws IOException {
334
335     Object JavaDoc ob = cell.getObject();
336
337     if (ob instanceof BigNumber) {
338       BigNumber ddc = (BigNumber) ob;
339       byte[] buf = ddc.toByteArray();
340       writeByte(ddc.getState());
341       writeShort((short) ddc.getScale());
342       writeInt(buf.length);
343       write(buf);
344     }
345     else if (ob instanceof String JavaDoc) {
346       String JavaDoc str = (String JavaDoc) ob;
347       writeInt(str.length());
348       writeChars(str);
349     }
350     else if (ob instanceof Boolean JavaDoc) {
351       Boolean JavaDoc bool = (Boolean JavaDoc) ob;
352       writeByte((byte) (bool.booleanValue() ? 1 : 0));
353     }
354     else if (ob instanceof java.util.Date JavaDoc) {
355       Date JavaDoc date = (Date JavaDoc) ob;
356       writeLong(date.getTime());
357     }
358     else if (ob instanceof ByteLongObject) {
359       ByteLongObject blob = (ByteLongObject) ob;
360       writeInt(blob.length());
361       write(blob.getByteArray());
362     }
363     else {
364       throw new Error JavaDoc("Don't know how to serialize class " + ob.getClass());
365     }
366
367   }
368
369   public final void writeBoolean(boolean v) throws IOException {
370     write(v ? 1 : 0);
371   }
372
373   public final void writeByte(int v) throws IOException {
374     write(v);
375   }
376
377   public final void writeShort(int v) throws IOException {
378     write((v >>> 8) & 0xFF);
379     write((v >>> 0) & 0xFF);
380   }
381
382   public final void writeChar(int v) throws IOException {
383     write((v >>> 8) & 0xFF);
384     write((v >>> 0) & 0xFF);
385   }
386
387   public final void writeInt(int v) throws IOException {
388     write((v >>> 24) & 0xFF);
389     write((v >>> 16) & 0xFF);
390     write((v >>> 8) & 0xFF);
391     write((v >>> 0) & 0xFF);
392   }
393
394   public final void writeLong(long v) throws IOException {
395     write((int)(v >>> 56) & 0xFF);
396     write((int)(v >>> 48) & 0xFF);
397     write((int)(v >>> 40) & 0xFF);
398     write((int)(v >>> 32) & 0xFF);
399     write((int)(v >>> 24) & 0xFF);
400     write((int)(v >>> 16) & 0xFF);
401     write((int)(v >>> 8) & 0xFF);
402     write((int)(v >>> 0) & 0xFF);
403   }
404
405   public final void writeChars(String JavaDoc s) throws IOException {
406     int len = s.length();
407     for (int i = 0 ; i < len ; ++i) {
408       int v = s.charAt(i);
409       write((v >>> 8) & 0xFF);
410       write((v >>> 0) & 0xFF);
411     }
412   }
413
414
415
416   // ---------- Implemented from CellInput ----------
417

418   public int read() throws IOException {
419     return buf[count++] & 0x0FF;
420   }
421
422   public int read(byte b[], int off, int len) throws IOException {
423     if (len <= 0) {
424       return 0;
425     }
426     System.arraycopy(buf, count, b, off, len);
427     count += len;
428     return len;
429   }
430
431   public long skip(long n) throws IOException {
432     if (n < 0) {
433       return 0;
434     }
435     count += n;
436     return n;
437   }
438
439   public int available() throws IOException {
440     throw new Error JavaDoc("Not supported");
441   }
442
443   public void mark(int readAheadLimit) throws IOException {
444     throw new Error JavaDoc("Not supported");
445   }
446
447 // [ Function clash here but it should be okay ]
448
// public void reset() throws IOException {
449
// throw new Error("Not supported");
450
// }
451

452   public void close() throws IOException {
453     throw new Error JavaDoc("Not supported");
454   }
455
456
457   // ---------- Implemented from DataInput ----------
458

459   public void readFully(byte[] b) throws IOException {
460     read(b, 0, b.length);
461   }
462
463   public void readFully(byte b[], int off, int len) throws IOException {
464     read(b, off, len);
465   }
466
467   public int skipBytes(int n) throws IOException {
468     return (int) skip(n);
469   }
470
471   public boolean readBoolean() throws IOException {
472     return (read() != 0);
473   }
474
475   public byte readByte() throws IOException {
476     return (byte) read();
477   }
478
479   public int readUnsignedByte() throws IOException {
480     return read();
481   }
482
483   public short readShort() throws IOException {
484     int ch1 = read();
485     int ch2 = read();
486     return (short)((ch1 << 8) + (ch2 << 0));
487   }
488
489   public int readUnsignedShort() throws IOException {
490     int ch1 = read();
491     int ch2 = read();
492     return (ch1 << 8) + (ch2 << 0);
493   }
494
495   public char readChar() throws IOException {
496     int ch1 = read();
497     int ch2 = read();
498     return (char)((ch1 << 8) + (ch2 << 0));
499   }
500
501   private char[] char_buffer;
502
503   public String JavaDoc readChars(int length) throws IOException {
504     if (length <= 8192) {
505       if (char_buffer == null) {
506         char_buffer = new char[8192];
507       }
508       for (int i = 0; i < length; ++i) {
509         char_buffer[i] = readChar();
510       }
511       return new String JavaDoc(char_buffer, 0, length);
512     }
513     else {
514       StringBuffer JavaDoc chrs = new StringBuffer JavaDoc(length);
515       for (int i = length; i > 0; --i) {
516         chrs.append(readChar());
517       }
518       return new String JavaDoc(chrs);
519     }
520   }
521
522   public int readInt() throws IOException {
523     int ch1 = read();
524     int ch2 = read();
525     int ch3 = read();
526     int ch4 = read();
527     return (int)((ch1 << 24) + (ch2 << 16) +
528                  (ch3 << 8) + (ch4 << 0));
529   }
530
531   public long readLong() throws IOException {
532     return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
533   }
534
535   public float readFloat() throws IOException {
536     return Float.intBitsToFloat(readInt());
537   }
538
539   public double readDouble() throws IOException {
540     return Double.longBitsToDouble(readLong());
541   }
542
543   public String JavaDoc readLine() throws IOException {
544     throw new Error JavaDoc("Not implemented.");
545   }
546
547   public String JavaDoc readUTF() throws IOException {
548     throw new Error JavaDoc("Not implemented.");
549   }
550
551   // ---------- Some statics -----------
552

553   /**
554    * A 0 size ByteLongObject object.
555    */

556   private static final ByteLongObject EMPTY_BYTE_LONG_OBJECT =
557                                             new ByteLongObject(new byte[0]);
558
559 }
560
Popular Tags