GEODE-3105: adding GetRegions handler for protobuf protocol Added a handler which will catch incoming getRegion requests and will call into the cache's rootRegion and return the names of the region it finds. Added unit test verifying hanlder behavior. Added integration test verifying module correctness for getRegion.
This closes #607 Signed-off-by: Brian Rowe <br...@pivotal.io> Signed-off-by: Hitesh Khamesra <hitesh...@yahoo.com> Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/b0fafd3d Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/b0fafd3d Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/b0fafd3d Branch: refs/heads/feature/GEODE-3109 Commit: b0fafd3da240257afd75ed09e10f61984b3c59b2 Parents: 6107561 Author: Brian Rowe <br...@pivotal.io> Authored: Tue Jun 27 16:15:53 2017 -0700 Committer: Hitesh Khamesra <hkhame...@pivotal.io> Committed: Wed Jun 28 13:39:51 2017 -0700 ---------------------------------------------------------------------- .../GenericProtocolServerConnection.java | 1 + .../protocol/protobuf/ProtobufOpsProcessor.java | 4 + .../protobuf/ProtobufStreamProcessor.java | 4 + .../GetRegionsRequestOperationHandler.java | 48 ++++++++ geode-protobuf/src/main/proto/region_API.proto | 3 +- .../org/apache/geode/protocol/MessageUtil.java | 11 ++ .../RoundTripCacheConnectionJUnitTest.java | 27 +++++ ...tRegionRequestOperationHandlerJUnitTest.java | 109 +++++++++++++++++++ 8 files changed, 206 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java index 8edd83c..a2e7305 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java @@ -67,6 +67,7 @@ public class GenericProtocolServerConnection extends ServerConnection { // TODO serialization types? messageHandler.receiveMessage(inputStream, outputStream, this.getCache()); } catch (IOException e) { + logger.warn(e); // TODO? } return; http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufOpsProcessor.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufOpsProcessor.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufOpsProcessor.java index 29d3317..4318fb4 100644 --- a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufOpsProcessor.java +++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufOpsProcessor.java @@ -56,6 +56,8 @@ public class ProtobufOpsProcessor { return request.getGetRequest(); case PUTALLREQUEST: return request.getPutAllRequest(); + case GETREGIONSREQUEST: + return request.getGetRegionsRequest(); default: throw new InvalidProtocolMessageException( "Unknown request type: " + request.getRequestAPICase().getNumber()); @@ -73,6 +75,8 @@ public class ProtobufOpsProcessor { return builder.setGetResponse((RegionAPI.GetResponse) response).build(); case PUTALLREQUEST: return builder.setPutAllResponse((RegionAPI.PutAllResponse) response).build(); + case GETREGIONSREQUEST: + return builder.setGetRegionsResponse((RegionAPI.GetRegionsResponse) response).build(); default: throw new InvalidProtocolMessageException( "Unknown request type: " + requestType.getNumber()); http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufStreamProcessor.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufStreamProcessor.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufStreamProcessor.java index 21dbef5..4e76de4 100644 --- a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufStreamProcessor.java +++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/ProtobufStreamProcessor.java @@ -18,6 +18,7 @@ import org.apache.geode.cache.Cache; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.tier.sockets.ClientProtocolMessageHandler; import org.apache.geode.protocol.exception.InvalidProtocolMessageException; +import org.apache.geode.protocol.protobuf.operations.GetRegionsRequestOperationHandler; import org.apache.geode.protocol.protobuf.operations.GetRequestOperationHandler; import org.apache.geode.protocol.protobuf.operations.PutRequestOperationHandler; import org.apache.geode.protocol.protobuf.serializer.ProtobufProtocolSerializer; @@ -58,6 +59,9 @@ public class ProtobufStreamProcessor implements ClientProtocolMessageHandler { registry.registerOperationHandlerForOperationId( ClientProtocol.Request.RequestAPICase.PUTREQUEST.getNumber(), new PutRequestOperationHandler()); + registry.registerOperationHandlerForOperationId( + ClientProtocol.Request.RequestAPICase.GETREGIONSREQUEST.getNumber(), + new GetRegionsRequestOperationHandler()); } public void processOneMessage(InputStream inputStream, OutputStream outputStream, Cache cache) http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetRegionsRequestOperationHandler.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetRegionsRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetRegionsRequestOperationHandler.java new file mode 100644 index 0000000..dc1d8ac --- /dev/null +++ b/geode-protobuf/src/main/java/org/apache/geode/protocol/protobuf/operations/GetRegionsRequestOperationHandler.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.protocol.protobuf.operations; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.Region; +import org.apache.geode.protocol.operations.OperationHandler; +import org.apache.geode.protocol.protobuf.BasicTypes; +import org.apache.geode.protocol.protobuf.EncodingTypeTranslator; +import org.apache.geode.protocol.protobuf.ProtobufUtilities; +import org.apache.geode.protocol.protobuf.RegionAPI; +import org.apache.geode.serialization.SerializationService; +import org.apache.geode.serialization.exception.UnsupportedEncodingTypeException; +import org.apache.geode.serialization.registry.exception.CodecNotRegisteredForTypeException; + +import sun.reflect.generics.tree.BaseType; + +import java.util.Set; + +public class GetRegionsRequestOperationHandler + implements OperationHandler<RegionAPI.GetRegionsRequest, RegionAPI.GetRegionsResponse> { + + @Override + public RegionAPI.GetRegionsResponse process(SerializationService serializationService, + RegionAPI.GetRegionsRequest request, Cache cache) { + Set<Region<?, ?>> regions = cache.rootRegions(); + + RegionAPI.GetRegionsResponse.Builder builder = RegionAPI.GetRegionsResponse.newBuilder(); + + for (Region region : regions) { + builder.addRegions(BasicTypes.Region.newBuilder().setName(region.getName())); + } + builder.setSuccess(true); + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/main/proto/region_API.proto ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/main/proto/region_API.proto b/geode-protobuf/src/main/proto/region_API.proto index adeb011..d3af17a 100644 --- a/geode-protobuf/src/main/proto/region_API.proto +++ b/geode-protobuf/src/main/proto/region_API.proto @@ -104,5 +104,6 @@ message GetRegionsRequest { } message GetRegionsResponse { - repeated Region regions = 1; + bool success = 1; + repeated Region regions = 2; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/test/java/org/apache/geode/protocol/MessageUtil.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/test/java/org/apache/geode/protocol/MessageUtil.java b/geode-protobuf/src/test/java/org/apache/geode/protocol/MessageUtil.java index 73d0803..dc89724 100644 --- a/geode-protobuf/src/test/java/org/apache/geode/protocol/MessageUtil.java +++ b/geode-protobuf/src/test/java/org/apache/geode/protocol/MessageUtil.java @@ -103,4 +103,15 @@ public class MessageUtil { private static ClientProtocol.MessageHeader.Builder getMessageHeaderBuilder() { return ClientProtocol.MessageHeader.newBuilder(); } + + public static RegionAPI.GetRegionsRequest makeGetRegionsRequest() { + return RegionAPI.GetRegionsRequest.newBuilder().build(); + } + + public static ClientProtocol.Message makeGetRegionsRequestMessage( + ClientProtocol.MessageHeader header) { + ClientProtocol.Request request = + ClientProtocol.Request.newBuilder().setGetRegionsRequest(makeGetRegionsRequest()).build(); + return ClientProtocol.Message.newBuilder().setMessageHeader(header).setRequest(request).build(); + } } http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/test/java/org/apache/geode/protocol/RoundTripCacheConnectionJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/test/java/org/apache/geode/protocol/RoundTripCacheConnectionJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/protocol/RoundTripCacheConnectionJUnitTest.java index 1fbe821..77b984f 100644 --- a/geode-protobuf/src/test/java/org/apache/geode/protocol/RoundTripCacheConnectionJUnitTest.java +++ b/geode-protobuf/src/test/java/org/apache/geode/protocol/RoundTripCacheConnectionJUnitTest.java @@ -107,6 +107,33 @@ public class RoundTripCacheConnectionJUnitTest { validateGetResponse(socket, protobufProtocolSerializer); } + @Test + public void testNewProtocolGetRegionCallSucceeds() throws Exception { + System.setProperty("geode.feature-protobuf-protocol", "true"); + + Socket socket = new Socket("localhost", cacheServerPort); + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(socket::isConnected); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(110); + + + ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer(); + ClientProtocol.Message getRegionsMessage = + MessageUtil.makeGetRegionsRequestMessage(ClientProtocol.MessageHeader.newBuilder().build()); + protobufProtocolSerializer.serialize(getRegionsMessage, outputStream); + + ClientProtocol.Message message = + protobufProtocolSerializer.deserialize(socket.getInputStream()); + assertEquals(ClientProtocol.Message.MessageTypeCase.RESPONSE, message.getMessageTypeCase()); + ClientProtocol.Response response = message.getResponse(); + assertEquals(ClientProtocol.Response.ResponseAPICase.GETREGIONSRESPONSE, + response.getResponseAPICase()); + RegionAPI.GetRegionsResponse getRegionsResponse = response.getGetRegionsResponse(); + assertEquals(true, getRegionsResponse.getSuccess()); + assertEquals(1, getRegionsResponse.getRegionsCount()); + assertEquals(TEST_REGION, getRegionsResponse.getRegions(0).getName()); + } + private void validatePutResponse(Socket socket, ProtobufProtocolSerializer protobufProtocolSerializer) throws Exception { ClientProtocol.Message message = http://git-wip-us.apache.org/repos/asf/geode/blob/b0fafd3d/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetRegionRequestOperationHandlerJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetRegionRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetRegionRequestOperationHandlerJUnitTest.java new file mode 100644 index 0000000..e8f1e65 --- /dev/null +++ b/geode-protobuf/src/test/java/org/apache/geode/protocol/protobuf/operations/GetRegionRequestOperationHandlerJUnitTest.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.protocol.protobuf.operations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.geode.LogWriter; +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.Region; +import org.apache.geode.protocol.MessageUtil; +import org.apache.geode.protocol.protobuf.BasicTypes; +import org.apache.geode.protocol.protobuf.RegionAPI; +import org.apache.geode.serialization.SerializationService; +import org.apache.geode.serialization.exception.UnsupportedEncodingTypeException; +import org.apache.geode.serialization.registry.exception.CodecAlreadyRegisteredForTypeException; +import org.apache.geode.serialization.registry.exception.CodecNotRegisteredForTypeException; +import org.apache.geode.test.dunit.Assert; +import org.apache.geode.test.junit.categories.UnitTest; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Category(UnitTest.class) +public class GetRegionRequestOperationHandlerJUnitTest { + public static final String TEST_REGION1 = "test region 1"; + public static final String TEST_REGION2 = "test region 2"; + public static final String TEST_REGION3 = "test region 3"; + public Cache cacheStub; + public SerializationService serializationServiceStub; + private GetRegionsRequestOperationHandler operationHandler; + + @Before + public void setUp() throws Exception { + serializationServiceStub = mock(SerializationService.class); + when(serializationServiceStub.encode(BasicTypes.EncodingType.STRING, TEST_REGION1)) + .thenReturn(TEST_REGION1.getBytes(Charset.forName("UTF-8"))); + when(serializationServiceStub.encode(BasicTypes.EncodingType.STRING, TEST_REGION2)) + .thenReturn(TEST_REGION2.getBytes(Charset.forName("UTF-8"))); + when(serializationServiceStub.encode(BasicTypes.EncodingType.STRING, TEST_REGION3)) + .thenReturn(TEST_REGION3.getBytes(Charset.forName("UTF-8"))); + + Region<String, String> region1Stub = mock(Region.class); + when(region1Stub.getName()).thenReturn(TEST_REGION1); + Region<String, String> region2Stub = mock(Region.class); + when(region2Stub.getName()).thenReturn(TEST_REGION2); + Region<String, String> region3Stub = mock(Region.class); + when(region3Stub.getName()).thenReturn(TEST_REGION3); + + cacheStub = mock(Cache.class); + when(cacheStub.rootRegions()).thenReturn(Collections.unmodifiableSet( + new HashSet<Region<String, String>>(Arrays.asList(region1Stub, region2Stub, region3Stub)))); + operationHandler = new GetRegionsRequestOperationHandler(); + } + + @Test + public void processReturnsCacheRegions() throws CodecAlreadyRegisteredForTypeException, + UnsupportedEncodingTypeException, CodecNotRegisteredForTypeException { + RegionAPI.GetRegionsResponse response = operationHandler.process(serializationServiceStub, + MessageUtil.makeGetRegionsRequest(), cacheStub); + + Assert.assertEquals(true, response.getSuccess()); + Assert.assertEquals(3, response.getRegionsCount()); + + // There's no guarantee for what order we receive the regions in from the response + String name1 = response.getRegions(0).getName(); + String name2 = response.getRegions(1).getName(); + String name3 = response.getRegions(2).getName(); + Assert.assertTrue("The same region was returned multiple times", + name1 != name2 && name1 != name3 && name2 != name3); + Assert.assertTrue(name1 == TEST_REGION1 || name1 == TEST_REGION2 || name1 == TEST_REGION3); + Assert.assertTrue(name2 == TEST_REGION1 || name2 == TEST_REGION2 || name2 == TEST_REGION3); + Assert.assertTrue(name3 == TEST_REGION1 || name3 == TEST_REGION2 || name3 == TEST_REGION3); + } + + @Test + public void processReturnsNoCacheRegions() throws CodecAlreadyRegisteredForTypeException, + UnsupportedEncodingTypeException, CodecNotRegisteredForTypeException { + Cache emptyCache = mock(Cache.class);; + when(emptyCache.rootRegions()) + .thenReturn(Collections.unmodifiableSet(new HashSet<Region<String, String>>())); + RegionAPI.GetRegionsResponse response = operationHandler.process(serializationServiceStub, + MessageUtil.makeGetRegionsRequest(), emptyCache); + + Assert.assertEquals(true, response.getSuccess()); + Assert.assertEquals(0, response.getRegionsCount()); + } +}