Gateway: allow overriding the Gateway implementation

Allows mocking the gateway and overriding it from plugins.

Closes #13412
This commit is contained in:
Boaz Leskes 2015-09-08 21:50:16 +02:00
parent 65e7aba780
commit 37d4727c0a
7 changed files with 94 additions and 25 deletions

View File

@ -145,7 +145,11 @@ public abstract class ExtensionPoint {
if (instance == null) {
throw new IllegalArgumentException("Unknown [" + this.name + "] type [" + type + "]");
}
binder.bind(extensionClass).to(instance).asEagerSingleton();
if (extensionClass == instance) {
binder.bind(extensionClass).asEagerSingleton();
} else {
binder.bind(extensionClass).to(instance).asEagerSingleton();
}
return type;
}

View File

@ -19,19 +19,38 @@
package org.elasticsearch.gateway;
import org.elasticsearch.common.inject.*;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.ExtensionPoint;
/**
*
*/
public class GatewayModule extends AbstractModule {
public static final String GATEWAY_TYPE_KEY = "gateway.type";
private final ExtensionPoint.SelectedType<Gateway> gatewayTypes = new ExtensionPoint.SelectedType<>("gateway", Gateway.class);
private final Settings settings;
public GatewayModule(Settings settings) {
this.settings = settings;
registerGatewayType("default", Gateway.class);
}
/**
* Adds a custom Discovery type.
*/
public void registerGatewayType(String type, Class<? extends Gateway> clazz) {
gatewayTypes.registerExtension(type, clazz);
}
@Override
protected void configure() {
bind(MetaStateService.class).asEagerSingleton();
bind(DanglingIndicesState.class).asEagerSingleton();
bind(GatewayService.class).asEagerSingleton();
bind(Gateway.class).asEagerSingleton();
gatewayTypes.bindType(binder(), settings, GATEWAY_TYPE_KEY, "default");
bind(TransportNodesListGatewayMetaState.class).asEagerSingleton();
bind(GatewayMetaState.class).asEagerSingleton();
bind(TransportNodesListGatewayStartedShards.class).asEagerSingleton();

View File

@ -188,7 +188,7 @@ public class Node implements Releasable {
modules.add(new SearchModule(settings));
modules.add(new ActionModule(false));
modules.add(new MonitorModule(settings));
modules.add(new GatewayModule());
modules.add(new GatewayModule(settings));
modules.add(new NodeClientModule());
modules.add(new ShapeModule());
modules.add(new PercolatorModule());

View File

@ -60,7 +60,6 @@ public class ReplicaRecoveryBenchmark {
BootstrapForTesting.ensureInitialized();
Settings settings = settingsBuilder()
.put("gateway.type", "local")
.put(DiskThresholdDecider.CLUSTER_ROUTING_ALLOCATION_DISK_THRESHOLD_ENABLED, "false")
.put(SETTING_NUMBER_OF_SHARDS, 1)
.put(SETTING_NUMBER_OF_REPLICAS, 0)

View File

@ -166,7 +166,6 @@ public class ClusterRerouteIT extends ESIntegTestCase {
@Test
public void testDelayWithALargeAmountOfShards() throws Exception {
Settings commonSettings = settingsBuilder()
.put("gateway.type", "local")
.put(ThrottlingAllocationDecider.CLUSTER_ROUTING_ALLOCATION_CONCURRENT_RECOVERIES, 1)
.build();
logger.info("--> starting 4 nodes");

View File

@ -18,12 +18,7 @@
*/
package org.elasticsearch.common.inject;
import org.elasticsearch.common.inject.spi.Element;
import org.elasticsearch.common.inject.spi.Elements;
import org.elasticsearch.common.inject.spi.InstanceBinding;
import org.elasticsearch.common.inject.spi.LinkedKeyBinding;
import org.elasticsearch.common.inject.spi.ProviderInstanceBinding;
import org.elasticsearch.common.inject.spi.ProviderLookup;
import org.elasticsearch.common.inject.spi.*;
import org.elasticsearch.test.ESTestCase;
import java.lang.annotation.Annotation;
@ -45,11 +40,17 @@ public abstract class ModuleTestCase extends ESTestCase {
List<Element> elements = Elements.getElements(module);
for (Element element : elements) {
if (element instanceof LinkedKeyBinding) {
LinkedKeyBinding binding = (LinkedKeyBinding)element;
LinkedKeyBinding binding = (LinkedKeyBinding) element;
if (to.equals(binding.getKey().getTypeLiteral().getType())) {
assertSame(clazz, binding.getLinkedKey().getTypeLiteral().getType());
return;
}
} else if (element instanceof UntargettedBinding) {
UntargettedBinding binding = (UntargettedBinding) element;
if (to.equals(binding.getKey().getTypeLiteral().getType())) {
assertSame(clazz, to);
return;
}
}
}
StringBuilder s = new StringBuilder();
@ -88,12 +89,12 @@ public abstract class ModuleTestCase extends ESTestCase {
boolean providerFound = false;
for (Element element : elements) {
if (element instanceof LinkedKeyBinding) {
LinkedKeyBinding binding = (LinkedKeyBinding)element;
LinkedKeyBinding binding = (LinkedKeyBinding) element;
if (to.equals(binding.getKey().getTypeLiteral().getType())) {
bindings.add(binding.getLinkedKey().getTypeLiteral().getType());
}
} else if (element instanceof ProviderInstanceBinding) {
ProviderInstanceBinding binding = (ProviderInstanceBinding)element;
ProviderInstanceBinding binding = (ProviderInstanceBinding) element;
String setType = binding.getKey().getTypeLiteral().getType().toString();
if (setType.equals("java.util.Map<java.lang.String, " + to.getName() + ">")) {
providerFound = true;
@ -108,7 +109,6 @@ public abstract class ModuleTestCase extends ESTestCase {
}
/**
* Configures the module and checks a Set of the "to" class
* is bound to "classes". There may be more classes bound
@ -120,12 +120,12 @@ public abstract class ModuleTestCase extends ESTestCase {
boolean providerFound = false;
for (Element element : elements) {
if (element instanceof LinkedKeyBinding) {
LinkedKeyBinding binding = (LinkedKeyBinding)element;
LinkedKeyBinding binding = (LinkedKeyBinding) element;
if (to.equals(binding.getKey().getTypeLiteral().getType())) {
bindings.add(binding.getLinkedKey().getTypeLiteral().getType());
}
} else if (element instanceof ProviderInstanceBinding) {
ProviderInstanceBinding binding = (ProviderInstanceBinding)element;
ProviderInstanceBinding binding = (ProviderInstanceBinding) element;
String setType = binding.getKey().getTypeLiteral().getType().toString();
if (setType.equals("java.util.Set<" + to.getName() + ">")) {
providerFound = true;
@ -178,23 +178,23 @@ public abstract class ModuleTestCase extends ESTestCase {
* and that all of the "expected" values are bound.
*/
@SuppressWarnings("unchecked")
public <K,V> void assertMapInstanceBinding(Module module, Class<K> keyType, Class<V> valueType, Map<K,V> expected) throws Exception {
public <K, V> void assertMapInstanceBinding(Module module, Class<K> keyType, Class<V> valueType, Map<K, V> expected) throws Exception {
// this method is insane because java type erasure makes it incredibly difficult...
Map<K,Key> keys = new HashMap<>();
Map<Key,V> values = new HashMap<>();
Map<K, Key> keys = new HashMap<>();
Map<Key, V> values = new HashMap<>();
List<Element> elements = Elements.getElements(module);
for (Element element : elements) {
if (element instanceof InstanceBinding) {
InstanceBinding binding = (InstanceBinding) element;
if (binding.getKey().getRawType().equals(valueType)) {
values.put(binding.getKey(), (V)binding.getInstance());
values.put(binding.getKey(), (V) binding.getInstance());
} else if (binding.getInstance() instanceof Map.Entry) {
Map.Entry entry = (Map.Entry)binding.getInstance();
Map.Entry entry = (Map.Entry) binding.getInstance();
Object key = entry.getKey();
Object providerValue = entry.getValue();
if (key.getClass().equals(keyType) && providerValue instanceof ProviderLookup.ProviderImpl) {
ProviderLookup.ProviderImpl provider = (ProviderLookup.ProviderImpl)providerValue;
keys.put((K)key, provider.getKey());
ProviderLookup.ProviderImpl provider = (ProviderLookup.ProviderImpl) providerValue;
keys.put((K) key, provider.getKey());
}
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.gateway;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.ModuleTestCase;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.NodeEnvironment;
public class GatewayModuleTests extends ModuleTestCase {
public void testCustomGateway() {
GatewayModule gatewayModule = new GatewayModule(Settings.builder().put(GatewayModule.GATEWAY_TYPE_KEY, "mock").build());
gatewayModule.registerGatewayType("mock", MockGateway.class);
assertBinding(gatewayModule, Gateway.class, MockGateway.class);
}
public void testDefaultGateway() {
GatewayModule gatewayModule = new GatewayModule(Settings.EMPTY);
assertBinding(gatewayModule, Gateway.class, Gateway.class);
}
public static class MockGateway extends Gateway {
@Inject
public MockGateway(Settings settings, ClusterService clusterService, NodeEnvironment nodeEnv, GatewayMetaState metaState, TransportNodesListGatewayMetaState listGatewayMetaState, ClusterName clusterName) {
super(settings, clusterService, nodeEnv, metaState, listGatewayMetaState, clusterName);
}
}
}