org.elasticsearch.client.transport.TransportClient Maven / Gradle / Ivy
Show all versions of elasticsearch Show documentation
/*
* Licensed to Elasticsearch 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 org.elasticsearch.Build;
import org.elasticsearch.Version;
import org.elasticsearch.action.Action;
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.cache.recycler.PageCacheRecycler;
import org.elasticsearch.client.support.AbstractClient;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.client.transport.support.TransportProxyClient;
import org.elasticsearch.cluster.ClusterNameModule;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.inject.ModulesBuilder;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.indices.breaker.CircuitBreakerModule;
import org.elasticsearch.monitor.MonitorService;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsModule;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPoolModule;
import org.elasticsearch.transport.TransportModule;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.netty.NettyTransport;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.common.settings.Settings.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)}.
*
* 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 AbstractClient {
/**
* Handy method ot create a {@link org.elasticsearch.client.transport.TransportClient.Builder}.
*/
public static Builder builder() {
return new Builder();
}
/**
* A builder used to create an instance of the transport client.
*/
public static class Builder {
private Settings settings = Settings.EMPTY;
private List> pluginClasses = new ArrayList<>();
private HostFailureListener hostFailedListener;
/**
* The settings to configure the transport client with.
*/
public Builder settings(Settings.Builder settings) {
return settings(settings.build());
}
/**
* The settings to configure the transport client with.
*/
public Builder settings(Settings settings) {
if (settings.get("plugin.types") != null) {
throw new IllegalArgumentException("plugin.types is no longer supported. Use the addPlugin method on TransportClient.");
}
this.settings = settings;
return this;
}
/**
* Add the given plugin to the client when it is created.
*/
public Builder addPlugin(Class pluginClass) {
pluginClasses.add(pluginClass);
return this;
}
/**
* Builds a new instance of the transport client.
*/
public TransportClient build() {
Settings settings = InternalSettingsPreparer.prepareSettings(this.settings);
settings = settingsBuilder()
.put(NettyTransport.PING_SCHEDULE, "5s") // enable by default the transport schedule ping interval
.put(settings)
.put("network.server", false)
.put("node.client", true)
.put(CLIENT_TYPE_SETTING, CLIENT_TYPE)
.build();
PluginsService pluginsService = new PluginsService(settings, null, null, pluginClasses);
this.settings = pluginsService.updatedSettings();
Version version = Version.CURRENT;
final ThreadPool threadPool = new ThreadPool(settings);
NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
boolean success = false;
try {
ModulesBuilder modules = new ModulesBuilder();
modules.add(new Version.Module(version));
// plugin modules must be added here, before others or we can get crazy injection errors...
for (Module pluginModule : pluginsService.nodeModules()) {
modules.add(pluginModule);
}
modules.add(new PluginsModule(pluginsService));
modules.add(new SettingsModule(this.settings));
modules.add(new NetworkModule(namedWriteableRegistry));
modules.add(new ClusterNameModule(this.settings));
modules.add(new ThreadPoolModule(threadPool));
modules.add(new TransportModule(this.settings, namedWriteableRegistry));
modules.add(new SearchModule() {
@Override
protected void configure() {
// noop
}
});
modules.add(new ActionModule(true));
modules.add(new ClientTransportModule(hostFailedListener));
modules.add(new CircuitBreakerModule(this.settings));
pluginsService.processModules(modules);
Injector injector = modules.createInjector();
final TransportService transportService = injector.getInstance(TransportService.class);
transportService.start();
transportService.acceptIncomingRequests();
TransportClient transportClient = new TransportClient(injector);
success = true;
return transportClient;
} finally {
if (!success) {
ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS);
}
}
}
public Builder setHostFailedListener(HostFailureListener hostFailedListener) {
this.hostFailedListener = hostFailedListener;
return this;
}
}
public static final String CLIENT_TYPE = "transport";
final Injector injector;
private final TransportClientNodesService nodesService;
private final TransportProxyClient proxy;
private TransportClient(Injector injector) {
super(injector.getInstance(Settings.class), injector.getInstance(ThreadPool.class), injector.getInstance(Headers.class));
this.injector = injector;
nodesService = injector.getInstance(TransportClientNodesService.class);
proxy = injector.getInstance(TransportProxyClient.class);
}
TransportClientNodesService nodeService() {
return nodesService;
}
/**
* Returns the current registered transport addresses to use (added using
* {@link #addTransportAddress(org.elasticsearch.common.transport.TransportAddress)}.
*/
public List transportAddresses() {
return nodesService.transportAddresses();
}
/**
* Returns the current connected transport nodes that this client will use.
*
* The nodes include all the nodes that are currently alive based on the transport
* addresses provided.
*/
public List connectedNodes() {
return nodesService.connectedNodes();
}
/**
* The list of filtered nodes that were not connected to, for example, due to
* mismatch in cluster name.
*/
public List filteredNodes() {
return nodesService.filteredNodes();
}
/**
* Returns the listed nodes in the transport client (ones added to it).
*/
public List listedNodes() {
return nodesService.listedNodes();
}
/**
* Adds a transport address that will be used to connect to.
*
* 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.
*
* 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.
*
* 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.
*
* 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.
*/
@Override
public void 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 plugin : injector.getInstance(PluginsService.class).nodeServices()) {
injector.getInstance(plugin).close();
}
try {
ThreadPool.terminate(injector.getInstance(ThreadPool.class), 10, TimeUnit.SECONDS);
} catch (Exception e) {
// ignore
}
injector.getInstance(PageCacheRecycler.class).close();
}
@Override
protected > void doExecute(Action action, Request request, ActionListener listener) {
proxy.execute(action, request, listener);
}
/**
* Listener that allows to be notified whenever a node failure / disconnect happens
*/
public interface HostFailureListener {
/**
* Called once a node disconnect is detected.
* @param node the node that has been disconnected
* @param ex the exception causing the disconnection
*/
void onNodeDisconnected(DiscoveryNode node, Throwable ex);
}
// pkg private for testing
TransportClientNodesService getNodesService() {
return nodesService;
}
}