All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.zbus.transport.AbstractClient Maven / Gradle / Ivy

There is a newer version: 1.0.0-b1
Show newest version
package io.zbus.transport;
 
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import io.zbus.kit.logging.Logger;
import io.zbus.kit.logging.LoggerFactory;
import io.zbus.transport.Sync.Ticket;


public abstract class AbstractClient extends AttributeMap implements Client {
	private static final Logger log = LoggerFactory.getLogger(AbstractClient.class); 
	 
	protected Session session;  
	protected String clientId;
	protected int invokeTimeout = 3000;
	protected int connectTimeout = 3000;  
	
	protected CountDownLatch activeLatch = new CountDownLatch(1);    
	protected final Sync sync = new Sync();    
	
	protected volatile MessageHandler msgHandler; 
	protected volatile ErrorHandler errorHandler;
	protected volatile ConnectedHandler connectedHandler;
	protected volatile DisconnectedHandler disconnectedHandler;  
	  
	 
	public AbstractClient(){  
		
		onConnected(new ConnectedHandler() { 
			@Override
			public void onConnected() throws IOException {
				String msg = String.format("Connection(%s) OK, ID=%s", serverAddress(), clientId);
				log.info(msg);
			}
		});
		
		onDisconnected(new DisconnectedHandler() { 
			@Override
			public void onDisconnected() throws IOException {
				log.warn("Disconnected from(%s) ID=%s", serverAddress(), clientId);
				ensureConnectedAsync();//automatically reconnect by default
			}
		}); 
	}  
	  
	protected abstract String serverAddress();
	 
	
	protected synchronized void cleanSession() throws IOException{
		if(session != null){
			session.close();
			session = null;
			activeLatch = new CountDownLatch(1);
		} 
	}
	 
	
	public boolean hasConnected() {
		return session != null && session.active();
	}
	
	private Thread asyncConnectThread; 
	public void ensureConnectedAsync(){
		if(hasConnected()) return;
		if(asyncConnectThread != null) return;
		
		asyncConnectThread = new Thread(new Runnable() { 
			@Override
			public void run() {
				try {
					while(!hasConnected()){
						try{
							connectSync(connectTimeout); 
							if(!hasConnected()){
								Thread.sleep(connectTimeout);
							}
						} catch (IOException e) {    
							String msg = String.format("Trying again(%s) in %.1f seconds", serverAddress(), connectTimeout/1000.0); 
							log.warn(msg); 
							Thread.sleep(connectTimeout);
						} catch (InterruptedException e) {
							throw e;
						} catch (Exception e) {
							log.error(e.getMessage(), e);
							break;
						}  
					} 
					asyncConnectThread = null;
				} catch (InterruptedException e) {
					//ignore
				}  
			}
		}); 
		asyncConnectThread.start(); 
	}
	
	
	public void sendMessage(REQ req) throws IOException, InterruptedException{
		if(!hasConnected()){
			connectSync(connectTimeout);  
			if(!hasConnected()){
				String msg = String.format("Connection(%s) failed", serverAddress()); 
				throw new IOException(msg);
			}
		}  
		session.write(req);  
    } 
	
	 
	@Override
	public void close() throws IOException {
		onConnected(null);
		onDisconnected(null);
		
		if(asyncConnectThread != null){
			asyncConnectThread.interrupt();
			asyncConnectThread = null;
		}
		
		if(session != null){
			session.close();
			session = null;
		}   
	}
	
	public void onMessage(MessageHandler msgHandler){
    	this.msgHandler = msgHandler;
    }
    
    public void onError(ErrorHandler errorHandler){
    	this.errorHandler = errorHandler;
    } 
    
    public void onConnected(ConnectedHandler connectedHandler){
    	this.connectedHandler = connectedHandler;
    } 
    
    public void onDisconnected(DisconnectedHandler disconnectedHandler){
    	this.disconnectedHandler = disconnectedHandler;
    }
  

	@Override
	public void sessionCreated(Session session) throws IOException { 
		this.session = session;
		this.clientId = this.session.id();
		activeLatch.countDown();
		if(connectedHandler != null){
			connectedHandler.onConnected();
		}
	}

	public void sessionToDestroy(Session session) throws IOException {
		if(this.session != null){
			this.session.close(); 
			this.session = null;
		}
		sync.clearTicket();
		
		if(disconnectedHandler != null){
			disconnectedHandler.onDisconnected();
		}   
	} 

	@Override
	public void onError(Throwable e, Session sess) throws IOException { 
		if(errorHandler != null){
			errorHandler.onError(e, session);
		} else {
			log.error(e.getMessage(), e);
		}
	} 
	
	@Override
	public void onIdle(Session sess) throws IOException { 
		
	}
	 
	public void invokeAsync(REQ req, ResultCallback callback) throws IOException { 
		Ticket ticket = null;
		if(callback != null){
			ticket = sync.createTicket(req, invokeTimeout, callback);
		} else {  
			if(req.getId() == null){ //if message id missing, set it
				req.setId(Sync.nextId()); 
			} 
		}
		try{
			sendMessage(req); 
		} catch(IOException e) {
			if(ticket != null){
				sync.removeTicket(ticket.getId());
			}
			throw e;
		} catch (InterruptedException e) {
			log.warn(e.getMessage(), e);
		}  
	} 
	
	public RES invokeSync(REQ req) throws IOException, InterruptedException {
		return this.invokeSync(req, this.invokeTimeout);
	}
	 
	public RES invokeSync(REQ req, long timeout) throws IOException, InterruptedException {
		Ticket ticket = null;
		try { 
			ticket = sync.createTicket(req, timeout);
			sendMessage(req);   
			if (!ticket.await(timeout, TimeUnit.MILLISECONDS)) {
				return null;
			}
			return ticket.response();
		} finally {
			if (ticket != null) {
				sync.removeTicket(ticket.getId());
			}
		}
	} 
	
	@Override
	public void onMessage(Object msg, Session sess) throws IOException {
		@SuppressWarnings("unchecked")
		RES res = (RES)msg;   
    	Ticket ticket = sync.removeTicket(res);
    	if(ticket != null){
    		ticket.notifyResponse(res); 
    		return;
    	}   
    	
    	if(msgHandler != null){
    		msgHandler.handle(res, sess);
    		return;
    	} 
    	
    	log.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!Drop,%s", res);
	}  
	
	public int getInvokeTimeout() {
		return invokeTimeout;
	}

	public void setInvokeTimeout(int invokeTimeout) {
		this.invokeTimeout = invokeTimeout;
	}   
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy