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 <a href="tim.fox@jboss.com">Tim Fox</a> * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a> * @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(); } }