/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ package org.apache.catalina.tribes.io;
/** * The XByteBuffer provides a dual functionality. * One, it stores message bytes and automatically extends the byte buffer if needed.<BR> * Two, it can encode and decode packages so that they can be defined and identified * as they come in on a socket. * <br> * <b>THIS CLASS IS NOT THREAD SAFE</B><BR> * <br> * Transfer package: * <ul> * <li><b>START_DATA</b>- 7 bytes - <i>FLT2002</i></li> * <li><b>SIZE</b> - 4 bytes - size of the data package</li> * <li><b>DATA</b> - should be as many bytes as the prev SIZE</li> * <li><b>END_DATA</b> - 7 bytes - <i>TLF2003</i></li> * </ul>
*/ publicclass XByteBuffer implements Serializable {
privatestaticfinallong serialVersionUID = 1L;
privatestaticfinal Log log = LogFactory.getLog(XByteBuffer.class); protectedstaticfinal StringManager sm = StringManager.getManager(XByteBuffer.class);
/** * This is a package header, 7 bytes (FLT2002)
*/ privatestaticfinalbyte[] START_DATA = {70,76,84,50,48,48,50};
/** * This is the package footer, 7 bytes (TLF2003)
*/ privatestaticfinalbyte[] END_DATA = {84,76,70,50,48,48,51};
/** * Variable to hold the data
*/ protectedbyte[] buf = null;
/** * Current length of data in the buffer
*/ protectedint bufSize = 0;
/** * Flag for discarding invalid packages * If this flag is set to true, and append(byte[],...) is called, * the data added will be inspected, and if it doesn't start with * <code>START_DATA</code> it will be thrown away. *
*/ protectedboolean discard = true;
/** * Constructs a new XByteBuffer.<br> * TODO use a pool of byte[] for performance * @param size the initial size of the byte buffer * @param discard Flag for discarding invalid packages
*/ public XByteBuffer(int size, boolean discard) {
buf = newbyte[size]; this.discard = discard;
}
public XByteBuffer(byte[] data,boolean discard) { this(data,data.length+128,discard);
}
public XByteBuffer(byte[] data, int size,boolean discard) { int length = Math.max(data.length,size);
buf = newbyte[length];
System.arraycopy(data,0,buf,0,data.length);
bufSize = data.length; this.discard = discard;
}
/** * @return the bytes in the buffer, in its exact length
*/ publicbyte[] getBytes() { byte[] b = newbyte[bufSize];
System.arraycopy(buf,0,b,0,bufSize); return b;
}
/** * Appends the data to the buffer. If the data is incorrectly formatted, ie, the data should always start with the * header, false will be returned and the data will be discarded. * @param b - bytes to be appended * @param len - the number of bytes to append. * @return true if the data was appended correctly. Returns false if the package is incorrect, ie missing header or something, or the length of data is 0
*/ publicboolean append(ByteBuffer b, int len) { int newcount = bufSize + len; if (newcount > buf.length) {
expand(newcount);
}
b.get(buf,bufSize,len);
/** * Internal mechanism to make a check if a complete package exists * within the buffer * @return - true if a complete package (header,compress,size,data,footer) exists within the buffer
*/ publicint countPackages() { return countPackages(false);
}
publicint countPackages(boolean first)
{ int cnt = 0; int pos = START_DATA.length; int start = 0;
while ( start < bufSize ) { //first check start header int index = firstIndexOf(buf,start,START_DATA); //if the header (START_DATA) isn't the first thing or //the buffer isn't even 14 bytes if ( index != start || ((bufSize-start)<14) ) { break;
} //next 4 bytes are compress flag not needed for count packages //then get the size 4 bytes int size = toInt(buf, pos); //now the total buffer has to be long enough to hold //START_DATA.length+4+size+END_DATA.length
pos = start + START_DATA.length + 4 + size; if ( (pos + END_DATA.length) > bufSize) { break;
} //and finally check the footer of the package END_DATA int newpos = firstIndexOf(buf, pos, END_DATA); //mismatch, there is no package if (newpos != pos) { break;
} //increase the packet count
cnt++; //reset the values
start = pos + END_DATA.length;
pos = start + START_DATA.length; //we only want to verify that we have at least one package if ( first ) { break;
}
} return cnt;
}
/** * Method to check if a package exists in this byte buffer. * @return - true if a complete package (header,options,size,data,footer) exists within the buffer
*/ publicboolean doesPackageExist() { return (countPackages(true)>0);
}
/** * Extracts the message bytes from a package. * If no package exists, a IllegalStateException will be thrown. * @param clearFromBuffer - if true, the package will be removed from the byte buffer * @return - returns the actual message bytes (header, compress,size and footer not included).
*/ public XByteBuffer extractDataPackage(boolean clearFromBuffer) { int psize = countPackages(true); if (psize == 0) { thrownew IllegalStateException(sm.getString("xByteBuffer.no.package"));
} int size = toInt(buf, START_DATA.length);
XByteBuffer xbuf = BufferPool.getBufferPool().getBuffer(size,false);
xbuf.setLength(size);
System.arraycopy(buf, START_DATA.length + 4, xbuf.getBytesDirect(), 0, size); if (clearFromBuffer) { int totalsize = START_DATA.length + 4 + size + END_DATA.length;
bufSize = bufSize - totalsize;
System.arraycopy(buf, totalsize, buf, 0, bufSize);
} return xbuf;
publicstaticbyte[] createDataPackage(byte[] data) { int length = getDataPackageLength(data.length); byte[] result = newbyte[length]; return createDataPackage(data,0,data.length,result,0);
}
// public static void fillDataPackage(byte[] data, int doff, int dlength, XByteBuffer buf) { // int pkglen = getDataPackageLength(dlength); // if ( buf.getCapacity() < pkglen ) buf.expand(pkglen); // createDataPackage(data,doff,dlength,buf.getBytesDirect(),buf.getLength()); // }
/** * Convert four bytes to an int * @param b - the byte array containing the four bytes * @param off - the offset * @return the integer value constructed from the four bytes
*/ publicstaticint toInt(byte[] b,int off){ return ( ( b[off+3]) & 0xFF) +
( ( ( b[off+2]) & 0xFF) << 8) +
( ( ( b[off+1]) & 0xFF) << 16) +
( ( ( b[off+0]) & 0xFF) << 24);
}
/** * Convert eight bytes to a long * @param b - the byte array containing the four bytes * @param off - the offset * @return the long value constructed from the eight bytes
*/ publicstaticlong toLong(byte[] b,int off){ return ( ( (long) b[off+7]) & 0xFF) +
( ( ( (long) b[off+6]) & 0xFF) << 8) +
( ( ( (long) b[off+5]) & 0xFF) << 16) +
( ( ( (long) b[off+4]) & 0xFF) << 24) +
( ( ( (long) b[off+3]) & 0xFF) << 32) +
( ( ( (long) b[off+2]) & 0xFF) << 40) +
( ( ( (long) b[off+1]) & 0xFF) << 48) +
( ( ( (long) b[off+0]) & 0xFF) << 56);
}
/** * Converts a boolean and put it in a byte array. * @param bool the integer * @param data the byte buffer in which the boolean will be placed * @param offset the offset in the byte array * @return the byte array
*/ publicstaticbyte[] toBytes(boolean bool, byte[] data, int offset) {
data[offset] = (byte)(bool?1:0); return data;
}
/** * Converts a byte array entry to boolean. * @param b byte array * @param offset within byte array * @return true if byte array entry is non-zero, false otherwise
*/ publicstaticboolean toBoolean(byte[] b, int offset) { return b[offset] != 0;
}
/** * Converts an integer to four bytes. * @param n the integer * @param b the byte buffer in which the integer will be placed * @param offset the offset in the byte array * @return four bytes in an array
*/ publicstaticbyte[] toBytes(int n, byte[] b, int offset) {
b[offset+3] = (byte) (n);
n >>>= 8;
b[offset+2] = (byte) (n);
n >>>= 8;
b[offset+1] = (byte) (n);
n >>>= 8;
b[offset+0] = (byte) (n); return b;
}
/** * Converts a long to eight bytes. * @param n the long * @param b the byte buffer in which the integer will be placed * @param offset the offset in the byte array * @return eight bytes in an array
*/ publicstaticbyte[] toBytes(long n, byte[] b, int offset) {
b[offset+7] = (byte) (n);
n >>>= 8;
b[offset+6] = (byte) (n);
n >>>= 8;
b[offset+5] = (byte) (n);
n >>>= 8;
b[offset+4] = (byte) (n);
n >>>= 8;
b[offset+3] = (byte) (n);
n >>>= 8;
b[offset+2] = (byte) (n);
n >>>= 8;
b[offset+1] = (byte) (n);
n >>>= 8;
b[offset+0] = (byte) (n); return b;
}
/** * Similar to a String.IndexOf, but uses pure bytes. * @param src - the source bytes to be searched * @param srcOff - offset on the source buffer * @param find - the string to be found within src * @return - the index of the first matching byte. -1 if the find array is not found
*/ publicstaticint firstIndexOf(byte[] src, int srcOff, byte[] find){ int result = -1; if (find.length > src.length) { return result;
} if (find.length == 0 || src.length == 0) { return result;
} if (srcOff >= src.length ) { thrownew ArrayIndexOutOfBoundsException();
} boolean found = false; int srclen = src.length; int findlen = find.length; byte first = find[0]; int pos = srcOff; while (!found) { //find the first byte while (pos < srclen){ if (first == src[pos]) { break;
}
pos++;
} if (pos >= srclen) { return -1;
}
//we found the first character //match the rest of the bytes - they have to match if ( (srclen - pos) < findlen) { return -1;
} //assume it does exist
found = true; for (int i = 1; ( (i < findlen) && found); i++) {
found = (find[i] == src[pos + i]);
} if (found) {
result = pos;
} elseif ( (srclen - pos) < findlen) { return -1; //no more matches possible
} else {
pos++;
}
} return result;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.