diff --git a/src/main/java/io/tarantool/driver/api/MessagePackMapperBuilder.java b/src/main/java/io/tarantool/driver/api/MessagePackMapperBuilder.java index 7b1392a4..da8e13cb 100644 --- a/src/main/java/io/tarantool/driver/api/MessagePackMapperBuilder.java +++ b/src/main/java/io/tarantool/driver/api/MessagePackMapperBuilder.java @@ -7,6 +7,7 @@ import org.msgpack.value.Value; import org.msgpack.value.ValueType; +import java.util.Collection; import java.util.List; import java.util.Map; diff --git a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java index 1a7ec1a6..078014f1 100644 --- a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java +++ b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java @@ -285,11 +285,10 @@ public CompletableFuture> callForTupleResult( Supplier argumentsMapperSupplier, Class tupleClass) throws TarantoolClientException { - Supplier, SingleValueCallResult>>> - resultMapperSupplier = () -> - mapperFactoryFactory.getTarantoolResultMapper(config.getMessagePackMapper(), tupleClass); TarantoolRequestSignature signature = TarantoolRequestSignature.create( - functionName, arguments, tupleClass, argumentsMapperSupplier, resultMapperSupplier); + functionName, arguments, argumentsMapperSupplier, tupleClass); + Supplier, SingleValueCallResult>>> resultMapperSupplier = + () -> mapperFactoryFactory.getTarantoolResultMapper(config.getMessagePackMapper(), tupleClass); return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @@ -355,10 +354,10 @@ public CompletableFuture callForSingleResult( Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException { - Supplier>> resultMapperSupplier = () -> - mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass); TarantoolRequestSignature signature = TarantoolRequestSignature.create( - functionName, arguments, resultClass, argumentsMapperSupplier, resultMapperSupplier); + functionName, arguments, argumentsMapperSupplier, resultClass); + Supplier>> resultMapperSupplier = + () -> mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass); return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @@ -369,10 +368,10 @@ public CompletableFuture callForSingleResult( Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException { - Supplier>> resultMapperSupplier = () -> - mapperFactoryFactory.getSingleValueResultMapper(valueConverter); TarantoolRequestSignature signature = TarantoolRequestSignature.create( - functionName, arguments, valueConverter.getClass(), argumentsMapperSupplier, resultMapperSupplier); + functionName, arguments, argumentsMapperSupplier, valueConverter); + Supplier>> resultMapperSupplier = + () -> mapperFactoryFactory.getSingleValueResultMapper(valueConverter); return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @@ -464,10 +463,10 @@ public > CompletableFuture callForMultiResult( Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException { - Supplier>> resultMapperSupplier = () -> - mapperFactoryFactory.getDefaultMultiValueMapper(config.getMessagePackMapper(), resultClass); TarantoolRequestSignature signature = TarantoolRequestSignature.create( - functionName, arguments, resultClass, argumentsMapperSupplier, resultMapperSupplier); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, resultClass); + Supplier>> resultMapperSupplier = + () -> mapperFactoryFactory.getDefaultMultiValueMapper(config.getMessagePackMapper(), resultClass); return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @@ -479,10 +478,10 @@ public > CompletableFuture callForMultiResult( Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { - Supplier>> resultMapperSupplier = () -> - mapperFactoryFactory.getMultiValueResultMapper(resultContainerSupplier, valueConverter); TarantoolRequestSignature signature = TarantoolRequestSignature.create( - functionName, arguments, valueConverter.getClass(), argumentsMapperSupplier, resultMapperSupplier); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, valueConverter); + Supplier>> resultMapperSupplier = + () -> mapperFactoryFactory.getMultiValueResultMapper(resultContainerSupplier, valueConverter); return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @@ -591,7 +590,7 @@ public CompletableFuture> eval( Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolRequestSignature signature = TarantoolRequestSignature.create( - expression, arguments, List.class, argumentsMapperSupplier, resultMapperSupplier); + expression, arguments, argumentsMapperSupplier, resultMapperSupplier); MessagePackObjectMapper argumentsMapper = argumentsMapperCache.computeIfAbsent( signature, s -> argumentsMapperSupplier.get()); MessagePackValueMapper resultMapper = resultMapperCache.computeIfAbsent( diff --git a/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java b/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java index 62ab1470..1516013d 100644 --- a/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java +++ b/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java @@ -6,7 +6,6 @@ import org.msgpack.value.Value; import io.tarantool.driver.protocol.TarantoolRequest; -import io.tarantool.driver.protocol.TarantoolRequestSignature; /** * Intermediate request metadata holder diff --git a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java index 5700e328..742417e9 100644 --- a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java @@ -66,24 +66,32 @@ public TarantoolSpace( String spaceIdStr = String.valueOf(this.spaceId); methodSignatures.put( TarantoolDeleteRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolDeleteRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolDeleteRequest.class.getName())); methodSignatures.put( TarantoolInsertRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolInsertRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolInsertRequest.class.getName())); methodSignatures.put( TarantoolReplaceRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolReplaceRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolReplaceRequest.class.getName())); methodSignatures.put( TarantoolSelectRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolSelectRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolSelectRequest.class.getName())); methodSignatures.put( TarantoolUpdateRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolUpdateRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolUpdateRequest.class.getName())); methodSignatures.put( TarantoolUpsertRequest.class.getName(), - new TarantoolRequestSignature(spaceIdStr, TarantoolUpsertRequest.class.getName())); + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent(TarantoolUpsertRequest.class.getName())); methodSignatures.put( - "truncate", new TarantoolRequestSignature(spaceIdStr, "truncate", TarantoolCallRequest.class.getName())); + "truncate", + new TarantoolRequestSignature() + .addComponent(spaceIdStr).addComponent("truncate").addComponent(TarantoolCallRequest.class.getName())); } @Override diff --git a/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java index d22a2ecb..689d5f1c 100644 --- a/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java +++ b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java @@ -2,13 +2,15 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.function.Supplier; +import org.msgpack.value.Value; + import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.MessagePackValueMapper; +import io.tarantool.driver.mappers.converters.ValueConverter; /** * Represents a request signature, uniquely defining the operation and the @@ -18,11 +20,19 @@ * * @author Alexey Kuzin */ -public class TarantoolRequestSignature { +public final class TarantoolRequestSignature { - private List components = new LinkedList<>(); + private List components = new ArrayList<>(); private int hashCode = 1; + /** + * Constructor. + * + * Creates an empty signature - do not use it without providing the components! + */ + public TarantoolRequestSignature() { + } + /** * Constructor. * @@ -32,8 +42,11 @@ public class TarantoolRequestSignature { * * @param initialComponents initial signature components */ - public TarantoolRequestSignature(Object... initialComponents) { + private TarantoolRequestSignature(Object[] initialComponents) { for (Object component : initialComponents) { + if (component == null) { + continue; + } String componentValue = component instanceof String ? (String) component : component.getClass().getName(); components.add(componentValue); hashCode = 31 * hashCode + Objects.hashCode(componentValue); @@ -50,9 +63,11 @@ public TarantoolRequestSignature(Object... initialComponents) { * @return this signature object instance */ public TarantoolRequestSignature addComponent(Object component) { - String componentValue = component instanceof String ? (String) component : component.getClass().getName(); - components.add(componentValue); - hashCode = 31 * hashCode + Objects.hashCode(componentValue); + if (component != null) { + String componentValue = component instanceof String ? (String) component : component.getClass().getName(); + components.add(componentValue); + hashCode = 31 * hashCode + Objects.hashCode(componentValue); + } return this; } @@ -78,28 +93,107 @@ public String toString() { } /** - * Factory method for a typical RPC usage + * Factory method for building the common signature part * * @param functionName name of the remote function * @param arguments list of arguments for the remote function + * @param argumentsMapperSupplier arguments mapper supplier + * @return new request signature + */ + private static TarantoolRequestSignature create(String functionName, Collection arguments, + Supplier argumentsMapperSupplier) { + Object[] components = new Object[arguments.size() + 2]; + int i = 0; + components[i++] = functionName; + for (Object argument : arguments) { + components[i++] = argument.getClass().getName(); + } + components[i++] = Integer.toHexString(argumentsMapperSupplier.hashCode()); + return new TarantoolRequestSignature(components); + } + + /** + * Factory method for caching default result mapper suppliers + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function + * @param argumentsMapperSupplier arguments mapper supplier * @param resultClass type of the expected result. It's necessary * for polymorphic functions, e.g. accepting a * Tarantool space as an argument + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, Collection arguments, + Supplier argumentsMapperSupplier, Class resultClass) { + return TarantoolRequestSignature.create(functionName, arguments, argumentsMapperSupplier) + .addComponent(resultClass.getName()); + } + + /** + * Factory method for caching default result mapper suppliers + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function + * @param argumentsMapperSupplier arguments mapper supplier + * @param valueConverter single value result converter + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, Collection arguments, + Supplier argumentsMapperSupplier, + ValueConverter valueConverter) { + return TarantoolRequestSignature.create(functionName, arguments, argumentsMapperSupplier) + .addComponent(Integer.toHexString(valueConverter.hashCode())); + } + + /** + * Factory method for caching default multi value result mapper suppliers + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function + * @param argumentsMapperSupplier arguments mapper supplier + * @param resultContainerSupplier multi value result container supplier + * @param valueConverter multi value result container item converter + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, Collection arguments, + Supplier argumentsMapperSupplier, + Supplier resultContainerSupplier, ValueConverter valueConverter) { + return TarantoolRequestSignature.create(functionName, arguments, argumentsMapperSupplier) + .addComponent(Integer.toHexString(resultContainerSupplier.hashCode())) + .addComponent(Integer.toHexString(valueConverter.hashCode())); + } + + /** + * Factory method for caching default multi value result mapper suppliers + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function + * @param argumentsMapperSupplier arguments mapper supplier + * @param resultContainerSupplier multi value result container supplier + * @param resultClass multi value result item class + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, Collection arguments, + Supplier argumentsMapperSupplier, + Supplier resultContainerSupplier, Class resultClass) { + return TarantoolRequestSignature.create(functionName, arguments, argumentsMapperSupplier) + .addComponent(Integer.toHexString(resultContainerSupplier.hashCode())) + .addComponent(resultClass.getName()); + } + + /** + * Factory method for a typical RPC usage + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function * @param argumentsMapperSupplier arguments mapper supplier * @param resultMapperSupplier result mapper supplier * @return new request signature */ - public static TarantoolRequestSignature create(String functionName, Collection arguments, Class resultClass, + public static TarantoolRequestSignature create(String functionName, Collection arguments, Supplier argumentsMapperSupplier, Supplier resultMapperSupplier) { - List components = new ArrayList<>(arguments.size() + 4); - components.add(functionName); - for (Object argument : arguments) { - components.add(argument.getClass().getName()); - } - components.add(resultClass.getName()); - components.add(Integer.toHexString(argumentsMapperSupplier.hashCode())); - components.add(Integer.toHexString(resultMapperSupplier.hashCode())); - return new TarantoolRequestSignature(components.toArray(new Object[] {})); + return TarantoolRequestSignature.create(functionName, arguments, argumentsMapperSupplier) + .addComponent(Integer.toHexString(resultMapperSupplier.hashCode())); } } diff --git a/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java b/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java index affd29d7..1e812760 100644 --- a/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java +++ b/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java @@ -28,36 +28,36 @@ public void testEquals() { testCases.put( "empty and non-empty signatures should be not equal", new TarantoolRequestSignatureTestCase( - new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})), new TarantoolRequestSignature(), false )); testCases.put( "two signatures can be equal with different component contents", new TarantoolRequestSignatureTestCase( - new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})), - new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param three", 4})), + new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param three", 4})), true )); testCases.put( "two signatures with different String components should not be equal", new TarantoolRequestSignatureTestCase( - new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})), - new TarantoolRequestSignature( - "other_function", Arrays.asList(new Object[]{"param three", 4})), + new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature() + .addComponent("other_function").addComponent(Arrays.asList(new Object[]{"param three", 4})), false )); testCases.put( "two signatures should not be equal with different component order", new TarantoolRequestSignatureTestCase( - new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})), - new TarantoolRequestSignature( - Arrays.asList(new Object[]{"param three", 4}), "function"), + new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature() + .addComponent(Arrays.asList(new Object[]{"param three", 4})).addComponent("function"), false )); @@ -75,10 +75,10 @@ public void testEquals() { @Test public void testSignatureAddComponent() { - TarantoolRequestSignature signature = new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})); - TarantoolRequestSignature updatedSignature = new TarantoolRequestSignature( - "function", Arrays.asList(new Object[]{"param one", "param two"})); + TarantoolRequestSignature signature = new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})); + TarantoolRequestSignature updatedSignature = new TarantoolRequestSignature() + .addComponent("function").addComponent(Arrays.asList(new Object[]{"param one", "param two"})); updatedSignature.addComponent("one more parameter"); assertNotEquals(signature.hashCode(), updatedSignature.hashCode()); assertNotEquals(signature, updatedSignature, "updated signature should not be equal to the source");