This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
/*
* 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 org.apache.catalina.tribes.util.StringManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
*
*
* @version 1.0
*/
public class BufferPool {
private static final Log log = LogFactory.getLog(BufferPool.class);
public static final int DEFAULT_POOL_SIZE = 100*1024*1024; //100MB
protected static final StringManager sm = StringManager.getManager(BufferPool.class);
protected static volatile BufferPool instance = null;
protected final BufferPoolAPI pool;
private BufferPool(BufferPoolAPI pool) {
this.pool = pool;
}
public XByteBuffer getBuffer(int minSize, boolean discard) {
if ( pool != null ) return pool.getBuffer(minSize, discard);
else return new XByteBuffer(minSize,discard);
}
public void returnBuffer(XByteBuffer buffer) {
if ( pool != null ) pool.returnBuffer(buffer);
}
public void clear() {
if ( pool != null ) pool.clear();
}
public static BufferPool getBufferPool() {
if (instance == null) {
synchronized (BufferPool.class) {
if (instance == null) {
BufferPoolAPI pool = new BufferPool15Impl();
pool.setMaxSize(DEFAULT_POOL_SIZE);
log.info(sm.getString("bufferPool.created",
Integer.toString(DEFAULT_POOL_SIZE), pool.getClass().getName()));
instance = new BufferPool(pool);
}
}
}
return instance;
}
public static interface BufferPoolAPI {
public void setMaxSize(int bytes);
public XByteBuffer getBuffer(int minSize, boolean discard);
public void returnBuffer(XByteBuffer buffer);
public void clear();
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* @version 1.0
*/
class BufferPool15Impl implements BufferPool.BufferPoolAPI {
protected int maxSize;
protected final AtomicInteger size = new AtomicInteger(0);
protected final ConcurrentLinkedQueue<XByteBuffer> queue =
new ConcurrentLinkedQueue<>();
@Override
public void setMaxSize(int bytes) {
this.maxSize = bytes;
}
@Override
public XByteBuffer getBuffer(int minSize, boolean discard) {
XByteBuffer buffer = queue.poll();
if ( buffer != null ) size.addAndGet(-buffer.getCapacity());
if ( buffer == null ) buffer = new XByteBuffer(minSize,discard);
else if ( buffer.getCapacity() <= minSize ) buffer.expand(minSize);
buffer.setDiscard(discard);
buffer.reset();
return buffer;
}
@Override
public void returnBuffer(XByteBuffer buffer) {
if ( (size.get() + buffer.getCapacity()) <= maxSize ) {
size.addAndGet(buffer.getCapacity());
queue.offer(buffer);
}
}
@Override
public void clear() {
queue.clear();
size.set(0);
}
public int getMaxSize() {
return maxSize;
}
}

View File

@@ -0,0 +1,374 @@
/*
* 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.sql.Timestamp;
import java.util.Arrays;
import org.apache.catalina.tribes.Channel;
import org.apache.catalina.tribes.ChannelMessage;
import org.apache.catalina.tribes.Member;
import org.apache.catalina.tribes.membership.MemberImpl;
import org.apache.catalina.tribes.util.UUIDGenerator;
/**
* The <code>ChannelData</code> object is used to transfer a message through the
* channel interceptor stack and eventually out on a transport to be sent
* to another node. While the message is being processed by the different
* interceptors, the message data can be manipulated as each interceptor seems appropriate.
* @author Peter Rossbach
*/
public class ChannelData implements ChannelMessage {
private static final long serialVersionUID = 1L;
public static final ChannelData[] EMPTY_DATA_ARRAY = new ChannelData[0];
public static volatile boolean USE_SECURE_RANDOM_FOR_UUID = false;
/**
* The options this message was sent with
*/
private int options = 0 ;
/**
* The message data, stored in a dynamic buffer
*/
private XByteBuffer message ;
/**
* The timestamp that goes with this message
*/
private long timestamp ;
/**
* A unique message id
*/
private byte[] uniqueId ;
/**
* The source or reply-to address for this message
*/
private Member address;
/**
* Creates an empty channel data with a new unique Id
* @see #ChannelData(boolean)
*/
public ChannelData() {
this(true);
}
/**
* Create an empty channel data object
* @param generateUUID boolean - if true, a unique Id will be generated
*/
public ChannelData(boolean generateUUID) {
if ( generateUUID ) generateUUID();
}
/**
* Creates a new channel data object with data
* @param uniqueId - unique message id
* @param message - message data
* @param timestamp - message timestamp
*/
public ChannelData(byte[] uniqueId, XByteBuffer message, long timestamp) {
this.uniqueId = uniqueId;
this.message = message;
this.timestamp = timestamp;
}
/**
* @return Returns the message byte buffer
*/
@Override
public XByteBuffer getMessage() {
return message;
}
/**
* @param message The message to send.
*/
@Override
public void setMessage(XByteBuffer message) {
this.message = message;
}
/**
* @return Returns the timestamp.
*/
@Override
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp The timestamp to send
*/
@Override
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return Returns the uniqueId.
*/
@Override
public byte[] getUniqueId() {
return uniqueId;
}
/**
* @param uniqueId The uniqueId to send.
*/
public void setUniqueId(byte[] uniqueId) {
this.uniqueId = uniqueId;
}
/**
* @return returns the message options
* see org.apache.catalina.tribes.Channel#sendMessage(org.apache.catalina.tribes.Member[], java.io.Serializable, int)
*
*/
@Override
public int getOptions() {
return options;
}
/**
* Sets the message options.
*
* @param options the message options
*/
@Override
public void setOptions(int options) {
this.options = options;
}
/**
* Returns the source or reply-to address
* @return Member
*/
@Override
public Member getAddress() {
return address;
}
/**
* Sets the source or reply-to address
* @param address Member
*/
@Override
public void setAddress(Member address) {
this.address = address;
}
/**
* Generates a UUID and invokes setUniqueId
*/
public void generateUUID() {
byte[] data = new byte[16];
UUIDGenerator.randomUUID(USE_SECURE_RANDOM_FOR_UUID,data,0);
setUniqueId(data);
}
public int getDataPackageLength() {
int length =
4 + //options
8 + //timestamp off=4
4 + //unique id length off=12
uniqueId.length+ //id data off=12+uniqueId.length
4 + //addr length off=12+uniqueId.length+4
address.getDataLength()+ //member data off=12+uniqueId.length+4+add.length
4 + //message length off=12+uniqueId.length+4+add.length+4
message.getLength();
return length;
}
/**
* Serializes the ChannelData object into a byte[] array
* @return byte[]
*/
public byte[] getDataPackage() {
int length = getDataPackageLength();
byte[] data = new byte[length];
int offset = 0;
return getDataPackage(data,offset);
}
public byte[] getDataPackage(byte[] data, int offset) {
byte[] addr = address.getData(false);
XByteBuffer.toBytes(options,data,offset);
offset += 4; //options
XByteBuffer.toBytes(timestamp,data,offset);
offset += 8; //timestamp
XByteBuffer.toBytes(uniqueId.length,data,offset);
offset += 4; //uniqueId.length
System.arraycopy(uniqueId,0,data,offset,uniqueId.length);
offset += uniqueId.length; //uniqueId data
XByteBuffer.toBytes(addr.length,data,offset);
offset += 4; //addr.length
System.arraycopy(addr,0,data,offset,addr.length);
offset += addr.length; //addr data
XByteBuffer.toBytes(message.getLength(),data,offset);
offset += 4; //message.length
System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength());
return data;
}
/**
* Deserializes a ChannelData object from a byte array
* @param xbuf byte[]
* @return ChannelData
*/
public static ChannelData getDataFromPackage(XByteBuffer xbuf) {
ChannelData data = new ChannelData(false);
int offset = 0;
data.setOptions(XByteBuffer.toInt(xbuf.getBytesDirect(),offset));
offset += 4; //options
data.setTimestamp(XByteBuffer.toLong(xbuf.getBytesDirect(),offset));
offset += 8; //timestamp
data.uniqueId = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)];
offset += 4; //uniqueId length
System.arraycopy(xbuf.getBytesDirect(),offset,data.uniqueId,0,data.uniqueId.length);
offset += data.uniqueId.length; //uniqueId data
//byte[] addr = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)];
int addrlen = XByteBuffer.toInt(xbuf.getBytesDirect(),offset);
offset += 4; //addr length
//System.arraycopy(xbuf.getBytesDirect(),offset,addr,0,addr.length);
data.setAddress(MemberImpl.getMember(xbuf.getBytesDirect(),offset,addrlen));
//offset += addr.length; //addr data
offset += addrlen;
int xsize = XByteBuffer.toInt(xbuf.getBytesDirect(),offset);
offset += 4; //xsize length
System.arraycopy(xbuf.getBytesDirect(),offset,xbuf.getBytesDirect(),0,xsize);
xbuf.setLength(xsize);
data.message = xbuf;
return data;
}
public static ChannelData getDataFromPackage(byte[] b) {
ChannelData data = new ChannelData(false);
int offset = 0;
data.setOptions(XByteBuffer.toInt(b,offset));
offset += 4; //options
data.setTimestamp(XByteBuffer.toLong(b,offset));
offset += 8; //timestamp
data.uniqueId = new byte[XByteBuffer.toInt(b,offset)];
offset += 4; //uniqueId length
System.arraycopy(b,offset,data.uniqueId,0,data.uniqueId.length);
offset += data.uniqueId.length; //uniqueId data
byte[] addr = new byte[XByteBuffer.toInt(b,offset)];
offset += 4; //addr length
System.arraycopy(b,offset,addr,0,addr.length);
data.setAddress(MemberImpl.getMember(addr));
offset += addr.length; //addr data
int xsize = XByteBuffer.toInt(b,offset);
//data.message = new XByteBuffer(new byte[xsize],false);
data.message = BufferPool.getBufferPool().getBuffer(xsize,false);
offset += 4; //message length
System.arraycopy(b,offset,data.message.getBytesDirect(),0,xsize);
data.message.append(b,offset,xsize);
offset += xsize; //message data
return data;
}
@Override
public int hashCode() {
return XByteBuffer.toInt(getUniqueId(),0);
}
/**
* Compares to ChannelData objects, only compares on getUniqueId().equals(o.getUniqueId())
* @param o Object
* @return boolean
*/
@Override
public boolean equals(Object o) {
if ( o instanceof ChannelData ) {
return Arrays.equals(getUniqueId(),((ChannelData)o).getUniqueId());
} else return false;
}
/**
* Create a shallow clone, only the data gets recreated
* @return ClusterData
*/
@Override
public ChannelData clone() {
ChannelData clone;
try {
clone = (ChannelData) super.clone();
} catch (CloneNotSupportedException e) {
// Cannot happen
throw new AssertionError();
}
if (this.message != null) {
clone.message = new XByteBuffer(this.message.getBytesDirect(),false);
}
return clone;
}
/**
* Complete clone
* @return ClusterData
*/
@Override
public Object deepclone() {
byte[] d = this.getDataPackage();
return ChannelData.getDataFromPackage(d);
}
/**
* Utility method, returns true if the options flag indicates that an ack
* is to be sent after the message has been received and processed
* @param options int - the options for the message
* @return boolean
* @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK
* @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK
*/
public static boolean sendAckSync(int options) {
return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) &&
( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) == Channel.SEND_OPTIONS_SYNCHRONIZED_ACK);
}
/**
* Utility method, returns true if the options flag indicates that an ack
* is to be sent after the message has been received but not yet processed
* @param options int - the options for the message
* @return boolean
* @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK
* @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK
*/
public static boolean sendAckAsync(int options) {
return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) &&
( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) != Channel.SEND_OPTIONS_SYNCHRONIZED_ACK);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("ClusterData[src=");
buf.append(getAddress()).append("; id=");
buf.append(bToS(getUniqueId())).append("; sent=");
buf.append(new Timestamp(this.getTimestamp()).toString()).append("]");
return buf.toString();
}
public static String bToS(byte[] data) {
StringBuilder buf = new StringBuilder(4*16);
buf.append("{");
for (int i=0; data!=null && i<data.length; i++ ) buf.append(String.valueOf(data[i])).append(" ");
buf.append("}");
return buf.toString();
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.IOException;
import java.io.OutputStream;
/**
* Byte array output stream that exposes the byte array directly
*
* @version 1.0
*/
public class DirectByteArrayOutputStream extends OutputStream {
private final XByteBuffer buffer;
public DirectByteArrayOutputStream(int size) {
buffer = new XByteBuffer(size,false);
}
/**
* Writes the specified byte to this output stream.
*
* @param b the <code>byte</code>.
* @throws IOException if an I/O error occurs. In particular, an
* <code>IOException</code> may be thrown if the output stream has
* been closed.
*/
@Override
public void write(int b) throws IOException {
buffer.append((byte)b);
}
public int size() {
return buffer.getLength();
}
public byte[] getArrayDirect() {
return buffer.getBytesDirect();
}
public byte[] getArray() {
return buffer.getBytes();
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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 org.apache.catalina.tribes.ChannelMessage;
/**
* Internal interface, similar to the MessageListener but used
* at the IO base
* The listen callback interface is used by the replication system
* when data has been received. The interface does not care about
* objects and marshalling and just passes the bytes straight through.
*/
public interface ListenCallback
{
/**
* This method is invoked on the callback object to notify it that new data has
* been received from one of the cluster nodes.
* @param data - the message bytes received from the cluster/replication system
*/
public void messageDataReceived(ChannelMessage data);
}

View File

@@ -0,0 +1,27 @@
# 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.
bufferPool.created=Created a buffer pool with max size:[{0}] bytes of type: [{1}]
objectReader.retrieveFailed.socketReceiverBufferSize=Unable to retrieve the socket receiver buffer size, setting to default 43800 bytes.
replicationStream.conflict=conflicting non-public interface class loaders
xByteBuffer.discarded.invalidHeader=Discarded the package, invalid header
xByteBuffer.no.package=No package exists in XByteBuffer
xByteBuffer.size.larger.buffer=Size is larger than existing buffer.
xByteBuffer.unableCreate=Unable to create data package, buffer is too small.
xByteBuffer.unableTrim=Cannot trim more bytes than are available. length:[{0}] trim:[{1}]
xByteBuffer.wrong.class=Message has the wrong class. It should implement Serializable, instead it is:[{0}]

View File

@@ -0,0 +1,20 @@
# 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.
objectReader.retrieveFailed.socketReceiverBufferSize=Kann die Größe der Socket Puffer nicht auslesen. Setze sie auf den Standardwert von 43800 Bytes.
xByteBuffer.no.package=In XByteBuffer existiert kein Paket
xByteBuffer.unableCreate=Kann Daten Paket nicht erzeugen, da der Puffer zu klein ist
xByteBuffer.wrong.class=Nachricht hat eine falsche Klasse. Sie sollte Serializable implementieren, sie implementiert aber: [{0}]

View File

@@ -0,0 +1,23 @@
# 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.
objectReader.retrieveFailed.socketReceiverBufferSize=Incapáz de recuperar el tamaño del buffer receptor, fijando el valor por defecto a 43800 bytes.\n
replicationStream.conflict=hay conflicto en la clase de los cargadores de la interfaz no pública
xByteBuffer.no.package=No existe paquete en XByteBuffer
xByteBuffer.size.larger.buffer=El tamaño es mayor que el buffer
xByteBuffer.unableCreate=Imposible crear el paquete de datos, el buffer es demasiado pequeño.
xByteBuffer.wrong.class=El mensaje tiene la clase errónea. Debe implementar Serializable, pero en su lugar es:[{0}]

View File

@@ -0,0 +1,27 @@
# 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.
bufferPool.created=Création d''un pool de tampons de taille maximale: [{0}] octets de type: [{1}]
objectReader.retrieveFailed.socketReceiverBufferSize=Incapacité de récupérer la taille du tampon du socket de réception, forcé à 43800 octets
replicationStream.conflict=Conflit entre des interfaces non-publics ayant des chargeurs de classe différents
xByteBuffer.discarded.invalidHeader=L'en-tête est invalide donc le paquet a été abandonné
xByteBuffer.no.package=Il n'y a aucun package dans XByteBuffer
xByteBuffer.size.larger.buffer=La taille est plus grande que celle du buffer existant
xByteBuffer.unableCreate=Impossible de créer le package data, le tampon de mémoire est trop petit
xByteBuffer.unableTrim=Impossible d''élaguer plus d''octets que ce qui est disponible, longueur: [{0}] élagage: [{1}]
xByteBuffer.wrong.class=Message n''a pas la bonne classe. Cela doit implémenter Serializable au lieu de [{0}]

View File

@@ -0,0 +1,27 @@
# 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.
bufferPool.created=最大サイズ[{1}]のタイプの[{0}]バイトのバッファプールを作成しました。
objectReader.retrieveFailed.socketReceiverBufferSize=TCP ソケットのレシーバーバッファサイズを取得できなかったため初期値として 43800 byte を設定します。
replicationStream.conflict=public でないインターフェイスのクラスローダーが複数存在します。
xByteBuffer.discarded.invalidHeader=ヘッダーが不正なためパッケージを破棄します。
xByteBuffer.no.package=XByteBuffer にパッケージがありません。
xByteBuffer.size.larger.buffer=バッファ長より大きな値がサイズとして指定されました。
xByteBuffer.unableCreate=バッファーが小さすぎてデータパッケージを作成できません。
xByteBuffer.unableTrim=利用可能なバイト数より多くのバイトをトリムすることはできません。 長さ:[{0}]トリム:[{1}]
xByteBuffer.wrong.class=メッセージのClassが間違っています。 それはSerializableを実装するはずですが、代わりに[{0}]です。

View File

@@ -0,0 +1,27 @@
# 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.
bufferPool.created=타입이 [{1}](이)고 최대 크기가 [{0}] 바이트를 사용하여 버퍼 풀을 생성했습니다.
objectReader.retrieveFailed.socketReceiverBufferSize=소켓 receiver의 버퍼 크기를 알 수 없습니다. 기본 값인 43800 바이트로 설정합니다.
replicationStream.conflict=해당 클래스의 클래스로더와, 그 클래스의 특정 non-public 인터페이스의 클래스로더가 일치하지 않아 충돌합니다.
xByteBuffer.discarded.invalidHeader=유효하지 않은 헤더로 인해 패키지를 폐기했습니다.
xByteBuffer.no.package=XByteBuffer에 어떤 패키지도 존재하지 않습니다.
xByteBuffer.size.larger.buffer=크기가 기존 버퍼의 길이보다 큽니다.
xByteBuffer.unableCreate=데이터 패키지를 생성할 수 없습니다. 버퍼가 너무 작습니다.
xByteBuffer.unableTrim=가용한 버퍼 크기보다 더 많은 바이트들을 잘라낼 수는 없습니다. 버퍼 길이:[{0}], 잘라낼 길이:[{1}]
xByteBuffer.wrong.class=메시지가 Serializable 인터페이스를 구현하지 않은 클래스입니다. 클래스는 [{0}]입니다.

View File

@@ -0,0 +1,16 @@
# 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.
replicationStream.conflict=конфликтующие не-публичные загрузчики классов

View File

@@ -0,0 +1,23 @@
# 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.
objectReader.retrieveFailed.socketReceiverBufferSize=无法检索套接字接收器缓冲区大小设置为默认43800字节。
replicationStream.conflict=和非公开接口类加载器冲突
xByteBuffer.no.package=XByteBuffer中不存在数据包
xByteBuffer.size.larger.buffer=大小比现有缓冲区大。
xByteBuffer.unableCreate=不能创建数据包, buffer 太小
xByteBuffer.wrong.class=消息对应类不符合要求。 它应该实现Serializable而不是[{0}]。

View File

@@ -0,0 +1,167 @@
/*
* 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.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import org.apache.catalina.tribes.ChannelMessage;
import org.apache.catalina.tribes.util.StringManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* The object reader object is an object used in conjunction with
* java.nio TCP messages. This object stores the message bytes in a
* <code>XByteBuffer</code> until a full package has been received.
* This object uses an XByteBuffer which is an extendable object buffer that also allows
* for message encoding and decoding.
*/
public class ObjectReader {
private static final Log log = LogFactory.getLog(ObjectReader.class);
protected static final StringManager sm = StringManager.getManager(ObjectReader.class);
private XByteBuffer buffer;
protected long lastAccess = System.currentTimeMillis();
protected boolean accessed = false;
private volatile boolean cancelled;
public ObjectReader(int packetSize) {
this.buffer = new XByteBuffer(packetSize, true);
}
/**
* Creates an <code>ObjectReader</code> for a TCP NIO socket channel
* @param channel - the channel to be read.
*/
public ObjectReader(SocketChannel channel) {
this(channel.socket());
}
/**
* Creates an <code>ObjectReader</code> for a TCP socket
* @param socket Socket
*/
public ObjectReader(Socket socket) {
try{
this.buffer = new XByteBuffer(socket.getReceiveBufferSize(), true);
}catch ( IOException x ) {
//unable to get buffer size
log.warn(sm.getString("objectReader.retrieveFailed.socketReceiverBufferSize"));
this.buffer = new XByteBuffer(43800,true);
}
}
public synchronized void access() {
this.accessed = true;
this.lastAccess = System.currentTimeMillis();
}
public synchronized void finish() {
this.accessed = false;
this.lastAccess = System.currentTimeMillis();
}
public synchronized boolean isAccessed() {
return this.accessed;
}
/**
* Append new bytes to buffer.
* @see XByteBuffer#countPackages()
* @param data new transfer buffer
* @param len length in buffer
* @param count whether to return the count
* @return number of messages that was sent to callback (or -1 if count == false)
*/
public int append(ByteBuffer data, int len, boolean count) {
buffer.append(data,len);
int pkgCnt = -1;
if ( count ) pkgCnt = buffer.countPackages();
return pkgCnt;
}
public int append(byte[] data,int off,int len, boolean count) {
buffer.append(data,off,len);
int pkgCnt = -1;
if ( count ) pkgCnt = buffer.countPackages();
return pkgCnt;
}
/**
* Send buffer to cluster listener (callback).
* Is message complete receiver send message to callback?
*
* @see org.apache.catalina.tribes.transport.ReceiverBase#messageDataReceived(ChannelMessage)
* @see XByteBuffer#doesPackageExist()
* @see XByteBuffer#extractPackage(boolean)
*
* @return number of received packages/messages
*/
public ChannelMessage[] execute() {
int pkgCnt = buffer.countPackages();
ChannelMessage[] result = new ChannelMessage[pkgCnt];
for (int i=0; i<pkgCnt; i++) {
ChannelMessage data = buffer.extractPackage(true);
result[i] = data;
}
return result;
}
public int bufferSize() {
return buffer.getLength();
}
public boolean hasPackage() {
return buffer.countPackages(true)>0;
}
/**
* Returns the number of packages that the reader has read
* @return int
*/
public int count() {
return buffer.countPackages();
}
public void close() {
this.buffer = null;
}
public synchronized long getLastAccess() {
return lastAccess;
}
public boolean isCancelled() {
return cancelled;
}
public synchronized void setLastAccess(long lastAccess) {
this.lastAccess = lastAccess;
}
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@@ -0,0 +1,170 @@
/*
* 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.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import org.apache.catalina.tribes.util.StringManager;
/**
* Custom subclass of <code>ObjectInputStream</code> that loads from the
* class loader for this web application. This allows classes defined only
* with the web application to be found correctly.
*
* @author Craig R. McClanahan
* @author Bip Thelin
*/
public final class ReplicationStream extends ObjectInputStream {
static final StringManager sm = StringManager.getManager(ReplicationStream.class);
/**
* The class loader we will use to resolve classes.
*/
private ClassLoader[] classLoaders = null;
/**
* Construct a new instance of CustomObjectInputStream
*
* @param stream The input stream we will read from
* @param classLoaders The class loader array used to instantiate objects
*
* @exception IOException if an input/output error occurs
*/
public ReplicationStream(InputStream stream,
ClassLoader[] classLoaders)
throws IOException {
super(stream);
this.classLoaders = classLoaders;
}
/**
* Load the local class equivalent of the specified stream class
* description, by using the class loader assigned to this Context.
*
* @param classDesc Class description from the input stream
*
* @exception ClassNotFoundException if this class cannot be found
* @exception IOException if an input/output error occurs
*/
@Override
public Class<?> resolveClass(ObjectStreamClass classDesc)
throws ClassNotFoundException, IOException {
String name = classDesc.getName();
try {
return resolveClass(name);
} catch (ClassNotFoundException e) {
return super.resolveClass(classDesc);
}
}
public Class<?> resolveClass(String name) throws ClassNotFoundException {
boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes");
try {
if (tryRepFirst)
return findReplicationClass(name);
else
return findExternalClass(name);
} catch (Exception x) {
if (tryRepFirst)
return findExternalClass(name);
else
return findReplicationClass(name);
}
}
/**
* ObjectInputStream.resolveProxyClass has some funky way of using
* the incorrect class loader to resolve proxy classes, let's do it our way instead
*/
@Override
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException {
ClassLoader latestLoader;
if (classLoaders != null && classLoaders.length > 0) {
latestLoader = classLoaders[0];
} else {
latestLoader = null;
}
ClassLoader nonPublicLoader = null;
boolean hasNonPublicInterface = false;
// define proxy in class loader of non-public interface(s), if any
Class<?>[] classObjs = new Class[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
Class<?> cl = this.resolveClass(interfaces[i]);
if (latestLoader==null) latestLoader = cl.getClassLoader();
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
if (hasNonPublicInterface) {
if (nonPublicLoader != cl.getClassLoader()) {
throw new IllegalAccessError(
sm.getString("replicationStream.conflict"));
}
} else {
nonPublicLoader = cl.getClassLoader();
hasNonPublicInterface = true;
}
}
classObjs[i] = cl;
}
try {
return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader
: latestLoader, classObjs);
} catch (IllegalArgumentException e) {
throw new ClassNotFoundException(null, e);
}
}
public Class<?> findReplicationClass(String name)
throws ClassNotFoundException {
Class<?> clazz = Class.forName(name, false, getClass().getClassLoader());
return clazz;
}
public Class<?> findExternalClass(String name) throws ClassNotFoundException {
ClassNotFoundException cnfe = null;
for (int i=0; i<classLoaders.length; i++ ) {
try {
Class<?> clazz = Class.forName(name, false, classLoaders[i]);
return clazz;
} catch ( ClassNotFoundException x ) {
cnfe = x;
}
}
if ( cnfe != null ) throw cnfe;
else throw new ClassNotFoundException(name);
}
@Override
public void close() throws IOException {
this.classLoaders = null;
super.close();
}
}

View File

@@ -0,0 +1,596 @@
/*
* 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;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.catalina.tribes.util.StringManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* 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>
*/
public class XByteBuffer implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(XByteBuffer.class);
protected static final StringManager sm = StringManager.getManager(XByteBuffer.class);
/**
* This is a package header, 7 bytes (FLT2002)
*/
private static final byte[] START_DATA = {70,76,84,50,48,48,50};
/**
* This is the package footer, 7 bytes (TLF2003)
*/
private static final byte[] END_DATA = {84,76,70,50,48,48,51};
/**
* 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.<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 = 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(sm.getString("xByteBuffer.size.larger.buffer"));
bufSize = size;
}
public void trim(int length) {
if ( (bufSize - length) < 0 )
throw new ArrayIndexOutOfBoundsException(sm.getString("xByteBuffer.unableTrim",
Integer.toString(bufSize), Integer.toString(length)));
bufSize -= length;
}
public void reset() {
bufSize = 0;
}
public byte[] getBytesDirect() {
return this.buf;
}
/**
* @return 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 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(sm.getString("xByteBuffer.discarded.invalidHeader"));
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(sm.getString("xByteBuffer.discarded.invalidHeader"));
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);
}
/**
* 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) {
throw new java.lang.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;
}
public ChannelData extractPackage(boolean clearFromBuffer) {
XByteBuffer xbuf = extractDataPackage(clearFromBuffer);
ChannelData cdata = ChannelData.getDataFromPackage(xbuf);
return cdata;
}
/**
* Creates a complete data package
* @param cdata - the message data to be contained within the package
* @return - a full package (header,size,data,footer)
*/
public static byte[] createDataPackage(ChannelData cdata) {
// return createDataPackage(cdata.getDataPackage());
//avoid one extra byte array creation
int dlength = cdata.getDataPackageLength();
int length = getDataPackageLength(dlength);
byte[] data = new byte[length];
int offset = 0;
System.arraycopy(START_DATA, 0, data, offset, START_DATA.length);
offset += START_DATA.length;
toBytes(dlength,data, START_DATA.length);
offset += 4;
cdata.getDataPackage(data,offset);
offset += dlength;
System.arraycopy(END_DATA, 0, data, offset, END_DATA.length);
offset += END_DATA.length;
return data;
}
public static byte[] createDataPackage(byte[] data, int doff, int dlength, byte[] buffer, int bufoff) {
if ( (buffer.length-bufoff) > getDataPackageLength(dlength) ) {
throw new ArrayIndexOutOfBoundsException(sm.getString("xByteBuffer.unableCreate"));
}
System.arraycopy(START_DATA, 0, buffer, bufoff, START_DATA.length);
toBytes(data.length,buffer, bufoff+START_DATA.length);
System.arraycopy(data, doff, buffer, bufoff+START_DATA.length + 4, dlength);
System.arraycopy(END_DATA, 0, buffer, bufoff+START_DATA.length + 4 + data.length, END_DATA.length);
return buffer;
}
public static int getDataPackageLength(int datalength) {
int length =
START_DATA.length + //header length
4 + //data length indicator
datalength + //actual data length
END_DATA.length; //footer length
return length;
}
public static byte[] createDataPackage(byte[] data) {
int length = getDataPackageLength(data.length);
byte[] result = new byte[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
*/
public static int 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
*/
public static long 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
*/
public static byte[] 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
*/
public static boolean 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
*/
public static byte[] 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
*/
public static byte[] 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
*/
public static int 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 ) throw new java.lang.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;
} else if ( (srclen - pos) < findlen) {
return -1; //no more matches possible
} else {
pos++;
}
}
return result;
}
public static Serializable deserialize(byte[] data)
throws IOException, ClassNotFoundException, ClassCastException {
return deserialize(data,0,data.length);
}
public static Serializable deserialize(byte[] data, int offset, int length)
throws IOException, ClassNotFoundException, ClassCastException {
return deserialize(data,offset,length,null);
}
private static final AtomicInteger invokecount = new AtomicInteger(0);
public static Serializable deserialize(byte[] data, int offset, int length, ClassLoader[] cls)
throws IOException, ClassNotFoundException, ClassCastException {
invokecount.addAndGet(1);
Object message = null;
if ( cls == null ) cls = new ClassLoader[0];
if (data != null && length > 0) {
InputStream instream = new ByteArrayInputStream(data,offset,length);
ObjectInputStream stream = null;
stream = (cls.length>0)? new ReplicationStream(instream,cls):new ObjectInputStream(instream);
message = stream.readObject();
instream.close();
stream.close();
}
if ( message == null ) {
return null;
} else if (message instanceof Serializable)
return (Serializable) message;
else {
throw new ClassCastException(sm.getString("xByteBuffer.wrong.class", message.getClass().getName()));
}
}
/**
* Serializes a message into cluster data
* @param msg ClusterMessage
* @return serialized content as byte[] array
* @throws IOException Serialization error
*/
public static byte[] serialize(Serializable msg) throws IOException {
ByteArrayOutputStream outs = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(outs);
out.writeObject(msg);
out.flush();
byte[] data = outs.toByteArray();
return data;
}
public void setDiscard(boolean discard) {
this.discard = discard;
}
public boolean getDiscard() {
return discard;
}
}