init
This commit is contained in:
154
java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
Normal file
154
java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.ReceiverBase;
|
||||
import org.apache.catalina.tribes.transport.RxTaskPool;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public class BioReceiver extends ReceiverBase implements Runnable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioReceiver.class);
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(BioReceiver.class);
|
||||
|
||||
protected ServerSocket serverSocket;
|
||||
|
||||
public BioReceiver() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
super.start();
|
||||
try {
|
||||
setPool(new RxTaskPool(getMaxThreads(),getMinThreads(),this));
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("bioReceiver.threadpool.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
try {
|
||||
getBind();
|
||||
bind();
|
||||
String channelName = "";
|
||||
if (getChannel().getName() != null) channelName = "[" + getChannel().getName() + "]";
|
||||
Thread t = new Thread(this, "BioReceiver" + channelName);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("bioReceiver.start.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractRxTask createRxTask() {
|
||||
return getReplicationThread();
|
||||
}
|
||||
|
||||
protected BioReplicationTask getReplicationThread() {
|
||||
BioReplicationTask result = new BioReplicationTask(this);
|
||||
result.setOptions(getWorkerThreadOptions());
|
||||
result.setUseBufferPool(this.getUseBufferPool());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
setListen(false);
|
||||
try {
|
||||
this.serverSocket.close();
|
||||
} catch (Exception x) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReceiver.socket.closeFailed"), x);
|
||||
}
|
||||
}
|
||||
super.stop();
|
||||
}
|
||||
|
||||
|
||||
protected void bind() throws IOException {
|
||||
// allocate an unbound server socket channel
|
||||
serverSocket = new ServerSocket();
|
||||
// set the port the server channel will listen to
|
||||
//serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
|
||||
bind(serverSocket,getPort(),getAutoBind());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
listen();
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("bioReceiver.run.fail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
public void listen() throws Exception {
|
||||
if (doListen()) {
|
||||
log.warn(sm.getString("bioReceiver.already.started"));
|
||||
return;
|
||||
}
|
||||
setListen(true);
|
||||
|
||||
while ( doListen() ) {
|
||||
Socket socket = null;
|
||||
if ( getTaskPool().available() < 1 ) {
|
||||
if ( log.isWarnEnabled() )
|
||||
log.warn(sm.getString("bioReceiver.threads.busy"));
|
||||
}
|
||||
BioReplicationTask task = (BioReplicationTask)getTaskPool().getRxTask();
|
||||
if ( task == null ) continue; //should never happen
|
||||
try {
|
||||
socket = serverSocket.accept();
|
||||
}catch ( Exception x ) {
|
||||
if ( doListen() ) throw x;
|
||||
}
|
||||
if ( !doListen() ) {
|
||||
task.setDoRun(false);
|
||||
task.serviceSocket(null,null);
|
||||
getExecutor().execute(task);
|
||||
break; //regular shutdown
|
||||
}
|
||||
if ( socket == null ) continue;
|
||||
socket.setReceiveBufferSize(getRxBufSize());
|
||||
socket.setSendBufferSize(getTxBufSize());
|
||||
socket.setTcpNoDelay(getTcpNoDelay());
|
||||
socket.setKeepAlive(getSoKeepAlive());
|
||||
socket.setOOBInline(getOoBInline());
|
||||
socket.setReuseAddress(getSoReuseAddress());
|
||||
socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
|
||||
socket.setSoTimeout(getTimeout());
|
||||
ObjectReader reader = new ObjectReader(socket);
|
||||
task.serviceSocket(socket,reader);
|
||||
getExecutor().execute(task);
|
||||
}//while
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.transport.bio;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.io.BufferPool;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.ListenCallback;
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.Constants;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A worker thread class which can drain channels and echo-back the input. Each
|
||||
* instance is constructed with a reference to the owning thread pool object.
|
||||
* When started, the thread loops forever waiting to be awakened to service the
|
||||
* channel associated with a SelectionKey object. The worker is tasked by
|
||||
* calling its serviceChannel() method with a SelectionKey object. The
|
||||
* serviceChannel() method stores the key reference in the thread object then
|
||||
* calls notify() to wake it up. When the channel has been drained, the worker
|
||||
* thread returns itself to its parent pool.
|
||||
*/
|
||||
public class BioReplicationTask extends AbstractRxTask {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioReplicationTask.class);
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(BioReplicationTask.class);
|
||||
|
||||
protected Socket socket;
|
||||
protected ObjectReader reader;
|
||||
|
||||
public BioReplicationTask (ListenCallback callback) {
|
||||
super(callback);
|
||||
}
|
||||
|
||||
// loop forever waiting for work to do
|
||||
@Override
|
||||
public synchronized void run()
|
||||
{
|
||||
if ( socket == null ) return;
|
||||
try {
|
||||
drainSocket();
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("bioReplicationTask.unable.service"), x);
|
||||
}finally {
|
||||
try {
|
||||
socket.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.socket.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.reader.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
reader = null;
|
||||
socket = null;
|
||||
}
|
||||
// done, ready for more, return to pool
|
||||
if ( getTaskPool() != null ) getTaskPool().returnWorker (this);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void serviceSocket(Socket socket, ObjectReader reader) {
|
||||
this.socket = socket;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
protected void execute(ObjectReader reader) throws Exception{
|
||||
int pkgcnt = reader.count();
|
||||
|
||||
if ( pkgcnt > 0 ) {
|
||||
ChannelMessage[] msgs = reader.execute();
|
||||
for ( int i=0; i<msgs.length; i++ ) {
|
||||
/**
|
||||
* Use send ack here if you want to ack the request to the remote
|
||||
* server before completing the request
|
||||
* This is considered an asynchronous request
|
||||
*/
|
||||
if (ChannelData.sendAckAsync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
|
||||
try {
|
||||
//process the message
|
||||
getCallback().messageDataReceived(msgs[i]);
|
||||
/**
|
||||
* Use send ack here if you want the request to complete on this
|
||||
* server before sending the ack to the remote server
|
||||
* This is considered a synchronized request
|
||||
*/
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
|
||||
}catch ( Exception x ) {
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.FAIL_ACK_COMMAND);
|
||||
log.error(sm.getString("bioReplicationTask.messageDataReceived.error"),x);
|
||||
}
|
||||
if ( getUseBufferPool() ) {
|
||||
BufferPool.getBufferPool().returnBuffer(msgs[i].getMessage());
|
||||
msgs[i].setMessage(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual code which drains the channel associated with
|
||||
* the given key. This method assumes the key has been
|
||||
* modified prior to invocation to turn off selection
|
||||
* interest in OP_READ. When this method completes it
|
||||
* re-enables OP_READ and calls wakeup() on the selector
|
||||
* so the selector will resume watching this channel.
|
||||
* @throws Exception IO exception or execute exception
|
||||
*/
|
||||
protected void drainSocket() throws Exception {
|
||||
InputStream in = socket.getInputStream();
|
||||
// loop while data available, channel is non-blocking
|
||||
byte[] buf = new byte[1024];
|
||||
int length = in.read(buf);
|
||||
while ( length >= 0 ) {
|
||||
int count = reader.append(buf,0,length,true);
|
||||
if ( count > 0 ) execute(reader);
|
||||
length = in.read(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a reply-acknowledgment (6,2,3)
|
||||
* @param command The command to write
|
||||
*/
|
||||
protected void sendAck(byte[] command) {
|
||||
try {
|
||||
OutputStream out = socket.getOutputStream();
|
||||
out.write(command);
|
||||
out.flush();
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("ACK sent to " + socket.getPort());
|
||||
}
|
||||
} catch ( java.io.IOException x ) {
|
||||
log.warn(sm.getString("bioReplicationTask.unable.sendAck", x.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
setDoRun(false);
|
||||
try {
|
||||
socket.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.socket.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.reader.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
reader = null;
|
||||
socket = null;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
281
java/org/apache/catalina/tribes/transport/bio/BioSender.java
Normal file
281
java/org/apache/catalina/tribes/transport/bio/BioSender.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.catalina.tribes.RemoteProcessException;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.Constants;
|
||||
import org.apache.catalina.tribes.transport.SenderState;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Send cluster messages with only one socket. Ack and keep Alive Handling is
|
||||
* supported
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
* @since 5.5.16
|
||||
*/
|
||||
public class BioSender extends AbstractSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioSender.class);
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(BioSender.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* current sender socket
|
||||
*/
|
||||
private Socket socket = null;
|
||||
private OutputStream soOut = null;
|
||||
private InputStream soIn = null;
|
||||
|
||||
protected final XByteBuffer ackbuf =
|
||||
new XByteBuffer(Constants.ACK_COMMAND.length, true);
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Constructor
|
||||
|
||||
public BioSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Connect other cluster member receiver
|
||||
* @see org.apache.catalina.tribes.transport.DataSender#connect()
|
||||
*/
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
openSocket();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* disconnect and close socket
|
||||
*
|
||||
* @see org.apache.catalina.tribes.transport.DataSender#disconnect()
|
||||
*/
|
||||
@Override
|
||||
public void disconnect() {
|
||||
boolean connect = isConnected();
|
||||
closeSocket();
|
||||
if (connect) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.disconnect", getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message.
|
||||
* @param data The data to send
|
||||
* @param waitForAck Wait for an ack
|
||||
* @throws IOException An IO error occurred sending the message
|
||||
*/
|
||||
public void sendMessage(byte[] data, boolean waitForAck) throws IOException {
|
||||
IOException exception = null;
|
||||
setAttempt(0);
|
||||
try {
|
||||
// first try with existing connection
|
||||
pushMessage(data,false,waitForAck);
|
||||
} catch (IOException x) {
|
||||
SenderState.getSenderState(getDestination()).setSuspect();
|
||||
exception = x;
|
||||
if (log.isTraceEnabled()) log.trace(sm.getString("bioSender.send.again", getAddress().getHostAddress(),Integer.valueOf(getPort())),x);
|
||||
while ( getAttempt()<getMaxRetryAttempts() ) {
|
||||
try {
|
||||
setAttempt(getAttempt()+1);
|
||||
// second try with fresh connection
|
||||
pushMessage(data, true,waitForAck);
|
||||
exception = null;
|
||||
} catch (IOException xx) {
|
||||
exception = xx;
|
||||
closeSocket();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setRequestCount(getRequestCount()+1);
|
||||
keepalive();
|
||||
if ( exception != null ) throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder("DataSender[(");
|
||||
buf.append(super.toString()).append(")");
|
||||
buf.append(getAddress()).append(":").append(getPort()).append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Protected Methods
|
||||
|
||||
/**
|
||||
* Open real socket and set time out when waitForAck is enabled
|
||||
* is socket open return directly.
|
||||
* @throws IOException Error opening socket
|
||||
*/
|
||||
protected void openSocket() throws IOException {
|
||||
if(isConnected()) return ;
|
||||
try {
|
||||
socket = new Socket();
|
||||
InetSocketAddress sockaddr = new InetSocketAddress(getAddress(), getPort());
|
||||
socket.connect(sockaddr,(int)getTimeout());
|
||||
socket.setSendBufferSize(getTxBufSize());
|
||||
socket.setReceiveBufferSize(getRxBufSize());
|
||||
socket.setSoTimeout( (int) getTimeout());
|
||||
socket.setTcpNoDelay(getTcpNoDelay());
|
||||
socket.setKeepAlive(getSoKeepAlive());
|
||||
socket.setReuseAddress(getSoReuseAddress());
|
||||
socket.setOOBInline(getOoBInline());
|
||||
socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
|
||||
socket.setTrafficClass(getSoTrafficClass());
|
||||
setConnected(true);
|
||||
soOut = socket.getOutputStream();
|
||||
soIn = socket.getInputStream();
|
||||
setRequestCount(0);
|
||||
setConnectTime(System.currentTimeMillis());
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.openSocket", getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
} catch (IOException ex1) {
|
||||
SenderState.getSenderState(getDestination()).setSuspect();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.openSocket.failure",getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)), ex1);
|
||||
throw ex1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Close socket.
|
||||
*
|
||||
* @see #disconnect()
|
||||
*/
|
||||
protected void closeSocket() {
|
||||
if(isConnected()) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException x) {
|
||||
// Ignore
|
||||
} finally {
|
||||
socket = null;
|
||||
soOut = null;
|
||||
soIn = null;
|
||||
}
|
||||
}
|
||||
setRequestCount(0);
|
||||
setConnected(false);
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.closeSocket",getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push messages with only one socket at a time
|
||||
* Wait for ack is needed and make auto retry when write message is failed.
|
||||
* After sending error close and reopen socket again.
|
||||
*
|
||||
* After successful sending update stats
|
||||
*
|
||||
* WARNING: Subclasses must be very careful that only one thread call this pushMessage at once!!!
|
||||
*
|
||||
* @see #closeSocket()
|
||||
* @see #openSocket()
|
||||
* @see #sendMessage(byte[], boolean)
|
||||
*
|
||||
* @param data Data to send
|
||||
* @param reconnect Do a reconnect (close socket then reopen)
|
||||
* @param waitForAck Wait for an acknowledgement
|
||||
* @throws IOException IO error writing data
|
||||
* @since 5.5.10
|
||||
*/
|
||||
|
||||
protected void pushMessage(byte[] data, boolean reconnect, boolean waitForAck) throws IOException {
|
||||
keepalive();
|
||||
if ( reconnect ) closeSocket();
|
||||
if (!isConnected()) openSocket();
|
||||
soOut.write(data);
|
||||
soOut.flush();
|
||||
if (waitForAck) waitForAck();
|
||||
SenderState.getSenderState(getDestination()).setReady();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Acknowledgement from other server.
|
||||
* FIXME Please, not wait only for three characters, better control that the wait ack message is correct.
|
||||
* @throws IOException An IO error occurred
|
||||
*/
|
||||
protected void waitForAck() throws java.io.IOException {
|
||||
try {
|
||||
boolean ackReceived = false;
|
||||
boolean failAckReceived = false;
|
||||
ackbuf.clear();
|
||||
int bytesRead = 0;
|
||||
int i = soIn.read();
|
||||
while ((i != -1) && (bytesRead < Constants.ACK_COMMAND.length)) {
|
||||
bytesRead++;
|
||||
byte d = (byte)i;
|
||||
ackbuf.append(d);
|
||||
if (ackbuf.doesPackageExist() ) {
|
||||
byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes();
|
||||
ackReceived = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.ACK_DATA);
|
||||
failAckReceived = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA);
|
||||
ackReceived = ackReceived || failAckReceived;
|
||||
break;
|
||||
}
|
||||
i = soIn.read();
|
||||
}
|
||||
if (!ackReceived) {
|
||||
if (i == -1) throw new IOException(sm.getString("bioSender.ack.eof",getAddress(), Integer.valueOf(socket.getLocalPort())));
|
||||
else throw new IOException(sm.getString("bioSender.ack.wrong",getAddress(), Integer.valueOf(socket.getLocalPort())));
|
||||
} else if ( failAckReceived && getThrowOnFailedAck()) {
|
||||
throw new RemoteProcessException(sm.getString("bioSender.fail.AckReceived"));
|
||||
}
|
||||
} catch (IOException x) {
|
||||
String errmsg = sm.getString("bioSender.ack.missing", getAddress(), Integer.valueOf(socket.getLocalPort()), Long.valueOf(getTimeout()));
|
||||
if ( SenderState.getSenderState(getDestination()).isReady() ) {
|
||||
SenderState.getSenderState(getDestination()).setSuspect();
|
||||
if ( log.isWarnEnabled() ) log.warn(errmsg, x);
|
||||
} else {
|
||||
if ( log.isDebugEnabled() )log.debug(errmsg, x);
|
||||
}
|
||||
throw x;
|
||||
} finally {
|
||||
ackbuf.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
bioReceiver.already.started=ServerSocket already started
|
||||
bioReceiver.run.fail=Unable to run replication listener.
|
||||
bioReceiver.socket.closeFailed=Failed to close socket
|
||||
bioReceiver.start.fail=Unable to start cluster receiver
|
||||
bioReceiver.threadpool.fail=ThreadPool cannot be initialized. Listener not started
|
||||
bioReceiver.threads.busy=All BIO server replication threads are busy, unable to handle more requests until a thread is freed up.
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=Error thrown from messageDataReceived.
|
||||
bioReplicationTask.reader.closeFailed=Failed to close reader
|
||||
bioReplicationTask.socket.closeFailed=Failed to close socket
|
||||
bioReplicationTask.unable.sendAck=Unable to send ACK back through channel, channel disconnected?: [{0}]
|
||||
bioReplicationTask.unable.service=Unable to service bio socket
|
||||
|
||||
bioSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again.
|
||||
bioSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}]
|
||||
bioSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer})
|
||||
bioSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer})
|
||||
bioSender.fail.AckReceived=Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer})
|
||||
bioSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer})
|
||||
bioSender.send.again=Send data again to [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.retrieve.fail=Unable to retrieve a sender from the sender pool
|
||||
pooledMultiSender.unable.retrieve.sender=Unable to retrieve a data sender, time out([{0}] ms) error.
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
bioReceiver.socket.closeFailed=Socket konnte nicht geschlossen werden
|
||||
|
||||
bioSender.send.again=Sende Daten erneut an [{0}:{1,number,integer}]
|
||||
@@ -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.
|
||||
|
||||
bioReceiver.socket.closeFailed=Fallo al cerrar el socket
|
||||
|
||||
bioReplicationTask.reader.closeFailed=Fallo al cerrar el lector
|
||||
|
||||
bioSender.ack.eof=EOF alcanzado en puerto local [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=No puedo leer reconocimiento desde [{0}:{1,number,integer}] en {2,number,integer} ms. Desconectando conector e intentando otra vez.
|
||||
bioSender.ack.wrong=Falta ACK correcto tras 10 bytes leídos en puerto local [{0}:{1,number,integer}]
|
||||
bioSender.closeSocket=El remitente cerró el conector con [{0}:{1,number,integer}] (contador de cierre {2,number,integer})
|
||||
bioSender.disconnect=Remitente desconectado de [{0}:{1,number,integer}] (contador de desconexión {2,number,integer})
|
||||
bioSender.openSocket=Remitente abrió conector con [{0}:{1,number,integer}] (contador de apertura {2,number,integer})
|
||||
bioSender.openSocket.failure=¡No pude abrir conector de remitente [{0}:{1,number,integer}]! (contador de fallo de apertura {2,number,integer})
|
||||
bioSender.send.again=Enviar datos de nuevo a [{0}:{1,number,integer}]
|
||||
@@ -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.
|
||||
|
||||
bioReceiver.already.started=Le ServerSocket a déjà démarré
|
||||
bioReceiver.run.fail=Impossible d'exécuter l’écouteur de réplication
|
||||
bioReceiver.socket.closeFailed=Echec de fermeture de la connection
|
||||
bioReceiver.start.fail=Impossible de démarrer le receveur du cluster
|
||||
bioReceiver.threadpool.fail=Le ThreadPool n'a pas pu être initialisé, l'écouteur n'a pas démarré
|
||||
bioReceiver.threads.busy=Tous les fils d'exécution du serveur de réplication sont occupés, impossible de traiter plus de requêtes avant qu'un ne se libère
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=Erreur lors de messageDataReceived
|
||||
bioReplicationTask.reader.closeFailed=Echec de fermeture du lecteur
|
||||
bioReplicationTask.socket.closeFailed=Ecech de la fermeture du socket
|
||||
bioReplicationTask.unable.sendAck=Impossible de renvoyer une confirmation par le canal, il peut être déconnecté: [{0}]
|
||||
bioReplicationTask.unable.service=Incapable de traiter un socket BIO
|
||||
|
||||
bioSender.ack.eof=EOF recontré sur le port local [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=Incapable de lire l'accusé de réception de [{0}:{1,number,integer}] en {2,number,integer] ms. Déconnexion de la socket et nouvel tentative.
|
||||
bioSender.ack.wrong=Il manque un ACK correct après la lecture de 10 octets sur le port local [{0}]: {1,number,integer}
|
||||
bioSender.closeSocket=Sender fermeture du socket vers [{0}:{1,number,integer}] (nombre de fermetures {2,number,integer})
|
||||
bioSender.disconnect=L'envoyeur s'est déconnecté de [{0}:{1,number,integer}] (nombre de déconnections {2,number,integer})
|
||||
bioSender.fail.AckReceived=Reçu une confirmation en échec: org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=L''expéditeur ouvre une socket vers [{0}:{1,number,integer}] ({2,number,integer} sockets ouvertes})
|
||||
bioSender.openSocket.failure=Echec d'ouverture du socket d'envoi [{0}:{1,number,integer} (nombre d'écecs d'ouverture {2,number,integer})
|
||||
bioSender.send.again=Envoyer les données à nouveau à [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.retrieve.fail=Impossible d'obtenir un envoyeur à partir du pool
|
||||
pooledMultiSender.unable.retrieve.sender=Impossible de récupéré un expéditeur de données. délai d''attente ([{0}] ms) dépassé
|
||||
@@ -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.
|
||||
|
||||
bioReceiver.already.started=サーバーソケットはすでに開始しています。
|
||||
bioReceiver.run.fail=レプリケーションリスナーを実行できません。
|
||||
bioReceiver.socket.closeFailed=ソケットを切断できませんでした。
|
||||
bioReceiver.start.fail=クラスタレシーバを起動できません
|
||||
bioReceiver.threadpool.fail=スレッドプールを初期化できません。リスナーを開始しませんでした。
|
||||
bioReceiver.threads.busy=全ての BIO サーバーレプリケーションスレッドがビジー状態です。スレッドが解放されるまで新しいリクエストは処理できません。
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=messageDataReceivedから送出されたエラー
|
||||
bioReplicationTask.reader.closeFailed=Readerを閉じることに失敗しました。
|
||||
bioReplicationTask.socket.closeFailed=ソケットクロースに失敗
|
||||
bioReplicationTask.unable.sendAck=チャンネルへACKを送信できません。チャンネルが切断されているかもしれません: [{0}]
|
||||
bioReplicationTask.unable.service=bio ソケットを開始できません。
|
||||
|
||||
bioSender.ack.eof=ローカルポート[{0}:{1、number、integer}]でEOF
|
||||
bioSender.ack.missing=[{0}:{1,number,integer}] から [{2,number,integer}] ms 以内に確認応答(ACK)を読み取ることができませんでした。ソケットを切断して再試行してください。
|
||||
bioSender.ack.wrong=ローカルポート [{0}:{1,number,integer}] から 10 バイト読み込んだ後に正しい ACK が見つかりません。
|
||||
bioSender.closeSocket=[{0}:{1、number、integer}](close count {2、number、integer})に送信側のクローズソケット
|
||||
bioSender.disconnect=[{0}:{1,number,integer}](切断カウント{2,number,integer})からのSender切断
|
||||
bioSender.fail.AckReceived=失敗したACK:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATAの受信
|
||||
bioSender.openSocket=Sender オブジェクトが [{0}:{1,number,integer}] (接続数 {2,number,integer}) へソケット接続を開始しました。
|
||||
bioSender.openSocket.failure=開いているSender側ソケット[{0}:{1,number,integer}]失敗! (オープン失敗カウント{2,number,integer}))
|
||||
bioSender.send.again=[{0}:{1,number,integer}] へデータを再送します。
|
||||
|
||||
pooledMultiSender.retrieve.fail=SenderプールからSenderを取得できません。
|
||||
pooledMultiSender.unable.retrieve.sender=データSenderを取得できません。タイムアウト([{0}] ms)エラー。
|
||||
@@ -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.
|
||||
|
||||
bioReceiver.already.started=ServerSocket이 이미 시작되었습니다.
|
||||
bioReceiver.run.fail=복제 리스너를 실행할 수 없습니다.
|
||||
bioReceiver.socket.closeFailed=소켓을 닫지 못했습니다.
|
||||
bioReceiver.start.fail=클러스터 Receiver를 시작할 수 없습니다.
|
||||
bioReceiver.threadpool.fail=쓰레드풀이 초기화될 수 없습니다. 리스너가 시작되지 않았습니다.
|
||||
bioReceiver.threads.busy=모든 BIO 서버 복제 쓰레드들이 작업 중입니다. 유휴 쓰레드가 하나라도 생기기 전에는, 더 이상 요청을 처리할 수 없습니다.
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=messageDataReceived로부터 오류 발생
|
||||
bioReplicationTask.reader.closeFailed=Reader를 닫지 못했습니다.
|
||||
bioReplicationTask.socket.closeFailed=소켓을 닫지 못했습니다.
|
||||
bioReplicationTask.unable.sendAck=채널을 통해 ACK을 되돌려 보낼 수 없습니다. 채널의 연결이 끊겼나요?: [{0}]
|
||||
bioReplicationTask.unable.service=BIO 소켓을 서비스할 수 없습니다.
|
||||
|
||||
bioSender.ack.eof=로컬 포트 [{0}:{1,number,integer}]에서 EOF에 도달했습니다.
|
||||
bioSender.ack.missing=[{0}:{1,number,integer}](으)로부터 ACK을 {2,number,integer} 밀리초 내에 읽을 수 없습니다. 소켓 연결을 끊고, 다시 시도합니다.
|
||||
bioSender.ack.wrong=10 바이트들을 로컬 포트 [{0}]에서 읽고 난 후 올바른 ACK를 받지 못했습니다: {1,number,integer}]
|
||||
bioSender.closeSocket=Sender가 소켓 닫기 메시지를 [{0}:{1,number,integer}]에 전송합니다. (전송 회수: {2,number,integer})
|
||||
bioSender.disconnect=Sender가 [{0}:{1,number,integer}](으)로부터 연결을 끊습니다. (연결 끊기 회수: {2,number,integer})
|
||||
bioSender.fail.AckReceived=실패한 ACK을 받았습니다: org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=Sender가 [{0}:{1,number,integer}]을(를) 향해 소켓을 엽니다. (연 소켓 개수: {2,number,integer})
|
||||
bioSender.openSocket.failure=Sender 소켓 [{0}:{1,number,integer}]을(를) 열지 못했습니다! (열기 실패 회수: {2,number,integer})
|
||||
bioSender.send.again=데이터를 [{0}:{1,number,integer}](으)로 다시 전송합니다.
|
||||
|
||||
pooledMultiSender.retrieve.fail=Sender 풀로부터 sender를 검색할 수 없습니다.
|
||||
pooledMultiSender.unable.retrieve.sender=데이터 sender를 조회할 수 없습니다. 제한 시간 초과 ([{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.
|
||||
|
||||
bioSender.send.again=Послать данные ещё раз в [{0}:{1,number,integer}]
|
||||
@@ -0,0 +1,32 @@
|
||||
# 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.
|
||||
|
||||
bioReceiver.socket.closeFailed=socket.关闭失败
|
||||
bioReceiver.threadpool.fail=线程池可以初始化。侦听器未启动
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=错误抛出,来自于消息数据收到
|
||||
bioReplicationTask.reader.closeFailed=无法关闭reader
|
||||
bioReplicationTask.socket.closeFailed=无法关闭套接字
|
||||
bioReplicationTask.unable.service=不能服务bio套接字
|
||||
|
||||
bioSender.ack.eof=在本地端口[{0}:{1,number,integer}]达到EOF
|
||||
bioSender.ack.missing=不能读确认表格:[{0}] {1,number,integer}] in {2,number,integer} 毫秒, 失去socket连接, 重试连接.
|
||||
bioSender.ack.wrong=在本地端口[{0}:{1,number,integer}]读取10个字节后丢失正确的ACK
|
||||
bioSender.closeSocket=发件人关闭套接字到[{0}:{1,number,integer}](关闭计数{2,数字,整数})
|
||||
bioSender.fail.AckReceived=收到一个失败的 ack ):org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=发件人打开套接字到[{0}:{1,number,integer}](打开计数{2,数字,整数})
|
||||
bioSender.send.again=再次发送数据到 [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.unable.retrieve.sender=无法获取数据发送器,超时([{0}] ms)错误
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.MultiPointSender;
|
||||
|
||||
public class MultipointBioSender extends AbstractSender implements MultiPointSender {
|
||||
public MultipointBioSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
protected final HashMap<Member, BioSender> bioSenders = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
|
||||
byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
|
||||
BioSender[] senders = setupForSend(destination);
|
||||
ChannelException cx = null;
|
||||
for ( int i=0; i<senders.length; i++ ) {
|
||||
try {
|
||||
senders[i].sendMessage(data,(msg.getOptions()&Channel.SEND_OPTIONS_USE_ACK)==Channel.SEND_OPTIONS_USE_ACK);
|
||||
} catch (Exception x) {
|
||||
if (cx == null) cx = new ChannelException(x);
|
||||
cx.addFaultyMember(destination[i],x);
|
||||
}
|
||||
}
|
||||
if (cx!=null ) throw cx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected BioSender[] setupForSend(Member[] destination) throws ChannelException {
|
||||
ChannelException cx = null;
|
||||
BioSender[] result = new BioSender[destination.length];
|
||||
for ( int i=0; i<destination.length; i++ ) {
|
||||
try {
|
||||
BioSender sender = bioSenders.get(destination[i]);
|
||||
if (sender == null) {
|
||||
sender = new BioSender();
|
||||
AbstractSender.transferProperties(this,sender);
|
||||
sender.setDestination(destination[i]);
|
||||
bioSenders.put(destination[i], sender);
|
||||
}
|
||||
result[i] = sender;
|
||||
if (!result[i].isConnected() ) result[i].connect();
|
||||
result[i].keepalive();
|
||||
}catch (Exception x ) {
|
||||
if ( cx== null ) cx = new ChannelException(x);
|
||||
cx.addFaultyMember(destination[i],x);
|
||||
}
|
||||
}
|
||||
if ( cx!=null ) throw cx;
|
||||
else return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
//do nothing, we connect on demand
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
|
||||
private synchronized void close() throws ChannelException {
|
||||
ChannelException x = null;
|
||||
Object[] members = bioSenders.keySet().toArray();
|
||||
for (int i=0; i<members.length; i++ ) {
|
||||
Member mbr = (Member)members[i];
|
||||
try {
|
||||
BioSender sender = bioSenders.get(mbr);
|
||||
sender.disconnect();
|
||||
}catch ( Exception e ) {
|
||||
if ( x == null ) x = new ChannelException(e);
|
||||
x.addFaultyMember(mbr,e);
|
||||
}
|
||||
bioSenders.remove(mbr);
|
||||
}
|
||||
if ( x != null ) throw x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Member member) {
|
||||
// NO-OP
|
||||
// Members are defined by the array of members specified in the call to
|
||||
// sendMessage()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Member member) {
|
||||
//disconnect senders
|
||||
BioSender sender = bioSenders.remove(member);
|
||||
if ( sender != null ) sender.disconnect();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect() {
|
||||
try {
|
||||
close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
setConnected(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
disconnect();
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean keepalive() {
|
||||
boolean result = false;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<Member,BioSender>[] entries = bioSenders.entrySet().toArray(new Map.Entry[bioSenders.size()]);
|
||||
for ( int i=0; i<entries.length; i++ ) {
|
||||
BioSender sender = entries[i].getValue();
|
||||
if ( sender.keepalive() ) {
|
||||
bioSenders.remove(entries[i].getKey());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.transport.bio;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.DataSender;
|
||||
import org.apache.catalina.tribes.transport.MultiPointSender;
|
||||
import org.apache.catalina.tribes.transport.PooledSender;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
|
||||
public class PooledMultiSender extends PooledSender {
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(PooledMultiSender.class);
|
||||
|
||||
public PooledMultiSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
|
||||
MultiPointSender sender = null;
|
||||
try {
|
||||
sender = (MultiPointSender)getSender();
|
||||
if (sender == null) {
|
||||
ChannelException cx = new ChannelException(sm.getString(
|
||||
"pooledMultiSender.unable.retrieve.sender", Long.toString(getMaxWait())));
|
||||
for (int i = 0; i < destination.length; i++)
|
||||
cx.addFaultyMember(destination[i], new NullPointerException(sm.getString("pooledMultiSender.retrieve.fail")));
|
||||
throw cx;
|
||||
} else {
|
||||
sender.sendMessage(destination, msg);
|
||||
}
|
||||
sender.keepalive();
|
||||
}finally {
|
||||
if ( sender != null ) returnSender(sender);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSender getNewDataSender() {
|
||||
MultipointBioSender sender = new MultipointBioSender();
|
||||
AbstractSender.transferProperties(this,sender);
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user