View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.util;
20  
21  import java.io.Externalizable;
22  import java.io.IOException;
23  import java.io.ObjectInput;
24  import java.io.ObjectOutput;
25  import java.io.ObjectOutputStream;
26  import java.io.OutputStream;
27  import java.io.UTFDataFormatException;
28  
29  import jgroup.core.ConfigManager;
30  
31  /**
32   *  The <code>OutMessage</code> class is an output stream specially
33   *  designed to be used with a transport layer which fragments messages.
34   *  Messages are stored in fragments, each fragment being composed by an
35   *  header, a payload and a trailer.  The length of these fields may be
36   *  configured when creating a new <code>OutMessage</code>. Data written
37   *  in the message are stored in the payload field of the fragments.
38   *
39   *  @author Alberto Montresor
40   *  @author Hein Meling
41   *  @since Jgroup 0.8
42   */
43  public final class OutMessage
44    extends OutputStream
45    implements ObjectOutput, Externalizable
46  {
47  
48    ////////////////////////////////////////////////////////////////////////////////////////////
49    // Constants
50    ////////////////////////////////////////////////////////////////////////////////////////////
51  
52    private static final long serialVersionUID = -6820954817177822595L;
53  
54    /** Initial number of fragments composing a message */
55    private static final int NUM_BUFFER = 16;     
56  
57  
58    ////////////////////////////////////////////////////////////////////////////////////////////
59    // Static section
60    ////////////////////////////////////////////////////////////////////////////////////////////
61  
62    /** Temporary buffer used in writeTemp */
63    private static byte[] temp = new byte[8];
64  
65  
66    ////////////////////////////////////////////////////////////////////////////////////////////
67    // Fields
68    ////////////////////////////////////////////////////////////////////////////////////////////
69  
70    private int       payload;            // Payload size in bytes
71    private int       header;             // Header size in bytes
72    private int       trailer;            // Trailer size in bytes
73    private int       totlen;             // Total length of a fragment
74    private int       endpayload;         // Last byte used for payload
75  
76    private int       position;           // Current position in the stream [0..byteCount]
77    private int       fragment;           // Current fragment number
78    private int       offset;             // Current offset in the fragment
79    
80    private int       fragmentCount;      // Total number of fragments used
81    private int       byteCount;          // Total number of bytes written
82    private int       maxsize;            // Max size in bytes
83    
84    private byte[]    buffer;             // Current fragment
85    private byte[][]  fragments;          // Byte array fragments
86  
87    /** Number of bytes written so far */
88    private int written;
89  
90  
91    ////////////////////////////////////////////////////////////////////////////////////////////
92    // Constructors
93    ////////////////////////////////////////////////////////////////////////////////////////////
94  
95    /**
96     *  Construct a message with header and trailer of length zero. In
97     *  this way, OutMessage may be used as a more efficient version of
98     *  ByteArrayOutputStream.
99     */
100   public OutMessage(int payload)
101   {
102     this(payload, 0, 0);
103   }
104 
105 
106   /**
107    *  Construct a OutMessage starting from an InMessage. In this way, it
108    *  possible to forward messages received from other servers without
109    *  copying them.
110    */
111   public OutMessage(InMessage msg)
112   {
113     // Store and compute fixed limits
114     this.payload = msg.getPayload();
115     this.header  = msg.getHeader();
116     this.trailer = msg.getTrailer();
117     endpayload = payload + header;
118     totlen = endpayload + trailer;
119 
120     // Initialize variables regarding message size
121     byteCount = msg.getByteCount();
122     fragmentCount = msg.getFragmentCount();
123     /*
124      * Patch to avoid problems when forwarding/resending a message
125      * to a different set of receivers (or different cluster) than
126      * the original InMessage had in its trailer.  This means that
127      * the MsgJG will want to add flow control data and a different
128      * receiver set to the trailer of the newly created OutMessage.
129      * The size of these fields may differ (require more capacity)
130      * than the original InMessage.  Note that the actual byte count,
131      * and the size of the allocated fragments double array will not
132      * change until more capacity is required.
133      *
134      * The original code looked like this:
135      *   maxsize = byteCount;
136      */
137     maxsize = Integer.MAX_VALUE;
138 
139     // Initialize variables regarding message position in the stream
140     position = 0;
141     fragment = 0;
142     offset = header;
143 
144     // Create fragments
145     fragments = msg.getFragments();
146     buffer = fragments[0];
147   }
148 
149 
150   /**
151    *  This constructor builds a message output stream subdivided in
152    *  fragments of length <code>header + payload + trailer</code>.
153    *  Used for messages whose size is initially unknown.
154    *
155    *  @exception IndexOutOfBoundsException
156    *    Raised if <code>payload</code> is negative or equal to zero;
157    *    <code>header</code> is negative; <code>trailer</code> is negative.
158    */
159   public OutMessage(int payload, int header, int trailer)
160   {
161     if (payload <= 0 || header < 0 || trailer < 0)
162       throw new IndexOutOfBoundsException();
163 
164     // Store and compute fixed limits
165     this.payload = payload;
166     this.header  = header;
167     this.trailer = trailer;
168     endpayload = payload + header;
169     totlen = endpayload + trailer;
170 
171     // Initialize variables regarding message size
172     byteCount = 0;
173     fragmentCount = 1;
174     maxsize = Integer.MAX_VALUE;
175 
176     // Initialize variables regarding message position in the stream
177     position = 0;
178     fragment = 0;
179     offset = header;
180 
181     // Create fragments
182     fragments = new byte[NUM_BUFFER][];
183     fragments[0] = new byte[totlen];
184     buffer = fragments[0];
185   }
186 
187 
188   /**
189    *  This constructor builds a message output stream subdivided in
190    *  fragments.  Used for messages whose size is known a priori.  If
191    *  <code>maxsize</code> is less than <code>payload</code>, the
192    *  payload of the message is set to <code>maxsize</code>.  The total
193    *  length of each fragments is <code>header + payload +
194    *  trailer</code>.
195    *
196    *  @exception IndexOutOfBoundsException
197    *    Raised if <code>payload</code> is negative or equal to zero;
198    *    <code>header</code> is negative; <code>trailer</code> is
199    *    negative; <code>maxsize</code> is negative or equal to zero.
200    */
201   public OutMessage(int payload, int header, int trailer, int maxsize)
202   {
203     if (payload <= 0 || header < 0 || trailer < 0 || maxsize <= 0)
204       throw new IndexOutOfBoundsException();
205 
206     // Store and compute fixed limits
207     this.payload = (maxsize < payload ? maxsize : payload);
208     this.header = header;
209     this.trailer = trailer;
210     endpayload = this.payload + header;
211     totlen = endpayload + trailer;
212 
213     /*
214      * Initialize variables regarding message size; the total number of
215      * bytes is already set to maxsize; in this way, in the following
216      * we'll skip to check whether the size exceed maxsize or not.
217      */
218     byteCount = maxsize;
219     fragmentCount = ((maxsize-1) / this.payload) + 1;
220     this.maxsize = maxsize;
221 
222     // Initialize variables regarding message position in the stream
223     position = 0;
224     fragment = 0;
225     offset = header;
226     
227     // Create fragments
228     fragments = new byte[fragmentCount][];
229     for (int i=0; i< fragmentCount; i++)
230       fragments[i] = new byte[totlen];  
231     buffer = fragments[0];
232   }
233 
234 
235   /**
236    *  Clear and reset the <code>OutMessage</code> to the given new
237    *  maxsize.  This occurs by reusing the already allocated memory for
238    *  the fragments of this <code>OutMessage</code>.
239    */
240   public void clear(int newmaxsize)
241   {
242     if (newmaxsize > maxsize)
243       throw new IllegalStateException("The newmaxsize cannot be greater than the creation time maxsize");
244 
245     /*
246      * Initialize variables regarding message size; the total number of
247      * byte is already set to maxsize; in this way, in the following
248      * we'll skip to check whether the size exceed maxsize or not.
249      */
250     byteCount = newmaxsize;
251     fragmentCount = ((newmaxsize-1) / this.payload) + 1;
252 
253     // Initialize variables regarding message position in the stream
254     position = 0;
255     fragment = 0;
256     offset = header;
257 
258     buffer = fragments[0];
259   }
260 
261 
262   ////////////////////////////////////////////////////////////////////////////////////////////
263   // Methods from Externalizable
264   ////////////////////////////////////////////////////////////////////////////////////////////
265 
266   /**
267    *  Default constructor for externalization.
268    */
269   public OutMessage() { }
270 
271 
272   /**
273    *  Restores the content of this object from the marshalled data contained
274    *  in the specified input stream.
275    *
276    *  @param in the stream to be read
277    */
278   public void readExternal(ObjectInput in)
279     throws IOException
280   {
281     payload       = in.readInt();
282     header        = in.readInt();
283     trailer       = in.readInt();
284     endpayload    = payload + header;
285     totlen        = endpayload + trailer;
286     fragmentCount = in.readInt();
287     byteCount     = in.readInt();
288     maxsize       = in.readInt();
289     written       = in.readInt();
290 
291     // Initialize variables for message position in the stream
292     position = 0;
293     fragment = 0;
294     offset   = header;
295 
296     // Reconstruct fragments from stream
297     fragments = new byte[fragmentCount][];
298     int fcount = fragmentCount - 1;
299     for (int i = 0; i < fcount; i++) {
300       fragments[i] = new byte[totlen];
301       in.readFully(fragments[i]);
302     }
303     fragments[fcount] = new byte[totlen];
304     int lastFragLen = getLastPayload() + header + trailer;
305     in.readFully(fragments[fcount], 0, lastFragLen);
306     buffer = fragments[0];
307 //    System.out.println("outmsg READ: " + this.toString(true));
308   }
309 
310 
311   /**
312    *  Marshals the content of this object to the specified output stream.
313    * 
314    *  @param out the stream to be written
315    */
316   public void writeExternal(ObjectOutput out)
317     throws IOException
318   {
319     out.writeInt(payload);
320     out.writeInt(header);
321     out.writeInt(trailer);
322     out.writeInt(fragmentCount);
323     out.writeInt(byteCount);
324     out.writeInt(maxsize);
325     out.writeInt(written);
326 
327     int fcount = fragmentCount - 1;
328     for (int i = 0; i < fcount; i++) {
329       out.write(fragments[i]);
330     }
331     int lastFragLen = getLastPayload() + header + trailer;
332     out.write(fragments[fcount], 0, lastFragLen);
333 //    System.out.println("outmsg WRITE: " + this.toString(true));
334   }
335 
336 
337   ////////////////////////////////////////////////////////////////////////////////////////////
338   // Methods inherited from OutputStream
339   ////////////////////////////////////////////////////////////////////////////////////////////
340 
341   /**
342    * Writes the specified byte to this byte array output stream. 
343    * <p>
344    * If the total number of bytes written in the message exceeds the maximum
345    * length, a <code>ArrayIndexOutOfBoundsException</code> is thrown.
346    *
347    * @param   b   the byte to be written.
348    */
349   public void write(int b) 
350   {
351     /* Increase the number of stored bytes */
352     position++;
353     if (position > byteCount) {
354       byteCount = position; 
355       if (position > maxsize)
356         throw new ArrayIndexOutOfBoundsException();
357       if (offset == endpayload) {
358         /*
359          * We have reached the end of the last fragment; we add a
360          * another fragment to store the new byte; fragment, offset and
361          * buffer are updated to point to the fist byte of the new
362          * fragment.
363          */
364         fragment++;
365         offset = header;
366         enlargeSpace(byteCount);
367         buffer = fragments[fragment];
368       }
369     }
370     /* We write the byte and increment offset */
371     buffer[offset++] = (byte) b;
372     written += 1;
373   }
374   
375   
376   /**
377    * Writes <code>len</code> bytes from the specified byte array 
378    * starting at offset <code>off</code> to this msg output stream.
379    * <p>
380    * If <code>b</code> is <code>null</code>, a 
381    * <code>NullPointerException</code> is thrown.
382    * <p>
383    * If <code>off</code> is negative, or <code>len</code> is negative, or 
384    * <code>off+len</code> is greater than the length of the array 
385    * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
386    * <p>
387    * If the total number of bytes written in the message exceeds the maximum
388    * length, a <tt>ArrayIndexOutOfBoundsException</tt> is thrown.
389    *
390    * @param   b     the data.
391    * @param   off   the start offset in the data.
392    * @param   len   the number of bytes to write.
393    */
394   public void write(byte[] b, int off, int len) 
395   {
396     if ((off<0) || (off>b.length) || (len<0) || ((off+len) > b.length)) {
397       throw new IndexOutOfBoundsException();
398     } else if (len == 0) {
399       return;
400     } else {
401       position += len;
402       if (position > byteCount) {
403         byteCount = position;
404         if (position > maxsize) {
405           throw new ArrayIndexOutOfBoundsException();
406         }
407       }
408       if (offset + len <= endpayload) {
409         System.arraycopy(b, off, buffer, offset, len);
410         offset += len;
411       } else {
412         enlargeSpace(byteCount);
413         int todo = endpayload - offset;
414         System.arraycopy(b, off, buffer, offset, todo);
415         int remaining = len-todo;
416         off += todo;
417         fragment++;  
418         while (remaining > payload) {                       
419           System.arraycopy(b, off, fragments[fragment], header, payload);
420           remaining -= payload;
421           off += payload;
422           fragment++;
423         }
424         System.arraycopy(b, off, fragments[fragment], header, remaining);
425         offset = remaining + header;
426         buffer = fragments[fragment];
427         
428       }
429     }
430     written += len;
431   }
432 
433   /**
434    * Writes <code>b.length</code> bytes from the specified byte array 
435    * to this output stream. The general contract for <code>write(b)</code> 
436    * is that it should have exactly the same effect as the call 
437    * <code>write(b, 0, b.length)</code>.
438    * <p>
439    * If the total number of bytes written in the message exceeds the maximum
440    * length, a <tt>ArrayIndexOutOfBoundsException</tt> is thrown.
441    *
442    * @param      b   the data.
443    *
444    */
445   public void write(byte[] b) 
446   {
447     write(b, 0, b.length);
448   }
449 
450   ////////////////////////////////////////////////////////////////////////////////////////////
451   // Methods from DataOutput
452   ////////////////////////////////////////////////////////////////////////////////////////////
453 
454   /**
455    * Writes a <code>boolean</code> value to this output stream.
456    * If the argument <code>v</code>
457    * is <code>true</code>, the value <code>(byte)1</code>
458    * is written; if <code>v</code> is <code>false</code>,
459    * the  value <code>(byte)0</code> is written.
460    * The byte written by this method may
461    * be read by the <code>readBoolean</code>
462    * method of interface <code>DataInput</code>,
463    * which will then return a <code>boolean</code>
464    * equal to <code>v</code>.
465    *
466    * @param      v   the boolean to be written.
467    * @exception  IOException  if an I/O error occurs.
468    */
469   public void writeBoolean(boolean v) throws IOException
470   {
471     write(v ? 1 : 0);
472   }
473   
474   /**
475    * Writes to the output stream the eight low-
476    * order bits of the argument <code>v</code>.
477    * The 24 high-order bits of <code>v</code>
478    * are ignored. (This means  that <code>writeByte</code>
479    * does exactly the same thing as <code>write</code>
480    * for an integer argument.) The byte written
481    * by this method may be read by the <code>readByte</code>
482    * method of interface <code>DataInput</code>,
483    * which will then return a <code>byte</code>
484    * equal to <code>(byte)v</code>.
485    *
486    * @param      v   the byte value to be written.
487    * @exception  IOException  if an I/O error occurs.
488    */
489   public void writeByte(int v) throws IOException
490   {
491     write(v);
492   }
493   
494   /**
495    * Writes two bytes to the output
496    * stream to represent the value of the argument.
497    * The byte values to be written, in the  order
498    * shown, are: <p>
499    * <pre><code>
500    * (byte)(0xff &amp; (v &gt;&gt; 8))
501    * (byte)(0xff &amp; v)
502    * </code> </pre> <p>
503    * The bytes written by this method may be
504    * read by the <code>readShort</code> method
505    * of interface <code>DataInput</code> , which
506    * will then return a <code>short</code> equal
507    * to <code>(short)v</code>.
508    *
509    * @param      v   the <code>short</code> value to be written.
510    * @exception  IOException  if an I/O error occurs.
511    */
512   public void writeShort(int v) throws IOException
513   {
514     write2(v);
515   }
516   
517   /**
518    * Writes a <code>char</code> value, wich
519    * is comprised of two bytes, to the
520    * output stream.
521    * The byte values to be written, in the  order
522    * shown, are:
523    * <p><pre><code>
524    * (byte)(0xff &amp; (v &gt;&gt; 8))
525    * (byte)(0xff &amp; v)
526    * </code></pre><p>
527    * The bytes written by this method may be
528    * read by the <code>readChar</code> method
529    * of interface <code>DataInput</code> , which
530    * will then return a <code>char</code> equal
531    * to <code>(char)v</code>.
532    *
533    * @param      v   the <code>char</code> value to be written.
534    * @exception  IOException  if an I/O error occurs.
535    */
536   public void writeChar(int v) throws IOException
537   {
538     write2(v);
539   }
540   
541   /**
542    * Writes an <code>int</code> value, which is
543    * comprised of four bytes, to the output stream.
544    * The byte values to be written, in the  order
545    * shown, are:
546    * <p><pre><code>
547    * (byte)(0xff &amp; (v &gt;&gt; 24))
548    * (byte)(0xff &amp; (v &gt;&gt; 16))
549    * (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
550    * (byte)(0xff &amp; v)
551    * </code></pre><p>
552    * The bytes written by this method may be read
553    * by the <code>readInt</code> method of interface
554    * <code>DataInput</code> , which will then
555    * return an <code>int</code> equal to <code>v</code>.
556    *
557    * @param      v   the <code>int</code> value to be written.
558    * @exception  IOException  if an I/O error occurs.
559    */
560   public void writeInt(int v) throws IOException
561   {
562     write4(v);
563   }
564   
565   /**
566    * Writes an <code>long</code> value, which is
567    * comprised of four bytes, to the output stream.
568    * The byte values to be written, in the  order
569    * shown, are:
570    * <p><pre><code>
571    * (byte)(0xff &amp; (v &gt;&gt; 48))
572    * (byte)(0xff &amp; (v &gt;&gt; 40))
573    * (byte)(0xff &amp; (v &gt;&gt; 32))
574    * (byte)(0xff &amp; (v &gt;&gt; 24))
575    * (byte)(0xff &amp; (v &gt;&gt; 16))
576    * (byte)(0xff &amp; (v &gt;&gt;  8))
577    * (byte)(0xff &amp; v)
578    * </code></pre><p>
579    * The bytes written by this method may be
580    * read by the <code>readLong</code> method
581    * of interface <code>DataInput</code> , which
582    * will then return a <code>long</code> equal
583    * to <code>v</code>.
584    *
585    * @param      v   the <code>long</code> value to be written.
586    * @exception  IOException  if an I/O error occurs.
587    */
588   public void writeLong(long v) throws IOException
589   {
590     write8(v);
591   }
592   
593   /**
594    * Writes a <code>float</code> value,
595    * which is comprised of four bytes, to the output stream.
596    * It does this as if it first converts this
597    * <code>float</code> value to an <code>int</code>
598    * in exactly the manner of the <code>Float.floatToIntBits</code>
599    * method  and then writes the <code>int</code>
600    * value in exactly the manner of the  <code>writeInt</code>
601    * method.  The bytes written by this method
602    * may be read by the <code>readFloat</code>
603    * method of interface <code>DataInput</code>,
604    * which will then return a <code>float</code>
605    * equal to <code>v</code>.
606    *
607    * @param      v   the <code>float</code> value to be written.
608    * @exception  IOException  if an I/O error occurs.
609    */
610   public void writeFloat(float v) throws IOException
611   {
612     write4(Float.floatToIntBits(v));
613   }
614   
615   /**
616    * Writes a <code>double</code> value,
617    * which is comprised of eight bytes, to the output stream.
618    * It does this as if it first converts this
619    * <code>double</code> value to a <code>long</code>
620    * in exactly the manner of the <code>Double.doubleToLongBits</code>
621    * method  and then writes the <code>long</code>
622    * value in exactly the manner of the  <code>writeLong</code>
623    * method. The bytes written by this method
624    * may be read by the <code>readDouble</code>
625    * method of interface <code>DataInput</code>,
626    * which will then return a <code>double</code>
627    * equal to <code>v</code>.
628    *
629    * @param      v   the <code>double</code> value to be written.
630    * @exception  IOException  if an I/O error occurs.
631    */
632   public void writeDouble(double v) throws IOException
633   {
634     write8(Double.doubleToLongBits(v));
635   }
636   
637   /**
638    * Writes a string to the output stream.
639    * For every character in the string
640    * <code>s</code>,  taken in order, one byte
641    * is written to the output stream.  If
642    * <code>s</code> is <code>null</code>, a <code>NullPointerException</code>
643    * is thrown.<p>  If <code>s.length</code>
644    * is zero, then no bytes are written. Otherwise,
645    * the character <code>s[0]</code> is written
646    * first, then <code>s[1]</code>, and so on;
647    * the last character written is <code>s[s.length-1]</code>.
648    * For each character, one byte is written,
649    * the low-order byte, in exactly the manner
650    * of the <code>writeByte</code> method . The
651    * high-order eight bits of each character
652    * in the string are ignored.
653    *
654    * @param      s   the string of bytes to be written.
655    * @exception  IOException  if an I/O error occurs.
656    */
657   public void writeBytes(String s) throws IOException
658   {
659     int len = s.length();
660     for (int i = 0 ; i < len ; i++) {
661       write((byte)s.charAt(i));
662     }
663   }
664   
665   /**
666    * Writes every character in the string <code>s</code>,
667    * to the output stream, in order,
668    * two bytes per character. If <code>s</code>
669    * is <code>null</code>, a <code>NullPointerException</code>
670    * is thrown.  If <code>s.length</code>
671    * is zero, then no characters are written.
672    * Otherwise, the character <code>s[0]</code>
673    * is written first, then <code>s[1]</code>,
674    * and so on; the last character written is
675    * <code>s[s.length-1]</code>. For each character,
676    * two bytes are actually written, high-order
677    * byte first, in exactly the manner of the
678    * <code>writeChar</code> method.
679    *
680    * @param      s   the string value to be written.
681    * @exception  IOException  if an I/O error occurs.
682    */
683   public void writeChars(String s) throws IOException
684   {
685     int len = s.length();
686     for (int i = 0 ; i < len ; i++) {
687       int v = s.charAt(i);
688       write((v >>> 8) & 0xFF);
689       write((v >>> 0) & 0xFF);
690     }
691   }
692   
693   /**
694    * Writes two bytes of length information
695    * to the output stream, followed
696    * by the Java modified UTF representation
697    * of  every character in the string <code>s</code>.
698    * If <code>s</code> is <code>null</code>,
699    * a <code>NullPointerException</code> is thrown.
700    * Each character in the string <code>s</code>
701    * is converted to a group of one, two, or
702    * three bytes, depending on the value of the
703    * character.<p>
704    * If a character <code>c</code>
705    * is in the range <code>&#92;u0001</code> through
706    * <code>&#92;u007f</code>, it is represented
707    * by one byte:<p>
708    * <pre>(byte)c </pre>  <p>
709    * If a character <code>c</code> is <code>&#92;u0000</code>
710    * or is in the range <code>&#92;u0080</code>
711    * through <code>&#92;u07ff</code>, then it is
712    * represented by two bytes, to be written
713    * in the order shown:<p> <pre><code>
714    * (byte)(0xc0 | (0x1f &amp; (c &gt;&gt; 6)))
715    * (byte)(0x80 | (0x3f &amp; c))
716    *  </code></pre>  <p> If a character
717    * <code>c</code> is in the range <code>&#92;u0800</code>
718    * through <code>uffff</code>, then it is
719    * represented by three bytes, to be written
720    * in the order shown:<p> <pre><code>
721    * (byte)(0xc0 | (0x0f &amp; (c &gt;&gt; 12)))
722    * (byte)(0x80 | (0x3f &amp; (c &gt;&gt;  6)))
723    * (byte)(0x80 | (0x3f &amp; c))
724    *  </code></pre>  <p> First,
725    * the total number of bytes needed to represent
726    * all the characters of <code>s</code> is
727    * calculated. If this number is larger than
728    * <code>65535</code>, then a <code>UTFDataFormatError</code>
729    * is thrown. Otherwise, this length is written
730    * to the output stream in exactly the manner
731    * of the <code>writeShort</code> method;
732    * after this, the one-, two-, or three-byte
733    * representation of each character in the
734    * string <code>s</code> is written.<p>  The
735    * bytes written by this method may be read
736    * by the <code>readUTF</code> method of interface
737    * <code>DataInput</code> , which will then
738    * return a <code>String</code> equal to <code>s</code>.
739    *
740    * @param      str   the string value to be written.
741    * @exception  IOException  if an I/O error occurs.
742    */
743   public void writeUTF(String str) throws IOException
744   {
745     int strlen = str.length();
746     int utflen = 0;
747     char[] charr = new char[strlen];
748     int c, count = 0;
749     
750     str.getChars(0, strlen, charr, 0);
751     
752     for (int i = 0; i < strlen; i++) {
753       c = charr[i];
754       if ((c >= 0x0001) && (c <= 0x007F)) {
755         utflen++;
756       } else if (c > 0x07FF) {
757         utflen += 3;
758       } else {
759         utflen += 2;
760       }
761     }
762     
763     if (utflen > 65535)
764       throw new UTFDataFormatException();
765     
766     byte[] bytearr = new byte[utflen+2];
767     bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
768     bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
769     for (int i = 0; i < strlen; i++) {
770       c = charr[i];
771       if ((c >= 0x0001) && (c <= 0x007F)) {
772         bytearr[count++] = (byte) c;
773       } else if (c > 0x07FF) {
774         bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
775         bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
776         bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
777       } else {
778         bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
779         bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
780       }
781     }
782     write(bytearr);
783   }
784 
785   /**
786    * Returns the current value of the counter <code>written</code>, 
787    * the number of bytes written to this data output stream so far.
788    * Note: in this version, the counter may overflow.
789    *
790    * @return  the value of the <code>written</code> field.
791    * @see     java.io.DataOutputStream#written
792    */
793   public final int size() {
794     return written;
795   }
796 
797 
798   ////////////////////////////////////////////////////////////////////////////////////////////
799   // Methods from ObjectOutput
800   ////////////////////////////////////////////////////////////////////////////////////////////
801 
802   /**
803    * Write an object to the underlying storage or stream.  The
804    * class that implements this interface defines how the object is
805    * written.
806    *
807    * @exception IOException Any of the usual Input/Output related exceptions.
808    */
809   public void writeObject(Object obj)
810     throws IOException
811   {
812     // workaround since OutMessage don't provide native support for writeObject()
813     ObjectOutputStream oos = new ObjectOutputStream(this);
814     oos.writeObject(obj);
815   }
816 
817 
818   ////////////////////////////////////////////////////////////////////////////////////////////
819   // Public methods
820   ////////////////////////////////////////////////////////////////////////////////////////////
821 
822   /**
823    *  Move the current position in the stream to the specified
824    *  <code>position</code>. <p>
825    *
826    *  @exception IndexOutOfBoundsException
827    *    Raised if the new position in the message exceeds the maximum
828    *    length.
829    */
830   public void seek(int position)
831   {
832     fragment = position / payload;
833     offset = header + position % payload;
834     this.position = position;
835     /*
836      * FIXED HEIN 29/7-02: this didn't enlarge the space, when the
837      * position was at the first position in the next fragment.  Thus,
838      * it was fixed using >= instead of >.  See also related comment in
839      * the enlargeSpace() method below.
840      */
841     if (position >= byteCount) {
842       byteCount = position;
843       if (position > maxsize) {
844         throw new IndexOutOfBoundsException("New position (" + position
845           + ") exceeds maximum length:" + maxsize);
846       }
847       enlargeSpace(position);
848     }
849     buffer = fragments[fragment];
850   }
851 
852 
853   /**
854    *  Write a short integer value <code>v</code> into the stream at the
855    *  current position.  <p>
856    *
857    *  @exception ArrayIndexOutOfBoundsException
858    *    Raised if the total number of bytes written in the message
859    *    exceeds the maximum length.
860    */
861   public void write2(int v)
862   {
863     position += 2;
864     if (position > byteCount) {
865       byteCount = position;
866       if (position > maxsize)
867         throw new ArrayIndexOutOfBoundsException();
868     }
869     if (offset + 2 > endpayload) {
870       temp[0] = (byte) (v >>> 8);
871       temp[1] = (byte) (v >>> 0);
872       writeTemp(temp, 2);
873     } else {
874       buffer[offset++] = (byte) (v >>>  8);
875       buffer[offset++] = (byte) (v >>>  0);
876     }
877     written += 2;
878   }
879 
880 
881   /**
882    *  Write an integer value <code>v</code> into the stream at the
883    *  current position.  <p>
884    *
885    *  @exception ArrayIndexOutOfBoundsException
886    *    Raised if the total number of bytes written in the message
887    *    exceeds the maximum length.
888    */
889   public void write4(int v)
890   {
891     position += 4;
892     if (position > byteCount) {
893       byteCount = position;
894       if (position > maxsize)
895         throw new ArrayIndexOutOfBoundsException();
896     }
897     if (offset + 4 > endpayload) {
898       temp[0] = (byte) (v >>> 24);
899       temp[1] = (byte) (v >>> 16);
900       temp[2] = (byte) (v >>>  8);
901       temp[3] = (byte) (v >>>  0);
902       writeTemp(temp, 4);
903     } else {
904       buffer[offset++] = (byte) (v >>>  24);
905       buffer[offset++] = (byte) (v >>>  16);
906       buffer[offset++] = (byte) (v >>>   8);
907       buffer[offset++] = (byte) (v >>>   0);
908     }
909     written += 4;
910   }
911 
912 
913   /**
914    *  Write a long value <code>v</code> into the stream at the current
915    *  position.  <p>
916    *
917    *  @exception ArrayIndexOutOfBoundsException
918    *    Raised if the total number of bytes written in the message
919    *    exceeds the maximum length.
920    */
921   public void write8(long v)
922   {
923     position += 8;
924     if (position > byteCount) {
925       byteCount = position;
926       if (position > maxsize)
927         throw new ArrayIndexOutOfBoundsException();
928     }
929     int v1 = (int) (v >>> 32);
930     int v2 = (int) (v & 0xFFFFFFFFL);
931     if (offset + 8 > endpayload) {
932       temp[0] = (byte) (v1 >>> 24);
933       temp[1] = (byte) (v1 >>> 16);
934       temp[2] = (byte) (v1 >>>  8);
935       temp[3] = (byte) (v1 >>>  0);
936       temp[4] = (byte) (v2 >>> 24);
937       temp[5] = (byte) (v2 >>> 16);
938       temp[6] = (byte) (v2 >>>  8);
939       temp[7] = (byte) (v2 >>>  0);
940       writeTemp(temp, 8);
941     } else {
942       buffer[offset++] = (byte) (v1 >>> 24);
943       buffer[offset++] = (byte) (v1 >>> 16);
944       buffer[offset++] = (byte) (v1 >>> 8);
945       buffer[offset++] = (byte) (v1 >>> 0);
946       buffer[offset++] = (byte) (v2 >>> 24);
947       buffer[offset++] = (byte) (v2 >>> 16);
948       buffer[offset++] = (byte) (v2 >>> 8);
949       buffer[offset++] = (byte) (v2 >>> 0);
950     }
951     written += 8;
952   }
953 
954   /**
955    *  Write the content of another <code>OutMessage</code> into the
956    *  current message. <p>
957    *
958    *  @exception ArrayIndexOutOfBoundsException
959    *    Raised if the total number of bytes written in the message
960    *    exceeds the maximum length.
961    */
962   public void write(OutMessage msg) 
963   {
964     byte[][] fragments = msg.getFragments();
965     int length = msg.getFragmentCount();
966     for (int i=0; i < length-1; i++)
967       write(fragments[i], msg.getHeader(), msg.getPayload());
968     write(fragments[length-1], msg.getHeader(), msg.getLastPayload());
969   }
970   
971   /**
972    *  Reset the byte array
973    */
974   public void reset()
975   {
976     // Reinitialize fragments
977     buffer = fragments[0];
978     
979     // Initialize variables regarding message size
980     byteCount = 0;
981     fragmentCount = 1;
982     maxsize = Integer.MAX_VALUE;
983 
984     // Initialize variables regarding message position in the stream
985     position = 0;
986     fragment = 0;
987     offset = header;
988   }
989 
990   /**
991    * Compute the checksum of the bytes stored in the message
992    *
993    * @return the computed checksum.
994    */
995   public int computeChecksum()
996   {
997     byte check = 0;
998 
999     for (int j = 0; j < fragmentCount-1; j++)
1000       for (int i = header; i < endpayload; i++)
1001         check ^= fragments[j][i];
1002     byte[] buffer = fragments[fragmentCount-1];
1003     int end = getLastPayload() + header;
1004     for (int i = header; i < end; i++)
1005       check ^= buffer[i];
1006 
1007     return check;
1008   }
1009 
1010 
1011   ////////////////////////////////////////////////////////////////////////////////////////////
1012   // Package methods
1013   ////////////////////////////////////////////////////////////////////////////////////////////
1014 
1015   /**
1016    *  Return the current position in this message.
1017    */
1018   public int getPosition()
1019   {
1020     return position;
1021   }
1022 
1023   /**
1024    *  Return the length of the payload for this message.
1025    */
1026   public int getPayload()
1027   {
1028     return payload;
1029   }
1030 
1031   /**
1032    *  Return the length of the header for this message.
1033    */
1034   public int getHeader()
1035   {
1036     return header;
1037   }
1038 
1039   /**
1040    *  Return the length of the trailer for this message.
1041    */
1042   public int getTrailer()
1043   {
1044     return trailer;
1045   }
1046 
1047   /**
1048    *  Returns the total number of bytes stored in this message.
1049    */
1050   public int getByteCount()
1051   {
1052     return byteCount;
1053   }
1054 
1055   /**
1056    *  Returns the number of fragments composing the message.
1057    */
1058   public int getFragmentCount()
1059   {
1060     return fragmentCount;
1061   }
1062 
1063   /**
1064    *  Returns the length of the payload of the last fragment composing
1065    *  the message.
1066    */
1067   public int getLastPayload()
1068   {
1069     if (byteCount % payload == 0)
1070       return payload;
1071     else
1072       return (byteCount % payload);
1073   }
1074   
1075   /**
1076    *  Returns an array of byte arrays which contains the fragments
1077    *  composing the message.  The length of fragment array may be
1078    *  greater than the number of fragments actually allocated; the
1079    *  actual number of fragments is obtained by invoking method
1080    *  <code>getFragmentCount</code>.
1081    */
1082   public byte[][] getFragments()
1083   {
1084     return fragments;
1085   }
1086 
1087   /**
1088    *  Converts the whole <code>OutMessage</code> into a byte array.
1089    */
1090   public byte[] toByteArray()
1091   {
1092     byte[] ret = new byte[byteCount];
1093     if (byteCount > 0) {
1094       for (int i=0; i < fragmentCount-1; i++) {
1095         System.arraycopy(fragments[i], 0, ret, i*payload, payload);
1096       }
1097       System.arraycopy(fragments[fragmentCount-1], 0, ret, 
1098         (fragmentCount-1)*payload, getLastPayload());
1099     }
1100     return ret;
1101   }
1102 
1103 
1104   ////////////////////////////////////////////////////////////////////////////////////////////
1105   // Private methods
1106   ////////////////////////////////////////////////////////////////////////////////////////////
1107 
1108   /**
1109    *  Copy <code>length</code> bytes from array <code>temp</code>; this
1110    *  method is invoked when methods <code>write2</code>,
1111    *  <code>write4</code>, or <code>write8</code> should write part of
1112    *  their data in the current fragment and the rest in the following
1113    *  fragment.
1114    */
1115   private void writeTemp(byte[] temp, int length)
1116   {
1117     enlargeSpace(byteCount);
1118     for (int i = 0; i < length; i++) {
1119       if (offset == endpayload) {
1120         fragment++;
1121         buffer = fragments[fragment];
1122         offset = header;
1123       }
1124       buffer[offset++] = temp[i];
1125     }
1126   }
1127 
1128 
1129   /**
1130    *  Allocate new byte fragments to guarantee that there is enough
1131    *  space to store <code>newsize</code> bytes.
1132    */
1133   private void enlargeSpace(int newsize)
1134   {
1135     /*
1136      * FIXED HEIN 29/7-02: computing the number of fragments was
1137      * incorrect when the newsize was equal to the payload.  This caused
1138      * a problem when doing seek(payload).  The seek() would compute
1139      * that it was in the first position of the next fragment, but
1140      * computing nfragment to one less fragment than seek() expected,
1141      * and so it didn't enlarge the space after all.  So when doing a
1142      * write() from the new current position, we would get a
1143      * NullPointerException since it was trying to access a buffer[]
1144      * that was not initialized.
1145      *
1146      * The old code was this:
1147      *    int nfragment = ((newsize-1) / payload) + 1;
1148      *
1149      * In anycase, this does not lead to many extra memory allocations,
1150      * since the case when newsize equals to payload is very rare.
1151      */
1152 
1153     /* Total number of fragments needed to store <code>newsize</code> bytes. */
1154     int nfragment = (newsize / payload) + 1;
1155     if (nfragment > fragments.length) {
1156       /* Double the fragments array */
1157       byte[][] tempbuffer = new byte[nfragment*2][];
1158       System.arraycopy(fragments, 0, tempbuffer, 0, fragments.length);
1159       fragments = tempbuffer;
1160     }
1161     for (int i = fragmentCount; i < nfragment; i++)
1162       fragments[i] = new byte[totlen];
1163     if (fragmentCount < nfragment)
1164       fragmentCount = nfragment;
1165   }
1166 
1167 
1168   ////////////////////////////////////////////////////////////////////////////////////////////
1169   // Object methods
1170   ////////////////////////////////////////////////////////////////////////////////////////////
1171 
1172   /**
1173    *  Returns a string representation of this object (used only for
1174    *  debugging)
1175    */
1176   public String toString(boolean all)
1177   {
1178     StringBuilder buf = new StringBuilder();
1179     buf.append("[OutMessage: byteCnt=");
1180     buf.append(byteCount);
1181     buf.append(", payload=");
1182     buf.append(payload);
1183     buf.append(", header=");
1184     buf.append(header);
1185     buf.append(", trailer=");
1186     buf.append(trailer);
1187     buf.append(", totlen=");
1188     buf.append(totlen);
1189     buf.append(", endpayload=");
1190     buf.append(endpayload);
1191     buf.append(", position=");
1192     buf.append(position);
1193     buf.append(", fragment=");
1194     buf.append(fragment);
1195     buf.append(", offset=");
1196     buf.append(offset);
1197     buf.append(", fragmentCount=");
1198     buf.append(fragmentCount);
1199     buf.append(", maxsize=");
1200     buf.append(maxsize);
1201     buf.append("]");
1202 
1203     if (ConfigManager.logMsgContent) {
1204       buf.append(": ");
1205     } else {
1206       // Return without logging message content
1207       return buf.toString();
1208     }
1209 
1210     if (all) {
1211       for (int i = 0; i < fragmentCount-1; i++) {
1212         for (int j = header; j < endpayload; j++) {
1213           buf.append(" ");
1214           buf.append(Util.byte2str(fragments[i][j]));
1215         }
1216       }
1217       int stop = byteCount - (fragmentCount-1)*payload + header;
1218       for (int j = header; j < stop; j++) {
1219         buf.append(" ");
1220         buf.append(Util.byte2str(fragments[fragmentCount-1][j]));
1221       }
1222     } else {
1223       for (int i = 0, j = header; j < endpayload; j++) {
1224         buf.append(" ");
1225         buf.append(Util.byte2str(fragments[i][j]));
1226       }
1227     }
1228     return buf.toString();
1229   }
1230 
1231 
1232   /**
1233    *  Returns a string representation of this object
1234    */
1235   public String toString()
1236   {
1237     return toString(false);
1238   }
1239 
1240 } // END OutMessage