From f46ca9bebcae8077bcb563fd62995d9a907640d4 Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Fri, 12 Jul 2024 17:11:41 -0500 Subject: [PATCH] wip --- gradle/verification-metadata.xml | 5 + .../elasticsearch/action/ActionModule.java | 4 + .../elasticsearch/action/IndicesRequest.java | 2 + .../qa/consistency-checks/build.gradle | 60 ++- .../security/CrossClusterShardTests.java | 412 +++++++++++++++--- 5 files changed, 389 insertions(+), 94 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5e26d96c4ca17..3e45f715395cd 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3607,6 +3607,11 @@ + + + + + diff --git a/server/src/main/java/org/elasticsearch/action/ActionModule.java b/server/src/main/java/org/elasticsearch/action/ActionModule.java index b550755ce7bdd..1f2a52835b503 100644 --- a/server/src/main/java/org/elasticsearch/action/ActionModule.java +++ b/server/src/main/java/org/elasticsearch/action/ActionModule.java @@ -445,6 +445,7 @@ public class ActionModule extends AbstractModule { private final SettingsFilter settingsFilter; private final List actionPlugins; private final Map> actions; + private static Map> debugActions; //testonly private final ActionFilters actionFilters; private final AutoCreateIndex autoCreateIndex; private final DestructiveOperations destructiveOperations; @@ -485,6 +486,9 @@ public ActionModule( this.actionPlugins = actionPlugins; this.threadPool = threadPool; actions = setupActions(actionPlugins); + // if("true".equalsIgnoreCase(System.getProperty("testonly"))) { + debugActions = actions; + // } actionFilters = setupActionFilters(actionPlugins); autoCreateIndex = new AutoCreateIndex(settings, clusterSettings, indexNameExpressionResolver, systemIndices); destructiveOperations = new DestructiveOperations(settings, clusterSettings); diff --git a/server/src/main/java/org/elasticsearch/action/IndicesRequest.java b/server/src/main/java/org/elasticsearch/action/IndicesRequest.java index 20913148fd9b3..687384cae128e 100644 --- a/server/src/main/java/org/elasticsearch/action/IndicesRequest.java +++ b/server/src/main/java/org/elasticsearch/action/IndicesRequest.java @@ -90,4 +90,6 @@ interface RemoteClusterShardRequest extends IndicesRequest { */ Collection shards(); } + + } diff --git a/x-pack/plugin/security/qa/consistency-checks/build.gradle b/x-pack/plugin/security/qa/consistency-checks/build.gradle index 6fa3deb773e4c..fc5f919e23c19 100644 --- a/x-pack/plugin/security/qa/consistency-checks/build.gradle +++ b/x-pack/plugin/security/qa/consistency-checks/build.gradle @@ -1,27 +1,43 @@ apply plugin: 'elasticsearch.standalone-test' -dependencies { +//since we are placing everything on the classpath for this test we need to force versions to converge or simply ignore them +configurations.all { + resolutionStrategy { + force "org.slf4j:slf4j-api:2.0.10" + force "commons-codec:commons-codec:1.16.1" + force "org.slf4j:slf4j-nop:2.0.10" + force "org.apache.commons:commons-lang3:3.14.0" + force "com.fasterxml.jackson.core:jackson-databind:2.15.0" + force "com.fasterxml.jackson.core:jackson-core:2.15.4" + force "com.fasterxml.jackson.core:jackson-annotations:2.15.4" + force "joda-time:joda-time:2.10.14" + force "org.ow2.asm:asm:8.0.1" + force "com.sun.mail:jakarta.mail:1.6.4" + + exclude group: 'commons-logging', module: 'commons-logging' + exclude group: 'jakarta.xml.bind', module: 'jakarta.xml.bind-api' + exclude group: 'jakarta.activation', module: 'jakarta.activation-api' + } +} + +dependencies { + testImplementation "org.reflections:reflections:0.10.2" + testImplementation "org.javassist:javassist:3.30.2-GA" testImplementation(testArtifact(project(xpackModule('core')))) - testImplementation project(path: ':modules:ingest-common') - testImplementation project(path: ':modules:data-streams') - testImplementation project(path: ':modules:lang-mustache') - testImplementation project(path: ':modules:rank-eval') - testImplementation project(path: ':modules:reindex') - testImplementation project(path: xpackModule('analytics')) - testImplementation project(path: xpackModule('async-search')) - testImplementation project(path: xpackModule('autoscaling')) - testImplementation project(path: xpackModule('ccr')) - testImplementation project(path: xpackModule('downsample')) - testImplementation project(path: xpackModule('eql')) - testImplementation project(path: xpackModule('esql')) - testImplementation project(path: xpackModule('esql-core')) - testImplementation project(path: xpackModule('frozen-indices')) - testImplementation project(path: xpackModule('graph')) - testImplementation project(path: xpackModule('ilm')) - testImplementation project(path: xpackModule('inference')) - testImplementation project(path: xpackModule('profiling')) - testImplementation project(path: xpackModule('rollup')) - testImplementation project(path: xpackModule('slm')) - testImplementation project(path: xpackModule('sql')) + + project.rootProject.subprojects.findAll { it.parent.path == ':modules' }.each { Project module -> + testImplementation module + } + + Project xpack = project(':x-pack:plugin') + xpack.subprojects.findAll { it.parent == xpack }.each { Project xpackModule -> + testImplementation xpackModule + } + +} + +tasks.named("test").configure { + systemProperty 'tests.security.manager', 'false' + //TODO: add system property for registry debug } diff --git a/x-pack/plugin/security/qa/consistency-checks/src/test/java/org/elasticsearch/xpack/security/CrossClusterShardTests.java b/x-pack/plugin/security/qa/consistency-checks/src/test/java/org/elasticsearch/xpack/security/CrossClusterShardTests.java index d9e870b031877..72f85134d331d 100644 --- a/x-pack/plugin/security/qa/consistency-checks/src/test/java/org/elasticsearch/xpack/security/CrossClusterShardTests.java +++ b/x-pack/plugin/security/qa/consistency-checks/src/test/java/org/elasticsearch/xpack/security/CrossClusterShardTests.java @@ -7,18 +7,25 @@ package org.elasticsearch.xpack.security; +import org.elasticsearch.action.ActionModule; +import org.elasticsearch.action.ActionType; +import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.RemoteClusterActionType; import org.elasticsearch.action.admin.cluster.shards.TransportClusterSearchShardsAction; import org.elasticsearch.action.search.TransportSearchShardsAction; import org.elasticsearch.action.support.TransportAction; import org.elasticsearch.action.support.single.shard.TransportSingleShardAction; -import org.elasticsearch.common.inject.Binding; import org.elasticsearch.common.inject.TypeLiteral; import org.elasticsearch.datastreams.DataStreamsPlugin; import org.elasticsearch.index.rankeval.RankEvalPlugin; import org.elasticsearch.ingest.IngestTestPlugin; import org.elasticsearch.ingest.common.IngestCommonPlugin; import org.elasticsearch.node.Node; +import org.elasticsearch.painless.PainlessPlugin; +import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.SystemIndexPlugin; +import org.elasticsearch.plugins.interceptor.RestServerActionPlugin; import org.elasticsearch.reindex.ReindexPlugin; import org.elasticsearch.script.mustache.MustachePlugin; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -26,6 +33,8 @@ import org.elasticsearch.xpack.autoscaling.Autoscaling; import org.elasticsearch.xpack.ccr.Ccr; import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; +import org.elasticsearch.xpack.core.XPackClientPlugin; +import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.security.action.apikey.CrossClusterApiKeyRoleDescriptorBuilder; import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege; import org.elasticsearch.xpack.downsample.Downsample; @@ -41,14 +50,21 @@ import org.elasticsearch.xpack.search.AsyncSearch; import org.elasticsearch.xpack.slm.SnapshotLifecycle; import org.elasticsearch.xpack.sql.plugin.SqlPlugin; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ConfigurationBuilder; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; +import java.lang.reflect.Constructor; import java.util.HashSet; import java.util.List; -import java.util.Locale; +import java.util.Map; import java.util.Set; -import java.util.function.Predicate; +import java.util.stream.Collectors; public class CrossClusterShardTests extends ESSingleNodeTestCase { @@ -69,97 +85,349 @@ public class CrossClusterShardTests extends ESSingleNodeTestCase { TransportSingleShardAction.class ); + private static final Set> ignoredPlugins = Set.of( +// RestServerActionPlugin.class, + PainlessPlugin.class //has extendtino that causes issues, +// XPackPlugin.class, //using xpacklocal plugin instead +// XPackClientPlugin.class + ); + @Override + @SuppressWarnings("unchecked") protected Collection> getPlugins() { final ArrayList> plugins = new ArrayList<>(super.getPlugins()); - plugins.addAll( - List.of( - LocalStateCompositeXPackPlugin.class, - AnalyticsPlugin.class, - AsyncSearch.class, - Autoscaling.class, - Ccr.class, - DataStreamsPlugin.class, - Downsample.class, - EqlPlugin.class, - EsqlPlugin.class, - FrozenIndices.class, - Graph.class, - IndexLifecycle.class, - InferencePlugin.class, - IngestCommonPlugin.class, - IngestTestPlugin.class, - MustachePlugin.class, - ProfilingPlugin.class, - RankEvalPlugin.class, - ReindexPlugin.class, - Rollup.class, - SnapshotLifecycle.class, - SqlPlugin.class - ) + + Reflections reflections = new Reflections( + new ConfigurationBuilder().forPackages("org.elasticsearch").addScanners(Scanners.SubTypes) ); + + + Set> actionPlugins = reflections.getSubTypesOf(ActionPlugin.class); + //actionPlugins.stream().filter(plugin -> ignoredPlugins.contains(RestServerActionPlugin.class) == false).forEach(plugin -> { + actionPlugins.stream().forEach(plugin -> { + + if(ignoredPlugins.contains(plugin)){ + System.out.println("** ignoring: " + plugin); + }else { + + boolean hasDefaultConstructor = false; + Constructor[] constructors = plugin.getDeclaredConstructors(); + for (Constructor constructor : constructors) { + if (constructor.getParameterCount() == 0) { + hasDefaultConstructor =true; + } + } + + if(hasDefaultConstructor) { + + if(plugin.getCanonicalName().contains("xpack")){ + System.out.println("** ignoring (handled by xpack local): " + plugin); + }else { + + System.out.println("** adding: " + plugin); + plugins.add((Class) plugin); + } + } else { + System.out.println("** ignoring (no default constructor): " + plugin); + } + } + + }); + + plugins.add(LocalStateCompositeXPackPlugin.class); + + + // plugins.addAll(actionPlugins); +// List.of( +// LocalStateCompositeXPackPlugin.class, +// AnalyticsPlugin.class, +// AsyncSearch.class, +// Autoscaling.class, +// Ccr.class, +// DataStreamsPlugin.class, +// Downsample.class, +// EqlPlugin.class, +// EsqlPlugin.class, +// FrozenIndices.class, +// Graph.class, +// IndexLifecycle.class, +// InferencePlugin.class, +// IngestCommonPlugin.class, +// IngestTestPlugin.class, +// MustachePlugin.class, +// ProfilingPlugin.class, +// RankEvalPlugin.class, +// ReindexPlugin.class, +// Rollup.class, +// SnapshotLifecycle.class, +// SqlPlugin.class +// ) + // ); return plugins; } - @SuppressWarnings("rawtypes") + + + + + @SuppressWarnings({"unchecked", "rawtypes"}) public void testCheckForNewShardLevelTransportActions() throws Exception { Node node = node(); - List> transportActionBindings = node.injector().findBindingsByType(TypeLiteral.get(TransportAction.class)); + Reflections reflections = new Reflections( + new ConfigurationBuilder().forPackages("org.elasticsearch").addScanners(Scanners.SubTypes) + ); + + // Find all subclasses of IndicesRequest + Set> indicesRequest = reflections.getSubTypesOf(IndicesRequest.class); + + //Find all transport actions instances from Guice (depends on the set of plugins this test is configured to use) + List allTransportActions = node.injector() + .findBindingsByType(TypeLiteral.get(TransportAction.class)).stream() + .map(binding -> binding.getProvider().get()) + .toList(); + + + for (TransportAction transportAction : allTransportActions) { + System.out.println("transportAction: " + transportAction.getClass()); + } + + + // Find the ActionType -> TransportAction mapping, both share the same action name + Field field = ActionModule.class.getDeclaredField("debugActions"); + field.setAccessible(true); + Map> actionRegistry = (Map>) field.get(null); + + // Find the TransportActions that can go across clusters based on the ActionType having a RemoteClusterActionType + Set crossClusterActions = new HashSet<>(); + for (TransportAction transportAction : allTransportActions) { + //read the parameters from the transport action superclass + ActionType actionType = actionRegistry.get(transportAction.actionName).getAction(); + crossClusterActions.add(actionType); + if(hasMemberWithType(actionType.getClass(), RemoteClusterActionType.class)){ + } + } + + + + for (ActionType actionType : crossClusterActions) { + System.out.println("actionType: " + actionType.getClass()); + } + // allowedRemoteClusterRequestTypes.add(getRequestTypeName(transportAction.getClass().getGenericSuperclass())); + + // Find the permissions allowed for RCS 2.0 Set crossClusterPrivilegeNames = new HashSet<>(); crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCS_INDICES_PRIVILEGE_NAMES)); crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCR_INDICES_PRIVILEGE_NAMES)); - List shardActions = transportActionBindings.stream() + // Find the allowed cluster action names based on the permissions for RCS 2.0 + Set allowedRemoteClusterActionNames = actionRegistry.keySet().stream() + .filter(actionName -> IndexPrivilege.get(crossClusterPrivilegeNames).predicate().test(actionName)).collect(Collectors.toSet()); + + + + + // Get a reference to all the TransportAction instances that are allowed by RCS 2.0 + List allowedRemoteClusterActions = node.injector() + .findBindingsByType(TypeLiteral.get(TransportAction.class)).stream() .map(binding -> binding.getProvider().get()) - .filter(action -> IndexPrivilege.get(crossClusterPrivilegeNames).predicate().test(action.actionName)) - .filter(this::actionIsLikelyShardAction) - .map(action -> action.actionName) + .filter(action -> allowedRemoteClusterActionNames.contains(action.actionName)) .toList(); - List actionsNotOnAllowlist = shardActions.stream().filter(Predicate.not(MANUALLY_CHECKED_SHARD_ACTIONS::contains)).toList(); - if (actionsNotOnAllowlist.isEmpty() == false) { - fail(""" - If this test fails, you likely just added a transport action, probably with `shard` in the name. Transport actions which - operate on shards directly and can be used across clusters must meet some additional requirements in order to be - handled correctly by all Elasticsearch infrastructure, so please make sure you have read the javadoc on the - IndicesRequest.RemoteClusterShardRequest interface and implemented it if appropriate and not already appropriately - implemented by a supertype, then add the name (as in "indices:data/read/get") of your new transport action to - MANUALLY_CHECKED_SHARD_ACTIONS above. Found actions not in allowlist: - """ + actionsNotOnAllowlist); + + // reverse the actionRegistry map to key by ActionHandler + + + + //Ignore any indices requests that are already marked with the RemoteClusterShardRequest interface + indicesRequest.removeAll(reflections.getSubTypesOf(IndicesRequest.RemoteClusterShardRequest.class)); + + + + //Type erasure makes the relationship between the transport action and the request type difficult to determine + + // List> +// List allTransportActionNames = transportActionBindings.stream() +// .map(binding -> binding.getProvider().get()) +// .map(action -> action.actionName) +// .toList(); + + + +// List> transportActionBindings = node.injector().findBindingsByType(TypeLiteral.get(TransportAction.class)); +// Set crossClusterPrivilegeNames = new HashSet<>(); +// crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCS_INDICES_PRIVILEGE_NAMES)); +// crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCR_INDICES_PRIVILEGE_NAMES)); +// List allTransportActionNames = transportActionBindings.stream() +// .map(binding -> binding.getProvider().get()) +// .map(action -> action.actionName) +// .toList(); +// + + +// // Find subclasses of RemoteClusterActionType +// Set> remoteClusterActionType = reflections.getSubTypesOf(RemoteClusterActionType.class); +// for (Class clazz : remoteClusterActionType) { +// System.out.println("**************** " + clazz.getName()); +// } + + + + +// for (Class clazz : candidatesToAddMarkerInterface) { +// +// System.out.println("**************** " + clazz.getName()); +// +// +// } + + + + + +// // Filter down that are likely to be missing the RemoteClusterShardRequest interface +// Class remoteClusterShardRequestClass = IndicesRequest.RemoteClusterShardRequest.class; +// Class indicesRequest = IndicesRequest.class; +// Set< Class> indicesRequestsWithoutShardInterface = new HashSet<>(); +// +// +// for (Class subclassWithShard : subclassesWithShards) { +// if (indicesRequest.isAssignableFrom(subclassWithShard)) { +// if (remoteClusterShardRequestClass.isAssignableFrom(subclassWithShard) == false) { +// // indices request does not have shard level interface - candidates to add the interface +// System.out.println(subclassWithShard.getCanonicalName() + ": does not have shard level interface"); +// indicesRequestsWithoutShardInterface.add(subclassWithShard); +// } +// } +// } +// +// // Find all subclasses of TransportRequest +// Class transportRequestClass = TransportRequest.class; +// Reflections reflections = new Reflections( +// new ConfigurationBuilder().forPackages("org.elasticsearch").addScanners(Scanners.SubTypes) +// ); +// Set> subclasses = reflections.getSubTypesOf(transportRequestClass); +// +// +// +// +// +// // Get a reference to all transport actions (on classpath) +// List> transportActionBindings = node.injector().findBindingsByType(TypeLiteral.get(TransportAction.class)); +// Set crossClusterPrivilegeNames = new HashSet<>(); +// crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCS_INDICES_PRIVILEGE_NAMES)); +// crossClusterPrivilegeNames.addAll(List.of(CrossClusterApiKeyRoleDescriptorBuilder.CCR_INDICES_PRIVILEGE_NAMES)); +// List allTransportActionNames = transportActionBindings.stream() +// .map(binding -> binding.getProvider().get()) +// .map(action -> action.actionName) +// .toList(); +// +// // Find the transport actions names that can go cross cluters +// RemoteClusterActionType + + +// List shardActions = transportActionBindings.stream() +// .map(binding -> binding.getProvider().get()) +// .filter(action -> IndexPrivilege.get(crossClusterPrivilegeNames).predicate().test(action.actionName)) +// .filter(this::actionIsLikelyShardAction) +// .map(action -> action.actionName) +// .toList(); +// +// List actionsNotOnAllowlist = shardActions.stream().filter(Predicate.not(MANUALLY_CHECKED_SHARD_ACTIONS::contains)).toList(); +// if (actionsNotOnAllowlist.isEmpty() == false) { +// fail(""" +// If this test fails, you likely just added a transport action, probably with `shard` in the name. Transport actions which +// operate on shards directly and can be used across clusters must meet some additional requirements in order to be +// handled correctly by all Elasticsearch infrastructure, so please make sure you have read the javadoc on the +// IndicesRequest.RemoteClusterShardRequest interface and implemented it if appropriate and not already appropriately +// implemented by a supertype, then add the name (as in "indices:data/read/get") of your new transport action to +// MANUALLY_CHECKED_SHARD_ACTIONS above. Found actions not in allowlist: +// """ + actionsNotOnAllowlist); +// } +// +// // Also make sure the allowlist stays up to date and doesn't have any unnecessary entries. +// List actionsOnAllowlistNotFound = MANUALLY_CHECKED_SHARD_ACTIONS.stream() +// .filter(Predicate.not(shardActions::contains)) +// .toList(); +// if (actionsOnAllowlistNotFound.isEmpty() == false) { +// fail( +// "Some actions were on the allowlist but not found in the list of cross-cluster capable transport actions, please remove " +// + "these from MANUALLY_CHECKED_SHARD_ACTIONS if they have been removed from Elasticsearch: " +// + actionsOnAllowlistNotFound +// ); +// } + + + + // // Find any IndicesRequest that have methods related to shards, these are the candidate requests for the marker interface +// Set> candidatesToAddMarkerInterface = new HashSet<>(); +// Set methodNames = Set.of("shard", "shards", "getShard", "getShards", "shardId", "shardIds", "getShardId", "getShardIds"); +// for (Class clazz : indicesRequest) { +// for (Method method : clazz.getDeclaredMethods()) { +// for (String methodName : methodNames) { +// if (method.getName().equals(methodName)) { +// candidatesToAddMarkerInterface.add((Class) method.getDeclaringClass()); +// } +// } +// } +// } + + + } +// +// /** +// * Getting to the actual request classes themselves is made difficult by the design of Elasticsearch's transport +// * protocol infrastructure combined with JVM type erasure. Therefore, we resort to a crude heuristic here. +// * @param transportAction The transportport action to be checked. +// * @return True if the action is suspected of being an action which may operate on shards directly. +// */ +// private boolean actionIsLikelyShardAction(TransportAction transportAction) { +// Class clazz = transportAction.getClass(); +// Set> classHeirarchy = new HashSet<>(); +// while (clazz != TransportAction.class) { +// classHeirarchy.add(clazz); +// clazz = clazz.getSuperclass(); +// } +// boolean hasCheckedSuperclass = classHeirarchy.stream().anyMatch(clz -> CHECKED_ABSTRACT_CLASSES.contains(clz)); +// boolean shardInClassName = classHeirarchy.stream().anyMatch(clz -> clz.getName().toLowerCase(Locale.ROOT).contains("shard")); +// return hasCheckedSuperclass == false +// && (shardInClassName +// || transportAction.actionName.toLowerCase(Locale.ROOT).contains("shard") +// || transportAction.actionName.toLowerCase(Locale.ROOT).contains("[s]")); +// } + + private static String getRequestTypeName(Type type) { + if (type instanceof ParameterizedType parameterizedType) { + Type[] typeArguments = parameterizedType.getActualTypeArguments(); + return getRequestTypeName(typeArguments[0]); + } else if (type instanceof Class) { + return ((Class) type).getName(); } + throw new RuntimeException("Unknown type: " + type); + } - // Also make sure the allowlist stays up to date and doesn't have any unnecessary entries. - List actionsOnAllowlistNotFound = MANUALLY_CHECKED_SHARD_ACTIONS.stream() - .filter(Predicate.not(shardActions::contains)) - .toList(); - if (actionsOnAllowlistNotFound.isEmpty() == false) { - fail( - "Some actions were on the allowlist but not found in the list of cross-cluster capable transport actions, please remove " - + "these from MANUALLY_CHECKED_SHARD_ACTIONS if they have been removed from Elasticsearch: " - + actionsOnAllowlistNotFound - ); + private static boolean hasMemberWithType(Class clazz, Class targetType) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (isTypeMatching(field.getGenericType(), targetType)) { + return true; + } + } + // Check superclass recursively + Class superclass = clazz.getSuperclass(); + if (superclass != null && superclass != Object.class) { + hasMemberWithType(superclass, targetType); } + return false; } - /** - * Getting to the actual request classes themselves is made difficult by the design of Elasticsearch's transport - * protocol infrastructure combined with JVM type erasure. Therefore, we resort to a crude heuristic here. - * @param transportAction The transportport action to be checked. - * @return True if the action is suspected of being an action which may operate on shards directly. - */ - private boolean actionIsLikelyShardAction(TransportAction transportAction) { - Class clazz = transportAction.getClass(); - Set> classHeirarchy = new HashSet<>(); - while (clazz != TransportAction.class) { - classHeirarchy.add(clazz); - clazz = clazz.getSuperclass(); + private static boolean isTypeMatching(Type type, Class targetType) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + return parameterizedType.getRawType().equals(targetType); + } else if (type instanceof Class) { + return type.equals(targetType); } - boolean hasCheckedSuperclass = classHeirarchy.stream().anyMatch(clz -> CHECKED_ABSTRACT_CLASSES.contains(clz)); - boolean shardInClassName = classHeirarchy.stream().anyMatch(clz -> clz.getName().toLowerCase(Locale.ROOT).contains("shard")); - return hasCheckedSuperclass == false - && (shardInClassName - || transportAction.actionName.toLowerCase(Locale.ROOT).contains("shard") - || transportAction.actionName.toLowerCase(Locale.ROOT).contains("[s]")); + return false; } }