org.zbus.remoting.RemotingClient Maven / Gradle / Ivy
package org.zbus.remoting;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zbus.remoting.callback.ConnectedCallback;
import org.zbus.remoting.callback.ErrorCallback;
import org.zbus.remoting.callback.MessageCallback;
import org.zbus.remoting.nio.Session;
import org.zbus.remoting.ticket.ResultCallback;
import org.zbus.remoting.ticket.Ticket;
import org.zbus.remoting.ticket.TicketManager;
public class RemotingClient implements Closeable{
private static final Logger log = LoggerFactory.getLogger(RemotingClient.class);
protected final ClientDispatcherManager dispatcherManager;
protected final String brokerAddress;
protected String serverHost = "127.0.0.1";
protected int serverPort = 15555;
protected Session session;
protected int readTimeout = 3000;
protected int connectTimeout = 3000;
private ConcurrentMap attributes = null;
protected MessageCallback messageCallback;
protected ConnectedCallback connectedCallback;
protected ErrorCallback errorCallback;
protected final ScheduledExecutorService heartbeator = Executors.newSingleThreadScheduledExecutor();
public RemotingClient(String serverHost, int serverPort, ClientDispatcherManager dispatcherManager) {
this(String.format("%s:%d", serverHost, serverPort), dispatcherManager);
}
public RemotingClient(String address, ClientDispatcherManager dispatcherManager){
this.brokerAddress = address;
if(!dispatcherManager.isStarted()){
dispatcherManager.start();
}
String[] blocks = address.split("[:]");
if(blocks.length > 2){
throw new IllegalArgumentException("Illegal address: "+address);
}
if(!dispatcherManager.isStarted()){
throw new IllegalStateException("ClientDispachterManager not started yet");
}
this.serverHost = blocks[0].trim();
if(blocks.length > 1){
this.serverPort = Integer.valueOf(blocks[1].trim());
}
this.dispatcherManager = dispatcherManager;
this.heartbeator.scheduleAtFixedRate(new Runnable() {
public void run() {
if(RemotingClient.this.hasConnected()){
Message hbt = new Message();
hbt.setCommand(Message.HEARTBEAT);
try {
RemotingClient.this.send(hbt);
} catch (IOException e) {
//ignore
}
}
}
}, 1000, 10000, TimeUnit.MILLISECONDS);
}
protected void initCallback() throws IOException {
if(this.connectedCallback != null){
onConnected(this.connectedCallback);
}
if(this.errorCallback != null){
onError(this.errorCallback);
}
if(this.messageCallback != null){
onMessage(this.messageCallback);
}
}
protected Session doConnect() throws IOException {
if(this.session != null ){
if (this.session.isActive() || this.session.isNew()){
return this.session;
}
}
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress(this.serverHost, this.serverPort));
this.session = new Session(dispatcherManager, channel, dispatcherManager.buildEventAdaptor());
initCallback();
dispatcherManager.registerSession(SelectionKey.OP_CONNECT, this.session);
return this.session;
}
public void connect(int timeoutMillis) throws IOException{
this.session = doConnect();
this.session.waitToConnect(timeoutMillis);
}
public boolean hasConnected(){
return session != null && session.isActive();
}
public void ensureConnected(){
while(!this.hasConnected()){
try {
this.connect(connectTimeout);
} catch (IOException e) {
log.info(e.getMessage(), e);
}
}
}
public void connectIfNeed() throws IOException{
if(!this.hasConnected()){
//同步进行连接操作
this.connect(this.connectTimeout);
}
if(!this.hasConnected()){
//throw new IOException("Connection failed"); TODO
}
}
public void invokeAsync(Message req, ResultCallback callback) throws IOException {
connectIfNeed();
Ticket ticket = null;
if(callback != null){
ticket = TicketManager.createTicket(req, readTimeout, callback);
} else {
if("".equals(req.getMsgId()) || req.getMsgId() == null){//没有设置消息ID则自动生成
req.setMsgId(Ticket.uuidTicket());
}
}
try{
session.write(req);
} catch(IOException e) {
if(ticket != null){
TicketManager.removeTicket(ticket.getId());
}
throw e;
}
}
public Message invokeSync(Message req) throws IOException {
return this.invokeSync(req, this.readTimeout);
}
public Message invokeSync(Message req, int timeout) throws IOException {
Ticket ticket = null;
try {
connectIfNeed();
ticket = TicketManager.createTicket(req, timeout);
session.write(req);
if(!ticket.await(timeout, TimeUnit.MILLISECONDS)){
if(!session.isActive()){
throw new IOException("Connection reset by peer");
} else {
return null;
}
}
return ticket.response();
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
} finally{
if(ticket != null){
TicketManager.removeTicket(ticket.getId());
}
}
return null;
}
public void close(){
if(this.session != null){
try {
this.session.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
this.heartbeator.shutdown();
}
public String getServerHost() {
return serverHost;
}
public void setServerHost(String serverHost) {
this.serverHost = serverHost;
}
public int getServerPort() {
return serverPort;
}
public void setServerPort(int serverPort) {
this.serverPort = serverPort;
}
public int getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Session getSession() {
return session;
}
@SuppressWarnings("unchecked")
public T attr(String key){
if(this.attributes == null){
return null;
}
return (T)this.attributes.get(key);
}
public void attr(String key, T value){
if(this.attributes == null){
synchronized (this) {
if(this.attributes == null){
this.attributes = new ConcurrentHashMap();
}
}
}
this.attributes.put(key, value);
}
/**
* asynchronous send message, return message fall into client's callback
* 异步发送消息,消息没有Ticket匹配,由Client的消息回调处理
* @param msg
* @throws IOException
*/
public void send(Message msg) throws IOException{
connectIfNeed();
//没有设置消息ID则自动生成
if("".equals(msg.getMsgId()) || msg.getMsgId() == null){
msg.setMsgId(Ticket.uuidTicket());
}
this.session.write(msg);
}
public void onMessage(MessageCallback messageCallback){
this.messageCallback = messageCallback;
if(this.session != null && this.messageCallback != null){
ClientEventAdaptor handler = (ClientEventAdaptor) this.session.getEventAdaptor();
handler.setMessageCallback(this.messageCallback);
}
}
public void onError(ErrorCallback errorCallback){
this.errorCallback = errorCallback;
if(this.session != null && this.errorCallback != null){
ClientEventAdaptor handler = (ClientEventAdaptor) this.session.getEventAdaptor();
handler.setErrorCallback(errorCallback);
}
}
public void onConnected(ConnectedCallback connectedCallback){
this.connectedCallback = connectedCallback;
if(this.session != null && connectedCallback != null){
ClientEventAdaptor handler = (ClientEventAdaptor) this.session.getEventAdaptor();
handler.setConnectedCallback(connectedCallback);
}
}
public String getBrokerAddress() {
return brokerAddress;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy