KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > encoding > IDLJavaSerializationOutputStream


1 /*
2  * @(#)IDLJavaSerializationOutputStream.java 1.4 04/06/07
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package com.sun.corba.se.impl.encoding;
8
9 import java.io.IOException JavaDoc;
10 import java.io.ObjectOutputStream JavaDoc;
11 import java.io.ByteArrayOutputStream JavaDoc;
12
13 import java.nio.ByteBuffer JavaDoc;
14
15 import com.sun.corba.se.spi.orb.ORB;
16 import com.sun.corba.se.spi.ior.IOR;
17 import com.sun.corba.se.spi.ior.IORFactories;
18 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
19 import com.sun.corba.se.spi.logging.CORBALogDomains;
20 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
21
22 import com.sun.corba.se.impl.util.Utility;
23 import com.sun.corba.se.impl.orbutil.ORBConstants;
24 import com.sun.corba.se.impl.orbutil.ORBUtility;
25 import com.sun.corba.se.impl.corba.TypeCodeImpl;
26 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
27 import com.sun.corba.se.impl.protocol.giopmsgheaders.Message;
28
29 import org.omg.CORBA.Any JavaDoc;
30 import org.omg.CORBA.TypeCode JavaDoc;
31 import org.omg.CORBA.Principal JavaDoc;
32 import org.omg.CORBA.CompletionStatus JavaDoc;
33
34 /**
35  * Implementation class that uses Java serialization for output streams.
36  * This assumes a GIOP version 1.2 message format.
37  *
38  * This class uses a ByteArrayOutputStream as the underlying buffer. The
39  * first 16 bytes are direct writes into the underlying buffer. This allows
40  * [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes.
41  * Subsequent write operations on this output stream object uses
42  * ObjectOutputStream class to write into the buffer. This allows marshaling
43  * complex types and graphs using the ObjectOutputStream implementation.
44  *
45  * Note, this class assumes a GIOP 1.2 style header. Note, we expect that the
46  * first 16 bytes are written only using the write_octet, write_long or
47  * write_ulong method calls.
48  *
49  * @author Ram Jeyaraman
50  */

51 public class IDLJavaSerializationOutputStream extends CDROutputStreamBase {
52
53     private ORB orb;
54     private byte encodingVersion;
55     private ObjectOutputStream JavaDoc os;
56     private _ByteArrayOutputStream bos;
57     private BufferManagerWrite bufferManager;
58
59     // [GIOPHeader(12) + requestID(4)] bytes
60
private final int directWriteLength = Message.GIOPMessageHeaderLength + 4;
61
62     protected ORBUtilSystemException wrapper;
63
64     class _ByteArrayOutputStream extends ByteArrayOutputStream JavaDoc {
65
66     _ByteArrayOutputStream(int initialSize) {
67         super(initialSize);
68     }
69     
70     byte[] getByteArray() {
71         return this.buf;
72     }
73     }
74
75     class MarshalObjectOutputStream extends ObjectOutputStream JavaDoc {
76
77     ORB orb;
78     
79     MarshalObjectOutputStream(java.io.OutputStream JavaDoc out, ORB orb)
80             throws IOException JavaDoc {
81
82         super(out);
83         this.orb = orb;
84         java.security.AccessController.doPrivileged(
85             new java.security.PrivilegedAction JavaDoc() {
86             public Object JavaDoc run() {
87             // needs SerializablePermission("enableSubstitution")
88
enableReplaceObject(true);
89             return null;
90             }
91             }
92         );
93     }
94
95     /**
96      * Checks for objects that are instances of java.rmi.Remote
97      * that need to be serialized as proxy (Stub) objects.
98      */

99     protected final Object JavaDoc replaceObject(Object JavaDoc obj) throws IOException JavaDoc {
100         try {
101         if ((obj instanceof java.rmi.Remote JavaDoc) &&
102                 !(StubAdapter.isStub(obj))) {
103             return Utility.autoConnect(obj, orb, true);
104         }
105         } catch (Exception JavaDoc e) {
106         IOException JavaDoc ie = new IOException JavaDoc("replaceObject failed");
107         ie.initCause(e);
108         throw ie;
109         }
110         return obj;
111     }
112     }
113
114     public IDLJavaSerializationOutputStream(byte encodingVersion) {
115     super();
116     this.encodingVersion = encodingVersion;
117     }
118
119     public void init(org.omg.CORBA.ORB JavaDoc orb, boolean littleEndian,
120              BufferManagerWrite bufferManager,
121              byte streamFormatVersion,
122              boolean usePooledByteBuffers) {
123     this.orb = (ORB) orb;
124     this.bufferManager = bufferManager;
125     wrapper = ORBUtilSystemException.get((ORB) orb,
126                          CORBALogDomains.RPC_ENCODING);
127     bos =
128         new _ByteArrayOutputStream(ORBConstants.GIOP_DEFAULT_BUFFER_SIZE);
129     }
130
131     // Called from read_octet or read_long or read_ulong method.
132
private void initObjectOutputStream() {
133     //System.out.print(" os ");
134
if (os != null) {
135         throw wrapper.javaStreamInitFailed();
136     }
137     try {
138         os = new MarshalObjectOutputStream(bos, orb);
139     } catch (Exception JavaDoc e) {
140         throw wrapper.javaStreamInitFailed(e);
141     }
142     }
143
144     // org.omg.CORBA.portable.OutputStream
145

146     // Primitive types.
147

148     public final void write_boolean(boolean value) {
149     try {
150         os.writeBoolean(value);
151     } catch (Exception JavaDoc e) {
152         throw wrapper.javaSerializationException(e, "write_boolean");
153     }
154     }
155
156     public final void write_char(char value) {
157     try {
158         os.writeChar(value);
159     } catch (Exception JavaDoc e) {
160         throw wrapper.javaSerializationException(e, "write_char");
161     }
162     }
163
164     public final void write_wchar(char value) {
165     this.write_char(value);
166     }
167
168     public final void write_octet(byte value) {
169
170     // check if size < [ GIOPHeader(12) + requestID(4)] bytes
171
if (bos.size() < directWriteLength) {
172         bos.write(value); // direct write.
173
if (bos.size() == directWriteLength) {
174         initObjectOutputStream();
175         }
176         return;
177     }
178
179     try {
180         os.writeByte(value);
181     } catch (Exception JavaDoc e) {
182         throw wrapper.javaSerializationException(e, "write_octet");
183     }
184     }
185
186     public final void write_short(short value) {
187     try {
188         os.writeShort(value);
189     } catch (Exception JavaDoc e) {
190         throw wrapper.javaSerializationException(e, "write_short");
191     }
192     }
193
194     public final void write_ushort(short value) {
195     this.write_short(value);
196     }
197
198     public final void write_long(int value) {
199
200     // check if size < [ GIOPHeader(12) + requestID(4)] bytes
201
if (bos.size() < directWriteLength) {
202
203         // Use big endian (network byte order). This is fixed.
204
// Both the writer and reader use the same byte order.
205
bos.write((byte)((value >>> 24) & 0xFF));
206             bos.write((byte)((value >>> 16) & 0xFF));
207             bos.write((byte)((value >>> 8) & 0xFF));
208             bos.write((byte)((value >>> 0) & 0xFF));
209
210         if (bos.size() == directWriteLength) {
211         initObjectOutputStream();
212         } else if (bos.size() > directWriteLength) {
213         // Cannot happen. All direct writes are contained
214
// within the first 16 bytes.
215
wrapper.javaSerializationException("write_long");
216         }
217         return;
218     }
219
220     try {
221         os.writeInt(value);
222     } catch (Exception JavaDoc e) {
223         throw wrapper.javaSerializationException(e, "write_long");
224     }
225     }
226
227     public final void write_ulong(int value) {
228         this.write_long(value);
229     }
230
231     public final void write_longlong(long value) {
232     try {
233         os.writeLong(value);
234     } catch (Exception JavaDoc e) {
235         throw wrapper.javaSerializationException(e, "write_longlong");
236     }
237     }
238
239     public final void write_ulonglong(long value) {
240         this.write_longlong(value);
241     }
242
243     public final void write_float(float value) {
244     try {
245         os.writeFloat(value);
246     } catch (Exception JavaDoc e) {
247         throw wrapper.javaSerializationException(e, "write_float");
248     }
249     }
250
251     public final void write_double(double value) {
252     try {
253         os.writeDouble(value);
254     } catch (Exception JavaDoc e) {
255         throw wrapper.javaSerializationException(e, "write_double");
256     }
257     }
258
259     // String types.
260

261     public final void write_string(String JavaDoc value) {
262     try {
263         os.writeUTF(value);
264     } catch (Exception JavaDoc e) {
265         throw wrapper.javaSerializationException(e, "write_string");
266     }
267     }
268
269     public final void write_wstring(String JavaDoc value) {
270     try {
271         os.writeObject(value);
272     } catch (Exception JavaDoc e) {
273         throw wrapper.javaSerializationException(e, "write_wstring");
274     }
275     }
276
277     // Array types.
278

279     public final void write_boolean_array(boolean[] value,
280                       int offset, int length) {
281         for (int i = 0; i < length; i++) {
282             write_boolean(value[offset + i]);
283     }
284     }
285
286     public final void write_char_array(char[] value, int offset, int length) {
287         for (int i = 0; i < length; i++) {
288             write_char(value[offset + i]);
289     }
290     }
291
292     public final void write_wchar_array(char[] value, int offset, int length) {
293     write_char_array(value, offset, length);
294     }
295
296     public final void write_octet_array(byte[] value, int offset, int length) {
297     try {
298         os.write(value, offset, length);
299     } catch (Exception JavaDoc e) {
300         throw wrapper.javaSerializationException(e, "write_octet_array");
301     }
302     }
303
304     public final void write_short_array(short[] value,
305                     int offset, int length) {
306         for (int i = 0; i < length; i++) {
307             write_short(value[offset + i]);
308     }
309     }
310
311     public final void write_ushort_array(short[] value,
312                      int offset, int length){
313         write_short_array(value, offset, length);
314     }
315
316     public final void write_long_array(int[] value, int offset, int length) {
317         for (int i = 0; i < length; i++) {
318             write_long(value[offset + i]);
319     }
320     }
321
322     public final void write_ulong_array(int[] value, int offset, int length) {
323     write_long_array(value, offset, length);
324     }
325
326     public final void write_longlong_array(long[] value,
327                        int offset, int length) {
328         for (int i = 0; i < length; i++) {
329             write_longlong(value[offset + i]);
330     }
331     }
332
333     public final void write_ulonglong_array(long[] value,
334                         int offset,int length) {
335     write_longlong_array(value, offset, length);
336     }
337
338     public final void write_float_array(float[] value,
339                     int offset, int length) {
340         for (int i = 0; i < length; i++) {
341             write_float(value[offset + i]);
342     }
343     }
344
345     public final void write_double_array(double[] value,
346                      int offset, int length) {
347         for (int i = 0; i < length; i++) {
348             write_double(value[offset + i]);
349     }
350     }
351
352     // Complex types (objects and graphs).
353

354     public final void write_Object(org.omg.CORBA.Object JavaDoc value) {
355         if (value == null) {
356         IOR nullIOR = IORFactories.makeIOR(orb);
357             nullIOR.write(parent);
358             return;
359         }
360         // IDL to Java formal 01-06-06 1.21.4.2
361
if (value instanceof org.omg.CORBA.LocalObject JavaDoc) {
362         throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE);
363     }
364     IOR ior = ORBUtility.connectAndGetIOR(orb, value);
365     ior.write(parent);
366     return;
367     }
368
369     public final void write_TypeCode(TypeCode JavaDoc tc) {
370         if (tc == null) {
371         throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
372     }
373         TypeCodeImpl tci;
374         if (tc instanceof TypeCodeImpl) {
375         tci = (TypeCodeImpl) tc;
376     } else {
377         tci = new TypeCodeImpl(orb, tc);
378     }
379         tci.write_value((org.omg.CORBA_2_3.portable.OutputStream JavaDoc) parent);
380     }
381
382     public final void write_any(Any JavaDoc any) {
383         if (any == null) {
384         throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
385     }
386         write_TypeCode(any.type());
387         any.write_value(parent);
388     }
389
390     public final void write_Principal(Principal JavaDoc p) {
391     // We don't need an implementation for this method, since principal
392
// is absent in GIOP version 1.2 or above.
393
write_long(p.name().length);
394         write_octet_array(p.name(), 0, p.name().length);
395     }
396     
397     public final void write_fixed(java.math.BigDecimal JavaDoc bigDecimal) {
398         // This string might contain sign and/or dot
399
this.write_fixed(bigDecimal.toString(), bigDecimal.signum());
400     }
401
402     // The string may contain a sign and dot
403
private void write_fixed(String JavaDoc string, int signum) {
404
405         int stringLength = string.length();
406
407         // Each octet contains (up to) two decimal digits.
408
byte doubleDigit = 0;
409         char ch;
410         byte digit;
411
412         // First calculate the string length without optional sign and dot.
413
int numDigits = 0;
414         for (int i=0; i<stringLength; i++) {
415             ch = string.charAt(i);
416             if (ch == '-' || ch == '+' || ch == '.')
417                 continue;
418             numDigits++;
419         }
420
421         for (int i=0; i<stringLength; i++) {
422             ch = string.charAt(i);
423             if (ch == '-' || ch == '+' || ch == '.')
424                 continue;
425             digit = (byte)Character.digit(ch, 10);
426             if (digit == -1) {
427         throw wrapper.badDigitInFixed(
428                         CompletionStatus.COMPLETED_MAYBE);
429             }
430             // If the fixed type has an odd number of decimal digits, then the
431
// representation begins with the first (most significant) digit.
432
// Otherwise, this first half-octet is all zero, and the first
433
// digit is in the second half-octet.
434
if (numDigits % 2 == 0) {
435                 doubleDigit |= digit;
436                 this.write_octet(doubleDigit);
437                 doubleDigit = 0;
438             } else {
439                 doubleDigit |= (digit << 4);
440             }
441             numDigits--;
442         }
443
444         // The sign configuration in the last half-octet of the representation,
445
// is 0xD for negative numbers and 0xC for positive and zero values.
446
if (signum == -1) {
447             doubleDigit |= 0xd;
448         } else {
449             doubleDigit |= 0xc;
450         }
451         this.write_octet(doubleDigit);
452     }
453
454     public final org.omg.CORBA.ORB JavaDoc orb() {
455         return this.orb;
456     }
457
458     // org.omg.CORBA_2_3.portable.OutputStream
459

460     public final void write_value(java.io.Serializable JavaDoc value) {
461         write_value(value, (String JavaDoc) null);
462     }
463
464     public final void write_value(java.io.Serializable JavaDoc value,
465                   java.lang.Class JavaDoc clz) {
466     write_value(value);
467     }
468
469     public final void write_value(java.io.Serializable JavaDoc value,
470                   String JavaDoc repository_id) {
471     try {
472         os.writeObject(value);
473     } catch (Exception JavaDoc e) {
474         throw wrapper.javaSerializationException(e, "write_value");
475     }
476     }
477
478     public final void write_value(java.io.Serializable JavaDoc value,
479                  org.omg.CORBA.portable.BoxedValueHelper JavaDoc factory) {
480     this.write_value(value, (String JavaDoc) null);
481     }
482
483     public final void write_abstract_interface(java.lang.Object JavaDoc obj) {
484
485     boolean isCorbaObject = false; // Assume value type.
486
org.omg.CORBA.Object JavaDoc theCorbaObject = null;
487         
488     // Is it a CORBA.Object?
489
if (obj != null && obj instanceof org.omg.CORBA.Object JavaDoc) {
490         theCorbaObject = (org.omg.CORBA.Object JavaDoc)obj;
491         isCorbaObject = true;
492     }
493         
494     // Write the boolean flag.
495
this.write_boolean(isCorbaObject);
496         
497     // Now write out the object.
498
if (isCorbaObject) {
499         write_Object(theCorbaObject);
500     } else {
501         try {
502         write_value((java.io.Serializable JavaDoc)obj);
503         } catch(ClassCastException JavaDoc cce) {
504         if (obj instanceof java.io.Serializable JavaDoc) {
505             throw cce;
506         } else {
507                     ORBUtility.throwNotSerializableForCorba(
508                             obj.getClass().getName());
509         }
510         }
511     }
512     }
513
514     // com.sun.corba.se.os.encoding.MarshalOutputStream
515

516     public final void start_block() {
517     throw wrapper.giopVersionError();
518     }
519
520     public final void end_block() {
521     throw wrapper.giopVersionError();
522     }
523
524     public final void putEndian() {
525     throw wrapper.giopVersionError();
526     }
527
528     public void writeTo(java.io.OutputStream JavaDoc s) throws IOException JavaDoc {
529     try {
530         os.flush();
531         bos.writeTo(s);
532     } catch (Exception JavaDoc e) {
533         throw wrapper.javaSerializationException(e, "writeTo");
534     }
535     }
536
537     public final byte[] toByteArray() {
538     try {
539         os.flush();
540         return bos.toByteArray(); // new copy.
541
} catch (Exception JavaDoc e) {
542         throw wrapper.javaSerializationException(e, "toByteArray");
543     }
544     }
545
546     // org.omg.CORBA.DataOutputStream
547

548     public final void write_Abstract (java.lang.Object JavaDoc value) {
549     write_abstract_interface(value);
550     }
551
552     public final void write_Value(java.io.Serializable JavaDoc value) {
553         write_value(value);
554     }
555
556     public final void write_any_array(org.omg.CORBA.Any JavaDoc[] value,
557                       int offset, int length) {
558         for(int i = 0; i < length; i++) {
559             write_any(value[offset + i]);
560     }
561     }
562
563     // org.omg.CORBA.portable.ValueBase
564

565     public final String JavaDoc[] _truncatable_ids() {
566     throw wrapper.giopVersionError();
567     }
568
569     // Other.
570

571     public final int getSize() {
572     try {
573         os.flush();
574         return bos.size();
575     } catch (Exception JavaDoc e) {
576         throw wrapper.javaSerializationException(e, "write_boolean");
577     }
578     }
579
580     public final int getIndex() {
581         return getSize();
582     }
583
584     protected int getRealIndex(int index) {
585         return getSize();
586     }
587
588     public final void setIndex(int value) {
589     throw wrapper.giopVersionError();
590     }
591
592     public final ByteBuffer JavaDoc getByteBuffer() {
593     throw wrapper.giopVersionError();
594     }
595
596     public final void setByteBuffer(ByteBuffer JavaDoc byteBuffer) {
597     throw wrapper.giopVersionError();
598     }
599
600     public final boolean isLittleEndian() {
601     // Java serialization uses network byte order, that is, big-endian.
602
return false;
603     }
604
605     public ByteBufferWithInfo getByteBufferWithInfo() {
606     try {
607         os.flush();
608     } catch (Exception JavaDoc e) {
609         throw wrapper.javaSerializationException(
610                         e, "getByteBufferWithInfo");
611     }
612     ByteBuffer JavaDoc byteBuffer = ByteBuffer.wrap(bos.getByteArray());
613     byteBuffer.limit(bos.size());
614     return new ByteBufferWithInfo(this.orb, byteBuffer, bos.size());
615     }
616
617     public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
618     throw wrapper.giopVersionError();
619     }
620
621     public final BufferManagerWrite getBufferManager() {
622     return bufferManager;
623     }
624
625     // This will stay a custom add-on until the java-rtf issue is resolved.
626
// Then it should be declared in org.omg.CORBA.portable.OutputStream.
627
//
628
// Pads the string representation of bigDecimal with zeros to fit the given
629
// digits and scale before it gets written to the stream.
630
public final void write_fixed(java.math.BigDecimal JavaDoc bigDecimal,
631                   short digits, short scale) {
632         String JavaDoc string = bigDecimal.toString();
633         String JavaDoc integerPart;
634         String JavaDoc fractionPart;
635         StringBuffer JavaDoc stringBuffer;
636
637         // Get rid of the sign
638
if (string.charAt(0) == '-' || string.charAt(0) == '+') {
639             string = string.substring(1);
640         }
641
642         // Determine integer and fraction parts
643
int dotIndex = string.indexOf('.');
644         if (dotIndex == -1) {
645             integerPart = string;
646             fractionPart = null;
647         } else if (dotIndex == 0 ) {
648             integerPart = null;
649             fractionPart = string;
650         } else {
651             integerPart = string.substring(0, dotIndex);
652             fractionPart = string.substring(dotIndex + 1);
653         }
654
655         // Pad both parts with zeros as necessary
656
stringBuffer = new StringBuffer JavaDoc(digits);
657         if (fractionPart != null) {
658             stringBuffer.append(fractionPart);
659         }
660         while (stringBuffer.length() < scale) {
661             stringBuffer.append('0');
662         }
663         if (integerPart != null) {
664             stringBuffer.insert(0, integerPart);
665         }
666         while (stringBuffer.length() < digits) {
667             stringBuffer.insert(0, '0');
668         }
669
670         // This string contains no sign or dot
671
this.write_fixed(stringBuffer.toString(), bigDecimal.signum());
672     }
673
674     public final void writeOctetSequenceTo(
675         org.omg.CORBA.portable.OutputStream JavaDoc s) {
676     byte[] buf = this.toByteArray(); // new copy.
677
s.write_long(buf.length);
678         s.write_octet_array(buf, 0, buf.length);
679     }
680
681     public final GIOPVersion getGIOPVersion() {
682     return GIOPVersion.V1_2;
683     }
684
685     public final void writeIndirection(int tag, int posIndirectedTo) {
686     throw wrapper.giopVersionError();
687     }
688
689     void freeInternalCaches() {}
690
691     void printBuffer() {
692     byte[] buf = this.toByteArray();
693
694         System.out.println("+++++++ Output Buffer ++++++++");
695         System.out.println();
696         System.out.println("Current position: " + buf.length);
697         //System.out.println("Total length : " + buf.length);
698
System.out.println();
699
700         char[] charBuf = new char[16];
701
702         try {
703
704             for (int i = 0; i < buf.length; i += 16) {
705                 
706                 int j = 0;
707                 
708                 // For every 16 bytes, there is one line
709
// of output. First, the hex output of
710
// the 16 bytes with each byte separated
711
// by a space.
712
while (j < 16 && j + i < buf.length) {
713                     int k = buf[i + j];
714                     if (k < 0)
715                         k = 256 + k;
716                     String JavaDoc hex = Integer.toHexString(k);
717                     if (hex.length() == 1)
718                         hex = "0" + hex;
719                     System.out.print(hex + " ");
720                     j++;
721                 }
722                 
723                 // Add any extra spaces to align the
724
// text column in case we didn't end
725
// at 16
726
while (j < 16) {
727                     System.out.print(" ");
728                     j++;
729                 }
730                 
731                 // Now output the ASCII equivalents. Non-ASCII
732
// characters are shown as periods.
733
int x = 0;
734
735                 while (x < 16 && x + i < buf.length) {
736                     if (ORBUtility.isPrintable((char)buf[i + x])) {
737                         charBuf[x] = (char) buf[i + x];
738                     } else {
739                         charBuf[x] = '.';
740             }
741                     x++;
742                 }
743                 System.out.println(new String JavaDoc(charBuf, 0, x));
744             }
745         } catch (Throwable JavaDoc t) {
746             t.printStackTrace();
747         }
748         System.out.println("++++++++++++++++++++++++++++++");
749     }
750
751     public void alignOnBoundary(int octetBoundary) {
752     throw wrapper.giopVersionError();
753     }
754
755     // Needed by request and reply messages for GIOP versions >= 1.2 only.
756
public void setHeaderPadding(boolean headerPadding) {
757     // no-op. We don't care about body alignment while using
758
// Java serialization. What the GIOP spec states does not apply here.
759
}
760
761     // ValueOutputStream -----------------------------
762

763     public void start_value(String JavaDoc rep_id) {
764     throw wrapper.giopVersionError();
765     }
766
767     public void end_value() {
768     throw wrapper.giopVersionError();
769     }
770
771     // java.io.OutputStream
772

773     // Note: These methods are defined in the super class and accessible.
774

775     //public abstract void write(byte b[]) throws IOException;
776
//public abstract void write(byte b[], int off, int len)
777
// throws IOException;
778
//public abstract void flush() throws IOException;
779
//public abstract void close() throws IOException;
780
}
781
Popular Tags