package com.xxl.rpc.remoting.net.common;

import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory;
import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;
import com.xxl.rpc.remoting.net.params.BaseCallback;
import com.xxl.rpc.remoting.net.params.XxlRpcRequest;
import com.xxl.rpc.serialize.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xuxueli 2018-10-19
 */
public abstract class ConnectClient {
    protected static transient Logger logger = LoggerFactory.getLogger(ConnectClient.class);


    // ---------------------- iface ----------------------

    public abstract void init(String address, final Serializer serializer, final XxlRpcInvokerFactory xxlRpcInvokerFactory) throws Exception;

    public abstract void close();

    public abstract boolean isValidate();

    public abstract void send(XxlRpcRequest xxlRpcRequest) throws Exception ;


    // ---------------------- client pool map ----------------------

    /**
     * async send
     */
    public static void asyncSend(XxlRpcRequest xxlRpcRequest, String address,
                                 Class<? extends ConnectClient> connectClientImpl,
                                 final XxlRpcReferenceBean xxlRpcReferenceBean) throws Exception {

        // client pool	[tips03 : may save 35ms/100invoke if move it to constructor, but it is necessary. cause by ConcurrentHashMap.get]
        ConnectClient clientPool = ConnectClient.getPool(address, connectClientImpl, xxlRpcReferenceBean);

        try {
            if (!clientPool.isValidate()) {

            }

            // do invoke
            clientPool.send(xxlRpcRequest);
        } catch (Exception e) {
            throw e;
        }

    }

    private static ConcurrentHashMap<String, ConnectClient> connectClientMap;        // (static) alread addStopCallBack
    private static ConnectClient getPool(String address, Class<? extends ConnectClient> connectClientImpl,
                                         final XxlRpcReferenceBean xxlRpcReferenceBean) throws Exception {

        // init client-pool-map, avoid repeat init
        if (connectClientMap == null) {
            synchronized (ConnectClient.class) {
                if (connectClientMap == null) {
                    // init
                    connectClientMap = new ConcurrentHashMap<String, ConnectClient>();
                    // stop callback
                    xxlRpcReferenceBean.getInvokerFactory().addStopCallBack(new BaseCallback() {
                        @Override
                        public void run() throws Exception {
                            if (connectClientMap.size() > 0) {
                                for (String key: connectClientMap.keySet()) {
                                    ConnectClient clientPool = connectClientMap.get(key);
                                    clientPool.close();
                                }
                                connectClientMap.clear();
                            }
                        }
                    });
                }
            }
        }

        // get pool
        ConnectClient connectClient = connectClientMap.get(address);
        if (connectClient != null) {
            return connectClient;
        }

        // make pool, avoid repeat init
        synchronized (connectClientMap) {

            // re-get pool
            connectClient = connectClientMap.get(address);
            if (connectClient != null) {
                return connectClient;
            }

            // set pool
            ConnectClient connectClient_new = connectClientImpl.newInstance();
            connectClient_new.init(address, xxlRpcReferenceBean.getSerializer(), xxlRpcReferenceBean.getInvokerFactory());
            connectClientMap.put(address, connectClient_new);

            return connectClient_new;
        }

    }

}

@@ -1574,68 +1574,8 @@
 y %7B%0A
-            if (!clientPool.isValidate()) %7B%0A%0A            %7D%0A%0A
     
@@ -3160,32 +3160,225 @@
 p.get(address);%0A
+%0A        if (connectClient!=null && !connectClient.isValidate()) %7B%0A            connectClient.close();%0A            connectClient = null;%0A            connectClientMap.remove(address);%0A        %7D%0A%0A
         if (conn

update document