You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by go...@apache.org on 2018/03/21 17:47:11 UTC
[geode] branch develop updated: GEODE-2999,
GEODE-4836: Add PutIfAbsent to the Protobuf protocol.
This is an automated email from the ASF dual-hosted git repository.
gosullivan pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new c689dfd GEODE-2999, GEODE-4836: Add PutIfAbsent to the Protobuf protocol.
c689dfd is described below
commit c689dfd452e6462ca23969c6d50fbff51100e9f3
Author: Galen O'Sullivan <go...@pivotal.io>
AuthorDate: Wed Mar 14 17:03:10 2018 -0700
GEODE-2999, GEODE-4836: Add PutIfAbsent to the Protobuf protocol.
fix issues with getRequest not properly returning null.
This reverts commit 7a3da494e3b506e8cd485999db7a3cd42e200f85, which
originally reverted 6214a43be9d31fd0be1d133a8f0ad7379ea3f9c2.
This closes #1617
---
.../geode/experimental/driver/ProtobufRegion.java | 14 ++
.../apache/geode/experimental/driver/Region.java | 11 ++
.../geode/experimental/driver/ValueEncoder.java | 9 +-
.../experimental/driver/RegionIntegrationTest.java | 23 +++
.../experimental/driver/ValueEncoderTest.java | 2 +-
.../src/main/proto/v1/basicTypes.proto | 1 +
.../src/main/proto/v1/clientProtocol.proto | 3 +
.../src/main/proto/v1/region_API.proto | 9 +
.../protocol/protobuf/v1/ProtobufOpsProcessor.java | 6 +-
.../protobuf/v1/ProtobufStreamProcessor.java | 1 -
.../v1/operations/GetRequestOperationHandler.java | 4 -
...ava => PutIfAbsentRequestOperationHandler.java} | 60 +++----
.../registry/ProtobufOperationContextRegistry.java | 38 ++--
.../protobuf/v1/utilities/ProtobufUtilities.java | 7 +-
.../internal/protocol/protobuf/v1/MessageUtil.java | 17 ++
.../protobuf/v1/ProtobufRequestUtilities.java | 19 +-
.../v1/acceptance/CacheConnectionJUnitTest.java | 15 +-
.../v1/acceptance/CacheOperationsJUnitTest.java | 22 +--
.../GetAllRequestOperationHandlerJUnitTest.java | 4 +-
.../GetAndPutJsonDocumentsDUnitTest.java | 4 +-
.../GetRequestOperationHandlerJUnitTest.java | 5 +-
.../PutIfAbsentRequestIntegrationTest.java | 168 ++++++++++++++++++
...utIfAbsentRequestOperationHandlerJUnitTest.java | 197 +++++++++++++++++++++
23 files changed, 538 insertions(+), 101 deletions(-)
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufRegion.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufRegion.java
index 2870687..a7fc501 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufRegion.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufRegion.java
@@ -148,6 +148,20 @@ public class ProtobufRegion<K, V> implements Region<K, V> {
}
@Override
+ public V putIfAbsent(K key, V value) throws IOException {
+ final RegionAPI.PutIfAbsentRequest.Builder putIfAbsentRequest = RegionAPI.PutIfAbsentRequest
+ .newBuilder().setRegionName(name).setEntry(ValueEncoder.encodeEntry(key, value));
+
+ final Message request = Message.newBuilder().setPutIfAbsentRequest(putIfAbsentRequest).build();
+
+ final RegionAPI.PutIfAbsentResponse putIfAbsentResponse = protobufChannel
+ .sendRequest(request, MessageTypeCase.PUTIFABSENTRESPONSE).getPutIfAbsentResponse();
+
+
+ return (V) ValueEncoder.decodeValue(putIfAbsentResponse.getOldValue());
+ }
+
+ @Override
public void remove(K key) throws IOException {
final Message request = Message.newBuilder()
.setRemoveRequest(
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/Region.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/Region.java
index bbdbe2d..32cb381 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/Region.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/Region.java
@@ -86,6 +86,17 @@ public interface Region<K, V> {
void clear() throws IOException;
/**
+ * Puts the <code>value</code> into this region for the <code>key</code> if <code>key</code> does
+ * not already have a value associated with it.
+ *
+ * @return null if the value was set; the current value otherwise.
+ * NOTE that if the value in the region was set to null, this method will return null
+ * without setting a new value.
+ * @throws IOException
+ */
+ V putIfAbsent(K key, V value) throws IOException;
+
+ /**
* Removes any value associated with the <code>key</code> from this region.
*
* @param key Unique key associated with a value.
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ValueEncoder.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ValueEncoder.java
index 9c9b656..3d66bfe 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ValueEncoder.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ValueEncoder.java
@@ -14,7 +14,10 @@
*/
package org.apache.geode.experimental.driver;
+import java.util.Objects;
+
import com.google.protobuf.ByteString;
+import com.google.protobuf.NullValue;
import org.apache.geode.annotations.Experimental;
import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
@@ -35,7 +38,9 @@ class ValueEncoder {
*/
static BasicTypes.EncodedValue encodeValue(Object unencodedValue) {
BasicTypes.EncodedValue.Builder builder = BasicTypes.EncodedValue.newBuilder();
- if (Integer.class.equals(unencodedValue.getClass())) {
+ if (Objects.isNull(unencodedValue)) {
+ builder.setNullResult(NullValue.NULL_VALUE);
+ } else if (Integer.class.equals(unencodedValue.getClass())) {
builder.setIntResult((Integer) unencodedValue);
} else if (Long.class.equals(unencodedValue.getClass())) {
builder.setLongResult((Long) unencodedValue);
@@ -91,7 +96,7 @@ class ValueEncoder {
return encodedValue.getStringResult();
case JSONOBJECTRESULT:
return JSONWrapper.wrapJSON(encodedValue.getJsonObjectResult());
- case VALUE_NOT_SET:
+ case NULLRESULT:
return null;
default:
throw new IllegalStateException(
diff --git a/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/RegionIntegrationTest.java b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/RegionIntegrationTest.java
index 78af30c..6782ec2 100644
--- a/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/RegionIntegrationTest.java
+++ b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/RegionIntegrationTest.java
@@ -95,6 +95,29 @@ public class RegionIntegrationTest extends IntegrationTestBase {
}
@Test
+ public void putIfAbsent() throws Exception {
+ Region<JSONWrapper, JSONWrapper> region = driver.getRegion("region");
+ JSONWrapper document = JSONWrapper.wrapJSON(jsonDocument);
+
+ assertNull(region.putIfAbsent(document, document));
+
+ JSONWrapper value = region.get(document);
+ assertEquals(document, value);
+ assertEquals(1, serverRegion.size());
+
+ assertEquals(document, region.putIfAbsent(document, JSONWrapper.wrapJSON("{3 : 2}")));
+ value = region.get(document);
+ assertEquals(document, value);
+ assertEquals(1, serverRegion.size());
+
+ org.apache.geode.cache.Region.Entry entry =
+ (org.apache.geode.cache.Region.Entry) serverRegion.entrySet().iterator().next();
+
+ assertTrue(PdxInstance.class.isAssignableFrom(entry.getKey().getClass()));
+ assertTrue(PdxInstance.class.isAssignableFrom(entry.getValue().getClass()));
+ }
+
+ @Test
public void removeWithJSONKey() throws Exception {
Region<JSONWrapper, JSONWrapper> region = driver.getRegion("region");
JSONWrapper document = JSONWrapper.wrapJSON(jsonDocument);
diff --git a/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/ValueEncoderTest.java b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/ValueEncoderTest.java
index c8e7353..3a2989d 100644
--- a/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/ValueEncoderTest.java
+++ b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/ValueEncoderTest.java
@@ -33,7 +33,7 @@ public class ValueEncoderTest {
@Test
public void encodeAndDecode() throws Exception {
- final Object[] objects = {37, (short) 37, (byte) 37, 37L, 37., 37.F, true, "hello, world",
+ final Object[] objects = {37, (short) 37, (byte) 37, 37L, 37., 37.F, true, "hello, world", null,
JSONWrapper.wrapJSON(jsonDocument)};
for (Object object : objects) {
assertEquals(object, ValueEncoder.decodeValue(ValueEncoder.encodeValue(object)));
diff --git a/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto b/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
index a12718b..e8cfa15 100644
--- a/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
@@ -82,6 +82,7 @@ enum ErrorCode {
AUTHENTICATION_NOT_SUPPORTED = 13;
AUTHORIZATION_FAILED = 20;
INVALID_REQUEST = 50;
+ UNSUPPORTED_OPERATION = 60;
SERVER_ERROR = 100;
NO_AVAILABLE_SERVER = 101;
}
diff --git a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
index 2b21c89..c3b0f5f 100644
--- a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
@@ -78,6 +78,9 @@ message Message {
ClearRequest clearRequest = 32;
ClearResponse clearResponse = 33;
+
+ PutIfAbsentRequest putIfAbsentRequest = 34;
+ PutIfAbsentResponse putIfAbsentResponse = 35;
}
}
diff --git a/geode-protobuf-messages/src/main/proto/v1/region_API.proto b/geode-protobuf-messages/src/main/proto/v1/region_API.proto
index 407409f..b70765b 100644
--- a/geode-protobuf-messages/src/main/proto/v1/region_API.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/region_API.proto
@@ -32,6 +32,15 @@ message PutResponse {
// message presence indicates success.
}
+message PutIfAbsentRequest {
+ string regionName = 1;
+ Entry entry = 2;
+}
+
+message PutIfAbsentResponse {
+ EncodedValue oldValue = 1;
+}
+
message GetRequest {
string regionName = 1;
EncodedValue key = 2;
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
index 1f2d201..cfc71b3 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
@@ -25,7 +25,6 @@ import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.De
import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
import org.apache.geode.internal.protocol.protobuf.v1.state.ProtobufConnectionTerminatingStateProcessor;
import org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
-import org.apache.geode.internal.protocol.protobuf.v1.state.exception.OperationNotAuthorizedException;
/**
* This handles protobuf requests by determining the operation type of the request and dispatching
@@ -86,6 +85,11 @@ public class ProtobufOpsProcessor {
logger.error(exception);
return Failure.of(BasicTypes.ErrorCode.INVALID_REQUEST,
"Invalid execution context found for operation.");
+ } catch (UnsupportedOperationException exception) {
+ logger.error("Unsupported operation exception for request {}", requestType);
+ logger.error(exception);
+ return Failure.of(BasicTypes.ErrorCode.UNSUPPORTED_OPERATION,
+ "Unsupported operation:" + exception.getMessage());
} finally {
context.getStatistics().endOperation(startTime);
}
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufStreamProcessor.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufStreamProcessor.java
index e72774f..1558ee0 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufStreamProcessor.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufStreamProcessor.java
@@ -27,7 +27,6 @@ import org.apache.geode.internal.protocol.protobuf.statistics.ClientStatistics;
import org.apache.geode.internal.protocol.protobuf.v1.registry.ProtobufOperationContextRegistry;
import org.apache.geode.internal.protocol.protobuf.v1.serializer.ProtobufProtocolSerializer;
import org.apache.geode.internal.protocol.protobuf.v1.serializer.exception.InvalidProtocolMessageException;
-import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufUtilities;
/**
* This object handles an incoming stream containing protobuf messages. It parses the protobuf
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java
index 856bb13..089274b 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java
@@ -58,10 +58,6 @@ public class GetRequestOperationHandler
}
Object resultValue = region.get(decodedKey);
- if (resultValue == null) {
- return Success.of(RegionAPI.GetResponse.newBuilder().build());
- }
-
BasicTypes.EncodedValue encodedValue = serializationService.encode(resultValue);
return Success.of(RegionAPI.GetResponse.newBuilder().setResult(encodedValue).build());
} finally {
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandler.java
similarity index 56%
copy from geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java
copy to geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandler.java
index 856bb13..9713183 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandler.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandler.java
@@ -14,12 +14,11 @@
*/
package org.apache.geode.internal.protocol.protobuf.v1.operations;
+import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.apache.geode.annotations.Experimental;
import org.apache.geode.cache.Region;
import org.apache.geode.internal.exception.InvalidExecutionContextException;
-import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.protocol.operations.ProtobufOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
import org.apache.geode.internal.protocol.protobuf.v1.Failure;
@@ -30,49 +29,50 @@ import org.apache.geode.internal.protocol.protobuf.v1.Result;
import org.apache.geode.internal.protocol.protobuf.v1.Success;
import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.DecodingException;
import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
import org.apache.geode.security.ResourcePermission;
-@Experimental
-public class GetRequestOperationHandler
- implements ProtobufOperationHandler<RegionAPI.GetRequest, RegionAPI.GetResponse> {
- private static final Logger logger = LogService.getLogger();
+public class PutIfAbsentRequestOperationHandler implements
+ ProtobufOperationHandler<RegionAPI.PutIfAbsentRequest, RegionAPI.PutIfAbsentResponse> {
+ private static final Logger logger = LogManager.getLogger();
@Override
- public Result<RegionAPI.GetResponse> process(ProtobufSerializationService serializationService,
- RegionAPI.GetRequest request, MessageExecutionContext messageExecutionContext)
- throws InvalidExecutionContextException, EncodingException, DecodingException {
- String regionName = request.getRegionName();
- Region region = messageExecutionContext.getCache().getRegion(regionName);
+ public Result<RegionAPI.PutIfAbsentResponse> process(
+ ProtobufSerializationService serializationService, RegionAPI.PutIfAbsentRequest request,
+ MessageExecutionContext messageExecutionContext) throws InvalidExecutionContextException,
+ ConnectionStateException, EncodingException, DecodingException {
+
+ final String regionName = request.getRegionName();
+
+ Region<Object, Object> region;
+ try {
+ region = messageExecutionContext.getCache().getRegion(regionName);
+ } catch (IllegalArgumentException ex) {
+ return Failure.of(BasicTypes.ErrorCode.INVALID_REQUEST,
+ "Invalid region name: \"" + regionName + "\"");
+ }
+
if (region == null) {
- logger.error("Received get request for nonexistent region: {}", regionName);
+ logger.error("Received PutIfAbsentRequest for nonexistent region: {}", regionName);
return Failure.of(BasicTypes.ErrorCode.SERVER_ERROR,
"Region \"" + regionName + "\" not found");
}
- try {
- messageExecutionContext.getCache().setReadSerializedForCurrentThread(true);
+ final BasicTypes.Entry entry = request.getEntry();
- Object decodedKey = serializationService.decode(request.getKey());
- if (decodedKey == null) {
- return Failure.of(BasicTypes.ErrorCode.INVALID_REQUEST, "Performing a get on a NULL key.");
- }
- Object resultValue = region.get(decodedKey);
+ Object decodedValue = serializationService.decode(entry.getValue());
+ Object decodedKey = serializationService.decode(entry.getKey());
- if (resultValue == null) {
- return Success.of(RegionAPI.GetResponse.newBuilder().build());
- }
+ final Object oldValue = region.putIfAbsent(decodedKey, decodedValue);
- BasicTypes.EncodedValue encodedValue = serializationService.encode(resultValue);
- return Success.of(RegionAPI.GetResponse.newBuilder().setResult(encodedValue).build());
- } finally {
- messageExecutionContext.getCache().setReadSerializedForCurrentThread(false);
- }
+ return Success.of(RegionAPI.PutIfAbsentResponse.newBuilder()
+ .setOldValue(serializationService.encode(oldValue)).build());
}
- public static ResourcePermission determineRequiredPermission(RegionAPI.GetRequest request,
+ public static ResourcePermission determineRequiredPermission(RegionAPI.PutIfAbsentRequest request,
ProtobufSerializationService serializer) throws DecodingException {
return new ResourcePermission(ResourcePermission.Resource.DATA,
- ResourcePermission.Operation.READ, request.getRegionName(),
- serializer.decode(request.getKey()).toString());
+ ResourcePermission.Operation.WRITE, request.getRegionName(),
+ serializer.decode(request.getEntry().getKey()).toString());
}
}
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
index d950baa..64a5cba 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
@@ -36,6 +36,7 @@ import org.apache.geode.internal.protocol.protobuf.v1.operations.GetSizeRequestO
import org.apache.geode.internal.protocol.protobuf.v1.operations.KeySetOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.operations.OqlQueryRequestOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.operations.PutAllRequestOperationHandler;
+import org.apache.geode.internal.protocol.protobuf.v1.operations.PutIfAbsentRequestOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.operations.PutRequestOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.operations.RemoveRequestOperationHandler;
import org.apache.geode.internal.protocol.protobuf.v1.operations.security.AuthenticationRequestOperationHandler;
@@ -46,15 +47,14 @@ import org.apache.geode.security.ResourcePermission.Resource;
@Experimental
public class ProtobufOperationContextRegistry {
- private Map<ClientProtocol.Message.MessageTypeCase, ProtobufOperationContext> operationContexts =
+ private final Map<MessageTypeCase, ProtobufOperationContext> operationContexts =
new ConcurrentHashMap<>();
public ProtobufOperationContextRegistry() {
addContexts();
}
- public ProtobufOperationContext getOperationContext(
- ClientProtocol.Message.MessageTypeCase apiCase) {
+ public ProtobufOperationContext getOperationContext(MessageTypeCase apiCase) {
return operationContexts.get(apiCase);
}
@@ -67,69 +67,69 @@ public class ProtobufOperationContextRegistry {
}
private void addContexts() {
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.AUTHENTICATIONREQUEST,
+ operationContexts.put(MessageTypeCase.AUTHENTICATIONREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getAuthenticationRequest,
new AuthenticationRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setAuthenticationResponse(opsResp),
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.DISCONNECTCLIENTREQUEST,
+ operationContexts.put(MessageTypeCase.DISCONNECTCLIENTREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getDisconnectClientRequest,
new DisconnectClientRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setDisconnectClientResponse(opsResp),
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.GETREQUEST,
+ operationContexts.put(MessageTypeCase.GETREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getGetRequest,
new GetRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setGetResponse(opsResp),
GetRequestOperationHandler::determineRequiredPermission));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.GETALLREQUEST,
+ operationContexts.put(MessageTypeCase.GETALLREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getGetAllRequest,
new GetAllRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setGetAllResponse(opsResp),
// May require per-key checks, will be handled by OperationHandler
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.PUTREQUEST,
+ operationContexts.put(MessageTypeCase.PUTREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getPutRequest,
new PutRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setPutResponse(opsResp),
PutRequestOperationHandler::determineRequiredPermission));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.PUTALLREQUEST,
+ operationContexts.put(MessageTypeCase.PUTALLREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getPutAllRequest,
new PutAllRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setPutAllResponse(opsResp),
// May require per-key checks, will be handled by OperationHandler
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.REMOVEREQUEST,
+ operationContexts.put(MessageTypeCase.REMOVEREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getRemoveRequest,
new RemoveRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setRemoveResponse(opsResp),
RemoveRequestOperationHandler::determineRequiredPermission));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.GETREGIONNAMESREQUEST,
+ operationContexts.put(MessageTypeCase.GETREGIONNAMESREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getGetRegionNamesRequest,
new GetRegionNamesRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setGetRegionNamesResponse(opsResp),
ResourcePermissions.DATA_READ));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.GETSIZEREQUEST,
+ operationContexts.put(MessageTypeCase.GETSIZEREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getGetSizeRequest,
new GetSizeRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setGetSizeResponse(opsResp),
ResourcePermissions.DATA_READ));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.GETSERVERREQUEST,
+ operationContexts.put(MessageTypeCase.GETSERVERREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getGetServerRequest,
new GetServerOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setGetServerResponse(opsResp),
ResourcePermissions.CLUSTER_READ));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.EXECUTEFUNCTIONONREGIONREQUEST,
+ operationContexts.put(MessageTypeCase.EXECUTEFUNCTIONONREGIONREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getExecuteFunctionOnRegionRequest,
new ExecuteFunctionOnRegionRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder()
@@ -138,7 +138,7 @@ public class ProtobufOperationContextRegistry {
// requirements.
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.EXECUTEFUNCTIONONMEMBERREQUEST,
+ operationContexts.put(MessageTypeCase.EXECUTEFUNCTIONONMEMBERREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getExecuteFunctionOnMemberRequest,
new ExecuteFunctionOnMemberRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder()
@@ -147,7 +147,7 @@ public class ProtobufOperationContextRegistry {
// requirements.
this::skipAuthorizationCheck));
- operationContexts.put(ClientProtocol.Message.MessageTypeCase.EXECUTEFUNCTIONONGROUPREQUEST,
+ operationContexts.put(MessageTypeCase.EXECUTEFUNCTIONONGROUPREQUEST,
new ProtobufOperationContext<>(ClientProtocol.Message::getExecuteFunctionOnGroupRequest,
new ExecuteFunctionOnGroupRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder()
@@ -174,5 +174,11 @@ public class ProtobufOperationContextRegistry {
new ClearRequestOperationHandler(),
opsResp -> ClientProtocol.Message.newBuilder().setClearResponse(opsResp),
ClearRequestOperationHandler::determineRequiredPermission));
+
+ operationContexts.put(MessageTypeCase.PUTIFABSENTREQUEST,
+ new ProtobufOperationContext<>(ClientProtocol.Message::getPutIfAbsentRequest,
+ new PutIfAbsentRequestOperationHandler(),
+ opsResp -> ClientProtocol.Message.newBuilder().setPutIfAbsentResponse(opsResp),
+ PutIfAbsentRequestOperationHandler::determineRequiredPermission));
}
}
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/utilities/ProtobufUtilities.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/utilities/ProtobufUtilities.java
index d7e2a2d..877aac0 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/utilities/ProtobufUtilities.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/utilities/ProtobufUtilities.java
@@ -25,6 +25,9 @@ import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.En
* This class contains helper functions for assistance in creating protobuf objects. This class is
* mainly focused on helper functions which can be used in building BasicTypes for use in other
* messages or those used to create the top level Message objects.
+ * <p>
+ * Helper functions specific to creating ClientProtocol.Messages can be found at
+ * {@link ProtobufRequestUtilities}
*/
@Experimental
public abstract class ProtobufUtilities {
@@ -56,10 +59,6 @@ public abstract class ProtobufUtilities {
*/
public static BasicTypes.Entry createEntry(ProtobufSerializationService serializationService,
Object unencodedKey, Object unencodedValue) throws EncodingException {
- if (unencodedValue == null) {
- return BasicTypes.Entry.newBuilder().setKey(serializationService.encode(unencodedKey))
- .build();
- }
return createEntry(serializationService.encode(unencodedKey),
serializationService.encode(unencodedValue));
}
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/MessageUtil.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/MessageUtil.java
index 7080202..0e83b93 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/MessageUtil.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/MessageUtil.java
@@ -14,6 +14,7 @@
*/
package org.apache.geode.internal.protocol.protobuf.v1;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
@@ -24,7 +25,10 @@ import java.net.Socket;
import com.google.protobuf.MessageLite;
import org.apache.geode.internal.protocol.protobuf.ProtocolVersion;
+import org.apache.geode.internal.protocol.protobuf.v1.ProtobufRequestUtilities;
import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import org.apache.geode.internal.protocol.protobuf.v1.serializer.ProtobufProtocolSerializer;
+import org.apache.geode.internal.protocol.protobuf.v1.serializer.exception.InvalidProtocolMessageException;
import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufUtilities;
public class MessageUtil {
@@ -89,4 +93,17 @@ public class MessageUtil {
throw new RuntimeException(e); // never happens.
}
}
+
+ public static void validateGetResponse(Socket socket,
+ ProtobufProtocolSerializer protobufProtocolSerializer, Object expectedValue)
+ throws InvalidProtocolMessageException, IOException {
+
+ ClientProtocol.Message response =
+ protobufProtocolSerializer.deserialize(socket.getInputStream());
+ assertEquals(ClientProtocol.Message.MessageTypeCase.GETRESPONSE, response.getMessageTypeCase());
+ RegionAPI.GetResponse getResponse = response.getGetResponse();
+ BasicTypes.EncodedValue result = getResponse.getResult();
+ assertEquals(BasicTypes.EncodedValue.ValueCase.STRINGRESULT, result.getValueCase());
+ assertEquals(expectedValue, result.getStringResult());
+ }
}
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufRequestUtilities.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufRequestUtilities.java
index 873fe02..2faa4bb 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufRequestUtilities.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufRequestUtilities.java
@@ -17,10 +17,7 @@ package org.apache.geode.internal.protocol.protobuf.v1;
import java.util.Set;
import org.apache.geode.annotations.Experimental;
-import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
-import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
-import org.apache.geode.internal.protocol.protobuf.v1.LocatorAPI;
-import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
+import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufUtilities;
/**
* This class contains helper functions for generating ClientProtocol.Message objects
@@ -92,6 +89,20 @@ public abstract class ProtobufRequestUtilities {
}
/**
+ * Creates a request object containing a RegionAPI.PutIfAbsentRequest
+ *
+ * @param region - Name of the region to put data in
+ * @param entry - Encoded key,value pair, see createEntry in {@link ProtobufRequestUtilities}
+ * @return Request object containing the passed params.
+ */
+ public static ClientProtocol.Message createPutIfAbsentRequest(String region,
+ BasicTypes.Entry entry) {
+ RegionAPI.PutIfAbsentRequest putIfAbsentRequest =
+ RegionAPI.PutIfAbsentRequest.newBuilder().setRegionName(region).setEntry(entry).build();
+ return ClientProtocol.Message.newBuilder().setPutIfAbsentRequest(putIfAbsentRequest).build();
+ }
+
+ /**
* Create a request to get the values for multiple keys
*
* @param regionName - Name of the region to fetch from
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionJUnitTest.java
index bfb1ff8..677d966 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionJUnitTest.java
@@ -22,6 +22,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_
import static org.apache.geode.distributed.ConfigurationProperties.SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.internal.protocol.protobuf.v1.MessageUtil.validateGetResponse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -61,11 +62,9 @@ import org.apache.geode.internal.cache.tier.sockets.AcceptorImpl;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.net.SocketCreatorFactory;
import org.apache.geode.internal.protocol.protobuf.statistics.ProtobufClientStatistics;
-import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
import org.apache.geode.internal.protocol.protobuf.v1.MessageUtil;
import org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
-import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
import org.apache.geode.internal.protocol.protobuf.v1.serializer.ProtobufProtocolSerializer;
import org.apache.geode.internal.protocol.protobuf.v1.serializer.exception.InvalidProtocolMessageException;
import org.apache.geode.test.junit.categories.IntegrationTest;
@@ -215,18 +214,6 @@ public class CacheConnectionJUnitTest {
assertEquals(ClientProtocol.Message.MessageTypeCase.PUTRESPONSE, response.getMessageTypeCase());
}
- private void validateGetResponse(Socket socket,
- ProtobufProtocolSerializer protobufProtocolSerializer, Object expectedValue)
- throws InvalidProtocolMessageException, IOException {
- ClientProtocol.Message response = deserializeResponse(socket, protobufProtocolSerializer);
-
- assertEquals(ClientProtocol.Message.MessageTypeCase.GETRESPONSE, response.getMessageTypeCase());
- RegionAPI.GetResponse getResponse = response.getGetResponse();
- BasicTypes.EncodedValue result = getResponse.getResult();
- assertEquals(BasicTypes.EncodedValue.ValueCase.STRINGRESULT, result.getValueCase());
- assertEquals(expectedValue, result.getStringResult());
- }
-
private ClientProtocol.Message deserializeResponse(Socket socket,
ProtobufProtocolSerializer protobufProtocolSerializer)
throws InvalidProtocolMessageException, IOException {
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheOperationsJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheOperationsJUnitTest.java
index a997590..c312532 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheOperationsJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheOperationsJUnitTest.java
@@ -22,6 +22,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_
import static org.apache.geode.distributed.ConfigurationProperties.SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.internal.protocol.protobuf.v1.MessageUtil.validateGetResponse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -101,6 +102,7 @@ public class CacheOperationsJUnitTest {
@Rule
public TestName testName = new TestName();
+ private ProtobufProtocolSerializer protobufProtocolSerializer;
@Before
public void setup() throws Exception {
@@ -139,6 +141,7 @@ public class CacheOperationsJUnitTest {
MessageUtil.performAndVerifyHandshake(socket);
serializationService = new ProtobufSerializationService();
+ protobufProtocolSerializer = new ProtobufProtocolSerializer();
}
@After
@@ -174,7 +177,7 @@ public class CacheOperationsJUnitTest {
ProtobufRequestUtilities.createGetAllRequest(TEST_REGION, getEntries);
ClientProtocol.Message getAllMessage =
- ProtobufUtilities.createProtobufRequestWithGetAllRequest(getAllRequest);
+ ClientProtocol.Message.newBuilder().setGetAllRequest(getAllRequest).build();
protobufProtocolSerializer.serialize(getAllMessage, outputStream);
validateGetAllResponse(socket, protobufProtocolSerializer);
@@ -194,7 +197,6 @@ public class CacheOperationsJUnitTest {
regionFactory.create(regionName);
System.setProperty("geode.feature-protobuf-protocol", "true");
- ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
Set<BasicTypes.Entry> putEntries = new HashSet<>();
putEntries.add(ProtobufUtilities.createEntry(serializationService, 2.2f, TEST_MULTIOP_VALUE1));
putEntries.add(ProtobufUtilities.createEntry(serializationService, TEST_MULTIOP_KEY2,
@@ -224,7 +226,6 @@ public class CacheOperationsJUnitTest {
@Test
public void testResponseToGetWithNoData() throws Exception {
// Get request without any data set must return a null
- ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
ClientProtocol.Message getMessage =
MessageUtil.makeGetRequestMessage(serializationService, TEST_KEY, TEST_REGION);
protobufProtocolSerializer.serialize(getMessage, outputStream);
@@ -233,12 +234,11 @@ public class CacheOperationsJUnitTest {
assertEquals(ClientProtocol.Message.MessageTypeCase.GETRESPONSE, response.getMessageTypeCase());
RegionAPI.GetResponse getResponse = response.getGetResponse();
- assertFalse(getResponse.hasResult());
+ assertEquals(null, serializationService.decode(getResponse.getResult()));
}
@Test
public void testNewProtocolGetRegionNamesCallSucceeds() throws Exception {
- ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
RegionAPI.GetRegionNamesRequest getRegionNamesRequest =
ProtobufRequestUtilities.createGetRegionNamesRequest();
@@ -252,7 +252,6 @@ public class CacheOperationsJUnitTest {
public void testNewProtocolGetSizeCall() throws Exception {
System.setProperty("geode.feature-protobuf-protocol", "true");
- ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
ClientProtocol.Message putMessage = ProtobufRequestUtilities.createPutRequest(TEST_REGION,
ProtobufUtilities.createEntry(serializationService, TEST_KEY, TEST_VALUE));
protobufProtocolSerializer.serialize(putMessage, outputStream);
@@ -269,17 +268,6 @@ public class CacheOperationsJUnitTest {
assertEquals(1, getSizeResponse.getSize());
}
- private void validateGetResponse(Socket socket,
- ProtobufProtocolSerializer protobufProtocolSerializer, Object expectedValue)
- throws InvalidProtocolMessageException, IOException {
- ClientProtocol.Message response = deserializeResponse(socket, protobufProtocolSerializer);
-
- assertEquals(ClientProtocol.Message.MessageTypeCase.GETRESPONSE, response.getMessageTypeCase());
- RegionAPI.GetResponse getResponse = response.getGetResponse();
- BasicTypes.EncodedValue result = getResponse.getResult();
- assertEquals(BasicTypes.EncodedValue.ValueCase.STRINGRESULT, result.getValueCase());
- assertEquals(expectedValue, result.getStringResult());
- }
private ClientProtocol.Message deserializeResponse(Socket socket,
ProtobufProtocolSerializer protobufProtocolSerializer)
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
index 9ceb31f..e21f051 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
@@ -147,7 +147,7 @@ public class GetAllRequestOperationHandlerJUnitTest extends OperationHandlerJUni
}
@Test
- public void singeNullKey() throws Exception {
+ public void singleNullKey() throws Exception {
HashSet<BasicTypes.EncodedValue> testKeys = new HashSet<>();
testKeys.add(serializationService.encode(NO_VALUE_PRESENT_FOR_THIS_KEY));
RegionAPI.GetAllRequest getAllRequest =
@@ -158,7 +158,7 @@ public class GetAllRequestOperationHandlerJUnitTest extends OperationHandlerJUni
assertTrue(result instanceof Success);
RegionAPI.GetAllResponse message = (RegionAPI.GetAllResponse) result.getMessage();
assertEquals(1, message.getEntriesCount());
- assertFalse(message.getEntries(0).hasValue());
+ assertEquals(null, serializationService.decode(message.getEntries(0).getValue()));
assertEquals(NO_VALUE_PRESENT_FOR_THIS_KEY, message.getEntries(0).getKey().getStringResult());
verify(regionStub, times(1)).get(NO_VALUE_PRESENT_FOR_THIS_KEY);
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAndPutJsonDocumentsDUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAndPutJsonDocumentsDUnitTest.java
index e51b6df..2ddfbcb 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAndPutJsonDocumentsDUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAndPutJsonDocumentsDUnitTest.java
@@ -77,7 +77,7 @@ public class GetAndPutJsonDocumentsDUnitTest extends JUnit4CacheTestCase {
private static ProtobufSerializationService serializationService;
- VM storingVM;
+ private VM storingVM;
@Before
public void setUp() throws Exception {
@@ -103,8 +103,6 @@ public class GetAndPutJsonDocumentsDUnitTest extends JUnit4CacheTestCase {
}
}
-
-
@Test
public void testThatGetReturnsJSONDocumentForPdxInstance() throws Exception {
storeTestDocument();
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
index 973fa5a..4e7af95 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
@@ -100,10 +100,11 @@ public class GetRequestOperationHandlerJUnitTest extends OperationHandlerJUnitTe
@Test
public void processReturnsLookupFailureWhenKeyFoundWithNoValue() throws Exception {
RegionAPI.GetRequest getRequest = generateTestRequest(false, false, true);
- Result response = operationHandler.process(serializationService, getRequest,
- TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+ Result<RegionAPI.GetResponse> response = operationHandler.process(serializationService,
+ getRequest, TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
Assert.assertTrue(response instanceof Success);
+ Assert.assertNull(serializationService.decode(response.getMessage().getResult()));
}
@Test(expected = DecodingException.class)
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestIntegrationTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestIntegrationTest.java
new file mode 100644
index 0000000..008e495
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestIntegrationTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.internal.protocol.protobuf.v1.operations;
+
+import static org.apache.geode.internal.protocol.protobuf.v1.MessageUtil.validateGetResponse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import org.awaitility.Awaitility;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.DataPolicy;
+import org.apache.geode.cache.RegionFactory;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.internal.net.SocketCreatorFactory;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
+import org.apache.geode.internal.protocol.protobuf.v1.MessageUtil;
+import org.apache.geode.internal.protocol.protobuf.v1.ProtobufRequestUtilities;
+import org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
+import org.apache.geode.internal.protocol.protobuf.v1.serializer.ProtobufProtocolSerializer;
+import org.apache.geode.internal.protocol.protobuf.v1.serializer.exception.InvalidProtocolMessageException;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class PutIfAbsentRequestIntegrationTest {
+ private static final String TEST_REGION = "testRegion";
+ private static final Object TEST_KEY = "testKey";
+ private Cache cache;
+ private Socket socket;
+ private OutputStream outputStream;
+ private ProtobufSerializationService serializationService;
+ private ProtobufProtocolSerializer protobufProtocolSerializer;
+
+ @Rule
+ public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ private InputStream inputStream;
+
+ private void doSetup(DataPolicy dataPolicy) throws IOException {
+ System.setProperty("geode.feature-protobuf-protocol", "true");
+
+ CacheFactory cacheFactory = new CacheFactory(new Properties());
+ cacheFactory.set(ConfigurationProperties.MCAST_PORT, "0");
+ cacheFactory.set(ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION, "false");
+ cacheFactory.set(ConfigurationProperties.USE_CLUSTER_CONFIGURATION, "false");
+ cache = cacheFactory.create();
+
+ CacheServer cacheServer = cache.addCacheServer();
+ final int cacheServerPort = AvailablePortHelper.getRandomAvailableTCPPort();
+ cacheServer.setPort(cacheServerPort);
+ cacheServer.start();
+
+ RegionFactory<Object, Object> regionFactory = cache.createRegionFactory();
+ regionFactory.setDataPolicy(dataPolicy);
+ regionFactory.create(TEST_REGION);
+
+
+ socket = new Socket("localhost", cacheServerPort);
+ Awaitility.await().atMost(5, TimeUnit.SECONDS).until(socket::isConnected);
+ outputStream = socket.getOutputStream();
+ inputStream = socket.getInputStream();
+
+ MessageUtil.performAndVerifyHandshake(socket);
+
+ serializationService = new ProtobufSerializationService();
+ protobufProtocolSerializer = new ProtobufProtocolSerializer();
+ }
+
+ @After
+ public void cleanUp() throws IOException {
+ cache.close();
+ socket.close();
+ SocketCreatorFactory.close();
+ }
+
+ @Test
+ public void testPutIfAbsentRequest() throws Exception {
+ doSetup(DataPolicy.REPLICATE);
+
+ final BasicTypes.EncodedValue encodedKey = serializationService.encode(TEST_KEY);
+ final String testValue = "testValue";
+ final String testValue2 = "testValue2";
+ final BasicTypes.Entry entry1 = BasicTypes.Entry.newBuilder().setKey(encodedKey)
+ .setValue(serializationService.encode(testValue)).build();
+ assertNull(serializationService.decode(doPutIfAbsent(entry1).getOldValue()));
+
+ protobufProtocolSerializer.serialize(
+ ProtobufRequestUtilities.createGetRequest(TEST_REGION, encodedKey),
+ socket.getOutputStream());
+ validateGetResponse(socket, protobufProtocolSerializer, testValue);
+
+ final BasicTypes.Entry entry2 = BasicTypes.Entry.newBuilder().setKey(encodedKey)
+ .setValue(serializationService.encode(testValue2)).build();
+
+ // same value still present
+ assertEquals(testValue, serializationService.decode(doPutIfAbsent(entry2).getOldValue()));
+ protobufProtocolSerializer.serialize(
+ ProtobufRequestUtilities.createGetRequest(TEST_REGION, encodedKey),
+ socket.getOutputStream());
+ validateGetResponse(socket, protobufProtocolSerializer, testValue);
+ }
+
+ /**
+ * This should fail because DataPolicy.NORMAL doesn't allow concurrent cache ops.
+ */
+ @Test
+ public void testPutIfAbsentRequestOnDataPolicyNormal() throws Exception {
+ doSetup(DataPolicy.NORMAL);
+
+ final BasicTypes.EncodedValue encodedKey = serializationService.encode(TEST_KEY);
+ final String testValue = "testValue";
+ final BasicTypes.EncodedValue encodedValue = serializationService.encode(testValue);
+ final BasicTypes.Entry entry =
+ BasicTypes.Entry.newBuilder().setKey(encodedKey).setValue(encodedValue).build();
+ ProtobufRequestUtilities.createPutIfAbsentRequest(TEST_REGION, entry)
+ .writeDelimitedTo(outputStream);
+
+ final ClientProtocol.Message response = ClientProtocol.Message.parseDelimitedFrom(inputStream);
+
+ assertEquals(ClientProtocol.Message.MessageTypeCase.ERRORRESPONSE,
+ response.getMessageTypeCase());
+ assertEquals(BasicTypes.ErrorCode.UNSUPPORTED_OPERATION,
+ response.getErrorResponse().getError().getErrorCode());
+ }
+
+ private RegionAPI.PutIfAbsentResponse doPutIfAbsent(BasicTypes.Entry entry)
+ throws IOException, InvalidProtocolMessageException {
+ final ClientProtocol.Message putIfAbsentRequest =
+ ProtobufRequestUtilities.createPutIfAbsentRequest(TEST_REGION, entry);
+
+ protobufProtocolSerializer.serialize(putIfAbsentRequest, outputStream);
+ ClientProtocol.Message response = protobufProtocolSerializer.deserialize(inputStream);
+
+ assertEquals(ClientProtocol.Message.MessageTypeCase.PUTIFABSENTRESPONSE,
+ response.getMessageTypeCase());
+ return response.getPutIfAbsentResponse();
+ }
+
+
+}
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandlerJUnitTest.java
new file mode 100644
index 0000000..6531f75
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutIfAbsentRequestOperationHandlerJUnitTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.internal.protocol.protobuf.v1.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.internal.protocol.TestExecutionContext;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.DecodingException;
+import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufUtilities;
+import org.apache.geode.internal.util.PasswordUtil;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+@SuppressWarnings("unchecked") // Region lacks generics when we look it up
+public class PutIfAbsentRequestOperationHandlerJUnitTest extends OperationHandlerJUnitTest {
+ private final String TEST_KEY = "my key";
+ private final String TEST_VALUE = "99";
+ private final String TEST_REGION = "test region";
+ private Region regionMock;
+ private PutIfAbsentRequestOperationHandler operationHandler;
+
+ @Before
+ public void setUp() throws Exception {
+ regionMock = mock(Region.class);
+ operationHandler = new PutIfAbsentRequestOperationHandler();
+ when(cacheStub.getRegion(TEST_REGION)).thenReturn(regionMock);
+ }
+
+ @Test
+ public void newEntrySucceeds() throws Exception {
+ when(regionMock.putIfAbsent(TEST_KEY, TEST_VALUE)).thenReturn(null);
+
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ generateTestRequest(), TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertNull(serializationService.decode(result1.getMessage().getOldValue()));
+
+ verify(regionMock).putIfAbsent(TEST_KEY, TEST_VALUE);
+ verify(regionMock, times(1)).putIfAbsent(any(), any());
+ }
+
+ @Test
+ public void existingEntryFails() throws Exception {
+ when(regionMock.putIfAbsent(TEST_KEY, TEST_VALUE)).thenReturn(1);
+
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ generateTestRequest(), TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertNotNull(serializationService.decode(result1.getMessage().getOldValue()));
+
+ verify(regionMock).putIfAbsent(TEST_KEY, TEST_VALUE);
+ verify(regionMock, times(1)).putIfAbsent(any(), any());
+ }
+
+ @Test
+ public void nullValuePassedThrough() throws Exception {
+ final RegionAPI.PutIfAbsentRequest request =
+ RegionAPI.PutIfAbsentRequest.newBuilder().setRegionName(TEST_REGION)
+ .setEntry(ProtobufUtilities.createEntry(serializationService, TEST_KEY, null)).build();
+
+ Result<RegionAPI.PutIfAbsentResponse> response = operationHandler.process(serializationService,
+ request, TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertNull(serializationService.decode(response.getMessage().getOldValue()));
+
+ verify(regionMock).putIfAbsent(TEST_KEY, null);
+ }
+
+ @Test
+ public void nullKeyPassedThrough() throws Exception {
+ final RegionAPI.PutIfAbsentRequest request = RegionAPI.PutIfAbsentRequest.newBuilder()
+ .setRegionName(TEST_REGION)
+ .setEntry(ProtobufUtilities.createEntry(serializationService, null, TEST_VALUE)).build();
+
+ Result<RegionAPI.PutIfAbsentResponse> response = operationHandler.process(serializationService,
+ request, TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertNull(serializationService.decode(response.getMessage().getOldValue()));
+
+ verify(regionMock).putIfAbsent(null, TEST_VALUE);
+ }
+
+ @Test
+ public void failsWithNoAuthCacheExecutionContext() throws Exception {
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ RegionAPI.PutIfAbsentRequest.newBuilder().build(),
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(BasicTypes.ErrorCode.SERVER_ERROR,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ @Test(expected = DecodingException.class)
+ public void unsetEntrythrowsDecodingException() throws Exception {
+ Result<RegionAPI.PutIfAbsentResponse> result1 =
+ operationHandler.process(serializationService, generateTestRequest(true, false),
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(BasicTypes.ErrorCode.INVALID_REQUEST,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ @Test
+ public void unsetRegionGetsServerError() throws Exception {
+ Result<RegionAPI.PutIfAbsentResponse> result1 =
+ operationHandler.process(serializationService, generateTestRequest(false, true),
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(BasicTypes.ErrorCode.SERVER_ERROR,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ @Test
+ public void nonexistingRegionReturnsServerError() throws Exception {
+ when(cacheStub.getRegion(TEST_REGION)).thenReturn(null);
+
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ generateTestRequest(), TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(BasicTypes.ErrorCode.SERVER_ERROR,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ /**
+ * Some regions (DataPolicy.NORMAL, for example) don't support concurrent ops such as putIfAbsent.
+ */
+ @Test(expected = UnsupportedOperationException.class)
+ public void unsupportedOperation() throws Exception {
+ when(regionMock.putIfAbsent(any(), any())).thenThrow(new UnsupportedOperationException());
+
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ generateTestRequest(), TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+ assertEquals(BasicTypes.ErrorCode.INVALID_REQUEST,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ @Test
+ public void invalidRegionReturnsInvalidRequestError() throws Exception {
+ // doesn't test which regions are invalid; those are documented under Cache.getRegion.
+ when(cacheStub.getRegion(any())).thenThrow(new IllegalArgumentException());
+
+ Result<RegionAPI.PutIfAbsentResponse> result1 = operationHandler.process(serializationService,
+ generateTestRequest(), TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+ assertEquals(BasicTypes.ErrorCode.INVALID_REQUEST,
+ result1.getErrorMessage().getError().getErrorCode());
+ }
+
+ private RegionAPI.PutIfAbsentRequest generateTestRequest(boolean includeRegion,
+ boolean includeEntry) throws EncodingException {
+ RegionAPI.PutIfAbsentRequest.Builder builder = RegionAPI.PutIfAbsentRequest.newBuilder();
+
+ if (includeRegion) {
+ builder.setRegionName(TEST_REGION);
+ }
+
+ if (includeEntry) {
+ BasicTypes.EncodedValue testKey = serializationService.encode(TEST_KEY);
+ BasicTypes.EncodedValue testValue = serializationService.encode(TEST_VALUE);
+ BasicTypes.Entry testEntry = ProtobufUtilities.createEntry(testKey, testValue);
+ builder.setEntry(testEntry);
+ }
+
+ return builder.build();
+ }
+
+ private RegionAPI.PutIfAbsentRequest generateTestRequest() throws EncodingException {
+ return generateTestRequest(true, true);
+ }
+}
--
To stop receiving notification emails like this one, please contact
gosullivan@apache.org.