org.msgpack.rpc.transport.PooledStreamClientTransport Maven / Gradle / Ivy
The newest version!
//
// MessagePack-RPC for Java
//
// Copyright (C) 2010 FURUHASHI Sadayuki
//
// Licensed 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.msgpack.rpc.transport;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.msgpack.rpc.Session;
import org.msgpack.rpc.config.StreamClientConfig;
import org.msgpack.MessagePack;
public abstract class PooledStreamClientTransport implements ClientTransport {
private static final InternalLogger LOG =
InternalLoggerFactory.getInstance(PooledStreamClientTransport.class);
private final Object lock = new Object();
private final List pool = new ArrayList();
private final List errorChannelPool = new ArrayList();
private int reconnectionLimit;
private int connecting = 0;
protected final Session session;
protected final StreamClientConfig config;
protected final MessagePack messagePack;
public PooledStreamClientTransport(StreamClientConfig config,
Session session) {
this.session = session;
this.config = config;
this.reconnectionLimit = config.getReconnectionLimit();
this.messagePack = session.getEventLoop().getMessagePack();
}
protected Session getSession() {
return session;
}
protected StreamClientConfig getConfig() {
return config;
}
public void sendMessage(Object msg) {
synchronized (lock) {
if (connecting == -1) {
return;
} // already closed
if (pool.isEmpty()) {
if (connecting == 0) {
connecting++;
startConnection();
}
if (pool.isEmpty()) { // may be already connected
try {
messagePack.write(getPendingBuffer(), msg);
} catch (IOException e) {
// FIXME
}
return;
}
}
// FIXME pseudo connection load balancing
Channel c = pool.get(0);
sendMessageChannel(c, msg);
}
}
public void close() {
synchronized (lock) {
LOG.info("Close all channels");
if (pendingBuffer != null) {
closePendingBuffer(pendingBuffer);
pendingBuffer = null;
}
connecting = -1;
for (Channel c : pool) {
closeChannel(c);
}
for (Channel c : errorChannelPool) {
closeChannel(c);
}
pool.clear();
errorChannelPool.clear();
}
}
public void onConnected(Channel c) {
synchronized (lock) {
if (connecting == -1) {
closeChannel(c);
return;
} // already closed
LOG.debug("Success to connect new channel " + c);
pool.add(c);
connecting = 0;
if (pendingBuffer != null) {
flushPendingBuffer(pendingBuffer, c);
}
}
}
public void onConnectFailed(Channel c, Throwable cause) {
synchronized (lock) {
if (connecting == -1) {
return;
} // already closed
if (connecting < reconnectionLimit) {
LOG.info(String.format("Reconnect %s(retry:%s)", c,
connecting + 1), cause);
connecting++;
if (pool.remove(c)) {// remove error channel
errorChannelPool.add(c);
}
startConnection();
} else {
LOG.error(String.format(
"Fail to connect %s(tried %s times)", c,
reconnectionLimit), cause);
connecting = 0;
if (pendingBuffer != null) {
resetPendingBuffer(pendingBuffer);
}
session.transportConnectFailed();
}
}
}
public void onClosed(Channel c) {
synchronized (lock) {
if (connecting == -1) {
return;
} // already closed
LOG.info(String.format("Close channel %s", c));
pool.remove(c);
errorChannelPool.remove(c);
}
}
private PendingBuffer pendingBuffer = null;
protected PendingBuffer getPendingBuffer() {
if (pendingBuffer == null) {
pendingBuffer = newPendingBuffer();
}
return pendingBuffer;
}
protected abstract PendingBuffer newPendingBuffer();
protected abstract void resetPendingBuffer(PendingBuffer b);
protected abstract void flushPendingBuffer(PendingBuffer b, Channel c);
protected abstract void closePendingBuffer(PendingBuffer b);
protected abstract void startConnection();
protected abstract void sendMessageChannel(Channel c, Object msg);
protected abstract void closeChannel(Channel c);
}