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

com.xiaomi.infra.galaxy.sds.client.ThreadSafeClient Maven / Gradle / Ivy

There is a newer version: 1.3.6
Show newest version
package com.xiaomi.infra.galaxy.sds.client;

import com.xiaomi.infra.galaxy.sds.client.metrics.MetricsCollector;
import com.xiaomi.infra.galaxy.sds.client.metrics.RequestMetrics;
import com.xiaomi.infra.galaxy.sds.shared.clock.AdjustableClock;
import com.xiaomi.infra.galaxy.sds.thrift.CommonConstants;
import com.xiaomi.infra.galaxy.sds.thrift.Credential;
import com.xiaomi.infra.galaxy.sds.thrift.LatencyMetricType;
import com.xiaomi.infra.galaxy.sds.thrift.ThriftProtocol;
import libthrift091.protocol.TProtocol;
import libthrift091.transport.TTransport;
import org.apache.http.client.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Thread safe client proxy.
 *
 * @author heliangliang
 */
public class ThreadSafeClient {
  private static class ThreadSafeInvocationHandler implements InvocationHandler {
    private static final Logger LOG = LoggerFactory.getLogger(ThreadSafeInvocationHandler.class);
    private static final Map ctorCache =
        new ConcurrentHashMap();
    private final HttpClient client;
    private final Map customHeaders;
    private final Credential credential;
    private final AdjustableClock clock;
    private final ThriftProtocol protocol;
    final Class ifaceClass;
    final Class implClass;
    final String url;
    private int socketTimeout = 0;
    private int connTimeout = 0;
    private boolean supportAccountKey = false;
    private boolean isMetricsEnabled = false;
    private String sid;
    private MetricsCollector metricsCollector;


    private ThreadSafeInvocationHandler(HttpClient client, Map customHeaders,
                                        Credential credential, AdjustableClock clock, ThriftProtocol protocol,
                                        Class ifaceClass, Class implClass, String url, int socketTimeout,
                                        int connTimeout, boolean supportAccountKey, String sid, MetricsCollector metricsCollector) {
      this.client = client;
      this.customHeaders = customHeaders;
      this.credential = credential;
      this.clock = clock;
      this.protocol = protocol;
      this.ifaceClass = ifaceClass;
      this.implClass = implClass;
      this.url = url;
      this.socketTimeout = socketTimeout;
      this.connTimeout = connTimeout;
      this.supportAccountKey = supportAccountKey;
      this.sid = sid;
      this.metricsCollector = metricsCollector;
      if (metricsCollector != null) {
        isMetricsEnabled = true;
      }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      RequestMetrics requestMetrics = null;
      try {
        if (isMetricsEnabled) {
          requestMetrics = new RequestMetrics();
          requestMetrics.startEvent(LatencyMetricType.ExecutionTime);
          requestMetrics.setRequestTypeName(method.getName());
        }

        SdsTHttpClient sdsHttpClient = new SdsTHttpClient(url, client, this.credential, clock);
        sdsHttpClient.setSocketTimeout(socketTimeout)
            .setConnectTimeout(connTimeout)
            .setProtocol(protocol)
            .setQueryString(SdsRequestUtils.getQuery(method, args))
            .setSupportAccountKey(supportAccountKey)
            .setSid(sid);
        if (customHeaders != null) {
          for (Map.Entry header : customHeaders.entrySet()) {
            sdsHttpClient.setCustomHeader(header.getKey(), header.getValue());
          }
        }
        String protocolClassName = "libthrift091.protocol." + CommonConstants.THRIFT_PROTOCOL_MAP.get(protocol);
        Class protocolClass = Class.forName(protocolClassName);
        Constructor ctor = protocolClass.getDeclaredConstructor(TTransport.class);
        Impl client = getDeclaredConstructor(implClass).newInstance(ctor.newInstance(sdsHttpClient));
        return method.invoke(client, args);
      } catch (InvocationTargetException e) {
        throw e.getCause();
      } finally {
        if (isMetricsEnabled) {
          requestMetrics.endEvent(LatencyMetricType.ExecutionTime);
          metricsCollector.collect(requestMetrics);
        }
      }
    }

    public static  Constructor getDeclaredConstructor(Class clazz)
        throws NoSuchMethodException {
      Constructor ctor = ctorCache.get(clazz);
      if (ctor == null) {
        ctor = clazz.getDeclaredConstructor(TProtocol.class);
        ctorCache.put(clazz, ctor);
      }
      return ctor;
    }
  }

  /**
   * Create client wrapper which automatically retry the RPC calls for retryable errors until
   * success or reaches max retry time.
   */
  @SuppressWarnings("unchecked")
  public static  IFace getClient(HttpClient client, Map customHeaders,
                                              Credential credential, AdjustableClock clock, ThriftProtocol protocol,
                                              Class ifaceClass, Class implClass, String url, int socketTimeout,
                                              int connTimeout, boolean supportAccountKey, String sid) {
    return getClient(client, customHeaders, credential, clock, protocol, ifaceClass, implClass, url,
        socketTimeout, connTimeout, supportAccountKey, sid, null);
  }

  @SuppressWarnings("unchecked")
  public static  IFace getClient(HttpClient client, Map customHeaders,
                                              Credential credential, AdjustableClock clock, ThriftProtocol protocol,
                                              Class ifaceClass, Class implClass, String url, int socketTimeout,
                                              int connTimeout, boolean supportAccountKey, String sid,
      MetricsCollector metricsCollector) {
    return (IFace) Proxy.newProxyInstance(ThreadSafeClient.class.getClassLoader(),
        new Class[]{ifaceClass},
        new ThreadSafeInvocationHandler(client, customHeaders, credential, clock, protocol,
            ifaceClass, implClass, url, socketTimeout, connTimeout, supportAccountKey, sid, metricsCollector)
    );
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy