/* * Licensed to ElasticSearch and Shay Banon under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. ElasticSearch 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 org.elasticsearch.client.transport; import com.google.common.collect.ImmutableList; import org.elasticsearch.ElasticSearchException; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionModule; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestBuilder; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.count.CountRequest; import org.elasticsearch.action.count.CountResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.deletebyquery.DeleteByQueryRequest; import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse; import org.elasticsearch.action.explain.ExplainRequest; import org.elasticsearch.action.explain.ExplainResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.MultiGetRequest; import org.elasticsearch.action.get.MultiGetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.mlt.MoreLikeThisRequest; import org.elasticsearch.action.percolate.PercolateRequest; import org.elasticsearch.action.percolate.PercolateResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.client.AdminClient; import org.elasticsearch.client.support.DecoratingAdminClient; import org.elasticsearch.client.IngestClient; import org.elasticsearch.client.transport.support.InternalTransportClusterAdminClient; import org.elasticsearch.client.transport.support.InternalTransportIndicesAdminClient; import org.elasticsearch.client.transport.support.InternalTransportIngestClient; import org.elasticsearch.client.transport.support.InternalTransportSearchClient; import org.elasticsearch.cluster.ClusterNameModule; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.compress.CompressorFactory; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.inject.ModulesBuilder; import org.elasticsearch.common.io.CachedStreams; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.util.concurrent.ThreadLocals; import org.elasticsearch.env.Environment; import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.monitor.MonitorService; import org.elasticsearch.node.internal.InternalSettingsPerparer; import org.elasticsearch.plugins.PluginsModule; import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.search.TransportSearchModule; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPoolModule; import org.elasticsearch.transport.TransportModule; import org.elasticsearch.transport.TransportService; import java.util.concurrent.TimeUnit; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.count.CountRequestBuilder; import org.elasticsearch.action.delete.DeleteRequestBuilder; import org.elasticsearch.action.deletebyquery.DeleteByQueryRequestBuilder; import org.elasticsearch.action.explain.ExplainRequestBuilder; import org.elasticsearch.action.get.GetRequestBuilder; import org.elasticsearch.action.get.MultiGetRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder; import org.elasticsearch.action.percolate.PercolateRequestBuilder; import org.elasticsearch.action.search.MultiSearchRequestBuilder; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchScrollRequestBuilder; import org.elasticsearch.action.update.UpdateRequestBuilder; import org.elasticsearch.client.Client; import org.elasticsearch.threadpool.server.ServerThreadPool; import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; /** * The transport client allows to create a client that is not part of the cluster, but simply connects to one * or more nodes directly by adding their respective addresses using {@link #addTransportAddress(org.elasticsearch.common.transport.TransportAddress)}. * <p/> * <p>The transport client important modules used is the {@link org.elasticsearch.transport.TransportModule} which is * started in client mode (only connects, no bind). */ public class TransportClient extends AbstractComponent implements Client { private final Injector injector; private final Environment environment; private final Settings settings; private final PluginsService pluginsService; private final TransportClientNodesService nodesService; private final AdminClient adminClient; private final InternalTransportIngestClient internalIngestClient; private final InternalTransportSearchClient internalSearchClient; private final InternalTransportClusterAdminClient internalClusterAdminClient; private final InternalTransportIndicesAdminClient internalIndicesAdminClient; /** * Constructs a new transport client with settings loaded either from the classpath or the file system (the * <tt>elasticsearch.(yml|json)</tt> files optionally prefixed with <tt>config/</tt>). */ public TransportClient() throws ElasticSearchException { this(ImmutableSettings.Builder.EMPTY_SETTINGS, true); } /** * Constructs a new transport client with explicit settings and settings loaded either from the classpath or the file * system (the <tt>elasticsearch.(yml|json)</tt> files optionally prefixed with <tt>config/</tt>). */ public TransportClient(Settings settings) { this(settings, true); } /** * Constructs a new transport client with explicit settings and settings loaded either from the classpath or the file * system (the <tt>elasticsearch.(yml|json)</tt> files optionally prefixed with <tt>config/</tt>). */ public TransportClient(Settings.Builder settings) { this(settings.build(), true); } /** * Constructs a new transport client with the provided settings and the ability to control if settings will * be loaded from the classpath / file system (the <tt>elasticsearch.(yml|json)</tt> files optionally prefixed with * <tt>config/</tt>). * * @param settings The explicit settings. * @param loadConfigSettings <tt>true</tt> if settings should be loaded from the classpath/file system. * @throws ElasticSearchException */ public TransportClient(Settings.Builder settings, boolean loadConfigSettings) throws ElasticSearchException { this(settings.build(), loadConfigSettings); } /** * Constructs a new transport client with the provided settings and the ability to control if settings will * be loaded from the classpath / file system (the <tt>elasticsearch.(yml|json)</tt> files optionally prefixed with * <tt>config/</tt>). * * @param pSettings The explicit settings. * @param loadConfigSettings <tt>true</tt> if settings should be loaded from the classpath/file system. * @throws ElasticSearchException */ public TransportClient(Settings pSettings, boolean loadConfigSettings) throws ElasticSearchException { super(pSettings); Tuple<Settings, Environment> tuple = InternalSettingsPerparer.prepareSettings(pSettings, loadConfigSettings); Settings settings = settingsBuilder().put(tuple.v1()) .put("network.server", false) .put("node.client", true) .build(); this.environment = tuple.v2(); this.pluginsService = new PluginsService(settings, tuple.v2()); this.settings = pluginsService.updatedSettings(); CompressorFactory.configure(this.settings); ModulesBuilder modules = new ModulesBuilder(); modules.add(new PluginsModule(this.settings, pluginsService)); modules.add(new EnvironmentModule(environment)); modules.add(new SettingsModule(this.settings)); modules.add(new NetworkModule()); modules.add(new ClusterNameModule(this.settings)); modules.add(new ThreadPoolModule(this.settings)); modules.add(new TransportSearchModule()); modules.add(new TransportModule(this.settings)); modules.add(new ActionModule(true)); modules.add(new ClientTransportModule()); injector = modules.createInjector(); injector.getInstance(TransportService.class).start(); nodesService = injector.getInstance(TransportClientNodesService.class); internalIngestClient = injector.getInstance(InternalTransportIngestClient.class); internalSearchClient = injector.getInstance(InternalTransportSearchClient.class); internalClusterAdminClient = injector.getInstance(InternalTransportClusterAdminClient.class); internalIndicesAdminClient = injector.getInstance(InternalTransportIndicesAdminClient.class); adminClient = new DecoratingAdminClient(internalClusterAdminClient, internalIndicesAdminClient); } public AdminClient admin() { return adminClient; } /** * Returns the current registered transport addresses to use (added using * {@link #addTransportAddress(org.elasticsearch.common.transport.TransportAddress)}. */ public ImmutableList<TransportAddress> transportAddresses() { return nodesService.transportAddresses(); } /** * Returns the current connected transport nodes that this client will use. * <p/> * <p>The nodes include all the nodes that are currently alive based on the transport * addresses provided. */ public ImmutableList<DiscoveryNode> connectedNodes() { return nodesService.connectedNodes(); } /** * Returns the listed nodes in the transport client (ones added to it). */ public ImmutableList<DiscoveryNode> listedNodes() { return nodesService.listedNodes(); } /** * Adds a transport address that will be used to connect to. * <p/> * <p>The Node this transport address represents will be used if its possible to connect to it. * If it is unavailable, it will be automatically connected to once it is up. * <p/> * <p>In order to get the list of all the current connected nodes, please see {@link #connectedNodes()}. */ public TransportClient addTransportAddress(TransportAddress transportAddress) { nodesService.addTransportAddresses(transportAddress); return this; } /** * Adds a list of transport addresses that will be used to connect to. * <p/> * <p>The Node this transport address represents will be used if its possible to connect to it. * If it is unavailable, it will be automatically connected to once it is up. * <p/> * <p>In order to get the list of all the current connected nodes, please see {@link #connectedNodes()}. */ public TransportClient addTransportAddresses(TransportAddress... transportAddress) { nodesService.addTransportAddresses(transportAddress); return this; } /** * Removes a transport address from the list of transport addresses that are used to connect to. */ public TransportClient removeTransportAddress(TransportAddress transportAddress) { nodesService.removeTransportAddress(transportAddress); return this; } /** * Closes the client. */ public void close() { internalIndicesAdminClient.close(); internalClusterAdminClient.close(); internalSearchClient.close(); internalIngestClient.close(); injector.getInstance(TransportClientNodesService.class).close(); injector.getInstance(TransportService.class).close(); try { injector.getInstance(MonitorService.class).close(); } catch (Exception e) { // ignore, might not be bounded } for (Class<? extends LifecycleComponent> plugin : pluginsService.services()) { injector.getInstance(plugin).close(); } injector.getInstance(ServerThreadPool.class).shutdown(); try { injector.getInstance(ServerThreadPool.class).awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { logger.warn(e.getMessage(), e); } try { injector.getInstance(ServerThreadPool.class).shutdownNow(); } catch (Exception e) { logger.warn(e.getMessage(), e); } CacheRecycler.clear(); CachedStreams.clear(); ThreadLocals.clearReferencesThreadLocals(); } public <Request extends ActionRequest, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> ActionFuture<Response> execute(Action<Request, Response, RequestBuilder, IngestClient> action, Request request) { return internalIngestClient.execute(action, request); } public <Request extends ActionRequest, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void execute(Action<Request, Response, RequestBuilder, IngestClient> action, Request request, ActionListener<Response> listener) { internalIngestClient.execute(action, request, listener); } public ActionFuture<IndexResponse> index(IndexRequest request) { return internalIngestClient.index(request); } public void index(IndexRequest request, ActionListener<IndexResponse> listener) { internalIngestClient.index(request, listener); } public ActionFuture<UpdateResponse> update(UpdateRequest request) { return internalIngestClient.update(request); } public void update(UpdateRequest request, ActionListener<UpdateResponse> listener) { internalIngestClient.update(request, listener); } public ActionFuture<DeleteResponse> delete(DeleteRequest request) { return internalIngestClient.delete(request); } public void delete(DeleteRequest request, ActionListener<DeleteResponse> listener) { internalIngestClient.delete(request, listener); } public ActionFuture<BulkResponse> bulk(BulkRequest request) { return internalIngestClient.bulk(request); } public void bulk(BulkRequest request, ActionListener<BulkResponse> listener) { internalIngestClient.bulk(request, listener); } public ActionFuture<DeleteByQueryResponse> deleteByQuery(DeleteByQueryRequest request) { return internalSearchClient.deleteByQuery(request); } public void deleteByQuery(DeleteByQueryRequest request, ActionListener<DeleteByQueryResponse> listener) { internalSearchClient.deleteByQuery(request, listener); } public ActionFuture<GetResponse> get(GetRequest request) { return internalIngestClient.get(request); } public void get(GetRequest request, ActionListener<GetResponse> listener) { internalIngestClient.get(request, listener); } public ActionFuture<MultiGetResponse> multiGet(MultiGetRequest request) { return internalIngestClient.multiGet(request); } public void multiGet(MultiGetRequest request, ActionListener<MultiGetResponse> listener) { internalIngestClient.multiGet(request, listener); } public ActionFuture<CountResponse> count(CountRequest request) { return internalSearchClient.count(request); } public void count(CountRequest request, ActionListener<CountResponse> listener) { internalSearchClient.count(request, listener); } public ActionFuture<SearchResponse> search(SearchRequest request) { return internalSearchClient.search(request); } public void search(SearchRequest request, ActionListener<SearchResponse> listener) { internalSearchClient.search(request, listener); } public ActionFuture<SearchResponse> searchScroll(SearchScrollRequest request) { return internalSearchClient.searchScroll(request); } public void searchScroll(SearchScrollRequest request, ActionListener<SearchResponse> listener) { internalSearchClient.searchScroll(request, listener); } public ActionFuture<MultiSearchResponse> multiSearch(MultiSearchRequest request) { return internalSearchClient.multiSearch(request); } public void multiSearch(MultiSearchRequest request, ActionListener<MultiSearchResponse> listener) { internalSearchClient.multiSearch(request, listener); } public ActionFuture<SearchResponse> moreLikeThis(MoreLikeThisRequest request) { return internalSearchClient.moreLikeThis(request); } public void moreLikeThis(MoreLikeThisRequest request, ActionListener<SearchResponse> listener) { internalSearchClient.moreLikeThis(request, listener); } public ActionFuture<PercolateResponse> percolate(PercolateRequest request) { return internalIngestClient.percolate(request); } public void percolate(PercolateRequest request, ActionListener<PercolateResponse> listener) { internalIngestClient.percolate(request, listener); } public ActionFuture<ExplainResponse> explain(ExplainRequest request) { return internalSearchClient.explain(request); } public void explain(ExplainRequest request, ActionListener<ExplainResponse> listener) { internalSearchClient.explain(request, listener); } @Override public IndexRequestBuilder prepareIndex() { return internalIngestClient.prepareIndex(); } @Override public UpdateRequestBuilder prepareUpdate() { return internalIngestClient.prepareUpdate(); } @Override public UpdateRequestBuilder prepareUpdate(String index, String type, String id) { return internalIngestClient.prepareUpdate(index, type, id); } @Override public IndexRequestBuilder prepareIndex(String index, String type) { return internalIngestClient.prepareIndex(index, type); } @Override public IndexRequestBuilder prepareIndex(String index, String type, String id) { return internalIngestClient.prepareIndex(index, type, id); } @Override public DeleteRequestBuilder prepareDelete() { return internalIngestClient.prepareDelete(); } @Override public DeleteRequestBuilder prepareDelete(String index, String type, String id) { return internalIngestClient.prepareDelete(index, type, id); } @Override public BulkRequestBuilder prepareBulk() { return internalIngestClient.prepareBulk(); } @Override public DeleteByQueryRequestBuilder prepareDeleteByQuery(String... indices) { return internalSearchClient.prepareDeleteByQuery(indices); } @Override public GetRequestBuilder prepareGet() { return internalIngestClient.prepareGet(); } @Override public GetRequestBuilder prepareGet(String index, String type, String id) { return internalIngestClient.prepareGet(index, type, id); } @Override public MultiGetRequestBuilder prepareMultiGet() { return internalIngestClient.prepareMultiGet(); } @Override public CountRequestBuilder prepareCount(String... indices) { return internalSearchClient.prepareCount(indices); } @Override public SearchRequestBuilder prepareSearch(String... indices) { return internalSearchClient.prepareSearch(indices); } @Override public SearchScrollRequestBuilder prepareSearchScroll(String scrollId) { return internalSearchClient.prepareSearchScroll(scrollId); } @Override public MultiSearchRequestBuilder prepareMultiSearch() { return internalSearchClient.prepareMultiSearch(); } @Override public MoreLikeThisRequestBuilder prepareMoreLikeThis(String index, String type, String id) { return internalSearchClient.prepareMoreLikeThis(index, type, id); } @Override public PercolateRequestBuilder preparePercolate(String index, String type) { return internalIngestClient.preparePercolate(index, type); } @Override public ExplainRequestBuilder prepareExplain(String index, String type, String id) { return internalSearchClient.prepareExplain(index, type, id); } }