KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > util > io > ObjectOutputStream


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: ObjectOutputStream.java 1096 2004-03-26 21:41:16Z dblevins $
44  */

45 package org.openejb.util.io;
46
47
48 import java.io.Externalizable JavaDoc;
49 import java.io.IOException JavaDoc;
50 import java.io.InvalidClassException JavaDoc;
51 import java.io.NotSerializableException JavaDoc;
52 import java.io.ObjectOutput JavaDoc;
53 import java.io.ObjectStreamConstants JavaDoc;
54 import java.io.OutputStream JavaDoc;
55 import java.io.Serializable JavaDoc;
56 import java.lang.reflect.Field JavaDoc;
57 import java.util.ArrayList JavaDoc;
58 import java.util.Arrays JavaDoc;
59
60 import org.openejb.util.ArrayStack;
61
62 /**
63  * This is a faster ObjectOutputStream for high volume object serialization. <BR><BR>
64  *
65  * This ObjectOutputStream's strength is that it can be reused unlike the Sun ObjectOutputStream
66  * which needs to be discarded and re-instantiated. This ObjectOutputStream also has the main
67  * algorithm inlined. This of coarse looks terrible but is faster then delegating everything
68  * to reusable methods. This is implementation is not finished yet as it does not use the writeObject
69  * callback method and does not serialize exceptions to the stream as it should.<BR><BR>
70  *
71  * We chose not to implement the formula to generate the serialVersionID for classes that do not specify
72  * one explicitly as this adds a lot of overhead the first time a new class type is introduced into the stream.
73  * This will most likely be added as an optional function.<BR><BR>
74  *
75  * This ObjectOutputStream is not faster in all situations. When doing only a few dozen serializations during
76  * the life of the VM you will want to use the java.io.ObjectOutputStream. You'll notice however that this
77  * ObjectOutputStream performs considerably faster with a high number of serializations. This makes this implementation
78  * ideal for handling the heavy load of typical a server.<BR><BR>
79  *
80  * Run the SerializationPerformanceTest to get a better idea on how this OutputPerforms on your machine.<BR><BR>
81  *
82  * <PRE>
83  * example:
84  *
85  * $java org.openejb.test.SerializationPerformanceTest 20 100 10
86  * </PRE>
87  * <BR>
88  * Running the test with the above parameters will typically give results indicating
89  * this ObjectOutputStream running in 64% of the time it take the java.io.ObjectOutputSteam
90  * to complete, i.e. about 36% faster.
91  *
92  * @author David Blevins
93  * @version 0.50, 01/11/2000
94  * @since OpenEJB 1.0
95  */

96 public class ObjectOutputStream extends OutputStream JavaDoc implements ObjectOutput JavaDoc, ObjectStreamConstants JavaDoc {
97
98     /**
99      * Creates an ObjectOutputStream that writes to the specified OutputStream.
100      * The stream header is written to the stream. The caller may want to call
101      * flush immediately so that the corresponding ObjectInputStream can read
102      * the header immediately.
103      *
104      * @exception IOException Any exception thrown by the underlying OutputStream.
105
106      */

107 // private Handles handles;
108
private OutputStream JavaDoc out;
109     private ArrayStack classDescStack;
110     private byte buf[] = new byte[5000];
111     /**
112      * The number of valid bytes in the buffer.
113      */

114     private int count;
115
116     public ObjectOutputStream(OutputStream JavaDoc out) throws IOException JavaDoc {
117         this.out = out;
118
119         classDescStack = new ArrayStack();
120     }
121
122     public void reset() throws IOException JavaDoc{
123         resetStream();
124         count = 0;
125     }
126
127     public void serializeObject(Object JavaDoc obj, OutputStream JavaDoc out) throws NotSerializableException JavaDoc, IOException JavaDoc{
128         this.out = out;
129         serializeObject(obj);
130     }
131
132     public void serializeObject(Object JavaDoc obj) throws NotSerializableException JavaDoc, IOException JavaDoc{
133
134         if ( !Serializable JavaDoc.class.isAssignableFrom(obj.getClass()) && !Externalizable JavaDoc.class.isAssignableFrom(obj.getClass()) ) {
135             throw new NotSerializableException JavaDoc(obj.getClass().getName());
136         }
137
138         reset();
139
140         writeShort(STREAM_MAGIC);
141         writeShort(STREAM_VERSION);
142         writeObject(obj);
143
144     }
145
146
147     public void writeObject(Object JavaDoc obj) throws IOException JavaDoc{
148         try {
149             if ( obj == null ) {
150                 write(TC_NULL);
151                 return;
152             }
153             Class JavaDoc clazz = obj.getClass();
154             ClassDescriptor classDesc = null;
155
156             if ( clazz == ClassDescriptor.class ) classDesc = (ClassDescriptor)obj;
157             else classDesc = ClassDescriptor.lookupInternal(clazz);
158
159             if ( classDesc == null ) {
160                 write(TC_NULL);
161                 return;
162             }
163
164             int tmpInt = findWireOffset(obj);
165             if ( tmpInt >= 0 ) {
166                 write(TC_REFERENCE);
167                 tmpInt += baseWireHandle;
168                 //writeInt(int tmpInt){
169
write((tmpInt >>> 24) & 0xFF);
170                 write((tmpInt >>> 16) & 0xFF);
171                 write((tmpInt >>> 8) & 0xFF);
172                 write((tmpInt >>> 0) & 0xFF);
173                 //}
174
return;
175             }
176
177             if ( obj instanceof Class JavaDoc ) {
178                 write(TC_CLASS);
179                 write(TC_CLASSDESC);
180                 writeUTF(classDesc.getName());
181                 long value = classDesc.getSerialVersionUID();
182                 //writeLong(long value){
183
write((int)(value >>> 56) & 0xFF);
184                 write((int)(value >>> 48) & 0xFF);
185                 write((int)(value >>> 40) & 0xFF);
186                 write((int)(value >>> 32) & 0xFF);
187                 write((int)(value >>> 24) & 0xFF);
188                 write((int)(value >>> 16) & 0xFF);
189                 write((int)(value >>> 8) & 0xFF);
190                 write((int)(value >>> 0) & 0xFF);
191                 //}
192
assignWireOffset(classDesc);
193                 classDesc.writeClassInfo(this);
194                 write(TC_ENDBLOCKDATA);
195                 writeObject(classDesc.getSuperclass());
196                 assignWireOffset(clazz);
197                 return;
198             }
199
200             if ( obj instanceof ClassDescriptor ) {
201                 write(TC_CLASSDESC);
202                 writeUTF(classDesc.getName());
203                 long value = classDesc.getSerialVersionUID();
204                 //writeLong(long value){
205
write((int)(value >>> 56) & 0xFF);
206                 write((int)(value >>> 48) & 0xFF);
207                 write((int)(value >>> 40) & 0xFF);
208                 write((int)(value >>> 32) & 0xFF);
209                 write((int)(value >>> 24) & 0xFF);
210                 write((int)(value >>> 16) & 0xFF);
211                 write((int)(value >>> 8) & 0xFF);
212                 write((int)(value >>> 0) & 0xFF);
213                 //}
214
assignWireOffset(classDesc);
215                 write(classDesc.flags);
216                 tmpInt = classDesc.fields.length;
217                 write((tmpInt >>> 8) & 0xFF);
218                 write((tmpInt >>> 0) & 0xFF);
219                 FieldDescriptor field;
220                 for ( int i=0; i < classDesc.fields.length; i++ ) {
221                     field = classDesc.fields[i];
222                     write((int)field.typeCode);
223                     writeUTF(field.name);
224                     if ( !field.type.isPrimitive() ) writeObject(field.typeString);
225                 }
226                 write(TC_ENDBLOCKDATA);
227                 writeObject(classDesc.getSuperclass());
228                 return;
229             }
230             if ( obj instanceof String JavaDoc ) {
231                 write(TC_STRING);
232                 String JavaDoc s = ((String JavaDoc)obj).intern();
233                 assignWireOffset(s);
234                 writeUTF(s);
235                 return;
236             }
237             if ( clazz.isArray() ) {
238                 write(TC_ARRAY);
239                 writeObject(classDesc);
240                 assignWireOffset(obj);
241
242                 Class JavaDoc type = clazz.getComponentType();
243                 if ( type.isPrimitive() ) {
244                     if ( type == Integer.TYPE ) {
245                         int[] array = (int[])obj;
246                         tmpInt = array.length;
247                         //writeInt(int tmpInt){
248
write((tmpInt >>> 24) & 0xFF);
249                         write((tmpInt >>> 16) & 0xFF);
250                         write((tmpInt >>> 8) & 0xFF);
251                         write((tmpInt >>> 0) & 0xFF);
252                         //}
253
int value;
254                         for ( int i = 0; i < tmpInt; i++ ) {
255                             value = array[i];
256                             //writeInt(int tmpInt){
257
write((value >>> 24) & 0xFF);
258                             write((value >>> 16) & 0xFF);
259                             write((value >>> 8) & 0xFF);
260                             write((value >>> 0) & 0xFF);
261                             //}
262
}
263                         return;
264                     } else if ( type == Byte.TYPE ) {
265                         byte[] array = (byte[])obj;
266                         tmpInt = array.length;
267                         //writeInt(int tmpInt){
268
write((tmpInt >>> 24) & 0xFF);
269                         write((tmpInt >>> 16) & 0xFF);
270                         write((tmpInt >>> 8) & 0xFF);
271                         write((tmpInt >>> 0) & 0xFF);
272                         //}
273
write(array, 0, tmpInt);
274                         return;
275                     } else if ( type == Long.TYPE ) {
276                         long[] array = (long[])obj;
277                         tmpInt = array.length;
278                         //writeInt(int tmpInt){
279
write((tmpInt >>> 24) & 0xFF);
280                         write((tmpInt >>> 16) & 0xFF);
281                         write((tmpInt >>> 8) & 0xFF);
282                         write((tmpInt >>> 0) & 0xFF);
283                         //}
284
long value;
285                         for ( int i = 0; i < tmpInt; i++ ) {
286                             value = array[i];
287                             //writeLong(long value){
288
write((int)(value >>> 56) & 0xFF);
289                             write((int)(value >>> 48) & 0xFF);
290                             write((int)(value >>> 40) & 0xFF);
291                             write((int)(value >>> 32) & 0xFF);
292                             write((int)(value >>> 24) & 0xFF);
293                             write((int)(value >>> 16) & 0xFF);
294                             write((int)(value >>> 8) & 0xFF);
295                             write((int)(value >>> 0) & 0xFF);
296                             //}
297
}
298                         return;
299                     } else if ( type == Float.TYPE ) {
300                         float[] array = (float[])obj;
301                         tmpInt = array.length;
302                         //writeInt(int tmpInt){
303
write((tmpInt >>> 24) & 0xFF);
304                         write((tmpInt >>> 16) & 0xFF);
305                         write((tmpInt >>> 8) & 0xFF);
306                         write((tmpInt >>> 0) & 0xFF);
307                         //}
308
int value;
309                         for ( int i = 0; i < tmpInt; i++ ) {
310                             value = Float.floatToIntBits(array[i]);
311                             //writeInt(int value){
312
write((value >>> 24) & 0xFF);
313                             write((value >>> 16) & 0xFF);
314                             write((value >>> 8) & 0xFF);
315                             write((value >>> 0) & 0xFF);
316                             //}
317
}
318                         return;
319                     } else if ( type == Double.TYPE ) {
320                         double[] array = (double[])obj;
321                         tmpInt = array.length;
322                         //writeInt(int tmpInt){
323
write((tmpInt >>> 24) & 0xFF);
324                         write((tmpInt >>> 16) & 0xFF);
325                         write((tmpInt >>> 8) & 0xFF);
326                         write((tmpInt >>> 0) & 0xFF);
327                         //}
328
long value;
329                         for ( int i = 0; i < tmpInt; i++ ) {
330                             value = Double.doubleToLongBits(array[i]);
331                             //writeLong(long value){
332
write((int)(value >>> 56) & 0xFF);
333                             write((int)(value >>> 48) & 0xFF);
334                             write((int)(value >>> 40) & 0xFF);
335                             write((int)(value >>> 32) & 0xFF);
336                             write((int)(value >>> 24) & 0xFF);
337                             write((int)(value >>> 16) & 0xFF);
338                             write((int)(value >>> 8) & 0xFF);
339                             write((int)(value >>> 0) & 0xFF);
340                             //}
341
}
342                         return;
343                     } else if ( type == Short.TYPE ) {
344                         short[] array = (short[])obj;
345                         tmpInt = array.length;
346                         //writeInt(int tmpInt){
347
write((tmpInt >>> 24) & 0xFF);
348                         write((tmpInt >>> 16) & 0xFF);
349                         write((tmpInt >>> 8) & 0xFF);
350                         write((tmpInt >>> 0) & 0xFF);
351                         //}
352
short value;
353                         for ( int i = 0; i < tmpInt; i++ ) {
354                             value = array[i];
355                             //writeShort(short value){
356
write((value >>> 8) & 0xFF);
357                             write((value >>> 0) & 0xFF);
358                             //}
359
}
360                         return;
361                     } else if ( type == Character.TYPE ) {
362                         char[] array = (char[])obj;
363                         tmpInt = array.length;
364                         //writeInt(int tmpInt){
365
write((tmpInt >>> 24) & 0xFF);
366                         write((tmpInt >>> 16) & 0xFF);
367                         write((tmpInt >>> 8) & 0xFF);
368                         write((tmpInt >>> 0) & 0xFF);
369                         //}
370
char value;
371                         for ( int i = 0; i < tmpInt; i++ ) {
372                             value = array[i];
373                             //writeChar(char value){
374
write((value >>> 8) & 0xFF);
375                             write((value >>> 0) & 0xFF);
376                             //}
377
}
378                         return;
379                     } else if ( type == Boolean.TYPE ) {
380                         boolean[] array = (boolean[])obj;
381                         tmpInt = array.length;
382                         //writeInt(int tmpInt){
383
write((tmpInt >>> 24) & 0xFF);
384                         write((tmpInt >>> 16) & 0xFF);
385                         write((tmpInt >>> 8) & 0xFF);
386                         write((tmpInt >>> 0) & 0xFF);
387                         //}
388
for ( int i = 0; i < tmpInt; i++ ) {
389                             write(array[i] ? 1 : 0);
390                         }
391                         return;
392                     } else {
393                         throw new InvalidClassException JavaDoc(clazz.getName());
394                     }
395                 } else {
396                     Object JavaDoc[] array = (Object JavaDoc[])obj;
397                     int length = array.length;
398                     //writeInt(int length){
399
write((length >>> 24) & 0xFF);
400                     write((length >>> 16) & 0xFF);
401                     write((length >>> 8) & 0xFF);
402                     write((length >>> 0) & 0xFF);
403                     //}
404
for ( int i = 0; i < length; i++ ) writeObject(array[i]);
405                 }
406                 return;
407             }
408             write(TC_OBJECT);
409             writeObject(classDesc);
410             assignWireOffset(obj);
411             //writeObjectData(obj, classDesc);
412
if ( classDesc.isExternalizable() ) {
413                 writeExternal((Externalizable JavaDoc)obj);
414                 return;
415             }
416
417             int stackMark = classDescStack.size();
418             try {
419
420                 ClassDescriptor superClassDesc;
421                 while ( (superClassDesc = classDesc.getSuperclass()) != null ) {
422                     classDescStack.push(classDesc);
423                     classDesc = superClassDesc;
424                 }
425
426                 //classDesc is now the highest non-null superclass.
427
do {
428                     if ( classDesc.hasWriteObjectMethod() ) {
429                         /* DMB: NOT COMPLETE - Should start writing in block data format
430                          * and state the size of the data to come.
431                          */

432                         //setBlockData(true);
433
/* DMB: NOT COMPLETE - Should Invoke the writeObject
434                          * mehtod on the object.
435                          * Invoking the write object method requires a
436                          * sublcass of java.io.ObjectOutputStream to be
437                          * passed in. This implementation is not a subclass
438                          * of java.io.ObjectOutputStream.
439                          */

440                         //invokeObjectWriter(obj);
441
/* DMB: NOT COMPLETE - Should stop writing in block data format.
442                          * Denote the end of this mode by writing a terminator to the stream.
443                          */

444                         //setBlockData(false);
445
//writeCode(TC_ENDBLOCKDATA);
446
} else {
447                         FieldDescriptor[] fields = classDesc.getFields();
448                         Field JavaDoc field;
449                         if ( fields.length > 0 ) {
450                             for ( int i=0; i< fields.length; i++ ) {
451                                 field = fields[i].getField();
452                                 if ( field == null ) throw new InvalidClassException JavaDoc(clazz.getName(), "Nonexistent field " + fields[i].getName());
453                                 try {
454                                     switch ( fields[i].getTypeCode() ) {
455                                         case 'B':
456                                             write(field.getByte(obj));
457                                             break;
458                                         case 'C':
459                                             char charvalue = field.getChar(obj);
460                                             write((charvalue >>> 8) & 0xFF);
461                                             write((charvalue >>> 0) & 0xFF);
462                                             break;
463                                         case 'I':
464                                             int intvalue = field.getInt(obj);
465                                             write((intvalue >>> 24) & 0xFF);
466                                             write((intvalue >>> 16) & 0xFF);
467                                             write((intvalue >>> 8) & 0xFF);
468                                             write((intvalue >>> 0) & 0xFF);
469                                             break;
470                                         case 'Z':
471                                             write((field.getBoolean(obj)?1:0) );
472                                             break;
473                                         case 'J':
474                                             long longvalue = field.getLong(obj);
475                                             write((int)(longvalue >>> 56) & 0xFF);
476                                             write((int)(longvalue >>> 48) & 0xFF);
477                                             write((int)(longvalue >>> 40) & 0xFF);
478                                             write((int)(longvalue >>> 32) & 0xFF);
479                                             write((int)(longvalue >>> 24) & 0xFF);
480                                             write((int)(longvalue >>> 16) & 0xFF);
481                                             write((int)(longvalue >>> 8) & 0xFF);
482                                             write((int)(longvalue >>> 0) & 0xFF);
483                                             break;
484                                         case 'F':
485                                             int floatvalue = Float.floatToIntBits(field.getFloat(obj));
486                                             write((floatvalue >>> 24) & 0xFF);
487                                             write((floatvalue >>> 16) & 0xFF);
488                                             write((floatvalue >>> 8) & 0xFF);
489                                             write((floatvalue >>> 0) & 0xFF);
490                                             break;
491                                         case 'D':
492                                             long doublevalue = Double.doubleToLongBits(field.getDouble(obj));
493                                             write((int)(doublevalue >>> 56) & 0xFF);
494                                             write((int)(doublevalue >>> 48) & 0xFF);
495                                             write((int)(doublevalue >>> 40) & 0xFF);
496                                             write((int)(doublevalue >>> 32) & 0xFF);
497                                             write((int)(doublevalue >>> 24) & 0xFF);
498                                             write((int)(doublevalue >>> 16) & 0xFF);
499                                             write((int)(doublevalue >>> 8) & 0xFF);
500                                             write((int)(doublevalue >>> 0) & 0xFF);
501                                             break;
502                                         case 'S':
503                                             short shortvalue = field.getShort(obj);
504                                             write((shortvalue >>> 8) & 0xFF);
505                                             write((shortvalue >>> 0) & 0xFF);
506                                             break;
507                                         case '[':
508                                         case 'L':
509                                             writeObject(field.get(obj));
510                                             break;
511                                         default: throw new InvalidClassException JavaDoc(clazz.getName());
512                                     }
513                                 } catch ( IllegalAccessException JavaDoc e ) {
514                                     throw new InvalidClassException JavaDoc(clazz.getName(), e.getMessage());
515                                 } finally {
516                                 }
517                             }
518                         }
519                     }
520                 }while ( classDescStack.size() > stackMark && (classDesc = (ClassDescriptor)classDescStack.pop()) != null );
521
522             } finally {
523                 /* If an error occcured, make sure we set the stack back
524                  * the way it was before we started.
525                  */

526                 //classDescStack.setSize(stackMark);
527
}
528
529         } finally {
530         }
531     }
532
533     public void writeString(String JavaDoc s) throws IOException JavaDoc{
534         writeObject(s);
535     }
536
537     private void writeExternal(Externalizable JavaDoc ext) throws IOException JavaDoc{
538 // if (useDeprecatedExternalizableFormat) {
539
if ( false ) {
540             /* JDK 1.1 external data format.
541              * Don't write in block data mode and no terminator tag.
542              */

543             /* This method accepts a java.io.OutputStream as a parameter */
544             ext.writeExternal(this);
545         } else {
546             /* JDK 1.2 Externalizable data format writes in block data mode
547              * and terminates externalizable data with TAG_ENDBLOCKDATA.
548              */

549             /* DMB: NOT COMPLETE - Should start writing in block data format.
550              * This states the size of the data to come
551              */

552             //setBlockData(true);
553
try {
554                 /* This method accepts a java.io.ObjectOutputStream as a parameter */
555                 ext.writeExternal(this);
556             } finally {
557                 /* DMB: NOT COMPLETE - Should stop writing in block data format.
558                  * Denote the end of this mode by writing a terminator to the stream.
559                  */

560                 //setBlockData(false);
561
//writeCode(TC_ENDBLOCKDATA);
562
}
563         }
564     }
565
566
567
568
569     public void writeException(Throwable JavaDoc th) throws IOException JavaDoc{
570         /* DMB: NOT COMPLETE - Must write exceptions that occur during serialization
571          * to the stream.
572          */

573
574     }
575
576     public void writeReset() throws IOException JavaDoc{
577         /* DMB: NOT COMPLETE - Must write the reset byte when the reset() method
578          * is called.
579          */

580
581     }
582
583
584
585     /**
586      * Writes the specified byte (the low eight bits of the argument
587      * <code>b</code>) to the underlying output stream.
588      * <p>
589      * Implements the <code>write</code> method of <code>OutputStream</code>.
590      *
591      * @param b the <code>byte</code> to be written.
592      * @exception IOException if an I/O error occurs.
593      */

594 /* public void write(int b) throws IOException {
595         out.write(b);
596     }
597 */

598     /**
599      * Writes <code>len</code> bytes from the specified byte array
600      * starting at offset <code>off</code> to the underlying output stream.
601      *
602      * @param b the data.
603      * @param off the start offset in the data.
604      * @param len the number of bytes to write.
605      * @exception IOException if an I/O error occurs.
606      */

607 /* public void write(byte b[], int off, int len) throws IOException {
608         for (int i = 0 ; i < len ; i++) {
609             write(b[off + i]);
610         }
611     }
612 */

613     /**
614      * Writes the specified byte to this byte array output stream.
615      *
616      * @param b the byte to be written.
617      */

618     public void write(int b) {
619         try {
620             buf[count++] = (byte)b;
621         } catch ( ArrayIndexOutOfBoundsException JavaDoc e ) {
622             byte newbuf[] = new byte[Math.max(buf.length << 1, count)];
623             System.arraycopy(buf, 0, newbuf, 0, count-1);
624             buf = newbuf;
625         }
626     }
627
628     /**
629      * Writes <code>len</code> bytes from the specified byte array
630      * starting at offset <code>off</code> to this byte array output stream.
631      *
632      * @param b the data.
633      * @param off the start offset in the data.
634      * @param len the number of bytes to write.
635      */

636     public synchronized void write(byte b[], int off, int len) {
637         if ( len == 0 ) return;
638
639         int newcount = count + len;
640         if ( newcount > buf.length ) {
641             byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
642             System.arraycopy(buf, 0, newbuf, 0, count);
643             buf = newbuf;
644         }
645         System.arraycopy(b, off, buf, count, len);
646         count = newcount;
647     }
648
649
650     /**
651      * Flushes this data output stream. This forces any buffered output
652      * bytes to be written out to the stream.
653      * <p>
654      * The <code>flush</code> method of <code>DataOuputStream</code>
655      * calls the <code>flush</code> method of its underlying output stream.
656      *
657      * @exception IOException if an I/O error occurs.
658      */

659     public void flush() throws IOException JavaDoc {
660 // out.flush();
661
}
662
663     /**
664      * Creates a newly allocated byte array. Its size is the current
665      * size of this output stream and the valid contents of the buffer
666      * have been copied into it.
667      *
668      * @return the current contents of this output stream, as a byte array.
669      * @see java.io.ByteArrayOutputStream#size()
670      */

671     public byte[] toByteArray() {
672         byte newbuf[] = new byte[count];
673         System.arraycopy(buf, 0, newbuf, 0, count);
674         return newbuf;
675     }
676
677     /**
678      * Returns the current size of the buffer.
679      *
680      * @return the value of the <code>count</code> field, which is the number
681      * of valid bytes in this output stream.
682      */

683     public int size() {
684         return count;
685     }
686
687
688     /**
689      * Writes a <code>boolean</code> to the underlying output stream as
690      * a 1-byte value. The value <code>true</code> is written out as the
691      * value <code>(byte)1</code>; the value <code>false</code> is
692      * written out as the value <code>(byte)0</code>.
693      *
694      * @param v a <code>boolean</code> value to be written.
695      * @exception IOException if an I/O error occurs.
696      */

697     public final void writeBoolean(boolean v) throws IOException JavaDoc {
698         write(v ? 1 : 0);
699     }
700
701     /**
702      * Writes out a <code>byte</code> to the underlying output stream as
703      * a 1-byte value.
704      *
705      * @param v a <code>byte</code> value to be written.
706      * @exception IOException if an I/O error occurs.
707      */

708     public final void writeByte(int v) throws IOException JavaDoc {
709         write(v);
710     }
711
712     /**
713      * Writes a <code>short</code> to the underlying output stream as two
714      * bytes, high byte first.
715      *
716      * @param v a <code>short</code> to be written.
717      * @exception IOException if an I/O error occurs.
718      */

719     public final void writeShort(int v) throws IOException JavaDoc {
720         write((v >>> 8) & 0xFF);
721         write((v >>> 0) & 0xFF);
722     }
723
724     /**
725      * Writes a <code>char</code> to the underlying output stream as a
726      * 2-byte value, high byte first.
727      *
728      * @param v a <code>char</code> value to be written.
729      * @exception IOException if an I/O error occurs.
730      */

731     public final void writeChar(int v) throws IOException JavaDoc {
732         write((v >>> 8) & 0xFF);
733         write((v >>> 0) & 0xFF);
734     }
735
736     /**
737      * Writes an <code>int</code> to the underlying output stream as four
738      * bytes, high byte first.
739      *
740      * @param v an <code>int</code> to be written.
741      * @exception IOException if an I/O error occurs.
742      */

743     public final void writeInt(int v) throws IOException JavaDoc {
744         write((v >>> 24) & 0xFF);
745         write((v >>> 16) & 0xFF);
746         write((v >>> 8) & 0xFF);
747         write((v >>> 0) & 0xFF);
748     }
749
750     /**
751      * Writes a <code>long</code> to the underlying output stream as eight
752      * bytes, high byte first.
753      *
754      * @param v a <code>long</code> to be written.
755      * @exception IOException if an I/O error occurs.
756      */

757     public final void writeLong(long v) throws IOException JavaDoc {
758         write((int)(v >>> 56) & 0xFF);
759         write((int)(v >>> 48) & 0xFF);
760         write((int)(v >>> 40) & 0xFF);
761         write((int)(v >>> 32) & 0xFF);
762         write((int)(v >>> 24) & 0xFF);
763         write((int)(v >>> 16) & 0xFF);
764         write((int)(v >>> 8) & 0xFF);
765         write((int)(v >>> 0) & 0xFF);
766     }
767
768     /**
769      * Converts the float argument to an <code>int</code> using the
770      * <code>floatToIntBits</code> method in class <code>Float</code>,
771      * and then writes that <code>int</code> value to the underlying
772      * output stream as a 4-byte quantity, high byte first.
773      *
774      * @param v a <code>float</code> value to be written.
775      * @exception IOException if an I/O error occurs.
776      */

777     public final void writeFloat(float v) throws IOException JavaDoc {
778         writeInt(Float.floatToIntBits(v));
779     }
780
781     /**
782      * Converts the double argument to a <code>long</code> using the
783      * <code>doubleToLongBits</code> method in class <code>Double</code>,
784      * and then writes that <code>long</code> value to the underlying
785      * output stream as an 8-byte quantity, high byte first. *
786      * @param v a <code>double</code> value to be written.
787      * @exception IOException if an I/O error occurs.
788      * @see java.lang.Double#doubleToLongBits(double)
789      */

790     public final void writeDouble(double v) throws IOException JavaDoc {
791         writeLong(Double.doubleToLongBits(v));
792     }
793
794     /**
795      * Writes out the string to the underlying output stream as a
796      * sequence of bytes. Each character in the string is written out, in
797      * sequence, by discarding its high eight bits.
798      *
799      * @param s a string of bytes to be written.
800      * @exception IOException if an I/O error occurs.
801      */

802     public final void writeBytes(String JavaDoc s) throws IOException JavaDoc {
803         int tmpLen = s.length();
804         for ( int i = 0 ; i < tmpLen ; i++ ) {
805             write((byte)s.charAt(i));
806         }
807     }
808
809     /**
810      * Writes a string to the underlying output stream as a sequence of
811      * characters.
812      * @param s a <code>String</code> value to be written.
813      * @exception IOException if an I/O error occurs.
814      */

815     public final void writeChars(String JavaDoc s) throws IOException JavaDoc {
816         int tmpLen = s.length();
817         for ( int i = 0 ; i < tmpLen ; i++ ) {
818             int v = s.charAt(i);
819             write((v >>> 8) & 0xFF);
820             write((v >>> 0) & 0xFF);
821         }
822     }
823
824     /* These are to speed up the writing of strings.
825      * This method is called frequently and placing these here
826      * prevents constant allocation and garbage collection.
827      */

828
829     private char[] utfCharBuf = new char[32];
830     public final void writeUTF(String JavaDoc str) throws IOException JavaDoc {
831
832         int len = str.length();
833
834         if ( utfCharBuf.length < len ) utfCharBuf = new char[len];
835
836         str.getChars(0,len,utfCharBuf,0);
837
838         int mark = count;
839         write(0); // We will write over these two bytes with the
840
write(0); // UTF string length later.
841
for ( int i = 0 ; i < len ; i++ ) {
842             int c = utfCharBuf[i];
843             if ( (c >= 0x0001) && (c <= 0x007F) ) {
844                 write(c);
845             } else if ( c > 0x07FF ) {
846                 write(0xE0 | ((c >> 12) & 0x0F));
847                 write(0x80 | ((c >> 6) & 0x3F));
848                 write(0x80 | ((c >> 0) & 0x3F));
849             } else {
850                 write(0xC0 | ((c >> 6) & 0x1F));
851                 write(0x80 | ((c >> 0) & 0x3F));
852             }
853         }
854         // With the new algorythm this check is really pointless.
855
// if (tmpUtflen > 65535)throw new UTFDataFormatException();
856

857         len = count-mark-2;
858         buf[mark] = (byte)((len >>> 8) & 0xFF);
859         buf[mark+1] = (byte)((len >>> 0) & 0xFF);
860
861
862     }
863
864     /* Object references are mapped to the wire handles through a hashtable
865      * WireHandles are integers generated by the ObjectOutputStream,
866      * they need only be unique within a stream.
867      * Objects are assigned sequential handles and stored in wireHandle2Object.
868      * The handle for an object is its index in wireHandle2Object.
869      * Object with the "same" hashcode are chained using wireHash2Handle.
870      * The hashcode of objects is used to index through the wireHash2Handle.
871      * -1 is the marker for unused cells in wireNextHandle
872      */

873     private ArrayList JavaDoc wireHandle2Object;
874     private int nextWireOffset;
875
876     /* the next five members implement an inline hashtable. */
877     private int[] wireHash2Handle; // hash spine
878
private int[] wireNextHandle; // next hash bucket entry
879
private int wireHashSizePower = 2; // current power of 2 hash table size - 1
880
private int wireHashLoadFactor = 7; // avg number of elements per bucket
881
private int wireHashCapacity = (1 << wireHashSizePower) * wireHashLoadFactor;
882
883     /*
884      * Insert the specified object into the hash array and link if
885      * necessary. Put the new object into the hash table and link the
886      * previous to it. Newer objects occur earlier in the list.
887      */

888     private void hashInsert(Object JavaDoc obj, int offset) {
889         int hash = System.identityHashCode(obj);
890         int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
891         wireNextHandle[offset] = wireHash2Handle[index];
892         wireHash2Handle[index] = offset;
893     }
894     /*
895      * Locate and return if found the handle for the specified object.
896      * -1 is returned if the object does not occur in the array of
897      * known objects.
898      */

899     private int findWireOffset(Object JavaDoc obj) {
900         int hash = System.identityHashCode(obj);
901         int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
902
903         for ( int handle = wireHash2Handle[index];
904             handle >= 0;
905             handle = wireNextHandle[handle] ) {
906
907             if ( wireHandle2Object.get(handle) == obj )
908                 return handle;
909         }
910         return -1;
911     }
912
913     /* Allocate a handle for an object.
914      * The Vector is indexed by the wireHandleOffset
915      * and contains the object.
916      * Allow caller to specify the hash method for the object.
917      */

918     private void assignWireOffset(Object JavaDoc obj)
919     throws IOException JavaDoc
920     {
921         if ( nextWireOffset == wireNextHandle.length ) {
922             int[] oldnexthandles = wireNextHandle;
923             wireNextHandle = new int[nextWireOffset*2];
924             System.arraycopy(oldnexthandles, 0,
925                              wireNextHandle, 0,
926                              nextWireOffset);
927         }
928         if ( nextWireOffset >= wireHashCapacity ) {
929             growWireHash2Handle();
930         }
931         wireHandle2Object.add(obj);
932         hashInsert(obj, nextWireOffset);
933         nextWireOffset++;
934         return;
935     }
936
937     private void growWireHash2Handle() {
938         // double hash table spine.
939
wireHashSizePower++;
940         wireHash2Handle = new int[(1 << wireHashSizePower) - 1];
941         Arrays.fill(wireHash2Handle, -1);
942
943         for ( int i = 0; i < nextWireOffset; i++ ) {
944             wireNextHandle[i] = 0;
945         }
946
947         // refill hash table.
948
for ( int i = 0; i < wireHandle2Object.size(); i++ ) {
949             hashInsert(wireHandle2Object.get(i), i);
950         }
951
952         wireHashCapacity = (1 << wireHashSizePower) * wireHashLoadFactor;
953     }
954
955     /*
956      * Internal reset function to reinitialize the state of the stream.
957      * Reset state of things changed by using the stream.
958      */

959     private void resetStream() throws IOException JavaDoc {
960         if ( wireHandle2Object == null ) {
961             wireHandle2Object = new ArrayList JavaDoc();
962             wireNextHandle = new int[4];
963             wireHash2Handle = new int[ (1 << wireHashSizePower) - 1];
964         } else {
965
966             // Storage Optimization for frequent calls to reset method.
967
// Do not reallocate, only reinitialize.
968
wireHandle2Object.clear();
969             for ( int i = 0; i < nextWireOffset; i++ ) {
970                 wireNextHandle[i] = 0;
971             }
972         }
973         nextWireOffset = 0;
974         Arrays.fill(wireHash2Handle, -1);
975
976         if ( classDescStack == null )
977             classDescStack = new ArrayStack();
978         else classDescStack.setSize(0);
979
980
981     }
982 }
Popular Tags