Skip to content

Commit

Permalink
Add alternate name for Plugin (#4968)
Browse files Browse the repository at this point in the history
Add alternate name for Plugin

Signed-off-by: Dinu John <[email protected]>
  • Loading branch information
dinujoh committed Sep 21, 2024
1 parent 915c7b1 commit 8abf1d5
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
public @interface DataPrepperPlugin {
String DEFAULT_DEPRECATED_NAME = "";

String DEFAULT_ALTERNATE_NAME = "";

/**
*
* @return Name of the plugin which should be unique for the type
Expand All @@ -46,6 +48,12 @@
*/
String deprecatedName() default DEFAULT_DEPRECATED_NAME;

/**
*
* @return Alternate name of the plugin which should be unique for the type
*/
String[] alternateNames() default {};

/**
* The class type for this plugin.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static org.opensearch.dataprepper.model.annotations.DataPrepperPlugin.DEFAULT_ALTERNATE_NAME;
import static org.opensearch.dataprepper.model.annotations.DataPrepperPlugin.DEFAULT_DEPRECATED_NAME;

/**
Expand Down Expand Up @@ -69,30 +72,34 @@ private Map<String, Map<Class<?>, Class<?>>> scanForPlugins() {

final Map<String, Map<Class<?>, Class<?>>> pluginsMap = new HashMap<>(dataPrepperPluginClasses.size());
for (final Class<?> concretePluginClass : dataPrepperPluginClasses) {
final DataPrepperPlugin dataPrepperPluginAnnotation = concretePluginClass.getAnnotation(DataPrepperPlugin.class);
final String pluginName = dataPrepperPluginAnnotation.name();
final Class<?> supportedType = dataPrepperPluginAnnotation.pluginType();

final Map<Class<?>, Class<?>> supportTypeToPluginTypeMap =
pluginsMap.computeIfAbsent(pluginName, k -> new HashMap<>());
supportTypeToPluginTypeMap.put(supportedType, concretePluginClass);

addOptionalDeprecatedPluginName(pluginsMap, concretePluginClass);
// plugin name
addPossiblePluginName(pluginsMap, concretePluginClass, DataPrepperPlugin::name, name -> true);
// deprecated plugin name
addPossiblePluginName(pluginsMap, concretePluginClass, DataPrepperPlugin::deprecatedName,
deprecatedPluginName -> !deprecatedPluginName.equals(DEFAULT_DEPRECATED_NAME));
// alternate plugin names
for (final String alternateName: concretePluginClass.getAnnotation(DataPrepperPlugin.class).alternateNames()) {
addPossiblePluginName(pluginsMap, concretePluginClass, DataPrepperPlugin -> alternateName,
alternatePluginName -> !alternatePluginName.equals(DEFAULT_ALTERNATE_NAME));
}
}

return pluginsMap;
}

private void addOptionalDeprecatedPluginName(
private void addPossiblePluginName(
final Map<String, Map<Class<?>, Class<?>>> pluginsMap,
final Class<?> concretePluginClass) {
final Class<?> concretePluginClass,
final Function<DataPrepperPlugin, String> possiblePluginNameFunction,
final Predicate<String> possiblePluginNamePredicate
) {
final DataPrepperPlugin dataPrepperPluginAnnotation = concretePluginClass.getAnnotation(DataPrepperPlugin.class);
final String deprecatedPluginName = dataPrepperPluginAnnotation.deprecatedName();
final String possiblePluginName = possiblePluginNameFunction.apply(dataPrepperPluginAnnotation);
final Class<?> supportedType = dataPrepperPluginAnnotation.pluginType();

if (!deprecatedPluginName.equals(DEFAULT_DEPRECATED_NAME)) {
if (possiblePluginNamePredicate.test(possiblePluginName)) {
final Map<Class<?>, Class<?>> supportTypeToPluginTypeMap =
pluginsMap.computeIfAbsent(deprecatedPluginName, k -> new HashMap<>());
pluginsMap.computeIfAbsent(possiblePluginName, k -> new HashMap<>());
supportTypeToPluginTypeMap.put(supportedType, concretePluginClass);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.opensearch.dataprepper.model.annotations.DataPrepperPlugin;
import org.opensearch.dataprepper.model.sink.Sink;
import org.opensearch.dataprepper.model.source.Source;
Expand Down Expand Up @@ -105,6 +107,29 @@ void findPlugin_should_return_plugin_if_found_for_deprecated_name_and_type_using
assertThat(optionalPlugin.get(), equalTo(TestSource.class));
}

@Test
void findPlugin_should_return_empty_for_default_alternate_name() {
given(reflections.getTypesAnnotatedWith(DataPrepperPlugin.class))
.willReturn(new HashSet<>(List.of(TestSource.class)));

final Optional<Class<? extends Source>> optionalPlugin = createObjectUnderTest()
.findPluginClass(Source.class, UUID.randomUUID().toString());
assertThat(optionalPlugin, notNullValue());
assertThat(optionalPlugin.isPresent(), equalTo(false));
}

@ParameterizedTest
@ValueSource(strings = {"test_source_alternate_name1", "test_source_alternate_name2"})
void findPlugin_should_return_plugin_if_found_for_alternate_name_and_type_using_pluginType(final String alternateSourceName) {
given(reflections.getTypesAnnotatedWith(DataPrepperPlugin.class))
.willReturn(new HashSet<>(List.of(TestSource.class)));

final Optional<Class<? extends Source>> optionalPlugin = createObjectUnderTest().findPluginClass(Source.class, alternateSourceName);
assertThat(optionalPlugin, notNullValue());
assertThat(optionalPlugin.isPresent(), equalTo(true));
assertThat(optionalPlugin.get(), equalTo(TestSource.class));
}

@Nested
class WithPredefinedPlugins {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,4 +401,33 @@ void loadPlugin_should_create_a_new_instance_of_the_first_plugin_found_with_corr
verify(beanFactoryProvider).get();
}
}

@Nested
class WithAlternatePluginName {
private static final String TEST_SINK_ALTERNATE_NAME = "test_sink_alternate_name";
private Class expectedPluginClass;

@BeforeEach
void setUp() {
expectedPluginClass = TestSink.class;
given(pluginSetting.getName()).willReturn(TEST_SINK_ALTERNATE_NAME);

given(firstPluginProvider.findPluginClass(baseClass, TEST_SINK_ALTERNATE_NAME))
.willReturn(Optional.of(expectedPluginClass));
}

@Test
void loadPlugin_should_create_a_new_instance_of_the_first_plugin_found_with_correct_name_and_alternate_name() {
final TestSink expectedInstance = mock(TestSink.class);
final Object convertedConfiguration = mock(Object.class);
given(pluginConfigurationConverter.convert(PluginSetting.class, pluginSetting))
.willReturn(convertedConfiguration);
given(pluginCreator.newPluginInstance(eq(expectedPluginClass), any(ComponentPluginArgumentsContext.class), eq(TEST_SINK_ALTERNATE_NAME)))
.willReturn(expectedInstance);

assertThat(createObjectUnderTest().loadPlugin(baseClass, pluginSetting), equalTo(expectedInstance));
MatcherAssert.assertThat(expectedInstance.getClass().getAnnotation(DataPrepperPlugin.class).alternateNames(), equalTo(new String[]{TEST_SINK_ALTERNATE_NAME}));
verify(beanFactoryProvider).get();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.stream.Collectors;
import java.time.Instant;

@DataPrepperPlugin(name = "test_sink", deprecatedName = "test_sink_deprecated_name", pluginType = Sink.class)
@DataPrepperPlugin(name = "test_sink", alternateNames = "test_sink_alternate_name", deprecatedName = "test_sink_deprecated_name", pluginType = Sink.class)
public class TestSink implements Sink<Record<String>> {
public boolean isShutdown = false;
private final List<Record<String>> collectedRecords;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

@DataPrepperPlugin(name = "test_source", deprecatedName = "test_source_deprecated_name", pluginType = Source.class)
@DataPrepperPlugin(name = "test_source", alternateNames = { "test_source_alternate_name1", "test_source_alternate_name2" }, deprecatedName = "test_source_deprecated_name", pluginType = Source.class)
public class TestSource implements Source<Record<String>> {
public static final List<Record<String>> TEST_DATA = Stream.of("TEST")
.map(Record::new).collect(Collectors.toList());
Expand Down

0 comments on commit 8abf1d5

Please sign in to comment.