Development Java Tutorial

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
 * 
 * A SafeUTF
 * 
 * @author Tim Fox
 * @author Adrian Brock
 * @version $Revision: 1174 $
 *
 * $Id: SafeUTF.java 1174 2006-08-02 14:14:32Z timfox $
 * 
 * There is a "bug" in JDK1.4 / 1.5 DataOutputStream.writeUTF()
 * which means it does not work with Strings >= 64K serialized size.
 * See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4806007
 * 
 * We work around this by chunking larger strings into smaller pieces.
 * 
 * Note we only support TextMessage and ObjectMessage bodies with serialized length >= 64K
 * We DO NOT support Strings written to BytesMessages or StreamMessages or written as keys or values
 * in MapMessages, or as String properties or other String fields having serialized length >= 64K
 * This is for performance reasons since there is an overhead in coping with large
 * Strings
 * 
 */
public class SafeUTF
{      
   //Default is 16K chunks
   private static final int CHUNK_SIZE = 16 * 1024;
   
   private static final byte NULL = 0;
   
   private static final byte NOT_NULL = 1;
   
   public static SafeUTF instance = new SafeUTF(CHUNK_SIZE);
   
   private int chunkSize;
   
   private int lastReadBufferSize;
   
   public int getLastReadBufferSize()
   {
      return lastReadBufferSize;
   }
   
   public SafeUTF(int chunkSize)
   {
      this.chunkSize = chunkSize;
   }
      
   public void safeWriteUTF(DataOutputStream out, String str) throws IOException
   {        
      if (str == null)
      {
         out.writeByte(NULL);
      }
      else
      {         
         int len = str.length();
          
         short numChunks;
         
         if (len == 0)
         {
            numChunks = 0;
         }
         else
         {
            numChunks = (short)(((len - 1) / chunkSize) + 1);
         }         
         
         out.writeByte(NOT_NULL);
         
         out.writeShort(numChunks);
              
         int i = 0;
         while (len > 0)
         {
            int beginCopy = i * chunkSize;
            
            int endCopy = len <= chunkSize ? beginCopy + len : beginCopy + chunkSize;
     
            String theChunk = str.substring(beginCopy, endCopy);
               
            out.writeUTF(theChunk);
            
            len -= chunkSize;
            
            i++;
         }
      }
   }
   
   public String safeReadUTF(DataInputStream in) throws IOException
   {   
      boolean isNull = in.readByte() == NULL;
      
      if (isNull)
      {
         return null;
      }
      
      short numChunks = in.readShort();
      
      int bufferSize = chunkSize * numChunks;
      
      // special handling for single chunk
      if (numChunks == 1)
      {
         // The text size is likely to be much smaller than the chunkSize
         // so set bufferSize to the min of the input stream available
         // and the maximum buffer size. Since the input stream
         // available() can be <= 0 we check for that and default to
         // a small msg size of 256 bytes.
         
         int inSize = in.available();
               
         if (inSize <= 0)
         {
            inSize = 256;
         }
         bufferSize = Math.min(inSize, bufferSize);
         
         lastReadBufferSize = bufferSize;
      }
        
      StringBuffer buff = new StringBuffer(bufferSize);
            
      for (int i = 0; i < numChunks; i++)
      {
         String s = in.readUTF();
         buff.append(s);
      }
      
      return buff.toString();
   }
      
}