init
This commit is contained in:
84
java/org/apache/catalina/tribes/io/BufferPool.java
Normal file
84
java/org/apache/catalina/tribes/io/BufferPool.java
Normal 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();
|
||||
}
|
||||
}
|
||||
67
java/org/apache/catalina/tribes/io/BufferPool15Impl.java
Normal file
67
java/org/apache/catalina/tribes/io/BufferPool15Impl.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
374
java/org/apache/catalina/tribes/io/ChannelData.java
Normal file
374
java/org/apache/catalina/tribes/io/ChannelData.java
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
40
java/org/apache/catalina/tribes/io/ListenCallback.java
Normal file
40
java/org/apache/catalina/tribes/io/ListenCallback.java
Normal 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);
|
||||
|
||||
}
|
||||
27
java/org/apache/catalina/tribes/io/LocalStrings.properties
Normal file
27
java/org/apache/catalina/tribes/io/LocalStrings.properties
Normal 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}]
|
||||
@@ -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}]
|
||||
@@ -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}]
|
||||
@@ -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}]
|
||||
@@ -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}]です。
|
||||
@@ -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}]입니다.
|
||||
@@ -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=конфликтующие не-публичные загрузчики классов
|
||||
@@ -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}]。
|
||||
167
java/org/apache/catalina/tribes/io/ObjectReader.java
Normal file
167
java/org/apache/catalina/tribes/io/ObjectReader.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
170
java/org/apache/catalina/tribes/io/ReplicationStream.java
Normal file
170
java/org/apache/catalina/tribes/io/ReplicationStream.java
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
596
java/org/apache/catalina/tribes/io/XByteBuffer.java
Normal file
596
java/org/apache/catalina/tribes/io/XByteBuffer.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user