Subversion Repositories SmartDukaan

Rev

Rev 2298 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package in.shop2020.thrift.clients;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import in.shop2020.config.ConfigException;
import in.shop2020.thrift.clients.config.ConfigClient;
import in.shop2020.utils.Logger;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public abstract class GenericClient {
        /**
         * Socket timeout to be set for thrift
         */
        private final int SOCKET_TIMEOUT = 1000 * 60 * 5;
        protected TSocket socket = null;
        protected TTransport transport = null;
        protected TProtocol protocol = null;
        
        /**
         * Max attempts on one instance of service to be tried before falling on next instance of service
         */
        protected static final int MAX_ATTEMPTS = 3;
        protected static final int FIRST_ATTEMPT = 1;
        /**
         * Max instances of service to be tried before dying
         */
        protected static final int TOTAL_SERVICES = 2;
        /**
         * Current service instance being used
         */
        protected int serviceNumber = 0;
        protected String hostname = "localhost";
        protected int port = 8080;
        
        protected String hostConfigKey;
        protected String portConfigKey;

                
        
        /**
         * Constructor
         * @param hostConfigKey
         * @param portConfigKey
         * @throws TTransportException
         */
        public GenericClient(String hostConfigKey, String portConfigKey) throws TTransportException{
                this.hostConfigKey = hostConfigKey; 
                this.portConfigKey = portConfigKey;
                loadConfigParameters(hostConfigKey, portConfigKey);
                connectToService(FIRST_ATTEMPT);
        }
        
        /**
         * Load config parameters for the given key set
         * @param hostConfigKey
         * @param portConfigKey
         */
        private void loadConfigParameters(String hostConfigKey, String  portConfigKey){
                this.hostname = getHost(hostConfigKey);
                this.port = getPort(portConfigKey);
        }
        

        /**
         * get the Host name from given key
         * @param key
         * @return
         */
        private String getHost(String key){
                try {
                        String host = ConfigClient.getClient().get(key);
                        return host;
                } catch (ConfigException e) {
                        Logger.log("Error while fetching hostname for key "+ key+" using localhost:"+ e, this);
                        return "localhost";
                }
        }
        
        /**
         * get the Port from given key
         * @param key
         * @return
         */
        private int getPort(String key){
                try {
                        String port = ConfigClient.getClient().get(key);
                        return Integer.parseInt(port);
                }catch (NumberFormatException ne){
                        Logger.log("Could not convert string to int for key "+ key+" using 8080 as port"+ ne, this);
                        return 8080;
                }
                catch (ConfigException e) {
                        Logger.log("Error while fetching port for key "+ key+" using 8080:"+ e, this);
                        return 8080;
                }
        }

        /**
         * Connect to the service. It also have mechanism to handle multiple service instances.
         * Connect to default service:
         *     If fails: Connect to another services instances till have tried all services.
         * Tries the default service at MAX_ATTEMPTS times  
         * @param attemptNumber
         * @throws TTransportException
         */
        private void connectToService(int attemptNumber) throws TTransportException{
                try{
                        openTransport();
                }catch (TTransportException e) {
                        if(attemptNumber < MAX_ATTEMPTS){
                                connectToService(attemptNumber+1);
                        }else{
                                if(serviceNumber < TOTAL_SERVICES){
                                        serviceNumber += 1;
                                        Logger.log("Maximum attempts have reached. Failing over to another service", null);
                                        loadConfigParameters(this.hostConfigKey + serviceNumber, this.portConfigKey + serviceNumber);
                                        connectToService(FIRST_ATTEMPT);
                                        updateConfigParameters(this.hostConfigKey, this.portConfigKey);
                                }else{
                                        Logger.log("Have tried enough services. Giving up.....", null);
                                        throw e;
                                }
                        }
                }
        }
        
        /**
         * Update the config parameters for the current service being used, so that next time these parameters can be used.
         * @param hostConfigKey
         * @param portConfigKey
         */
        private void updateConfigParameters(String hostConfigKey, String portConfigKey){
                try {
                        ConfigClient.getClient().set(hostConfigKey, this.hostname);
                        ConfigClient.getClient().set(portConfigKey, this.port+"");
                } catch (ConfigException e) {
                        Logger.log("Unable to update the keys in the section", null);
                }       
        }

        /**
         * Open the transport to connect to service.
         * @throws TTransportException
         */
        @PostConstruct
        protected void openTransport() throws TTransportException {
                Logger.log("Initializing socket infra ", this);
                socket = new TSocket(hostname, port);
                socket.setTimeout(SOCKET_TIMEOUT);
                transport = new TFramedTransport(socket);
                protocol = new TBinaryProtocol(transport);

                if(!transport.isOpen()){
                        transport.open();
                }else{
                        Logger.log("Transport was already open", this);
                }
        }


        /**
         * Close the transport
         */
        @PreDestroy
        protected void closeTransport(){
                if(transport != null && transport.isOpen()){
                        Logger.log("Closing transport :", this);
                        transport.close();
                }
        }

        /**
         * Close the connection.
         */
        public void closeConnection(){
                if(transport != null && transport.isOpen()){
                        Logger.log("Closing transport :", this);
                        transport.close();
                }
        }
        
        
        /**
         * Closing connection in finalize.
         */
        protected void finalize() throws Throwable{
                super.finalize();
                this.closeConnection();
        }
        
        public abstract void closeSession();
        
}