-
Notifications
You must be signed in to change notification settings - Fork 207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expanded plugin constructor capabilities #481
Expanded plugin constructor capabilities #481
Conversation
* This exists so that this class can still exhibit the correct behavior when creating new plugin | ||
* classes. This whole class is going to be deleted in the next major version, as will this method. | ||
*/ | ||
public static void dangerousMethod_setPluginFunction(final BiFunction<PluginSetting, Class<?>, Object> newPluginFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to call this method out. This class is in the common
package, but will be removed. Because the implementation for creating plugins is now in data-prepper-core, this class cannot use those classes. So, I created this as a way to allow this deprecated class to generate plugins the same way at that the new framework does.
As this class is going away, I felt fine with this quick hack. An alternative would be to remove all the old plugin code now rather than in v2.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with this as well because of the reasons you provided. Thanks!
private PluginArgumentsContext(final Builder builder) { | ||
typedArgumentsSuppliers = new HashMap<>(); | ||
|
||
Objects.requireNonNull(builder.pluginSetting); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's include an error message here.
private Object pluginConfiguration; | ||
private PluginSetting pluginSetting; | ||
|
||
Builder withPluginConfiguration(final Object pluginConfiguration) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a pluginConfiguration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the custom configuration supplied which is the type directed by this field: https://github.com/opensearch-project/data-prepper/blob/main/data-prepper-api/src/main/java/com/amazon/dataprepper/model/annotations/DataPrepperPlugin.java#L80
String.format("Data Prepper plugin requires a constructor which is either: " + | ||
"1. Annotated with @DataPrepperPlugin; " + | ||
"2. Contains a single argument of type %s; or " + | ||
"3. Has a default constructor. " + | ||
"Plugin %s with name %s is missing such constructor.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are putting the solution to an error before providing the context for the error. I would recommend putting "Plugin %s with name %s is missing such constructor."
first and then the solution.
I would also recommend the solution have a stronger call to action rather than stating the requirements. "Please ensure the plugin's constructor is either:"
|
||
class PluginCreator { | ||
private static final Logger LOG = LoggerFactory.getLogger(PluginCreator.class); | ||
|
||
<T> T newPluginInstance(final Class<T> pluginClass, | ||
final Object pluginConfiguration, | ||
final PluginArgumentsContext pluginConstructionContext, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you want to refer to this as a pluginConstructionContext
?
I would recommend just keeping it as pluginArgumentsContext
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through a few class names and it appears that IntelliJ didn't pick up renaming the parameter here. I'll fix this up to match.
*/ | ||
class PluginArgumentsContext { | ||
private final Map<Class<?>, Supplier<Object>> typedArgumentsSuppliers; | ||
private final Class<?> singleParameterObject; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be consistent on naming here and refer to this as an argument. singleArgument
|
||
if(builder.pluginConfiguration != null) { | ||
typedArgumentsSuppliers.put(builder.pluginConfiguration.getClass(), () -> builder.pluginConfiguration); | ||
singleParameterObject = builder.pluginConfiguration.getClass(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this singleParameterObject
ever be used when a builder.pluginConfiguration
is provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the singleParameterObject
is going to be the custom POJO type or the PluginSetting
.
return this; | ||
} | ||
|
||
Builder withPluginSetting(final PluginSetting pluginSetting) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is some nuance to how the parameters impact how the plugins are loaded. I really wish we had plugin documentation. I am worried we are going to build out the plugin documentation at the very end and miss some details. Is there any way we can start building out documentation of this framework now? It doesn't have to be perfect or finalized. Just a README in this package would be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I can add this next.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added the documentation and linked it from the Development guide. As plugin support is extended, I would like to reconsidering the linking, but I believe this is sufficient for now.
singleParameterObject = builder.pluginSetting.getClass(); | ||
} | ||
|
||
typedArgumentsSuppliers.put(PluginMetrics.class, () -> PluginMetrics.fromPluginSetting(builder.pluginSetting)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this only be added if the pluginMetrics value is non null?
Also, are we supporting an annotated constructor like pulbic SomePlugin(final PluginSettings pluginSettings, final PluginMetrics pluginMetrics) {...}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To answer your second question, yes, we are support that type of constructor. But, only if it is annotated with @DataPrepperConstructor
. The HTTPSource
shows something very similar to this.
I'm not quite sure what your first question is asking. At this point of the code we are only adding a Supplier
. So, no PluginMetric
is constructor unless the annotated constructor requests it.
final String error = | ||
String.format("Data Prepper plugin requires a constructor which is either: " + | ||
"1. Annotated with @DataPrepperPlugin; " + | ||
"2. Contains a single argument of type %s; or " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if there are two separate single argument constructors? What is the failure mode?
What is your vision for v2.0? Do you plan on supporting all of these scenarios in the future as well? Would it be possible to move to an explicit model which requires an annotated constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if there are two separate single argument constructors?
Because the @DataPrepperPlugin
allows configuring the pluginConfigurationType
, the single argument constructor will only match that type. So it should only ever be what is defined by pluginConfigurationType
.
What is your vision for v2.0? Do you plan on supporting all of these scenarios in the future as well? Would it be possible to move to an explicit model which requires an annotated constructor?
For 2.0, I'd like to remove the single argument constructor. Thus, the constructor must be either annotated with @DataPrepperConstructor
or be the default constructor.
We need to keep at least support for a single argument PluginSetting
in 1.x since that is the current behavior. I could change this so that the only implicit single argument constructor is PluginSetting
and disallow the POJO-based single-argument constructor. Would that help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to change this behavior so that the only single parameter constructor supported is PluginSetting
. Thus, plugins which use a POJO for the configuration must provide the @DataPrepperConstructor
annotation. I believe this should be simpler and is one fewer behavior to deprecate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a commit which, among other changes, now only permits a single-parameter constructor for PluginSetting
. To use the custom POJO configuration, plugin authors must add the @DataPrepperPluginConstructor
annotation.
* This exists so that this class can still exhibit the correct behavior when creating new plugin | ||
* classes. This whole class is going to be deleted in the next major version, as will this method. | ||
*/ | ||
public static void dangerousMethod_setPluginFunction(final BiFunction<PluginSetting, Class<?>, Object> newPluginFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with this as well because of the reasons you provided. Thanks!
...gins/http-source/src/main/java/com/amazon/dataprepper/plugins/source/loghttp/HTTPSource.java
Show resolved
Hide resolved
final String sslKeyFile, | ||
final String sslKeyPassword) { | ||
private int port = DEFAULT_PORT; | ||
@JsonProperty("request_timeout") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we use REQUEST_TIMEOUT constant here?
static final String REQUEST_TIMEOUT = "request_timeout"; | ||
static final String THREAD_COUNT = "thread_count"; | ||
static final String MAX_CONNECTION_COUNT = "max_connection_count"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can we remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string is no longer being used because the tests use a POJO. I pushed a change which added the string literal into the @JsonProperty
. For those properties which are being used elsewhere, I kept those as constants.
@JsonProperty("request_timeout") | ||
private int requestTimeoutInMillis = DEFAULT_REQUEST_TIMEOUT_MS; | ||
private int threadCount = DEFAULT_THREAD_COUNT; | ||
private int maxConnectionCount = DEFAULT_MAX_CONNECTION_COUNT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no jsonProperty annotation on top of this variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default conversion will support snake case, so this should serialize. But, I can add add it to be somewhat more thorough and consistent.
private int requestTimeoutInMillis = DEFAULT_REQUEST_TIMEOUT_MS; | ||
private int threadCount = DEFAULT_THREAD_COUNT; | ||
private int maxConnectionCount = DEFAULT_MAX_CONNECTION_COUNT; | ||
private int maxPendingRequests = DEFAULT_MAX_PENDING_REQUESTS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
…Constructor annotation. This is the preferred constructor. If no other constructor is available for a plugin, use the no-op constructor. Updated the HTTPSource plugin to use this capability to receive both a configuration model and PluginMetrics via the constructor. Signed-off-by: David Venable <[email protected]>
…g in a single parameter, un-annotated constructor. Cleaned up the HTTPSourceConfig. Other small changes. Signed-off-by: David Venable <[email protected]>
b53c5dc
to
d35b3b7
Compare
private String sslCertificateFile; | ||
|
||
@JsonProperty(SSL_KEY_FILE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a difference between upper case and lower case JsonProperties? I am wondering why ssl_key_password
and SSL_KEY_FILE
are different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSL_KEY_FILE
is a static final field whereas "ssl_key_password"
is a string literal. The former is used in some error strings so I kept it as constant. We could make them all constants if we wanted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I missed the quotes. For a second I thought the properties were defined in a different format. I'd prefer consistency but will defer to your preference here. I don't want to hold this up.
Signed-off-by: David Venable <[email protected]>
I also had left some commented out code in place. I just pushed a commit which cleaned that up. |
private String sslCertificateFile; | ||
|
||
@JsonProperty(SSL_KEY_FILE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I missed the quotes. For a second I thought the properties were defined in a different format. I'd prefer consistency but will defer to your preference here. I don't want to hold this up.
Support more constructors for plugins by adding the DataPrepperPluginConstructor annotation. This is the preferred constructor. If no other constructor is available for a plugin, use the no-op constructor. Updated the HTTPSource plugin to use this capability to receive both a configuration model and PluginMetrics via the constructor. For a single parameter, un-annotated constructor in plugins, the only supported parameter is once again PluginSetting. Signed-off-by: David Venable <[email protected]>
Description
@DataPrepperPluginConstructor
annotation@DataPrepperPluginConstructor
annotated-constructor. If not, then use the constructor which takes thePluginSetting
or configured model class. Finally, use the default constructor as the last option.PluginMetrics
object in the constructor.HTTPSource
to use a configuration model. It is provided into the constructor, and thePluginMetrics
is also now injected.Issues Resolved
This has some of the proposed functionality from #469.
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.