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
Adding ApiFilteringActionFilter #97985
Adding ApiFilteringActionFilter #97985
Conversation
Hi @masseyke, I've created a changelog YAML for you. |
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.
Looks pretty good, I have a couple suggestions.
|
||
public abstract Class<Res> getResponseClass(); | ||
|
||
public abstract CheckedFunction<Res, Res, Exception> getFilteringFunction(); |
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 reason we need the extra level of indirection? Couldn't this be protected abstract Res filterResponse(Res response) throws Exception
?
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.
Yeah I just did it this way because that's what I poorly refactored some code I'd written before.ActionListener::map
(which is consuming this) requires. But no reason to leak that detail here
|
||
private final ThreadContext threadContext; | ||
|
||
public ApiFilteringActionFilter(ThreadContext threadContext) { |
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: This could be protected
); | ||
} | ||
|
||
public abstract String getActionName(); |
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 could be passed in as a ctor arg instead of having a dynamic method?
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.
Yeah good point.
|
||
public abstract String getActionName(); | ||
|
||
public abstract Class<Res> getResponseClass(); |
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 the above, might be less boiler plate to pass this as a ctor arg
…nstructor, simplifying the filter method signature
…/elasticsearch into adding-ApiFilteringActionFilter
Pinging @elastic/es-core-infra (Team:Core/Infra) |
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.
LGTM
@SuppressWarnings("unchecked") | ||
private <Response extends ActionResponse> Response filter(Response response) throws Exception { | ||
if (response.getClass().equals(responseClass)) { | ||
return (Response) filterResponse((Res) response); |
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.
Are the casts necessary? Seems like the types match.
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 think that they are necessary. The problem is that ActionFilter doesn't have class-level generic types I could take advantage of -- they're just on the apply
method. I introduced generic types at the class level of ApiFilteringActionFilter so that I could use them throughout the class. They're the same as the ones for the apply
method, but the compiler doesn't know that. So I have to do the cast. I think the fix would be to add types at the class level for ActionFilter, but I wasn't sure what all that might break (since it can be used in 3rd-party plugins). Let me know if you're seeing something I'm not seeing though.
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.
Ah sorry, I see it is necessary for the argument to cast, but since Res is already a Response, no cast should be necessary?
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 compiler disagrees with you :)
> Task :x-pack:plugin:core:compileJava FAILED
/Users/kmassey/workspace/elasticsearch/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/api/filtering/ApiFilteringActionFilter.java:59: error: incompatible types: Res cannot be converted to Response
return filterResponse((Res) response);
^
where Res,Response are type-variables:
Res extends ActionResponse declared in class ApiFilteringActionFilter
Response extends ActionResponse declared in method <Response>filter(Response)
1 error
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.
Ok, I see, the names are quite confusing. :) Both Res and Response implement ActionFilter, but there is no association between the two. We can improve this in the future.
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 go ahead and merge this so that I can get some other PRs going, but let me know if I'm missing something and I'll fix this in a followup PR.
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.
LGTM
This adds an abstract ActionFilter meant to be extended in serverless modules that need to redact part of a response. When an implementing class is registered with a plugin, filterResponse() is applied if the transport action being called is the actionName passed to the constructor and the response's class is the responseClass passed to the constructor.
This PR adds an abstract ActionFilter meant to be extended in serverless modules that need to redact part of a response. When an implementing class is registered with a plugin, filterResponse() is applied if the transport action being called is the actionName passed to the constructor and the response's class is the responseClass passed to the constructor.