Subversion Repositories SmartDukaan

Rev

Rev 3123 | 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 = 0;
        
        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;
                try {
                        loadConfigParameters(hostConfigKey, portConfigKey);
                        connectToService(FIRST_ATTEMPT);
                } catch (ConfigException e) {
                        Logger.log("Config exception", this);
                        throw new TTransportException("Unable to get parameters from config server.");
                }
        }
        
        /**
         * Load config parameters for the given key set
         * @param hostConfigKey
         * @param portConfigKey
         */
        private void loadConfigParameters(String hostConfigKey, String  portConfigKey) throws ConfigException{
                this.hostname = getHost(hostConfigKey);
                this.port = getPort(portConfigKey);
        }
        

        /**
         * get the Host name from given key
         * @param key
         * @return
         * @throws ConfigException 
         */
        private String getHost(String key) throws ConfigException{
                String host = ConfigClient.getClient().get(key);
                return host;
        }
        
        /**
         * get the Port from given key
         * @param key
         * @return
         * @throws ConfigException 
         */
        private int getPort(String key) throws ConfigException{
                        String port = ConfigClient.getClient().get(key);
                        try{
                                int portNumber = Integer.parseInt(port);
                                return portNumber;
                        }catch (NumberFormatException e) {
                                Logger.log("Unable to parse the port number to string", null);
                                throw new ConfigException(100, "Unable to parse the port number to string");
                        }
                        
        }

        /**
         * 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
         * @throws ConfigException 
         */
        private void connectToService(int attemptNumber) throws TTransportException, ConfigException{
                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();
        
}