📄 xbytebuffer.java
字号:
/*
* 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;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
/**
* 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>
* @author Filip Hanik
* @version $Revision: 467173 $, $Date: 2006-10-24 01:12:17 +0200 (mar., 24 oct. 2006) $
*/
public class XByteBuffer
{
public static org.apache.juli.logging.Log log =
org.apache.juli.logging.LogFactory.getLog( XByteBuffer.class );
/**
* This is a package header, 7 bytes (FLT2002)
*/
public static final byte[] START_DATA = {70,76,84,50,48,48,50};
/**
* This is the package footer, 7 bytes (TLF2003)
*/
public static final byte[] END_DATA = {84,76,70,50,48,48,51};
/**
* Default size on the initial byte buffer
*/
private static final int DEF_SIZE = 2048;
/**
* Default size to extend the buffer with
*/
private static final int DEF_EXT = 1024;
/**
* Variable to hold the data
*/
protected byte[] buf = null;
/**
* Current length of data in the buffer
*/
protected int 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.
*
*/
protected boolean discard = true;
/**
* Constructs a new XByteBuffer
* @param size - the initial size of the byte buffer
* @todo use a pool of byte[] for performance
*/
public XByteBuffer(int size, boolean discard) {
buf = new byte[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 = new byte[length];
System.arraycopy(data,0,buf,0,data.length);
bufSize = data.length;
this.discard = discard;
}
public int getLength() {
return bufSize;
}
public void setLength(int size) {
if ( size > buf.length ) throw new ArrayIndexOutOfBoundsException("Size is larger than existing buffer.");
bufSize = size;
}
public void trim(int length) {
if ( (bufSize - length) < 0 )
throw new ArrayIndexOutOfBoundsException("Can't trim more bytes than are available. length:"+bufSize+" trim:"+length);
bufSize -= length;
}
public void reset() {
bufSize = 0;
}
public byte[] getBytesDirect() {
return this.buf;
}
/**
* Returns the bytes in the buffer, in its exact length
*/
public byte[] getBytes() {
byte[] b = new byte[bufSize];
System.arraycopy(buf,0,b,0,bufSize);
return b;
}
/**
* Resets the buffer
*/
public void clear() {
bufSize = 0;
}
/**
* 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 off - the offset to extract data from
* @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
*/
public boolean append(ByteBuffer b, int len) {
int newcount = bufSize + len;
if (newcount > buf.length) {
expand(newcount);
}
b.get(buf,bufSize,len);
bufSize = newcount;
if ( discard ) {
if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) {
bufSize = 0;
log.error("Discarded the package, invalid header");
return false;
}
}
return true;
}
public boolean append(byte i) {
int newcount = bufSize + 1;
if (newcount > buf.length) {
expand(newcount);
}
buf[bufSize] = i;
bufSize = newcount;
return true;
}
public boolean append(boolean i) {
int newcount = bufSize + 1;
if (newcount > buf.length) {
expand(newcount);
}
XByteBuffer.toBytes(i,buf,bufSize);
bufSize = newcount;
return true;
}
public boolean append(long i) {
int newcount = bufSize + 8;
if (newcount > buf.length) {
expand(newcount);
}
XByteBuffer.toBytes(i,buf,bufSize);
bufSize = newcount;
return true;
}
public boolean append(int i) {
int newcount = bufSize + 4;
if (newcount > buf.length) {
expand(newcount);
}
XByteBuffer.toBytes(i,buf,bufSize);
bufSize = newcount;
return true;
}
public boolean append(byte[] b, int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return false;
}
int newcount = bufSize + len;
if (newcount > buf.length) {
expand(newcount);
}
System.arraycopy(b, off, buf, bufSize, len);
bufSize = newcount;
if ( discard ) {
if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) {
bufSize = 0;
log.error("Discarded the package, invalid header");
return false;
}
}
return true;
}
public void expand(int newcount) {
//don't change the allocation strategy
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
System.arraycopy(buf, 0, newbuf, 0, bufSize);
buf = newbuf;
}
public int getCapacity() {
return buf.length;
}
/**
* 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
*/
public int countPackages() {
return countPackages(false);
}
public int countPackages(boolean first)
{
int cnt = 0;
int pos = START_DATA.length;
int start = 0;
while ( start < bufSize ) {
//first check start header
int index = XByteBuffer.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
*/
public boolean doesPackageExist() {
return (countPackages(true)>0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -