Skip to content
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

GEODE-3213: Refactor ProtoBuf handler flow #646

Closed
wants to merge 1 commit into from

Conversation

pivotal-amurmann
Copy link

Signed-off-by: Alexander Murmann amurmann@pivotal.io

Thank you for submitting a contribution to Apache Geode.

In order to streamline the review of the contribution we ask you
to ensure the following steps have been taken:

For all changes:

  • Is there a JIRA ticket associated with this PR? Is it referenced in the commit message?
    GEODE-3213

  • Has your PR been rebased against the latest commit within the target branch (typically develop)?

  • Is your initial contribution a single, squashed commit?

  • Does gradlew build run cleanly?

  • Have you written or updated unit tests to verify your changes?

  • If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under ASF 2.0?
    NA

Note:

Please ensure that once the PR is submitted, you check travis-ci for build issues and
submit an update to your PR as soon as possible. If you need help, please send an
email to dev@geode.apache.org.

@pivotal-amurmann
Copy link
Author

operationHandler.process(serializationServiceStub, generateTestRequest(), cacheStub);

Assert.assertEquals(ClientProtocol.Response.ResponseAPICase.ERRORRESPONSE,
response.getResponseAPICase());
Assert.assertTrue(result instanceof Failure);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to assert at the error message

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no. Is it worth asserting part of it?

operationHandler.process(serializationServiceStub, generateTestRequest(), cacheStub);

Assert.assertEquals(ClientProtocol.Response.ResponseAPICase.ERRORRESPONSE,
response.getResponseAPICase());
Assert.assertTrue(result instanceof Failure);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to assert at least the error message. Maybe later on the error code

operationHandler.process(serializationServiceStub, generateTestRequest(), cacheStub);

Assert.assertEquals(ClientProtocol.Response.ResponseAPICase.PUTRESPONSE,
response.getResponseAPICase());
Assert.assertNotNull(result);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should assert that we got back a Success Object rather than just result != null


import java.util.function.Function;

public class OperationContext<OperationReq, OperationResponse> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to maybe package restrict this class

ClientProtocol.ErrorResponse error =
ClientProtocol.ErrorResponse.newBuilder().setMessage(errorMessage).build();
return ClientProtocol.Response.newBuilder().setErrorResponse(error).build();
public static Failure createFailureResult(String errorMessage) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with this method description or its implementation. Either the method name should state createFailureResultWithErrorResponseForErrorMessage OR the signature becomes createFailureResult(ErrorResponse errorResponse).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pivotal-amurmann @kohlmu-pivotal Did this get addressed?

return ClientProtocol.Response.newBuilder().setGetResponse(getResponse).build();
public static Success<RegionAPI.GetResponse> createGetResult(
BasicTypes.EncodedValue resultValue) {
return new Success<>(RegionAPI.GetResponse.newBuilder().setResult(resultValue).build());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we replace these types of calls with inline Success.of(EncodedValue)

Copy link

@WireBaron WireBaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still reviewing, but here's some initial comments.


import java.util.function.Function;

public interface Result<SuccessType> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tightly bound to the ClientProtocol.ErrorResponse, can we give it a less generic name? Maybe ProtocolHandlerResponse?

* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.protocol.operations;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of package layout, I had thought the intent was to have generic code that could be used for any protocol in this package, while protobuf specific code would be under org.apache.geode.protocol.protobuf.* All of the Result and OperationContext code is now protobuf specific. Should it be moved?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wrote a test that enforces that every enum value has a handler. Of course that test won't pass until we have implemented all operations which isn't going to happen any time soon. So we removed it again. By the time all operations are implemented the test would basically enforce that we don't delete any of the operations and hook them up correctly. However, that's already enforced via the individual integration tests. So it's a very low value test.

ClientProtocol.Request.RequestAPICase requestType = request.getRequestAPICase();
OperationHandler opsHandler =
opsHandlerRegistry.getOperationHandlerForOperationId(requestType.getNumber());
OperationContext operationContext = operationContextRegistry.getOperationContext(requestType);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are we dealing with missing registry entries now that we're no longer throwing OperationNotRegisteredException?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we are getting a NPE for those which is awful and already lead to wasted time debugging the non-obvious error. Let's go back to throwing something specific.

Copy link
Contributor

@galen-pivotal galen-pivotal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review so far, a few comments.

I'm wondering how much the OperationHandlerContext adds here, or whether it would be cleaner to call through. On the other hand, so far it doesn't look worse than what we have so far.

import java.util.function.Function;

public class OperationContext<OperationReq, OperationResponse> {
private OperationHandler<OperationReq, OperationResponse> operationHandler;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these fields should be final.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could be public final and the getters removed. getFromRequest and getToResponse make it sound like the builder is doing something, when all it's doing is returning an imutable final field.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could even write a fromRequest (etc. family of) method that calls fromRequest.apply() on the arguments. Or we could have the context just have a process method that does things in the right order. I'm wondering what's the best way to write this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could even just make instances of some interface and not have references to these Functions at all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's a clear best way to do this, feel free to ignore this comment chain and carry on if you want.

SerializationService serializationService) {
this.opsHandlerRegistry = opsHandlerRegistry;
public ProtobufOpsProcessor(SerializationService serializationService,
OperationContextRegistry operationsContextRegistry) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a nitpick, but why are we using both operation and operations in names here?

private Function<OperationResponse, ClientProtocol.Response.Builder> toResponse;
private Function<ClientProtocol.ErrorResponse, ClientProtocol.Response.Builder> toErrorResponse;

public OperationContext(Function<ClientProtocol.Request, OperationReq> fromRequest,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use OperationRequest and OperationResponse?

@@ -50,47 +38,14 @@
* @param ex - exception which should be logged
* @return An error response containing the first three parameters.
*/
public static ClientProtocol.Response createAndLogErrorResponse(String errorMessage,
public static ClientProtocol.ErrorResponse createAndLogFailureResponse(String errorMessage,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why'd the name change to FailureResponse when the type changed to ErrorResponse?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think those were to changes that were made independently. Syncing this up right now

@@ -144,21 +138,22 @@ public void processReturnsErrorWhenUnableToDecodeRequest()
when(serializationServiceStub.decode(BasicTypes.EncodingType.STRING,
TEST_KEY.getBytes(Charset.forName("UTF-8")))).thenThrow(exception);

ClientProtocol.Request getRequest = generateTestRequest(false, false, false);
ClientProtocol.Response response = (ClientProtocol.Response) operationHandler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 getting rid of typecasts.

Copy link
Contributor

@galen-pivotal galen-pivotal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the Result type. It's interesting trying to do functional-style programming in Java. I think this code is better than what we have now and approve of shipping it.


import java.util.function.Function;

public class OperationContext<OperationRequest, OperationResponse> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to have these be implementations of an interface, since they're acting as an immutable collection of functions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@PurelyApplied
Copy link
Member

If you are using IntelliJ as your IDE, please remember to update your style file to that located in geode/etc/intellij-java-modified-google-style.xml to be consistent with Geode's established style guide. This file was updated June 13 with commit a561bd12 to be consistent with documented expectations. If you are using Eclipse, please import both style guidefiles, also located in geode/etc/.

After having done so, please optimize the imports to the correct order and to eliminate the use of the wildcard imports from the 25 offending files this pull request touches.

Signed-off-by: Alexander Murmann <amurmann@pivotal.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants