From fc3d84b87c8e83b9bf7a5a2ddbecac8cead11cac Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 10 Jun 2016 21:32:19 +0300 Subject: [PATCH 01/14] Introduce command options for events and failures. Bumped version to `0.4.3-SNAPSHOT`. --- build.gradle | 2 +- .../proto/spine/command_annotations.proto | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 client/src/main/proto/spine/command_annotations.proto diff --git a/build.gradle b/build.gradle index 2ffd2f3cc7c..14ebe2708eb 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ allprojects { apply plugin: 'jacoco' group = 'org.spine3' - version = '0.4.2' + version = '0.4.3-SNAPSHOT' } project.ext { diff --git a/client/src/main/proto/spine/command_annotations.proto b/client/src/main/proto/spine/command_annotations.proto new file mode 100644 index 00000000000..dd3245c4933 --- /dev/null +++ b/client/src/main/proto/spine/command_annotations.proto @@ -0,0 +1,55 @@ +// +// Copyright 2016, TeamDev Ltd. All rights reserved. +// +// Redistribution and use in source and/or binary forms, with or without +// modification, must retain the above copyright notice and the following +// disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +syntax = "proto3"; + +// We do not define the package for this file to allow shorter options for user-defined types. +// This would allow to write: +// +// option (events) = "MyFirstEvent, MySecondEvent"; +// +// instead of: +// +// option (spine.annotations.events) = "MyFirstEvent, MySecondEvent"; +// + +option java_generate_equals_and_hash = false; +option java_multiple_files = true; +option java_outer_classname = "CommandAnnotationsProto"; +option java_package = "org.spine3.annotations"; + +import "google/protobuf/descriptor.proto"; + + +//TODO:2016-06-10:alexander.yevsyukov: Obtain globally unique field numbers for options from Google. + +extend google.protobuf.MessageOptions { + // Specifies Protobuf type names of the events that are produced after a command is handled. + // The type names should be separated with commas. Space characters are allowed. + // If the events are of the same aggregate with the command, non-qualified names can be used. + // Otherwise, please use fully qualified names. + string events = 59000; + + // Specifies Protobuf type names of the failures that can be returned to the attempt to handle + // a command if business conditions do not allow the command execution. + // The type names should be separated with commas. Space characters are allowed. + // If the failures are of the same aggregate with the command, non-qualified names can be used. + // Otherwise, please use fully qualified names. + string failures = 59001; +} \ No newline at end of file From b77a34503b131971d107122415bff33db5f2e78b Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 10 Jun 2016 21:44:26 +0300 Subject: [PATCH 02/14] Add Spine-generated sources to examples source set. --- examples/build.gradle | 8 ++++ .../failures/CannotCancelTaskInProgress.java | 41 ------------------- 2 files changed, 8 insertions(+), 41 deletions(-) delete mode 100644 examples/src/main/java/org/spine3/examples/failure/failures/CannotCancelTaskInProgress.java diff --git a/examples/build.gradle b/examples/build.gradle index 090830b0057..d8c8256f7d8 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -16,6 +16,14 @@ dependencies { compile project(path: ':server'); } +sourceSets { + main { + java { + srcDir "$projectDir/generated/main/spine" + } + } +} + protobuf { generateProtoTasks { all().each { final task -> diff --git a/examples/src/main/java/org/spine3/examples/failure/failures/CannotCancelTaskInProgress.java b/examples/src/main/java/org/spine3/examples/failure/failures/CannotCancelTaskInProgress.java deleted file mode 100644 index af7b1c8d9d4..00000000000 --- a/examples/src/main/java/org/spine3/examples/failure/failures/CannotCancelTaskInProgress.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016, TeamDev Ltd. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.spine3.examples.failure.failures; - -import org.spine3.examples.failure.TaskId; -import org.spine3.server.failure.FailureThrowable; - -/** - * @author Alexander Yevsyukov - */ -public class CannotCancelTaskInProgress extends FailureThrowable { - - private static final long serialVersionUID = 0L; - - public CannotCancelTaskInProgress(TaskId taskId) { - super(Failures.CannotCancelTaskInProgress.newBuilder().setId(taskId).build()); - } - - @Override - public Failures.CannotCancelTaskInProgress getFailure() { - return (Failures.CannotCancelTaskInProgress) super.getFailure(); - } -} From 07ab83fee0b46a98d200290f4714b5372aca0e73 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Sat, 11 Jun 2016 00:20:08 +0300 Subject: [PATCH 03/14] Move `FailureThrowable` to `org.spine3.base`. Expeptions are delivered via `io.grpc.Status` to client side. So even though that most likely `FailureThrowable` will be used mainly in aggregate code, the client side needs to have the generated failure classes for working with gRPC statuses. --- build.gradle | 2 +- .../org/spine3/base}/FailureThrowable.java | 3 +-- .../server/aggregate/AggregateRepository.java | 2 +- .../org/spine3/server/command/CommandBus.java | 2 +- .../spine3/server/command/CommandHandler.java | 2 +- .../server/command/CommandStatusService.java | 2 +- .../org/spine3/server/command/ProblemLog.java | 2 +- .../server/command/CommandBusShould.java | 2 +- .../ProcessManagerRepositoryShould.java | 4 +-- values/src/main/proto/spine/time/time.proto | 26 ++++++++++--------- 10 files changed, 24 insertions(+), 23 deletions(-) rename {server/src/main/java/org/spine3/server/failure => client/src/main/java/org/spine3/base}/FailureThrowable.java (97%) diff --git a/build.gradle b/build.gradle index 14ebe2708eb..2b5497bae32 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ project.ext { PROTOBUF_VERSION = '3.0.0-beta-3'; PROTOBUF_DEPENDENCY = "com.google.protobuf:protoc:${project.PROTOBUF_VERSION}"; MAVEN_REPOSITORY_URL = 'http://maven.teamdev.com/repository/spine'; - SPINE_PROTOBUF_PLUGIN_VERSION = "1.4.3" + SPINE_PROTOBUF_PLUGIN_VERSION = "1.4.4" GRPC_VERSION = '0.14.0' } diff --git a/server/src/main/java/org/spine3/server/failure/FailureThrowable.java b/client/src/main/java/org/spine3/base/FailureThrowable.java similarity index 97% rename from server/src/main/java/org/spine3/server/failure/FailureThrowable.java rename to client/src/main/java/org/spine3/base/FailureThrowable.java index f0ef6f92d92..427e359acb2 100644 --- a/server/src/main/java/org/spine3/server/failure/FailureThrowable.java +++ b/client/src/main/java/org/spine3/base/FailureThrowable.java @@ -18,14 +18,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.spine3.server.failure; +package org.spine3.base; import com.google.common.base.Throwables; import com.google.protobuf.Any; import com.google.protobuf.GeneratedMessage; import com.google.protobuf.Timestamp; import com.google.protobuf.util.TimeUtil; -import org.spine3.base.Failure; /** * Abstract base for throwable business failures. diff --git a/server/src/main/java/org/spine3/server/aggregate/AggregateRepository.java b/server/src/main/java/org/spine3/server/aggregate/AggregateRepository.java index 45f21218a1c..bb78ced563e 100644 --- a/server/src/main/java/org/spine3/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/org/spine3/server/aggregate/AggregateRepository.java @@ -25,13 +25,13 @@ import org.spine3.base.CommandId; import org.spine3.base.Errors; import org.spine3.base.Event; +import org.spine3.base.FailureThrowable; import org.spine3.server.BoundedContext; import org.spine3.server.command.CommandDispatcher; import org.spine3.server.command.CommandStatusService; import org.spine3.server.entity.GetTargetIdFromCommand; import org.spine3.server.entity.Repository; import org.spine3.server.event.EventBus; -import org.spine3.server.failure.FailureThrowable; import org.spine3.server.storage.AggregateEvents; import org.spine3.server.storage.AggregateStorage; import org.spine3.server.storage.Storage; diff --git a/server/src/main/java/org/spine3/server/command/CommandBus.java b/server/src/main/java/org/spine3/server/command/CommandBus.java index 18e34e621a3..b8bbb9b0e37 100644 --- a/server/src/main/java/org/spine3/server/command/CommandBus.java +++ b/server/src/main/java/org/spine3/server/command/CommandBus.java @@ -34,6 +34,7 @@ import org.spine3.base.CommandId; import org.spine3.base.Error; import org.spine3.base.Errors; +import org.spine3.base.FailureThrowable; import org.spine3.base.Response; import org.spine3.base.Responses; import org.spine3.server.BoundedContext; @@ -41,7 +42,6 @@ import org.spine3.server.command.error.CommandException; import org.spine3.server.command.error.InvalidCommandException; import org.spine3.server.command.error.UnsupportedCommandException; -import org.spine3.server.failure.FailureThrowable; import org.spine3.server.type.CommandClass; import org.spine3.server.users.CurrentTenant; import org.spine3.time.Interval; diff --git a/server/src/main/java/org/spine3/server/command/CommandHandler.java b/server/src/main/java/org/spine3/server/command/CommandHandler.java index 5466e97ca53..ac28b085827 100644 --- a/server/src/main/java/org/spine3/server/command/CommandHandler.java +++ b/server/src/main/java/org/spine3/server/command/CommandHandler.java @@ -31,9 +31,9 @@ import org.spine3.base.EventContext; import org.spine3.base.EventId; import org.spine3.base.Events; +import org.spine3.base.FailureThrowable; import org.spine3.server.entity.Entity; import org.spine3.server.event.EventBus; -import org.spine3.server.failure.FailureThrowable; import org.spine3.server.reflect.CommandHandlerMethod; import org.spine3.server.reflect.MethodRegistry; diff --git a/server/src/main/java/org/spine3/server/command/CommandStatusService.java b/server/src/main/java/org/spine3/server/command/CommandStatusService.java index 1e8e150f1cb..c4dfefcfa56 100644 --- a/server/src/main/java/org/spine3/server/command/CommandStatusService.java +++ b/server/src/main/java/org/spine3/server/command/CommandStatusService.java @@ -21,7 +21,7 @@ package org.spine3.server.command; import org.spine3.base.CommandId; -import org.spine3.server.failure.FailureThrowable; +import org.spine3.base.FailureThrowable; /** * The service for updating a status of a command. diff --git a/server/src/main/java/org/spine3/server/command/ProblemLog.java b/server/src/main/java/org/spine3/server/command/ProblemLog.java index a5ee3e1c581..ea1e09e5b2e 100644 --- a/server/src/main/java/org/spine3/server/command/ProblemLog.java +++ b/server/src/main/java/org/spine3/server/command/ProblemLog.java @@ -23,7 +23,7 @@ import com.google.protobuf.Message; import org.spine3.base.Command; import org.spine3.base.CommandId; -import org.spine3.server.failure.FailureThrowable; +import org.spine3.base.FailureThrowable; import static org.spine3.base.Commands.formatCommandTypeAndId; import static org.spine3.base.Commands.formatMessageTypeAndId; diff --git a/server/src/test/java/org/spine3/server/command/CommandBusShould.java b/server/src/test/java/org/spine3/server/command/CommandBusShould.java index 5186b24853f..c7015ea5ea3 100644 --- a/server/src/test/java/org/spine3/server/command/CommandBusShould.java +++ b/server/src/test/java/org/spine3/server/command/CommandBusShould.java @@ -35,6 +35,7 @@ import org.spine3.base.CommandValidationError; import org.spine3.base.Error; import org.spine3.base.Errors; +import org.spine3.base.FailureThrowable; import org.spine3.base.Response; import org.spine3.base.Responses; import org.spine3.client.CommandFactory; @@ -44,7 +45,6 @@ import org.spine3.server.command.error.InvalidCommandException; import org.spine3.server.command.error.UnsupportedCommandException; import org.spine3.server.event.EventBus; -import org.spine3.server.failure.FailureThrowable; import org.spine3.server.storage.memory.InMemoryStorageFactory; import org.spine3.server.type.CommandClass; import org.spine3.server.users.CurrentTenant; diff --git a/server/src/test/java/org/spine3/server/procman/ProcessManagerRepositoryShould.java b/server/src/test/java/org/spine3/server/procman/ProcessManagerRepositoryShould.java index a542f81a6a1..f9b6898a2ea 100644 --- a/server/src/test/java/org/spine3/server/procman/ProcessManagerRepositoryShould.java +++ b/server/src/test/java/org/spine3/server/procman/ProcessManagerRepositoryShould.java @@ -34,6 +34,7 @@ import org.spine3.base.Event; import org.spine3.base.EventContext; import org.spine3.base.Events; +import org.spine3.base.FailureThrowable; import org.spine3.server.BoundedContext; import org.spine3.server.BoundedContextTestStubs; import org.spine3.server.command.Assign; @@ -41,7 +42,6 @@ import org.spine3.server.entity.IdFunction; import org.spine3.server.event.GetProducerIdFromEvent; import org.spine3.server.event.Subscribe; -import org.spine3.server.failure.FailureThrowable; import org.spine3.server.storage.memory.InMemoryStorageFactory; import org.spine3.server.type.CommandClass; import org.spine3.server.type.EventClass; @@ -64,8 +64,8 @@ import static org.mockito.Mockito.verify; import static org.spine3.protobuf.Messages.fromAny; import static org.spine3.testdata.TestAggregateIdFactory.newProjectId; -import static org.spine3.testdata.TestCommands.*; import static org.spine3.testdata.TestCommandContextFactory.createCommandContext; +import static org.spine3.testdata.TestCommands.*; import static org.spine3.testdata.TestEventMessageFactory.*; /** diff --git a/values/src/main/proto/spine/time/time.proto b/values/src/main/proto/spine/time/time.proto index aad103a8c90..5aaaa7f1f7f 100644 --- a/values/src/main/proto/spine/time/time.proto +++ b/values/src/main/proto/spine/time/time.proto @@ -26,6 +26,8 @@ option java_multiple_files = true; option java_outer_classname = "TimeProto"; option java_package = "org.spine3.time"; +import "spine/validate.proto"; + import "spine/time/zone_offset.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; @@ -51,17 +53,17 @@ enum MonthOfYear { // // Use this message for describing a date (e.g. a birthday). message LocalDate { - int32 year = 1; - MonthOfYear month = 2; - int32 day = 3; + int32 year = 1 [(required).value = true]; + MonthOfYear month = 2 [(required).value = true]; + int32 day = 3 [(required).value = true]; } // A time without time-zone. // // It is a description of a time, not an instant on a time-line. message LocalTime { - int32 hours = 1; - int32 minutes = 2; + int32 hours = 1 [(required).value = true]; + int32 minutes = 2 [(required).value = true]; int32 seconds = 3; int32 millis = 4; int64 nanos = 5; @@ -69,21 +71,21 @@ message LocalTime { // A time with an offset from UTC. message OffsetTime { - LocalTime time = 1; - ZoneOffset offset = 2; + LocalTime time = 1 [(required).value = true]; + ZoneOffset offset = 2 [(required).value = true]; } // A date with an offset from UTC. message OffsetDate { - LocalDate date = 1; - ZoneOffset offset = 2; + LocalDate date = 1 [(required).value = true]; + ZoneOffset offset = 2 [(required).value = true]; } // A date-time with an offset from UTC. message OffsetDateTime { - LocalDate date = 1; - LocalTime time = 2; - ZoneOffset offset = 3; + LocalDate date = 1 [(required).value = true]; + LocalTime time = 2; // A time field is optional for more flexibility. + ZoneOffset offset = 3 [(required).value = true]; } // An interval between two points in time. From e9be3e2dbf4d3ad17491ac58de5bb3b0adac4033 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Sun, 12 Jun 2016 02:16:47 +0300 Subject: [PATCH 04/14] Add documentation in the example of using failures. Increment version to 0.4.4 because of strange problems with publishing. We're advancing features anyway. --- build.gradle | 2 +- .../src/main/proto/spine_examples/failure/failures.proto | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2b5497bae32..9a080eebfb8 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ allprojects { apply plugin: 'jacoco' group = 'org.spine3' - version = '0.4.3-SNAPSHOT' + version = '0.4.4-SNAPSHOT' } project.ext { diff --git a/examples/src/main/proto/spine_examples/failure/failures.proto b/examples/src/main/proto/spine_examples/failure/failures.proto index 0b2d5b231fd..12cf273cacd 100644 --- a/examples/src/main/proto/spine_examples/failure/failures.proto +++ b/examples/src/main/proto/spine_examples/failure/failures.proto @@ -22,7 +22,12 @@ package spine_examples.failure; option java_package="org.spine3.examples.failure.failures"; option java_multiple_files = false; -// Do not specify java_outer_classname option as we're not generating multiple Java classes for failures. + +// Do not specify `java_outer_classname` option as we're not generating multiple Java classes for failures. +// All failure messages will be generated as sub-classes of the Failure class by Protobuf compiler. +// Then Spine Perotobuf Gradle plugin for Java will generate `FailureThrowable` classes for these messages. +// See `org.spine3.examples.failure.TaskAggregate` for using failure throwables in an aggregate. + option java_generate_equals_and_hash = true; import "spine_examples/failure/task.proto"; From 1460e64d06ce42c414cdf2eb35f3d07cf8903f1d Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Mon, 13 Jun 2016 02:34:20 +0300 Subject: [PATCH 05/14] Add licence tag. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94b0832406c..470767a1623 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # core-java -The Java implementation of the framework core. [![codecov.io](https://codecov.io/github/SpineEventEngine/core-java/coverage.svg?branch=master)](https://codecov.io/github/SpineEventEngine/core-java?branch=master) +[![license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) + +The Java implementation of the framework core. From 21c8f6c8e86198f9a533ef2d26fc6a0c8abd4dfe Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Mon, 13 Jun 2016 04:37:29 +0300 Subject: [PATCH 06/14] Introduce `ValueMismatch`. --- .../main/java/org/spine3/base/Mismatch.java | 62 +++++++++++++++++++ .../main/java/org/spine3/protobuf/Values.java | 43 +++++++++++++ .../src/main/proto/spine/base/failure.proto | 18 ++++++ 3 files changed, 123 insertions(+) create mode 100644 client/src/main/java/org/spine3/base/Mismatch.java diff --git a/client/src/main/java/org/spine3/base/Mismatch.java b/client/src/main/java/org/spine3/base/Mismatch.java new file mode 100644 index 00000000000..c894436feca --- /dev/null +++ b/client/src/main/java/org/spine3/base/Mismatch.java @@ -0,0 +1,62 @@ +/* + * Copyright 2016, TeamDev Ltd. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.spine3.base; + +import javax.annotation.Nullable; + +import static org.spine3.protobuf.Values.pack; + + +/** + * Factories for constructing {@link ValueMismatch} instances for different types of attributes. + */ +public class Mismatch { + + private Mismatch() {} + + /** + * Creates a {@link ValueMismatch} instance for a string attribute. + * + * @param expected the value expected by a command, or {@code null} if the command expects not populated field + * @param found the value found in an entity, or {@code null} if the value is not set + * @param requested the value requested as new one in the original command + * @param version the current version of the entity + * @return info on the mismatch + */ + public static ValueMismatch of(@Nullable String expected, @Nullable String found, String requested, int version) { + final ValueMismatch.Builder builder = ValueMismatch.newBuilder(); + if (expected != null) { + builder.setExpected(pack(expected)); + } + + if (found != null) { + builder.setActual(pack(found)); + } + + builder.setRequested(pack(requested)); + builder.setVersion(version); + + return builder.build(); + } + + //TODO:2016-06-13:alexander.yevsyukov: Add versions for other values including Message. + //TODO:2016-06-13:alexander.yevsyukov: Add tests. +} diff --git a/client/src/main/java/org/spine3/protobuf/Values.java b/client/src/main/java/org/spine3/protobuf/Values.java index ef3b223cdd8..8dc54a32c70 100644 --- a/client/src/main/java/org/spine3/protobuf/Values.java +++ b/client/src/main/java/org/spine3/protobuf/Values.java @@ -19,6 +19,7 @@ */ package org.spine3.protobuf; +import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.DoubleValue; import com.google.protobuf.FloatValue; @@ -49,6 +50,13 @@ public static StringValue newStringValue(String value) { return result; } + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(String value) { + return Any.pack(newStringValue(value)); + } + /** * Creates a new DoubleValue wrapping the passed number. * @@ -62,6 +70,13 @@ public static DoubleValue newDoubleValue(double value) { return result; } + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(double value) { + return Any.pack(newDoubleValue(value)); + } + /** * Creates a new FloatValue wrapping the passed number. * @@ -75,6 +90,13 @@ public static FloatValue newFloatValue(float value) { return result; } + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(float value) { + return Any.pack(newFloatValue(value)); + } + /** * Creates a new Int32Value wrapping the passed number. * @@ -88,6 +110,13 @@ public static Int32Value newIntegerValue(int value) { return result; } + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(int value) { + return Any.pack(newIntegerValue(value)); + } + /** * Creates a new Int64Value wrapping the passed number. * @@ -101,6 +130,13 @@ public static Int64Value newLongValue(long value) { return result; } + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(long value) { + return Any.pack(newLongValue(value)); + } + /** * Creates a new BoolValue wrapping the passed value. * @@ -113,4 +149,11 @@ public static BoolValue newBoolValue(boolean value) { .build(); return result; } + + /** + * Packs the passed value in to {@link Any}. + */ + public static Any pack(boolean value) { + return Any.pack(newBoolValue(value)); + } } diff --git a/client/src/main/proto/spine/base/failure.proto b/client/src/main/proto/spine/base/failure.proto index 2be5ff2ad5e..7a3e402b7d1 100644 --- a/client/src/main/proto/spine/base/failure.proto +++ b/client/src/main/proto/spine/base/failure.proto @@ -50,3 +50,21 @@ message Failure { // Additional information on the failure. map attributes = 4; } + +// A failure to handle a command because an entity contains a value different than requested in a command. +message ValueMismatch { + // An expected value. + // This field is not populated if the command expects to initialize the attribute. + google.protobuf.Any expected = 1; + + // An actual value in the entity. + // This field is not populated if the entity does not have the attribute set. + google.protobuf.Any actual = 2; + + // An optional attribute that may contain a value requested as the replacement + // for the `expected` value in the failed command. + google.protobuf.Any requested = 3; + + // A version of the entity, which generated the failure. + int32 version = 4; +} \ No newline at end of file From 9b29015bd77b538af339d81d6f2c5639413e8270 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Mon, 13 Jun 2016 11:55:47 +0300 Subject: [PATCH 07/14] Fix Javadocs in `Values`. --- .../main/java/org/spine3/protobuf/Values.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/client/src/main/java/org/spine3/protobuf/Values.java b/client/src/main/java/org/spine3/protobuf/Values.java index 8dc54a32c70..baeaadc3b70 100644 --- a/client/src/main/java/org/spine3/protobuf/Values.java +++ b/client/src/main/java/org/spine3/protobuf/Values.java @@ -38,7 +38,7 @@ public class Values { private Values() {} /** - * Creates a new StringValue wrapping the passed string. + * Creates a new {@code StringValue} wrapping the passed string. * * @param value the value to wrap * @return a new StringValue instance @@ -51,14 +51,14 @@ public static StringValue newStringValue(String value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(String value) { return Any.pack(newStringValue(value)); } /** - * Creates a new DoubleValue wrapping the passed number. + * Creates a new {@code DoubleValue} wrapping the passed number. * * @param value the value to wrap * @return a new DoubleValue instance @@ -71,14 +71,14 @@ public static DoubleValue newDoubleValue(double value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(double value) { return Any.pack(newDoubleValue(value)); } /** - * Creates a new FloatValue wrapping the passed number. + * Creates a new {@code FloatValue} wrapping the passed number. * * @param value the value to wrap * @return a new FloatValue instance @@ -91,14 +91,14 @@ public static FloatValue newFloatValue(float value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(float value) { return Any.pack(newFloatValue(value)); } /** - * Creates a new Int32Value wrapping the passed number. + * Creates a new {@code Int32Value} wrapping the passed number. * * @param value the value to wrap * @return a new Int32Value instance @@ -111,14 +111,14 @@ public static Int32Value newIntegerValue(int value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(int value) { return Any.pack(newIntegerValue(value)); } /** - * Creates a new Int64Value wrapping the passed number. + * Creates a new {@code Int64Value} wrapping the passed number. * * @param value the value to wrap * @return a new Int64Value instance @@ -131,14 +131,14 @@ public static Int64Value newLongValue(long value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(long value) { return Any.pack(newLongValue(value)); } /** - * Creates a new BoolValue wrapping the passed value. + * Creates a new {@code BoolValue} wrapping the passed value. * * @param value the value to wrap * @return a new BoolValue instance @@ -151,7 +151,7 @@ public static BoolValue newBoolValue(boolean value) { } /** - * Packs the passed value in to {@link Any}. + * Packs the passed value into {@link Any}. */ public static Any pack(boolean value) { return Any.pack(newBoolValue(value)); From 0a8940168fb57ecb7bcdf510abba180b413f8866 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Mon, 13 Jun 2016 11:59:06 +0300 Subject: [PATCH 08/14] Have `result` variables in all `Values.pack()`. To follow our Code Style convention. --- .../main/java/org/spine3/protobuf/Values.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/client/src/main/java/org/spine3/protobuf/Values.java b/client/src/main/java/org/spine3/protobuf/Values.java index baeaadc3b70..41a2d8cb33b 100644 --- a/client/src/main/java/org/spine3/protobuf/Values.java +++ b/client/src/main/java/org/spine3/protobuf/Values.java @@ -54,7 +54,8 @@ public static StringValue newStringValue(String value) { * Packs the passed value into {@link Any}. */ public static Any pack(String value) { - return Any.pack(newStringValue(value)); + final Any result = Any.pack(newStringValue(value)); + return result; } /** @@ -74,7 +75,8 @@ public static DoubleValue newDoubleValue(double value) { * Packs the passed value into {@link Any}. */ public static Any pack(double value) { - return Any.pack(newDoubleValue(value)); + final Any result = Any.pack(newDoubleValue(value)); + return result; } /** @@ -94,7 +96,8 @@ public static FloatValue newFloatValue(float value) { * Packs the passed value into {@link Any}. */ public static Any pack(float value) { - return Any.pack(newFloatValue(value)); + final Any result = Any.pack(newFloatValue(value)); + return result; } /** @@ -114,7 +117,8 @@ public static Int32Value newIntegerValue(int value) { * Packs the passed value into {@link Any}. */ public static Any pack(int value) { - return Any.pack(newIntegerValue(value)); + final Any result = Any.pack(newIntegerValue(value)); + return result; } /** @@ -134,7 +138,8 @@ public static Int64Value newLongValue(long value) { * Packs the passed value into {@link Any}. */ public static Any pack(long value) { - return Any.pack(newLongValue(value)); + final Any result = Any.pack(newLongValue(value)); + return result; } /** @@ -154,6 +159,7 @@ public static BoolValue newBoolValue(boolean value) { * Packs the passed value into {@link Any}. */ public static Any pack(boolean value) { - return Any.pack(newBoolValue(value)); + final Any result = Any.pack(newBoolValue(value)); + return result; } } From f35fa7a5e8dbbf924080d5fd949619ae7b13007a Mon Sep 17 00:00:00 2001 From: "andrey.lavrov" Date: Mon, 13 Jun 2016 13:26:50 +0300 Subject: [PATCH 09/14] Added tests for Mismatch with String params. --- .idea/codeStyleSettings.xml | 3 + .idea/inspectionProfiles/Project_Default.xml | 1 - .../java/org/spine3/base/MismatchShould.java | 65 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 client/src/test/java/org/spine3/base/MismatchShould.java diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index 258e4a12c25..ac430e1e003 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -4,6 +4,9 @@