gobblin.restli.SharedRestClientFactory Maven / Gradle / Ivy
 The newest version!
        
        /*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package gobblin.restli;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.linkedin.r2.filter.FilterChains;
import com.linkedin.r2.transport.common.Client;
import com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter;
import com.linkedin.r2.transport.http.client.HttpClientFactory;
import com.linkedin.restli.client.RestClient;
import com.typesafe.config.Config;
import gobblin.broker.ResourceCoordinate;
import gobblin.broker.ResourceInstance;
import gobblin.broker.iface.ConfigView;
import gobblin.broker.iface.NotConfiguredException;
import gobblin.broker.iface.ScopeType;
import gobblin.broker.iface.ScopedConfigView;
import gobblin.broker.iface.SharedResourceFactory;
import gobblin.broker.iface.SharedResourceFactoryResponse;
import gobblin.broker.iface.SharedResourcesBroker;
import gobblin.util.ExecutorsUtils;
import io.netty.channel.nio.NioEventLoopGroup;
/**
 * A {@link SharedResourceFactory} to create {@link RestClient}s.
 *
 * To configure, specify rest server uri at key "serverUri". Note uri must start with "http" or "https".
 */
public class SharedRestClientFactory> implements SharedResourceFactory {
  public static final String FACTORY_NAME = "restli";
  public static final String SERVER_URI_KEY = "serverUri";
  private static final Set RESTLI_SCHEMES = Sets.newHashSet("http", "https");
  @Override
  public String getName() {
    return FACTORY_NAME;
  }
  @Override
  public SharedResourceFactoryResponse
    createResource(SharedResourcesBroker broker, ScopedConfigView config) throws NotConfiguredException {
    try {
      SharedRestClientKey key = config.getKey();
      if (!(key instanceof UriRestClientKey)) {
        return new ResourceCoordinate<>(this, new UriRestClientKey(key.serviceName, resolveUriPrefix(config.getConfig(), key)),
            config.getScope());
      }
      String uriPrefix = ((UriRestClientKey) key).getUri();
      HttpClientFactory http = new HttpClientFactory(FilterChains.empty(),
          new NioEventLoopGroup(0 /* use default settings */,
              ExecutorsUtils.newDaemonThreadFactory(Optional.absent(), Optional.of("R2 Nio Event Loop-%d"))),
          true,
          Executors.newSingleThreadScheduledExecutor(
              ExecutorsUtils.newDaemonThreadFactory(Optional.absent(), Optional.of("R2 Netty Scheduler"))),
          true);
      Client r2Client = new TransportClientAdapter(http.getClient(Collections.emptyMap()));
      return new ResourceInstance<>(new RestClient(r2Client,uriPrefix));
    } catch (URISyntaxException use) {
      throw new RuntimeException("Could not create a rest client for key " + Optional.fromNullable(config.getKey().toConfigurationKey()).or("null"));
    }
  }
  @Override
  public S getAutoScope(SharedResourcesBroker broker, ConfigView config) {
    return broker.selfScope().getType().rootScope();
  }
  /**
   * Get a uri prefix from the input configuration.
   */
  public static String resolveUriPrefix(Config config, SharedRestClientKey key) throws URISyntaxException, NotConfiguredException {
    List connectionPrefixes = parseConnectionPrefixes(config, key);
    Preconditions.checkArgument(connectionPrefixes.size() > 0, "No uris found for service " + key.serviceName);
    return connectionPrefixes.get(new Random().nextInt(connectionPrefixes.size()));
  }
  /**
   * Parse the list of available input prefixes from the input configuration.
   */
  public static List parseConnectionPrefixes(Config config, SharedRestClientKey key) throws URISyntaxException, NotConfiguredException {
    if (key instanceof UriRestClientKey) {
      return Lists.newArrayList(((UriRestClientKey) key).getUri());
    }
    if (!config.hasPath(SERVER_URI_KEY)) {
      throw new NotConfiguredException("Missing key " + SERVER_URI_KEY);
    }
    List uris = Lists.newArrayList();
    for (String uri : Splitter.on(",").omitEmptyStrings().trimResults().splitToList(config.getString(SERVER_URI_KEY))) {
      uris.add(resolveUriPrefix(new URI(uri)));
    }
    return uris;
  }
  /**
   * Convert the input URI into a correctly formatted uri prefix. In the future, may also resolve d2 uris.
   */
  public static String resolveUriPrefix(URI serverURI)
      throws URISyntaxException {
    if (RESTLI_SCHEMES.contains(serverURI.getScheme())) {
      return new URI(serverURI.getScheme(), serverURI.getAuthority(), null, null, null).toString() + "/";
    }
    throw new RuntimeException("Unrecognized scheme for URI " + serverURI);
  }
}
             © 2015 - 2025 Weber Informatics LLC | Privacy Policy