From 7cd98b3694d1abf9fa5eaa52987ff6a10a477a2c Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 10:49:49 +0300 Subject: [PATCH 01/43] Backtick ID in diag message --- server/src/main/java/io/spine/server/entity/Repository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index 1aad04a8931..c7f44b85680 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -423,7 +423,7 @@ public E next() { Optional loaded = repository.find(id); if (!loaded.isPresent()) { String idStr = Identifier.toString(id); - throw newIllegalStateException("Unable to load entity with ID: %s", idStr); + throw newIllegalStateException("Unable to load entity with ID: `%s`.", idStr); } E entity = loaded.get(); From f5a37a5eb015c23628ce8f53c810186ceb5485d2 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 11:18:39 +0300 Subject: [PATCH 02/43] Annotate methods that must be called --- .../io/spine/server/aggregate/AggregatePartRepository.java | 3 ++- .../java/io/spine/server/aggregate/AggregateRepository.java | 2 ++ .../io/spine/server/entity/DefaultRecordBasedRepository.java | 2 +- .../io/spine/server/entity/EventDispatchingRepository.java | 2 ++ .../java/io/spine/server/procman/ProcessManagerRepository.java | 2 ++ .../java/io/spine/server/projection/ProjectionRepository.java | 1 + 6 files changed, 10 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java index 0b42ff3b8b3..d4b96a25411 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java @@ -20,6 +20,7 @@ package io.spine.server.aggregate; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.annotation.Internal; import io.spine.server.aggregate.model.AggregatePartClass; @@ -48,6 +49,7 @@ protected AggregatePartRepository() { } @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); boundedContext().aggregateRootDirectory() @@ -71,7 +73,6 @@ AggregatePartClass aggregatePartClass() { return (AggregatePartClass) entityModelClass(); } - //TODO:2017-06-06:alexander.yevsyukov: Cache aggregate roots shared among part repositories private AggregateRoot createAggregateRoot(I id) { AggregateRoot result = aggregatePartClass().createRoot(boundedContext(), id); return result; diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 285f7d344fa..4a410783572 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets.SetView; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.core.CommandId; import io.spine.core.Event; import io.spine.server.BoundedContext; @@ -117,6 +118,7 @@ protected AggregateRepository() { * */ @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { checkNotVoid(); diff --git a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java index 8dd685398f2..6bc3e65c23e 100644 --- a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java +++ b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java @@ -70,8 +70,8 @@ protected StorageConverter storageConverter() { * *

Performs validation of the entity class and initializes the storage converter. */ - @OverridingMethodsMustInvokeSuper @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); storageConverter(); diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 6bbcfbf1ff2..3924bcaf261 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -20,6 +20,7 @@ package io.spine.server.entity; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Message; import io.spine.base.EventMessage; import io.spine.core.Event; @@ -71,6 +72,7 @@ protected final EventRouting eventRouting() { * Registers} itself with the {@code EventBus} of the parent {@code BoundedContext}. */ @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); boundedContext().registerEventDispatcher(this); diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index f643ad35527..16acab15411 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Message; import io.spine.annotation.Internal; import io.spine.core.Event; @@ -135,6 +136,7 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { *

Throws an {@code IllegalStateException} otherwise. */ @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index e117a281a55..3fec8a4d289 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -114,6 +114,7 @@ public P create(I id) { * by the class of the projection. Throws an {@code IllegalStateException} otherwise. */ @Override + @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); ensureDispatchesEvents(); From 11ca2339df87068ec0980b96152ea546a84cda9d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 12:01:11 +0300 Subject: [PATCH 03/43] Make class final --- .../main/java/io/spine/server/entity/IncrementFromEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/io/spine/server/entity/IncrementFromEvent.java b/server/src/main/java/io/spine/server/entity/IncrementFromEvent.java index 4d4ba31cdb9..93d3871cebf 100644 --- a/server/src/main/java/io/spine/server/entity/IncrementFromEvent.java +++ b/server/src/main/java/io/spine/server/entity/IncrementFromEvent.java @@ -36,7 +36,7 @@ * current version of an {@code Aggregate} is the version of the last applied event. */ @Internal -public class IncrementFromEvent extends VersionIncrement { +public final class IncrementFromEvent extends VersionIncrement { private final EventEnvelope event; From 44ca29922ed41c191f75c9dd4d617c8d7b80a771 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 12:01:36 +0300 Subject: [PATCH 04/43] Fix Javadoc layout --- .../io/spine/server/bus/MessageDispatcher.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/io/spine/server/bus/MessageDispatcher.java b/server/src/main/java/io/spine/server/bus/MessageDispatcher.java index b689ab2dc14..3677379e091 100644 --- a/server/src/main/java/io/spine/server/bus/MessageDispatcher.java +++ b/server/src/main/java/io/spine/server/bus/MessageDispatcher.java @@ -29,13 +29,16 @@ /** * A dispatcher of a message. * - * @param the type of class of the dispatched messages - * @param the type of the message envelopes - * @param the type of the result of the {@linkplain #dispatch(MessageEnvelope) dispatching - * function}. For {@linkplain UnicastDispatcher unicast dispatching} is the type of - * the IDs of entity that receives a dispatched message. - * For {@linkplain MulticastDispatcher multicast dispatching} is the type of the set - * of entity IDs. + * @param + * the type of class of the dispatched messages + * @param + * the type of the message envelopes + * @param + * the type of the result of the {@linkplain #dispatch(MessageEnvelope) dispatching + * function}. For {@linkplain UnicastDispatcher unicast dispatching} is the type of + * the IDs of entity that receives a dispatched message. + * For {@linkplain MulticastDispatcher multicast dispatching} is the type of the set + * of entity IDs. */ public interface MessageDispatcher { From 647bffa978e26336b4b3a074a4f844a5acd2cc76 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 12:02:28 +0300 Subject: [PATCH 05/43] Introduce `DispatchingRepository` --- .../java/io/spine/server/BoundedContext.java | 33 +++++++++++------ .../server/entity/DispatchingRepository.java | 37 +++++++++++++++++++ .../entity/EventDispatchingRepository.java | 7 +++- 3 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 server/src/main/java/io/spine/server/entity/DispatchingRepository.java diff --git a/server/src/main/java/io/spine/server/BoundedContext.java b/server/src/main/java/io/spine/server/BoundedContext.java index 01f08ea24b2..65d4c67d050 100644 --- a/server/src/main/java/io/spine/server/BoundedContext.java +++ b/server/src/main/java/io/spine/server/BoundedContext.java @@ -33,6 +33,7 @@ import io.spine.server.commandbus.CommandDispatcher; import io.spine.server.commandbus.CommandDispatcherDelegate; import io.spine.server.commandbus.DelegatingCommandDispatcher; +import io.spine.server.entity.DispatchingRepository; import io.spine.server.entity.Entity; import io.spine.server.entity.Repository; import io.spine.server.entity.VisibilityGuard; @@ -165,10 +166,12 @@ private static CommandBus buildCommandBus(BoundedContextBuilder builder, EventBu /** * Creates a new instance of {@link IntegrationBus} with the given parameters. * - * @param builder the {@link BoundedContextBuilder} to obtain - * the {@link IntegrationBus.Builder} from - * @param eventBus the initialized {@link EventBus} - * @param name the name of the constructed Bounded Context + * @param builder + * the {@link BoundedContextBuilder} to obtain the {@link IntegrationBus.Builder} from + * @param eventBus + * the initialized {@link EventBus} + * @param name + * the name of the constructed Bounded Context * @return new instance of {@link IntegrationBus} */ private static IntegrationBus buildIntegrationBus(BoundedContextBuilder builder, @@ -219,6 +222,10 @@ public static BoundedContextBuilder newBuilder() { repository.setBoundedContext(this); guard.register(repository); repository.onRegistered(); + if (repository instanceof DispatchingRepository) { + DispatchingRepository dr = (DispatchingRepository) repository; + dr.validateRouting(); + } registerEventDispatcher(stand()); } @@ -270,10 +277,13 @@ private void registerWithIntegrationBus(ExternalDispatcherFactory dispatcher) } /** - * Registers the passed event dispatcher with the {@code EventBus} of - * this {@code BoundedContext}, if it dispatches domestic events. + * Registers the passed event dispatcher with the buses of this {@code BoundedContext}. + * + *

If the passed instance dispatches domestic events, registers it with the {@code EventBus}. * If the passed instance dispatches external events, registers it with * the {@code IntegrationBus}. + * + * @see #registerEventDispatcher(EventDispatcherDelegate) */ public void registerEventDispatcher(EventDispatcher dispatcher) { checkNotNull(dispatcher); @@ -288,10 +298,10 @@ public void registerEventDispatcher(EventDispatcher dispatcher) { } /** - * Registers the passed event dispatcher with the {@code EventBus} of - * this {@code BoundedContext}, if it dispatchers domestic events. - * If the passed instance dispatches external events, registers it with - * the {@code IntegrationBus}. + * Registers the passed delegate of an {@link EventDispatcher} with the buses of this + * {@code BoundedContext}. + * + * @see #registerEventDispatcher(EventDispatcher) */ public void registerEventDispatcher(EventDispatcherDelegate dispatcher) { checkNotNull(dispatcher); @@ -305,7 +315,8 @@ public void registerEventDispatcher(EventDispatcherDelegate dispatcher) { */ private static Supplier notExternalDispatcherFrom(Object dispatcher) { - return () -> newIllegalStateException("No external dispatcher provided by %s", dispatcher); + return () -> newIllegalStateException( + "No external dispatcher provided by `%s`.", dispatcher); } /** diff --git a/server/src/main/java/io/spine/server/entity/DispatchingRepository.java b/server/src/main/java/io/spine/server/entity/DispatchingRepository.java new file mode 100644 index 00000000000..84a18d24c78 --- /dev/null +++ b/server/src/main/java/io/spine/server/entity/DispatchingRepository.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.entity; + +/** + * The interface common to {@linkplain Repository repositories} that dispatch messages to + * its entities. + */ +public interface DispatchingRepository { + + /** + * Validates routing schema for types of messages that this repository dispatches + * to its entities. + * + * @throws IllegalStateException + * if a message type cannot be dispatched + */ + void validateRouting() throws IllegalStateException; +} diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 3924bcaf261..7e11af79cbe 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -43,7 +43,7 @@ public abstract class EventDispatchingRepository, S extends Message> extends DefaultRecordBasedRepository - implements EventDispatcher { + implements DispatchingRepository, EventDispatcher { private final EventRouting eventRouting; @@ -65,6 +65,11 @@ protected final EventRouting eventRouting() { return eventRouting; } + @Override + public final void validateRouting() throws IllegalStateException { + //TODO:2019-05-13:alexander.yevsyukov: Implement + } + /** * {@inheritDoc} * From a35c16b337454ccae90ab042d77e82f1308bdf0d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 13:04:31 +0300 Subject: [PATCH 06/43] Allow state dispatching only to projections --- .../java/io/spine/server/BoundedContext.java | 8 ++-- .../server/entity/DispatchingRepository.java | 37 ------------------- .../entity/EventDispatchingRepository.java | 7 +--- .../entity/model/StateSubscribingClass.java | 10 +++++ .../model/EventReceivingClassDelegate.java | 2 +- .../event/model/StateSubscriberMethod.java | 14 +++---- .../projection/ProjectionRepository.java | 14 +++++++ .../projection/model/ProjectionClass.java | 20 +++++----- .../server/route/StateUpdateRouting.java | 6 ++- 9 files changed, 52 insertions(+), 66 deletions(-) delete mode 100644 server/src/main/java/io/spine/server/entity/DispatchingRepository.java diff --git a/server/src/main/java/io/spine/server/BoundedContext.java b/server/src/main/java/io/spine/server/BoundedContext.java index 65d4c67d050..443916fb27c 100644 --- a/server/src/main/java/io/spine/server/BoundedContext.java +++ b/server/src/main/java/io/spine/server/BoundedContext.java @@ -33,7 +33,6 @@ import io.spine.server.commandbus.CommandDispatcher; import io.spine.server.commandbus.CommandDispatcherDelegate; import io.spine.server.commandbus.DelegatingCommandDispatcher; -import io.spine.server.entity.DispatchingRepository; import io.spine.server.entity.Entity; import io.spine.server.entity.Repository; import io.spine.server.entity.VisibilityGuard; @@ -46,6 +45,7 @@ import io.spine.server.integration.ExternalDispatcherFactory; import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.IntegrationBus; +import io.spine.server.projection.ProjectionRepository; import io.spine.server.stand.Stand; import io.spine.server.storage.StorageFactory; import io.spine.server.tenant.TenantIndex; @@ -222,9 +222,9 @@ public static BoundedContextBuilder newBuilder() { repository.setBoundedContext(this); guard.register(repository); repository.onRegistered(); - if (repository instanceof DispatchingRepository) { - DispatchingRepository dr = (DispatchingRepository) repository; - dr.validateRouting(); + if (repository instanceof ProjectionRepository) { + ProjectionRepository pr = (ProjectionRepository) repository; + pr.validateStateRouting(); } registerEventDispatcher(stand()); } diff --git a/server/src/main/java/io/spine/server/entity/DispatchingRepository.java b/server/src/main/java/io/spine/server/entity/DispatchingRepository.java deleted file mode 100644 index 84a18d24c78..00000000000 --- a/server/src/main/java/io/spine/server/entity/DispatchingRepository.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.entity; - -/** - * The interface common to {@linkplain Repository repositories} that dispatch messages to - * its entities. - */ -public interface DispatchingRepository { - - /** - * Validates routing schema for types of messages that this repository dispatches - * to its entities. - * - * @throws IllegalStateException - * if a message type cannot be dispatched - */ - void validateRouting() throws IllegalStateException; -} diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 7e11af79cbe..3924bcaf261 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -43,7 +43,7 @@ public abstract class EventDispatchingRepository, S extends Message> extends DefaultRecordBasedRepository - implements DispatchingRepository, EventDispatcher { + implements EventDispatcher { private final EventRouting eventRouting; @@ -65,11 +65,6 @@ protected final EventRouting eventRouting() { return eventRouting; } - @Override - public final void validateRouting() throws IllegalStateException { - //TODO:2019-05-13:alexander.yevsyukov: Implement - } - /** * {@inheritDoc} * diff --git a/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java b/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java index f9063d11e82..4d90594a2e1 100644 --- a/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java +++ b/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java @@ -39,4 +39,14 @@ public interface StateSubscribingClass { * Obtains external entity states to which the class is subscribed. */ Set externalStates(); + + /** + * Verifies if this class is {@linkplain io.spine.core.Subscribe subscribed} to updates of + * entity states either domestic or external. + */ + default boolean subscribesToStates() { + boolean dispatchesDomestic = !domesticStates().isEmpty(); + boolean dispatchesExternal = !externalStates().isEmpty(); + return dispatchesDomestic || dispatchesExternal; + } } diff --git a/server/src/main/java/io/spine/server/event/model/EventReceivingClassDelegate.java b/server/src/main/java/io/spine/server/event/model/EventReceivingClassDelegate.java index 8d9358d2efb..b2fdae954d0 100644 --- a/server/src/main/java/io/spine/server/event/model/EventReceivingClassDelegate.java +++ b/server/src/main/java/io/spine/server/event/model/EventReceivingClassDelegate.java @@ -145,7 +145,7 @@ private ImmutableSet extractStates(boolean external) { .filter(h -> h instanceof StateSubscriberMethod) .map(h -> (StateSubscriberMethod) h) .filter(external ? HandlerMethod::isExternal : HandlerMethod::isDomestic) - .map(StateSubscriberMethod::entityType) + .map(StateSubscriberMethod::stateType) .map(StateClass::from) .collect(toImmutableSet()); return result; diff --git a/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java b/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java index f4175a53db8..95316df6188 100644 --- a/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java +++ b/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java @@ -52,15 +52,15 @@ public final class StateSubscriberMethod extends SubscriberMethod implements Log private static final FieldPath TYPE_URL_PATH = FieldPaths.parse("id.type_url"); private final BoundedContextName contextOfSubscriber; - private final Class entityType; + private final Class stateType; private final Any typeUrlAsAny; StateSubscriberMethod(Method method, ParameterSpec parameterSpec) { super(checkNotFiltered(method), parameterSpec); this.contextOfSubscriber = contextOf(method.getDeclaringClass()); - this.entityType = firstParamType(rawMethod()); + this.stateType = firstParamType(rawMethod()); checkExternal(); - TypeUrl targetType = TypeUrl.of(this.entityType); + TypeUrl targetType = TypeUrl.of(this.stateType); this.typeUrlAsAny = toAny(targetType.value()); } @@ -74,16 +74,16 @@ private static Method checkNotFiltered(Method method) { } private void checkExternal() { - BoundedContextName originContext = contextOf(entityType()); + BoundedContextName originContext = contextOf(stateType()); boolean external = !originContext.equals(contextOfSubscriber); ensureExternalMatch(external); } /** - * Obtains the type of the entity to which the method is subscribed. + * Obtains the type of the entity state to which the method is subscribed. */ - public Class entityType() { - return entityType; + public Class stateType() { + return stateType; } @Override diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 3fec8a4d289..357a7b626b6 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -139,6 +139,20 @@ private void subscribeToSystemEvents() { systemSubscriber.registerIn(boundedContext()); } + /** + * Validates routing schema for types of state messages (if any) that this repository dispatches + * to its entities. + * + * @throws IllegalStateException + * if a message type cannot be dispatched + */ + public final void validateStateRouting() throws IllegalStateException { + if (!projectionClass().subscribesToStates()) { + return; + } + //TODO:2019-05-13:alexander.yevsyukov: Implement + } + @Override public Optional> createExternalDispatcher() { if (!dispatchesExternalEvents()) { diff --git a/server/src/main/java/io/spine/server/projection/model/ProjectionClass.java b/server/src/main/java/io/spine/server/projection/model/ProjectionClass.java index 36131427223..22e4828c2b1 100644 --- a/server/src/main/java/io/spine/server/projection/model/ProjectionClass.java +++ b/server/src/main/java/io/spine/server/projection/model/ProjectionClass.java @@ -67,28 +67,28 @@ public static

ProjectionClass

asProjectionClass(Class< } @Override - public Set domesticEvents() { + public final Set domesticEvents() { return delegate.domesticEvents(); } @Override - public Set externalEvents() { - return delegate.externalEvents(); + public final Set domesticStates() { + return delegate.domesticStates(); } @Override - public Collection - subscribersOf(EventClass eventClass, MessageClass originClass) { - return delegate.handlersOf(eventClass, originClass); + public final Set externalEvents() { + return delegate.externalEvents(); } @Override - public Set domesticStates() { - return delegate.domesticStates(); + public final Set externalStates() { + return delegate.externalStates(); } @Override - public Set externalStates() { - return delegate.externalStates(); + public final Collection + subscribersOf(EventClass eventClass, MessageClass originClass) { + return delegate.handlersOf(eventClass, originClass); } } diff --git a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java index c2d1af81c67..a16c8888558 100644 --- a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java +++ b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java @@ -48,7 +48,7 @@ public class StateUpdateRouting private static final long serialVersionUID = 0L; private StateUpdateRouting() { - super((message, context) -> noTargets()); + super(defaultStateRouting()); } /** @@ -104,4 +104,8 @@ EventRoute eventRoute() { return apply(state, context); }; } + + private static Route> defaultStateRouting() { + return (message, context) -> noTargets(); + } } From 72371cb86292923545a7520d96cd549b36627181 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 14:01:51 +0300 Subject: [PATCH 07/43] Fix Javadoc language --- .../io/spine/server/entity/model/StateSubscribingClass.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java b/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java index 4d90594a2e1..d977d97522b 100644 --- a/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java +++ b/server/src/main/java/io/spine/server/entity/model/StateSubscribingClass.java @@ -42,7 +42,7 @@ public interface StateSubscribingClass { /** * Verifies if this class is {@linkplain io.spine.core.Subscribe subscribed} to updates of - * entity states either domestic or external. + * entity states, either domestic or external. */ default boolean subscribesToStates() { boolean dispatchesDomestic = !domesticStates().isEmpty(); From 0ea0619d0a9942749454d6324e53a36e21680f53 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 17:36:10 +0300 Subject: [PATCH 08/43] Add initialization callback for repositories Also: * Allow non-public entity classes to declare columns. * Customize state routing during repo initialization. --- .../java/io/spine/server/BoundedContext.java | 5 -- .../aggregate/AggregatePartRepository.java | 6 +- .../server/aggregate/AggregateRepository.java | 4 +- .../entity/EventDispatchingRepository.java | 8 +-- .../io/spine/server/entity/Repository.java | 28 ++++++-- .../server/entity/storage/EntityColumn.java | 14 ++-- .../procman/ProcessManagerRepository.java | 6 +- .../projection/ProjectionRepository.java | 71 ++++++++++++++----- .../io/spine/server/route/EventRouting.java | 6 +- .../spine/system/server/MirrorProjection.java | 2 +- .../spine/system/server/MirrorRepository.java | 13 ++-- .../server/SystemProjectionRepository.java | 5 +- .../spine/server/entity/RepositoryTest.java | 2 +- .../given/groups/GroupNameProjection.java | 2 +- .../server/given/groups/GroupProjection.java | 2 +- .../given/EntitySubscriberProjection.java | 2 +- 16 files changed, 110 insertions(+), 66 deletions(-) diff --git a/server/src/main/java/io/spine/server/BoundedContext.java b/server/src/main/java/io/spine/server/BoundedContext.java index 443916fb27c..20667340132 100644 --- a/server/src/main/java/io/spine/server/BoundedContext.java +++ b/server/src/main/java/io/spine/server/BoundedContext.java @@ -45,7 +45,6 @@ import io.spine.server.integration.ExternalDispatcherFactory; import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.IntegrationBus; -import io.spine.server.projection.ProjectionRepository; import io.spine.server.stand.Stand; import io.spine.server.storage.StorageFactory; import io.spine.server.tenant.TenantIndex; @@ -222,10 +221,6 @@ public static BoundedContextBuilder newBuilder() { repository.setBoundedContext(this); guard.register(repository); repository.onRegistered(); - if (repository instanceof ProjectionRepository) { - ProjectionRepository pr = (ProjectionRepository) repository; - pr.validateStateRouting(); - } registerEventDispatcher(stand()); } diff --git a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java index d4b96a25411..c1930bc70d4 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java @@ -52,8 +52,8 @@ protected AggregatePartRepository() { @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); - boundedContext().aggregateRootDirectory() - .register(this); + context().aggregateRootDirectory() + .register(this); } @Override @@ -74,7 +74,7 @@ AggregatePartClass aggregatePartClass() { } private AggregateRoot createAggregateRoot(I id) { - AggregateRoot result = aggregatePartClass().createRoot(boundedContext(), id); + AggregateRoot result = aggregatePartClass().createRoot(context(), id); return result; } diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 4a410783572..13ad68a580b 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -124,7 +124,7 @@ public void onRegistered() { super.onRegistered(); - BoundedContext boundedContext = boundedContext(); + BoundedContext boundedContext = context(); boundedContext.registerCommandDispatcher(this); boundedContext.registerEventDispatcher(this); if (aggregateClass().importsEvents()) { @@ -400,7 +400,7 @@ protected final EventRouting eventImportRouting() { */ void postEvents(Collection events) { Iterable filteredEvents = eventFilter().filter(events); - EventBus bus = boundedContext().eventBus(); + EventBus bus = context().eventBus(); bus.post(filteredEvents); } diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 3924bcaf261..ed404d9e867 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -50,11 +50,11 @@ public abstract class EventDispatchingRepository defaultFunction) { + protected EventDispatchingRepository(EventRoute defaultRoute) { super(); - this.eventRouting = EventRouting.withDefault(defaultFunction); + this.eventRouting = EventRouting.withDefault(defaultRoute); } /** @@ -75,7 +75,7 @@ protected final EventRouting eventRouting() { @OverridingMethodsMustInvokeSuper public void onRegistered() { super.onRegistered(); - boundedContext().registerEventDispatcher(this); + context().registerEventDispatcher(this); } /** diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index c7f44b85680..5b7fe0d29b7 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -191,6 +191,22 @@ public final void setBoundedContext(BoundedContext boundedContext) { if (!isStorageAssigned()) { initStorage(boundedContext.storageFactory()); } + init(); + } + + /** + * A callback for performing additional initialization of the repository during its + * {@linkplain BoundedContext#register(Repository) registration} with a {@code BoundedContext}. + * + *

When this method is called, the repository already has {@link #context() BoundedContext} + * and the {@link #storage() Storage} {@linkplain #initStorage(StorageFactory) assigned}. + * + *

Default implementation does nothing. + */ + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc. + @OverridingMethodsMustInvokeSuper + protected void init() { + // Do nothing. } /** @@ -201,14 +217,14 @@ protected final boolean isRegistered() { } /** - * Obtains {@code BoundedContext} to which this repository belongs. + * Obtains the {@code BoundedContext} to which this repository belongs. * * @return parent {@code BoundedContext} * @throws IllegalStateException * if the repository is not registered {@linkplain BoundedContext#register(Repository) * registered} yet */ - protected final BoundedContext boundedContext() { + protected final BoundedContext context() { checkState(boundedContext != null, "The repository (class: `%s`) is not registered with a `BoundedContext`.", getClass().getName()); @@ -221,8 +237,8 @@ protected final BoundedContext boundedContext() { */ @OverridingMethodsMustInvokeSuper public void onRegistered() { - boundedContext().stand() - .registerTypeSupplier(this); + context().stand() + .registerTypeSupplier(this); } /** @@ -336,8 +352,8 @@ protected void logError(String msgFormat, protected EntityLifecycle lifecycleOf(I id) { checkNotNull(id); TypeUrl stateType = entityStateType(); - SystemWriteSide writeSide = boundedContext().systemClient() - .writeSide(); + SystemWriteSide writeSide = context().systemClient() + .writeSide(); EventFilter eventFilter = eventFilter(); EntityLifecycle lifecycle = EntityLifecycle .newBuilder() diff --git a/server/src/main/java/io/spine/server/entity/storage/EntityColumn.java b/server/src/main/java/io/spine/server/entity/storage/EntityColumn.java index 6718c7d00f3..360f40def46 100644 --- a/server/src/main/java/io/spine/server/entity/storage/EntityColumn.java +++ b/server/src/main/java/io/spine/server/entity/storage/EntityColumn.java @@ -222,6 +222,8 @@ private EntityColumn(Method getter, String storedName, boolean nullable) { this.getter = getter; + // To allow calling on non-public classes. + this.getter.setAccessible(true); this.entityType = getter.getDeclaringClass(); this.getterMethodName = getter.getName(); this.name = name; @@ -295,16 +297,16 @@ public boolean isNullable() { try { Serializable result = (Serializable) getter.invoke(source); if (!nullable) { - checkNotNull(result, format("Not null getter %s returned null.", getter.getName())); + checkNotNull(result, format("Not null getter `%s` returned null.", getter.getName())); } Serializable value = toPersistedValue(result); return value; } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException( - format("Could not invoke getter of property %s from object %s", - getName(), - source), - e); + throw newIllegalStateException( + e, "Could not invoke getter of property `%s` from object `%s`.", + getName(), + source + ); } } diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index 16acab15411..704c685fa4d 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -140,7 +140,7 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { public void onRegistered() { super.onRegistered(); - BoundedContext boundedContext = boundedContext(); + BoundedContext boundedContext = context(); boundedContext.registerCommandDispatcher(this); checkNotDeaf(); @@ -311,7 +311,7 @@ public void onError(CommandEnvelope cmd, RuntimeException exception) { */ void postEvents(Collection events) { Iterable filteredEvents = eventFilter().filter(events); - EventBus bus = boundedContext().eventBus(); + EventBus bus = context().eventBus(); bus.post(filteredEvents); } @@ -339,7 +339,7 @@ protected EntityLifecycle lifecycleOf(I id) { @Override protected P findOrCreate(I id) { P result = super.findOrCreate(id); - CommandBus commandBus = boundedContext().commandBus(); + CommandBus commandBus = context().commandBus(); result.setCommandBus(commandBus); return result; } diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 357a7b626b6..065caeb4c60 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -37,6 +37,7 @@ import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.ExternalMessageEnvelope; import io.spine.server.projection.model.ProjectionClass; +import io.spine.server.route.StateUpdateRouting; import io.spine.server.stand.Stand; import io.spine.server.storage.RecordStorage; import io.spine.server.storage.StorageFactory; @@ -52,7 +53,6 @@ import static io.spine.option.EntityOption.Kind.PROJECTION; import static io.spine.server.projection.model.ProjectionClass.asProjectionClass; import static io.spine.server.route.EventRoute.byProducerId; -import static io.spine.server.route.EventRoute.ignoreEntityUpdates; import static io.spine.util.Exceptions.newIllegalStateException; /** @@ -72,7 +72,54 @@ public abstract class ProjectionRepository, S e * Creates a new {@code ProjectionRepository}. */ protected ProjectionRepository() { - super(ignoreEntityUpdates(byProducerId())); + super(byProducerId()); + } + + /** + * Initializes the repository during its registration. + * + *

If projections of this repository are {@linkplain io.spine.core.Subscribe subscribed} to + * entity state updates, a routing for these updates is {@linkplain #createStateRouting() + * created}. If one of the states of entities cannot be routed during the created schema, + * {@code IllegalStateException} will be thrown. + * + * @throws IllegalStateException + * if the state routing does not cover one of the entity state types to which + * the entities are subscribed + */ + @Override + @OverridingMethodsMustInvokeSuper + protected void init() throws IllegalStateException{ + super.init(); + if (projectionClass().subscribesToStates()) { + eventRouting().routeStateUpdates(createStateRouting()); + validateStateRouting(); + } + } + + /** + * Creates {@code StateUpdateRouting} used by the repository. + * + *

Default implementation provides {@linkplain StateUpdateRouting#newInstance() + * default instance} of the {@code StateUpdateRouting}. Overriding repository classes + * may customize the routing if the default schema does not satisfy the routing needs. + */ + protected StateUpdateRouting createStateRouting() { + return StateUpdateRouting.newInstance(); + } + + /** + * Validates routing schema for types of state messages (if any) that this repository dispatches + * to its entities. + * + * @throws IllegalStateException + * if a message type cannot be dispatched + */ + private void validateStateRouting() throws IllegalStateException { + if (!projectionClass().subscribesToStates()) { + return; + } + //TODO:2019-05-13:alexander.yevsyukov: Implement } @VisibleForTesting @@ -84,7 +131,7 @@ static Timestamp nullToDefault(@Nullable Timestamp timestamp) { /** Obtains {@link EventStore} from which to get events during catch-up. */ EventStore eventStore() { - return boundedContext() + return context() .eventBus() .eventStore(); } @@ -136,21 +183,7 @@ private void ensureDispatchesEvents() { private void subscribeToSystemEvents() { ProjectionSystemEventWatcher systemSubscriber = new ProjectionSystemEventWatcher<>(this); - systemSubscriber.registerIn(boundedContext()); - } - - /** - * Validates routing schema for types of state messages (if any) that this repository dispatches - * to its entities. - * - * @throws IllegalStateException - * if a message type cannot be dispatched - */ - public final void validateStateRouting() throws IllegalStateException { - if (!projectionClass().subscribesToStates()) { - return; - } - //TODO:2019-05-13:alexander.yevsyukov: Implement + systemSubscriber.registerIn(context()); } @Override @@ -181,7 +214,7 @@ private Set createEventFilters() { * Obtains the {@code Stand} from the {@code BoundedContext} of this repository. */ protected final Stand stand() { - return boundedContext().stand(); + return context().stand(); } /** diff --git a/server/src/main/java/io/spine/server/route/EventRouting.java b/server/src/main/java/io/spine/server/route/EventRouting.java index 43570bc0e98..a6de81bd1fc 100644 --- a/server/src/main/java/io/spine/server/route/EventRouting.java +++ b/server/src/main/java/io/spine/server/route/EventRouting.java @@ -144,10 +144,6 @@ EventRouting route(Class eventType, EventRoute via) /** * Sets a custom routing schema for entity state updates. * - *

Setting a routing for state updates is equivalent to setting a route for events of type - * {@link EntityStateChanged io.spine.system.server.event.EntityStateChanged}. - * It is illegal to do both things simultaneously. - * * @param routing * the routing schema for entity state updates * @return {@code this} to allow chained calls when configuring the routing @@ -155,7 +151,7 @@ EventRouting route(Class eventType, EventRoute via) * if a route for {@link EntityStateChanged} is already set */ @CanIgnoreReturnValue - public EventRouting routeEntityStateUpdates(StateUpdateRouting routing) { + public EventRouting routeStateUpdates(StateUpdateRouting routing) { checkNotNull(routing); return route(EntityStateChanged.class, routing.eventRoute()); } diff --git a/server/src/main/java/io/spine/system/server/MirrorProjection.java b/server/src/main/java/io/spine/system/server/MirrorProjection.java index adf1f7e0e15..d329072b8e0 100644 --- a/server/src/main/java/io/spine/system/server/MirrorProjection.java +++ b/server/src/main/java/io/spine/system/server/MirrorProjection.java @@ -63,7 +63,7 @@ * subscriber method is an event used by the framework to bind the method to the event type. * The content of the event, in those cases, is irrelevant. */ -public final class MirrorProjection extends Projection { +final class MirrorProjection extends Projection { private static final String TYPE_COLUMN_NAME = "aggregate_type"; private static final String TYPE_COLUMN_QUERY_NAME = "aggregateType"; diff --git a/server/src/main/java/io/spine/system/server/MirrorRepository.java b/server/src/main/java/io/spine/system/server/MirrorRepository.java index b64676c4a74..a134f264ba1 100644 --- a/server/src/main/java/io/spine/system/server/MirrorRepository.java +++ b/server/src/main/java/io/spine/system/server/MirrorRepository.java @@ -21,6 +21,7 @@ package io.spine.system.server; import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Any; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.FieldMask; @@ -71,15 +72,15 @@ final class MirrorRepository extends SystemProjectionRepository { - private static final FieldMask AGGREGATE_STATE_WITH_VERSION = - fromFieldNumbers(Mirror.class, - ID_FIELD_NUMBER, STATE_FIELD_NUMBER, VERSION_FIELD_NUMBER); - private static final Logger log = Logging.get(MirrorRepository.class); + private static final FieldMask AGGREGATE_STATE_WITH_VERSION = fromFieldNumbers( + Mirror.class, ID_FIELD_NUMBER, STATE_FIELD_NUMBER, VERSION_FIELD_NUMBER + ); @Override - public void onRegistered() { - super.onRegistered(); + @OverridingMethodsMustInvokeSuper + protected void init() { + super.init(); prepareRouting(); } diff --git a/server/src/main/java/io/spine/system/server/SystemProjectionRepository.java b/server/src/main/java/io/spine/system/server/SystemProjectionRepository.java index f4f43692f48..d106aaca581 100644 --- a/server/src/main/java/io/spine/system/server/SystemProjectionRepository.java +++ b/server/src/main/java/io/spine/system/server/SystemProjectionRepository.java @@ -27,12 +27,13 @@ import io.spine.server.type.EventEnvelope; /** - * A repository for projections in a system bounded context. + * A repository for projections in a System Context. * *

Unlike an arbitrary {@link ProjectionRepository}, a {@code SystemProjectionRepository} * dispatches the events directly to the target projections. */ -public class SystemProjectionRepository, S extends Message> +public +abstract class SystemProjectionRepository, S extends Message> extends ProjectionRepository { /** diff --git a/server/src/test/java/io/spine/server/entity/RepositoryTest.java b/server/src/test/java/io/spine/server/entity/RepositoryTest.java index c0b0d0c731c..293b8d9e11e 100644 --- a/server/src/test/java/io/spine/server/entity/RepositoryTest.java +++ b/server/src/test/java/io/spine/server/entity/RepositoryTest.java @@ -90,7 +90,7 @@ void beUnregisteredOnInit() { @Test @DisplayName("not allow getting BoundedContext before registration") void notGetBcIfUnregistered() { - assertThrows(IllegalStateException.class, () -> new TestRepo().boundedContext()); + assertThrows(IllegalStateException.class, () -> new TestRepo().context()); } @Test diff --git a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java index f6338a53c30..03df3c1d37e 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java @@ -55,7 +55,7 @@ public void onRegistered() { .setUuid(org.getId() .getUuid()) .build())); - eventRouting().routeEntityStateUpdates(routing); + eventRouting().routeStateUpdates(routing); } } } diff --git a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java index 69f541859ce..0986b005d9c 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java @@ -53,7 +53,7 @@ public void onRegistered() { .setUuid(org.getHead() .getValue()) .build())); - eventRouting().routeEntityStateUpdates(routing); + eventRouting().routeStateUpdates(routing); } } } diff --git a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java index a360e936f7c..8a13cb138b5 100644 --- a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java +++ b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java @@ -60,7 +60,7 @@ public static final class Repository @Override public void onRegistered() { super.onRegistered(); - eventRouting().routeEntityStateUpdates( + eventRouting().routeStateUpdates( StateUpdateRouting .newInstance() .route(Project.class, (state, context) -> withId(state.getId())) From 0f31e9d8d6b7f1d761847d78b623c223982b348a Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Mon, 13 May 2019 17:39:14 +0300 Subject: [PATCH 09/43] Fix state routing customization --- .../server/given/groups/GroupProjection.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java index 0986b005d9c..2dc7237a77f 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java @@ -45,15 +45,13 @@ public static final class Repository extends ProjectionRepository { @Override - public void onRegistered() { - super.onRegistered(); - StateUpdateRouting routing = StateUpdateRouting.newInstance(); - routing.route(Organization.class, (org, eventContext) -> - withId(GroupId.newBuilder() - .setUuid(org.getHead() - .getValue()) - .build())); - eventRouting().routeStateUpdates(routing); + protected StateUpdateRouting createStateRouting() { + return super.createStateRouting() + .route(Organization.class, (org, eventContext) -> + withId(GroupId.newBuilder() + .setUuid(org.getHead() + .getValue()) + .build())); } } } From b05ad382638a1b907ec6f622b2a6bf1091e6786c Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Tue, 14 May 2019 10:03:31 +0300 Subject: [PATCH 10/43] Fix state routing --- .../given/groups/GroupNameProjection.java | 17 +++++++---------- .../given/EntitySubscriberProjection.java | 19 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java index 03df3c1d37e..257330649ae 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java @@ -46,16 +46,13 @@ public static final class Repository extends ProjectionRepository { @Override - public void onRegistered() { - super.onRegistered(); - - StateUpdateRouting routing = StateUpdateRouting.newInstance(); - routing.route(Organization.class, (org, ctx) -> withId( - GroupId.newBuilder() - .setUuid(org.getId() - .getUuid()) - .build())); - eventRouting().routeStateUpdates(routing); + protected StateUpdateRouting createStateRouting() { + return super.createStateRouting() + .route(Organization.class, (org, ctx) -> withId( + GroupId.newBuilder() + .setUuid(org.getId() + .getUuid()) + .build())); } } } diff --git a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java index 8a13cb138b5..029ea420216 100644 --- a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java +++ b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java @@ -44,10 +44,11 @@ public EntitySubscriberProjection(ProjectId id) { @Subscribe void onUpdate(Project aggregateState) { - List taskNames = aggregateState.getTaskList() - .stream() - .map(Task::getTitle) - .collect(toList()); + List taskNames = + aggregateState.getTaskList() + .stream() + .map(Task::getTitle) + .collect(toList()); builder().setProjectId(aggregateState.getId()) .setProjectName(aggregateState.getName()) .clearTaskName() @@ -58,13 +59,9 @@ public static final class Repository extends ProjectionRepository { @Override - public void onRegistered() { - super.onRegistered(); - eventRouting().routeStateUpdates( - StateUpdateRouting - .newInstance() - .route(Project.class, (state, context) -> withId(state.getId())) - ); + protected StateUpdateRouting createStateRouting() { + return super.createStateRouting() + .route(Project.class, (state, context) -> withId(state.getId())); } } } From 1a1787873ebc2782682d502e9eb0a20e47da078d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Tue, 14 May 2019 10:43:10 +0300 Subject: [PATCH 11/43] Rename method --- .../main/java/io/spine/server/route/StateUpdateRouting.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java index a16c8888558..9235aaf1ad4 100644 --- a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java +++ b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java @@ -48,7 +48,7 @@ public class StateUpdateRouting private static final long serialVersionUID = 0L; private StateUpdateRouting() { - super(defaultStateRouting()); + super(defaultStateRoute()); } /** @@ -105,7 +105,7 @@ EventRoute eventRoute() { }; } - private static Route> defaultStateRouting() { + private static Route> defaultStateRoute() { return (message, context) -> noTargets(); } } From 0c3de2d5d174c6ce040b5f9d4690ce5c8b88b216 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Tue, 14 May 2019 10:43:29 +0300 Subject: [PATCH 12/43] Fix diag message layout --- .../java/io/spine/server/projection/ProjectionRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 065caeb4c60..fafe17439d0 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -174,8 +174,8 @@ private void ensureDispatchesEvents() { boolean noExternalSubscriptions = !dispatchesExternalEvents(); if (noExternalSubscriptions) { throw newIllegalStateException( - "Projections of the repository `%s` have neither domestic nor external " + - "event subscriptions.", this); + "Projections of the repository `%s` have neither domestic nor external" + + " event subscriptions.", this); } } } From 8936c9f33f70c6ec63ce0e4fc7a9cd41e01847fe Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Tue, 14 May 2019 14:55:42 +0300 Subject: [PATCH 13/43] Improve default command routing --- .../server/aggregate/AggregateRepository.java | 8 +- .../server/commandbus/CommandValidator.java | 18 ++-- .../io/spine/server/entity/Repository.java | 12 +-- .../procman/ProcessManagerRepository.java | 16 ++-- .../io/spine/server/route/CommandRouting.java | 9 +- .../server/route/DefaultCommandRoute.java | 89 ++++++++++++++----- .../io/spine/server/route/EventProducers.java | 3 +- .../io/spine/server/route/FieldAtIndex.java | 13 ++- .../entity/DefaultCommandRouteTest.java | 13 +-- .../server/route/CommandRoutingTest.java | 2 +- .../java/io/spine/server/stand/StandTest.java | 1 - 11 files changed, 126 insertions(+), 58 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 13ad68a580b..b564f5893fd 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -47,10 +47,12 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Suppliers.memoize; import static com.google.common.collect.Sets.union; import static io.spine.option.EntityOption.Kind.AGGREGATE; import static io.spine.server.aggregate.model.AggregateClass.asAggregateClass; @@ -65,6 +67,7 @@ * the type of the aggregate IDs * @param * the type of the aggregates managed by this repository + * @see Aggregate */ @SuppressWarnings("ClassWithTooManyMethods") public abstract class AggregateRepository> @@ -76,7 +79,7 @@ public abstract class AggregateRepository> static final int DEFAULT_SNAPSHOT_TRIGGER = 100; /** The routing schema for commands handled by the aggregates. */ - private final CommandRouting commandRouting = CommandRouting.newInstance(); + private final Supplier> commandRouting; /** The routing schema for events to which aggregates react. */ private final EventRouting eventRouting = @@ -103,6 +106,7 @@ public abstract class AggregateRepository> /** Creates a new instance. */ protected AggregateRepository() { super(); + this.commandRouting = memoize(() -> CommandRouting.newInstance(idClass())); } /** @@ -360,7 +364,7 @@ public void onError(EventEnvelope event, RuntimeException exception) { * Obtains command routing instance used by this repository. */ protected final CommandRouting commandRouting() { - return commandRouting; + return commandRouting.get(); } /** diff --git a/server/src/main/java/io/spine/server/commandbus/CommandValidator.java b/server/src/main/java/io/spine/server/commandbus/CommandValidator.java index be1cf7c1d06..1afd4af68ed 100644 --- a/server/src/main/java/io/spine/server/commandbus/CommandValidator.java +++ b/server/src/main/java/io/spine/server/commandbus/CommandValidator.java @@ -26,6 +26,7 @@ import io.spine.base.CommandMessage; import io.spine.base.Identifier; import io.spine.core.Command; +import io.spine.core.CommandContext; import io.spine.core.CommandId; import io.spine.core.MessageInvalid; import io.spine.core.TenantId; @@ -58,6 +59,10 @@ */ final class CommandValidator implements EnvelopeValidator { + /** Default route for validating command message fields. */ + private static final DefaultCommandRoute defaultRoute = + DefaultCommandRoute.newInstance(Object.class); + private final CommandBus commandBus; CommandValidator(CommandBus commandBus) { @@ -181,12 +186,13 @@ private void validateContext() { private void validateTargetId() { CommandMessage message = command.message(); - Optional targetId = DefaultCommandRoute.asOptional(message); - if (targetId.isPresent()) { - Object target = targetId.get(); - if (Identifier.isEmpty(target)) { - addViolation("Command target entity ID cannot be empty."); - } + if (!DefaultCommandRoute.exists(message)) { + addViolation("The command message does not have a field with a command target ID."); + } + + Object target = defaultRoute.apply(message, CommandContext.getDefaultInstance()); + if (Identifier.isEmpty(target)) { + addViolation("Command target ID cannot be empty."); } } diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index 5b7fe0d29b7..80c5ac4b8a8 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -171,8 +171,8 @@ public TypeUrl entityStateType() { /** * Obtains classes of the events produced by this {@code Repository}. * - *

For convenience purposes the default version returns empty collection. This method should be - * overridden by repositories which actually produce events. + *

For convenience purposes the default version returns an empty set. + * This method should be overridden by repositories which actually produce events. */ public ImmutableSet outgoingEvents() { return ImmutableSet.of(); @@ -186,10 +186,10 @@ public ImmutableSet outgoingEvents() { * associated with the passed {@code BoundedContext}. */ @Internal - public final void setBoundedContext(BoundedContext boundedContext) { - this.boundedContext = boundedContext; + public final void setBoundedContext(BoundedContext context) { + this.boundedContext = context; if (!isStorageAssigned()) { - initStorage(boundedContext.storageFactory()); + initStorage(context.storageFactory()); } init(); } @@ -312,7 +312,7 @@ public void close() { /** * Verifies if the repository is open. */ - public boolean isOpen() { + public final boolean isOpen() { return storage != null; } diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index 704c685fa4d..e470e55deb1 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -52,8 +52,10 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Suppliers.memoize; import static io.spine.option.EntityOption.Kind.PROCESS_MANAGER; import static io.spine.server.procman.model.ProcessManagerClass.asProcessManagerClass; import static io.spine.server.tenant.TenantAwareRunner.with; @@ -62,9 +64,12 @@ /** * The abstract base for Process Managers repositories. * - * @param the type of IDs of process managers - * @param

the type of process managers - * @param the type of process manager state messages + * @param + * the type of IDs of process managers + * @param

+ * the type of process managers + * @param + * the type of process manager state messages * @see ProcessManager */ public abstract class ProcessManagerRepository { /** The command routing schema used by this repository. */ - private final CommandRouting commandRouting = CommandRouting.newInstance(); + private final Supplier> commandRouting; /** * The {@link CommandErrorHandler} tackling the dispatching errors. @@ -100,6 +105,7 @@ public abstract class ProcessManagerRepository CommandRouting.newInstance(idClass())); } /** @@ -201,7 +207,7 @@ public Set commandClasses() { * Obtains command routing schema used by this repository. */ protected final CommandRouting commandRouting() { - return commandRouting; + return commandRouting.get(); } /** diff --git a/server/src/main/java/io/spine/server/route/CommandRouting.java b/server/src/main/java/io/spine/server/route/CommandRouting.java index 25f0520946c..bd7244f3abc 100644 --- a/server/src/main/java/io/spine/server/route/CommandRouting.java +++ b/server/src/main/java/io/spine/server/route/CommandRouting.java @@ -51,11 +51,14 @@ private CommandRouting(CommandRoute defaultRoute) { /** * Creates a new command routing. * - * @param the type of entity identifiers returned by new routing + * @param + * the type of entity identifiers returned by new routing + * @param idClass + * the class of target entity identifiers * @return new routing instance */ - public static CommandRouting newInstance() { - CommandRoute defaultRoute = DefaultCommandRoute.newInstance(); + public static CommandRouting newInstance(Class idClass) { + CommandRoute defaultRoute = DefaultCommandRoute.newInstance(idClass); return new CommandRouting<>(defaultRoute); } diff --git a/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java b/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java index 7a2c6d692f5..8ccdf7bea10 100644 --- a/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java +++ b/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java @@ -20,48 +20,93 @@ package io.spine.server.route; -import com.google.protobuf.Message; +import com.google.protobuf.Descriptors.FieldDescriptor; import io.spine.base.CommandMessage; import io.spine.core.CommandContext; import io.spine.protobuf.MessageFieldException; -import java.util.Optional; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Obtains an ID of a command target entity from the first field of the command message. * * @param the type of target entity IDs */ -public class DefaultCommandRoute extends FieldAtIndex - implements CommandRoute { +public final class DefaultCommandRoute implements CommandRoute { private static final long serialVersionUID = 0L; + + /** + * ID of the target entity is the first field of the command message. + */ private static final int ID_FIELD_INDEX = 0; - private DefaultCommandRoute() { - super(ID_FIELD_INDEX); - } + private final Class idClass; - /** Creates a new instance. */ - public static DefaultCommandRoute newInstance() { - return new DefaultCommandRoute<>(); + private DefaultCommandRoute(Class cls) { + this.idClass = cls; } /** - * Tries to obtain a target ID from the passed command message. + * Creates a new instance. * - * @param commandMessage the message to get ID from - * @return an {@link Optional} of the ID or {@code Optional.empty()} - * if {@link DefaultCommandRoute#apply(Message, Message)} throws an exception - * if the command is not for an entity + * @param idClass + * the class of identifiers used for the routing */ - public static Optional asOptional(CommandMessage commandMessage) { - try { - DefaultCommandRoute function = newInstance(); - I id = function.apply(commandMessage, CommandContext.getDefaultInstance()); - return Optional.of(id); - } catch (MessageFieldException | ClassCastException ignored) { - return Optional.empty(); + public static DefaultCommandRoute newInstance(Class idClass) { + checkNotNull(idClass); + return new DefaultCommandRoute<>(idClass); + } + + @Override + public I apply(CommandMessage message, CommandContext ignored) throws MessageFieldException { + checkNotNull(message); + FieldDescriptor field = targetFieldFrom(message); + I result = targetFrom(field, message); + return result; + } + + private I targetFrom(FieldDescriptor field, CommandMessage message) { + Object value = message.getField(field); + Class valueClass = value.getClass(); + if (!idClass.isAssignableFrom(valueClass)) { + throw new MessageFieldException( + message, "The field `%s` has the type `%s` which is not assignable" + + " from the expected ID type `%s`.", + field.getName(), + valueClass.getName(), + idClass.getName() + + ); } + I casted = idClass.cast(value); + return casted; + } + + /** + * Obtains the descriptor of the command target field from the passed message. + */ + private static FieldDescriptor targetFieldFrom(CommandMessage message) { + List fields = message.getDescriptorForType() + .getFields(); + if (fields.size() <= ID_FIELD_INDEX) { + throw new MessageFieldException( + message, "There's no field with the index %d.", ID_FIELD_INDEX + ); + } + return fields.get(ID_FIELD_INDEX); + } + + /** + * Verifies of the passed command message potentially has a field with an entity ID. + */ + public static boolean exists(CommandMessage commandMessage) { + boolean hasAtLeastOneField = + commandMessage.getDescriptorForType() + .getFields() + .size() > ID_FIELD_INDEX; + return hasAtLeastOneField; } } diff --git a/server/src/main/java/io/spine/server/route/EventProducers.java b/server/src/main/java/io/spine/server/route/EventProducers.java index 88b90e36f9f..5fb63884846 100644 --- a/server/src/main/java/io/spine/server/route/EventProducers.java +++ b/server/src/main/java/io/spine/server/route/EventProducers.java @@ -44,8 +44,7 @@ static final class FromContext implements EventRoute { @Override public Set apply(EventMessage message, EventContext context) { - @SuppressWarnings("unchecked") // The route creator is responsible for the type check. - I id = (I) context.producer(); + @SuppressWarnings("unchecked") I id = (I) context.producer(); return ImmutableSet.of(id); } diff --git a/server/src/main/java/io/spine/server/route/FieldAtIndex.java b/server/src/main/java/io/spine/server/route/FieldAtIndex.java index a93012bbde0..25f58538206 100644 --- a/server/src/main/java/io/spine/server/route/FieldAtIndex.java +++ b/server/src/main/java/io/spine/server/route/FieldAtIndex.java @@ -24,6 +24,8 @@ import io.spine.protobuf.MessageField; import io.spine.protobuf.MessageFieldException; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Obtains an entity ID based on an event/command message. * @@ -56,6 +58,9 @@ abstract class FieldAtIndex implements */ @Override public I apply(M message, C ignored) throws MessageFieldException { + checkNotNull(message); + + @SuppressWarnings("unchecked") // we expect that the field is of this type I id = (I) idField.getValue(message); return id; @@ -71,13 +76,13 @@ private EntityIdField(int index) { } @Override - protected MessageFieldException createUnavailableFieldException(Message message) { - return new MessageFieldException(message, "There's no field with index %d", getIndex()); + protected MessageFieldException createUnavailableFieldException(Message msg) { + return new MessageFieldException(msg, "There's no field with index %d.", getIndex()); } @Override - protected boolean isFieldAvailable(Message message) { - boolean result = MessageField.getFieldCount(message) > getIndex(); + protected boolean isFieldAvailable(Message msg) { + boolean result = MessageField.getFieldCount(msg) > getIndex(); return result; } } diff --git a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java index 0be74b8460d..c81fc979931 100644 --- a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java +++ b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java @@ -20,15 +20,14 @@ package io.spine.server.entity; +import io.spine.core.CommandContext; import io.spine.server.route.DefaultCommandRoute; import io.spine.test.entity.command.EntCreateProject; import io.spine.testdata.Sample; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; @DisplayName("DefaultCommandRoute should") @@ -39,9 +38,11 @@ class DefaultCommandRouteTest { void getIdFromCommand() { EntCreateProject msg = Sample.messageOfType(EntCreateProject.class); - Optional id = DefaultCommandRoute.asOptional(msg); + assertTrue(DefaultCommandRoute.exists(msg)); - assertTrue(id.isPresent()); - assertEquals(msg.getProjectId(), id.get()); + assertThat(DefaultCommandRoute + .newInstance(io.spine.test.entity.ProjectId.class) + .apply(msg, CommandContext.getDefaultInstance())) + .isEqualTo(msg.getProjectId()); } } diff --git a/server/src/test/java/io/spine/server/route/CommandRoutingTest.java b/server/src/test/java/io/spine/server/route/CommandRoutingTest.java index 8db9d3a995b..c4475a9b43a 100644 --- a/server/src/test/java/io/spine/server/route/CommandRoutingTest.java +++ b/server/src/test/java/io/spine/server/route/CommandRoutingTest.java @@ -81,7 +81,7 @@ public Long apply(RegisterUser message, CommandContext context) { @BeforeEach void setUp() { - commandRouting = CommandRouting.newInstance(); + commandRouting = CommandRouting.newInstance(Long.class); } @Test diff --git a/server/src/test/java/io/spine/server/stand/StandTest.java b/server/src/test/java/io/spine/server/stand/StandTest.java index ad0346fe2c0..bdf657cc0bb 100644 --- a/server/src/test/java/io/spine/server/stand/StandTest.java +++ b/server/src/test/java/io/spine/server/stand/StandTest.java @@ -131,7 +131,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; From 85802678aa43fb15fa9dc6f89e95e62945eefb09 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Tue, 14 May 2019 16:48:06 +0300 Subject: [PATCH 14/43] Check the ID type explicitly during routing --- .../entity/EventDispatchingRepository.java | 12 +- .../procman/ProcessManagerRepository.java | 17 ++- .../projection/ProjectionRepository.java | 8 -- .../server/route/DefaultCommandRoute.java | 52 +------- .../io/spine/server/route/EventProducers.java | 35 ++---- .../io/spine/server/route/EventRoute.java | 26 +--- .../io/spine/server/route/FieldAtIndex.java | 89 -------------- .../io/spine/server/route/FirstField.java | 111 ++++++++++++++++++ .../system/server/SystemEventFactory.java | 8 +- .../spine/system/server/SystemRepository.java | 9 +- .../aggregate/given/importado/DotSpace.java | 8 +- .../given/klasse/EngineRepository.java | 2 +- .../server/route/EventProducersTest.java | 2 +- 13 files changed, 165 insertions(+), 214 deletions(-) delete mode 100644 server/src/main/java/io/spine/server/route/FieldAtIndex.java create mode 100644 server/src/main/java/io/spine/server/route/FirstField.java diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index ed404d9e867..64db06d568b 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -22,18 +22,17 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Message; -import io.spine.base.EventMessage; import io.spine.core.Event; import io.spine.server.event.EventDispatcher; import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.ExternalMessageEnvelope; -import io.spine.server.route.EventRoute; import io.spine.server.route.EventRouting; import io.spine.server.type.EventEnvelope; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.server.route.EventRoute.byProducerId; import static io.spine.server.tenant.TenantAwareRunner.with; /** @@ -47,14 +46,9 @@ public abstract class EventDispatchingRepository eventRouting; - /** - * Creates new repository instance. - * - * @param defaultRoute the default function for getting target entity IDs - */ - protected EventDispatchingRepository(EventRoute defaultRoute) { + protected EventDispatchingRepository() { super(); - this.eventRouting = EventRouting.withDefault(defaultRoute); + this.eventRouting = EventRouting.withDefault(byProducerId()); } /** diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index e470e55deb1..7c20635c27a 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -100,14 +100,23 @@ public abstract class ProcessManagerRepository CommandRouting.newInstance(idClass())); } + /** + * {@inheritDoc} + * + *

Customizes event routing to use first message field. + */ + @Override + @OverridingMethodsMustInvokeSuper + protected void init() { + super.init(); + eventRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); + } + /** * Obtains class information of process managers managed by this repository. */ diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index fafe17439d0..641cbd4fb2d 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -52,7 +52,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.option.EntityOption.Kind.PROJECTION; import static io.spine.server.projection.model.ProjectionClass.asProjectionClass; -import static io.spine.server.route.EventRoute.byProducerId; import static io.spine.util.Exceptions.newIllegalStateException; /** @@ -68,13 +67,6 @@ public abstract class ProjectionRepository, S e /** An underlying entity storage used to store projections. */ private RecordStorage recordStorage; - /** - * Creates a new {@code ProjectionRepository}. - */ - protected ProjectionRepository() { - super(byProducerId()); - } - /** * Initializes the repository during its registration. * diff --git a/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java b/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java index 8ccdf7bea10..eed3884c24b 100644 --- a/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java +++ b/server/src/main/java/io/spine/server/route/DefaultCommandRoute.java @@ -20,13 +20,10 @@ package io.spine.server.route; -import com.google.protobuf.Descriptors.FieldDescriptor; import io.spine.base.CommandMessage; import io.spine.core.CommandContext; import io.spine.protobuf.MessageFieldException; -import java.util.List; - import static com.google.common.base.Preconditions.checkNotNull; /** @@ -38,15 +35,10 @@ public final class DefaultCommandRoute implements CommandRoute idClass; + private final FirstField field; private DefaultCommandRoute(Class cls) { - this.idClass = cls; + this.field = new FirstField<>(cls); } /** @@ -63,50 +55,18 @@ public static DefaultCommandRoute newInstance(Class idClass) { @Override public I apply(CommandMessage message, CommandContext ignored) throws MessageFieldException { checkNotNull(message); - FieldDescriptor field = targetFieldFrom(message); - I result = targetFrom(field, message); + I result = field.apply(message, ignored); return result; } - private I targetFrom(FieldDescriptor field, CommandMessage message) { - Object value = message.getField(field); - Class valueClass = value.getClass(); - if (!idClass.isAssignableFrom(valueClass)) { - throw new MessageFieldException( - message, "The field `%s` has the type `%s` which is not assignable" + - " from the expected ID type `%s`.", - field.getName(), - valueClass.getName(), - idClass.getName() - - ); - } - I casted = idClass.cast(value); - return casted; - } - - /** - * Obtains the descriptor of the command target field from the passed message. - */ - private static FieldDescriptor targetFieldFrom(CommandMessage message) { - List fields = message.getDescriptorForType() - .getFields(); - if (fields.size() <= ID_FIELD_INDEX) { - throw new MessageFieldException( - message, "There's no field with the index %d.", ID_FIELD_INDEX - ); - } - return fields.get(ID_FIELD_INDEX); - } - /** * Verifies of the passed command message potentially has a field with an entity ID. */ public static boolean exists(CommandMessage commandMessage) { boolean hasAtLeastOneField = - commandMessage.getDescriptorForType() - .getFields() - .size() > ID_FIELD_INDEX; + !commandMessage.getDescriptorForType() + .getFields() + .isEmpty(); return hasAtLeastOneField; } } diff --git a/server/src/main/java/io/spine/server/route/EventProducers.java b/server/src/main/java/io/spine/server/route/EventProducers.java index 5fb63884846..3d7c58da733 100644 --- a/server/src/main/java/io/spine/server/route/EventProducers.java +++ b/server/src/main/java/io/spine/server/route/EventProducers.java @@ -50,7 +50,7 @@ public Set apply(EventMessage message, EventContext context) { @Override public String toString() { - return "EventProducers.fromContext()"; + return getClass().getName(); } } @@ -61,38 +61,21 @@ static final class FromFirstMessageField implements EventRoute func = FromEventMessage.fieldAt(0); + private final FirstField field; + + FromFirstMessageField(Class idClass) { + this.field = new FirstField<>(idClass); + } @Override public Set apply(EventMessage message, EventContext context) { - I id = func.apply(message, context); - return ImmutableSet.of(id); + I id = field.apply(message, context); + return EventRoute.withId(id); } @Override public String toString() { - return "EventProducers.fromFirstMessageField()"; - } - } - - /** - * Obtains an event producer ID from a field of an event message. - */ - static final class FromEventMessage extends FieldAtIndex { - - private static final long serialVersionUID = 0L; - - private FromEventMessage(int idIndex) { - super(idIndex); - } - - /** - * Creates a new instance. - * - * @param index a zero-based index of an ID field in this type of messages - */ - static FromEventMessage fieldAt(int index) { - return new FromEventMessage<>(index); + return getClass().getName(); } } } diff --git a/server/src/main/java/io/spine/server/route/EventRoute.java b/server/src/main/java/io/spine/server/route/EventRoute.java index 8b5fa27c1ec..320f311e381 100644 --- a/server/src/main/java/io/spine/server/route/EventRoute.java +++ b/server/src/main/java/io/spine/server/route/EventRoute.java @@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet; import io.spine.base.EventMessage; import io.spine.core.EventContext; -import io.spine.system.server.event.EntityStateChanged; import java.util.Set; @@ -53,29 +52,14 @@ static EventRoute byProducerId() { * Creates an event route that obtains event producer ID from an {@code EventContext} and * returns it as a sole element of the the immutable set. * - * @param the type of the IDs for which the event would be routed - * @return new route instance - */ - static EventRoute byFirstMessageField() { - return new EventProducers.FromFirstMessageField<>(); - } - - /** - * Creates an event route that ignores {@link EntityStateChanged} events and delegates all - * the other event routing to the given instance. - * - * @param forOthers - * the route for all the other events * @param - * the type of the event target IDs + * the type of the IDs of entities to which the event would be routed + * @param idClass + * the class of identifiers * @return new route instance */ - static EventRoute - ignoreEntityUpdates(EventRoute forOthers) { - checkNotNull(forOthers); - return (message, context) -> message instanceof EntityStateChanged - ? noTargets() - : forOthers.apply(message, context); + static EventRoute byFirstMessageField(Class idClass) { + return new EventProducers.FromFirstMessageField<>(idClass); } /** diff --git a/server/src/main/java/io/spine/server/route/FieldAtIndex.java b/server/src/main/java/io/spine/server/route/FieldAtIndex.java deleted file mode 100644 index 25f58538206..00000000000 --- a/server/src/main/java/io/spine/server/route/FieldAtIndex.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.route; - -import com.google.protobuf.Message; -import io.spine.protobuf.MessageField; -import io.spine.protobuf.MessageFieldException; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Obtains an entity ID based on an event/command message. - * - * @param the type of entity IDs - * @param the type of messages to get IDs from - * @param the type of the message context - */ -abstract class FieldAtIndex implements Unicast { - - private static final long serialVersionUID = 0L; - private final EntityIdField idField; - - /** - * Creates a new instance. - * - * @param idIndex a zero-based index of an ID field in this type of messages - */ - FieldAtIndex(int idIndex) { - this.idField = new EntityIdField(idIndex); - } - - /** - * Obtains the ID from the message field at the configured index. - * - *

Casts the value obtained from the field to the type of the generic - * parameter {@code }. - * - * @throws MessageFieldException if there is no field with required index - * @throws ClassCastException if the field type is not of the required type - */ - @Override - public I apply(M message, C ignored) throws MessageFieldException { - checkNotNull(message); - - - @SuppressWarnings("unchecked") // we expect that the field is of this type - I id = (I) idField.getValue(message); - return id; - } - - /** Accessor object for entity ID fields. */ - private static class EntityIdField extends MessageField { - - private static final long serialVersionUID = 0L; - - private EntityIdField(int index) { - super(index); - } - - @Override - protected MessageFieldException createUnavailableFieldException(Message msg) { - return new MessageFieldException(msg, "There's no field with index %d.", getIndex()); - } - - @Override - protected boolean isFieldAvailable(Message msg) { - boolean result = MessageField.getFieldCount(msg) > getIndex(); - return result; - } - } -} diff --git a/server/src/main/java/io/spine/server/route/FirstField.java b/server/src/main/java/io/spine/server/route/FirstField.java new file mode 100644 index 00000000000..60c82914077 --- /dev/null +++ b/server/src/main/java/io/spine/server/route/FirstField.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.route; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Exceptions.newIllegalStateException; + +/** + * Obtains the first field from multiple messages expecting each field + * being the identifier of the same type. + * + * @param + * the type of the identifiers + * @param + * the common supertype for messages + * @param + * the type of contexts of the messages + */ +final class FirstField implements Unicast { + + private static final long serialVersionUID = 0L; + private final Class idClass; + + FirstField(Class idClass) { + this.idClass = checkNotNull(idClass); + } + + @Override + public I apply(M message, C context) { + checkNotNull(message); + FieldDescriptor field = fieldIn(message); + I result = getValue(field, message); + return result; + } + + /** + * Obtains a descriptor of the first field of the passed. + * + * @throws IllegalStateException + * if the passed message does not declare fields, or + * the field is a repeated field or a map + */ + private FieldDescriptor fieldIn(M message) { + Descriptor type = message.getDescriptorForType(); + List fields = type.getFields(); + if (fields.isEmpty()) { + throw error("Cannot use the type `%s` for routing: it does not declare any field.", + type.getFullName()); + } + FieldDescriptor field = fields.get(0); + if (field.isMapField()) { + throw error("The field `%s` is a map and cannot be used for routing.", + field.getFullName()); + } + if (field.isRepeated()) { + throw error("The field `%s` is repeated and cannot be used for routing.", + field.getFullName()); + } + return field; + } + + private IllegalStateException error(String messageFormat, String firstArg) { + throw newIllegalStateException( + messageFormat + " Please declare a field with the type `%s`.", + firstArg, + idClass.getCanonicalName()); + } + + /** + * Obtains the value of first field making sure the value is of the expected type. + */ + private I getValue(FieldDescriptor field, M message) { + Object value = message.getField(field); + Class valueClass = value.getClass(); + if (!idClass.isAssignableFrom(valueClass)) { + throw newIllegalStateException( + "The field `%s` has the type `%s` which is not assignable" + + " from the expected ID type `%s`.", + field.getFullName(), + valueClass.getName(), + idClass.getName() + ); + } + I result = idClass.cast(value); + return result; + } +} diff --git a/server/src/main/java/io/spine/system/server/SystemEventFactory.java b/server/src/main/java/io/spine/system/server/SystemEventFactory.java index dcf89a7e817..678d232fe90 100644 --- a/server/src/main/java/io/spine/system/server/SystemEventFactory.java +++ b/server/src/main/java/io/spine/system/server/SystemEventFactory.java @@ -54,19 +54,19 @@ private SystemEventFactory(Message aggregateId, boolean multitenant) { * @return new instance of {@code SystemEventFactory} */ static SystemEventFactory forMessage(EventMessage message, boolean multitenant) { - Message aggregateId = getAggregateId(message); + Message aggregateId = aggregateIdFrom(message); return new SystemEventFactory(aggregateId, multitenant); } - private static Message getAggregateId(EventMessage systemEvent) { + private static Message aggregateIdFrom(EventMessage systemEvent) { Set routingOut = - EventRoute.byFirstMessageField() + EventRoute.byFirstMessageField(Object.class) .apply(systemEvent, EventContext.getDefaultInstance()); checkArgument(routingOut.size() == 1, "System event message must have aggregate ID in the first field."); Object id = routingOut.iterator() .next(); - checkArgument(id instanceof Message, "System aggregate ID must be a Message"); + checkArgument(id instanceof Message, "System aggregate ID must be a `Message`."); return (Message) id; } diff --git a/server/src/main/java/io/spine/system/server/SystemRepository.java b/server/src/main/java/io/spine/system/server/SystemRepository.java index fb266ff58d6..3641598bf4f 100644 --- a/server/src/main/java/io/spine/system/server/SystemRepository.java +++ b/server/src/main/java/io/spine/system/server/SystemRepository.java @@ -20,6 +20,7 @@ package io.spine.system.server; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.entity.EventFilter; @@ -33,9 +34,11 @@ abstract class SystemRepository> extends AggregateRepository { - SystemRepository() { - super(); - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField()); + @Override + @OverridingMethodsMustInvokeSuper + protected void init() { + super.init(); + eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); } @Override diff --git a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java index 16dc3b19652..696baab3209 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java +++ b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java @@ -20,6 +20,7 @@ package io.spine.server.aggregate.given.importado; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; @@ -35,7 +36,10 @@ public final class DotSpace extends AggregateRepository { * is to take producer ID from an {@code EventContext}. We redefine this to avoid the need * of creating {@code Event} instances. Real imports would need to create those. */ - public DotSpace() { - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField()); + @Override + @OverridingMethodsMustInvokeSuper + protected void init() { + super.init(); + eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java index 7a56f02a943..47bbe885d9f 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java @@ -31,6 +31,6 @@ public class EngineRepository extends AggregateRepository { public void routeImportByFirstMessageField() { - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField()); + eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); } } diff --git a/server/src/test/java/io/spine/server/route/EventProducersTest.java b/server/src/test/java/io/spine/server/route/EventProducersTest.java index eb768274371..489ac075a3f 100644 --- a/server/src/test/java/io/spine/server/route/EventProducersTest.java +++ b/server/src/test/java/io/spine/server/route/EventProducersTest.java @@ -48,7 +48,7 @@ void getIdFromContext() { @Test @DisplayName("create function for getting ID from first message field") void getIdFromFirstMsgField() { - EventRoute fn = EventRoute.byFirstMessageField(); + EventRoute fn = EventRoute.byFirstMessageField(Object.class); assertFunction(fn); } From 07cae8554e8615168fa020c7e4c7137a85808d4d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 11:18:56 +0300 Subject: [PATCH 15/43] Have common interface for standard rejections ... and use it for routing in tests. --- license-report.md | 16 ++-- .../entity/rejection/StandardRejection.java | 45 +++++++++++ .../server/entity/rejection/package-info.java | 31 +++++++ .../java/io/spine/server/route/ByContext.java | 40 +++++++++ .../server/route/ByFirstMessageField.java | 46 +++++++++++ .../io/spine/server/route/EventProducers.java | 81 ------------------- .../io/spine/server/route/EventRoute.java | 4 +- .../server/entity/standard_rejections.proto | 2 + .../given/repo/TestProcessManager.java | 1 - .../repo/TestProcessManagerRepository.java | 6 ++ .../server/route/EventProducersTest.java | 61 -------------- 11 files changed, 180 insertions(+), 153 deletions(-) create mode 100644 server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java create mode 100644 server/src/main/java/io/spine/server/entity/rejection/package-info.java create mode 100644 server/src/main/java/io/spine/server/route/ByContext.java create mode 100644 server/src/main/java/io/spine/server/route/ByFirstMessageField.java delete mode 100644 server/src/main/java/io/spine/server/route/EventProducers.java delete mode 100644 server/src/test/java/io/spine/server/route/EventProducersTest.java diff --git a/license-report.md b/license-report.md index dbb79eef898..c24f4e777eb 100644 --- a/license-report.md +++ b/license-report.md @@ -431,7 +431,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:26 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:05 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -821,7 +821,7 @@ This report was generated on **Mon May 13 10:24:26 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:27 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1359,7 +1359,7 @@ This report was generated on **Mon May 13 10:24:27 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:27 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2059,7 +2059,7 @@ This report was generated on **Mon May 13 10:24:27 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:28 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:07 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2603,7 +2603,7 @@ This report was generated on **Mon May 13 10:24:28 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:29 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:08 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3108,7 +3108,7 @@ This report was generated on **Mon May 13 10:24:29 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:29 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3621,7 +3621,7 @@ This report was generated on **Mon May 13 10:24:29 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:30 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4234,4 +4234,4 @@ This report was generated on **Mon May 13 10:24:30 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Mon May 13 10:24:30 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed May 15 11:05:10 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java b/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java new file mode 100644 index 00000000000..4c908789376 --- /dev/null +++ b/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.entity.rejection; + +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.Any; +import io.spine.annotation.GeneratedMixin; +import io.spine.base.RejectionMessage; +import io.spine.protobuf.AnyPacker; + +/** + * Interface common for {@link StandardRejections}. + */ +@Immutable +@GeneratedMixin +public interface StandardRejection extends RejectionMessage { + + Any getEntityId(); + + /** + * Obtains the ID of the entity from the {@linkplain #getEntityId() packed form}. + */ + default Object entityId() { + Object result = AnyPacker.unpack(getEntityId()); + return result; + } +} diff --git a/server/src/main/java/io/spine/server/entity/rejection/package-info.java b/server/src/main/java/io/spine/server/entity/rejection/package-info.java new file mode 100644 index 00000000000..aff946095f6 --- /dev/null +++ b/server/src/main/java/io/spine/server/entity/rejection/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019, TeamDev. 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. + */ + +/** + * This package contains classes and interfaces for rejections related to lifecycle of entities. + */ + +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.server.entity.rejection; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/src/main/java/io/spine/server/route/ByContext.java b/server/src/main/java/io/spine/server/route/ByContext.java new file mode 100644 index 00000000000..41c04b53f6c --- /dev/null +++ b/server/src/main/java/io/spine/server/route/ByContext.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.route; + +import io.spine.base.EventMessage; +import io.spine.core.EventContext; + +import java.util.Set; + +/** + * Obtains an event producer ID from the context of the event. + */ +final class ByContext implements EventRoute { + + private static final long serialVersionUID = 0L; + + @Override + public Set apply(EventMessage message, EventContext context) { + @SuppressWarnings("unchecked") I id = (I) context.producer(); + return EventRoute.withId(id); + } +} diff --git a/server/src/main/java/io/spine/server/route/ByFirstMessageField.java b/server/src/main/java/io/spine/server/route/ByFirstMessageField.java new file mode 100644 index 00000000000..960db92883e --- /dev/null +++ b/server/src/main/java/io/spine/server/route/ByFirstMessageField.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.route; + +import io.spine.base.EventMessage; +import io.spine.core.EventContext; + +import java.util.Set; + +/** + * The route that obtains a producer ID from the first field of the event message. + */ +final class ByFirstMessageField implements EventRoute { + + private static final long serialVersionUID = 0L; + + private final FirstField field; + + ByFirstMessageField(Class idClass) { + this.field = new FirstField<>(idClass); + } + + @Override + public Set apply(EventMessage message, EventContext context) { + I id = field.apply(message, context); + return EventRoute.withId(id); + } +} diff --git a/server/src/main/java/io/spine/server/route/EventProducers.java b/server/src/main/java/io/spine/server/route/EventProducers.java deleted file mode 100644 index 3d7c58da733..00000000000 --- a/server/src/main/java/io/spine/server/route/EventProducers.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.route; - -import com.google.common.collect.ImmutableSet; -import io.spine.base.EventMessage; -import io.spine.core.EventContext; - -import java.util.Set; - -/** - * Provides default {@link EventRoute}s for obtaining a producer ID from an event. - */ -final class EventProducers { - - /** Prevents instantiation of this utility class. */ - private EventProducers() { - } - - /** - * Obtains an event producer ID from the context of the event. - */ - static final class FromContext implements EventRoute { - - private static final long serialVersionUID = 0L; - - @Override - public Set apply(EventMessage message, EventContext context) { - @SuppressWarnings("unchecked") I id = (I) context.producer(); - return ImmutableSet.of(id); - } - - @Override - public String toString() { - return getClass().getName(); - } - } - - /** - * The route that obtains a producer ID from the first field of the event message. - */ - static final class FromFirstMessageField implements EventRoute { - - private static final long serialVersionUID = 0L; - - private final FirstField field; - - FromFirstMessageField(Class idClass) { - this.field = new FirstField<>(idClass); - } - - @Override - public Set apply(EventMessage message, EventContext context) { - I id = field.apply(message, context); - return EventRoute.withId(id); - } - - @Override - public String toString() { - return getClass().getName(); - } - } -} diff --git a/server/src/main/java/io/spine/server/route/EventRoute.java b/server/src/main/java/io/spine/server/route/EventRoute.java index 320f311e381..093e6bdd1e6 100644 --- a/server/src/main/java/io/spine/server/route/EventRoute.java +++ b/server/src/main/java/io/spine/server/route/EventRoute.java @@ -45,7 +45,7 @@ public interface EventRoute extends Multicast EventRoute byProducerId() { - return new EventProducers.FromContext<>(); + return new ByContext<>(); } /** @@ -59,7 +59,7 @@ static EventRoute byProducerId() { * @return new route instance */ static EventRoute byFirstMessageField(Class idClass) { - return new EventProducers.FromFirstMessageField<>(idClass); + return new ByFirstMessageField<>(idClass); } /** diff --git a/server/src/main/proto/spine/server/entity/standard_rejections.proto b/server/src/main/proto/spine/server/entity/standard_rejections.proto index a57d3603d9b..39f829902d9 100644 --- a/server/src/main/proto/spine/server/entity/standard_rejections.proto +++ b/server/src/main/proto/spine/server/entity/standard_rejections.proto @@ -30,6 +30,8 @@ option java_package = "io.spine.server.entity.rejection"; import "google/protobuf/any.proto"; +option (every_is).java_type = "StandardRejection"; + // The rejection thrown when a request for modification of an entity cannot be satisfied // because the entity is marked as `archived`. message CannotModifyArchivedEntity { diff --git a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java index c3a84d872ec..29bdc2ab85f 100644 --- a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java +++ b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java @@ -192,7 +192,6 @@ Nothing on(StandardRejections.EntityAlreadyArchived rejection) { @React Nothing on(StandardRejections.EntityAlreadyDeleted rejection) { - keep(rejection); return nothing(); } diff --git a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java index bc0d9d05e04..168334cd299 100644 --- a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java +++ b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java @@ -21,6 +21,7 @@ package io.spine.server.procman.given.repo; import io.spine.server.entity.EventFilter; +import io.spine.server.entity.rejection.StandardRejection; import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.type.CommandEnvelope; import io.spine.server.type.EventEnvelope; @@ -28,6 +29,8 @@ import io.spine.test.procman.ProjectId; import org.checkerframework.checker.nullness.qual.Nullable; +import static io.spine.server.route.EventRoute.withId; + public class TestProcessManagerRepository extends ProcessManagerRepository { @@ -35,6 +38,9 @@ public class TestProcessManagerRepository public TestProcessManagerRepository() { super(); + eventRouting() + .route(StandardRejection.class, + (event, context) -> withId((ProjectId) event.entityId())); } @Override diff --git a/server/src/test/java/io/spine/server/route/EventProducersTest.java b/server/src/test/java/io/spine/server/route/EventProducersTest.java deleted file mode 100644 index 489ac075a3f..00000000000 --- a/server/src/test/java/io/spine/server/route/EventProducersTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.route; - -import io.spine.base.EventMessage; -import io.spine.testing.Tests; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static io.spine.testing.DisplayNames.HAVE_PARAMETERLESS_CTOR; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@DisplayName("EventProducers utility should") -class EventProducersTest { - - @Test - @DisplayName(HAVE_PARAMETERLESS_CTOR) - void haveUtilityConstructor() { - Tests.assertHasPrivateParameterlessCtor(EventProducers.class); - } - - @Test - @DisplayName("create function for taking ID from context") - void getIdFromContext() { - EventRoute fn = EventRoute.byProducerId(); - assertFunction(fn); - } - - @Test - @DisplayName("create function for getting ID from first message field") - void getIdFromFirstMsgField() { - EventRoute fn = EventRoute.byFirstMessageField(Object.class); - assertFunction(fn); - } - - private static void assertFunction(EventRoute fn) { - assertNotNull(fn); - - // Check that custom toString() is provided. - assertFalse(fn.toString().contains(EventRoute.class.getSimpleName())); - } -} From af55b4d5da1fb03cbf01ce7db38794cda3f859ce Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 12:05:55 +0300 Subject: [PATCH 16/43] Have customization callback for state routing ... instead of factory method. --- .../projection/ProjectionRepository.java | 41 ++++++++++--------- .../server/route/StateUpdateRouting.java | 14 +++++++ .../given/groups/GroupNameProjection.java | 18 ++++---- .../server/given/groups/GroupProjection.java | 13 +++--- .../given/EntitySubscriberProjection.java | 5 +-- .../server/route/StateUpdateRoutingTest.java | 14 +++---- 6 files changed, 58 insertions(+), 47 deletions(-) diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 641cbd4fb2d..fc9ac88ff8b 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -50,6 +50,7 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.union; import static io.spine.option.EntityOption.Kind.PROJECTION; import static io.spine.server.projection.model.ProjectionClass.asProjectionClass; import static io.spine.util.Exceptions.newIllegalStateException; @@ -71,8 +72,9 @@ public abstract class ProjectionRepository, S e * Initializes the repository during its registration. * *

If projections of this repository are {@linkplain io.spine.core.Subscribe subscribed} to - * entity state updates, a routing for these updates is {@linkplain #createStateRouting() - * created}. If one of the states of entities cannot be routed during the created schema, + * entity state updates, a routing for state updates is created and + * {@linkplain #setupStateRouting(StateUpdateRouting) configured}. + * If one of the states of entities cannot be routed during the created schema, * {@code IllegalStateException} will be thrown. * * @throws IllegalStateException @@ -84,34 +86,33 @@ public abstract class ProjectionRepository, S e protected void init() throws IllegalStateException{ super.init(); if (projectionClass().subscribesToStates()) { - eventRouting().routeStateUpdates(createStateRouting()); - validateStateRouting(); + StateUpdateRouting routing = createStateRouting(); + eventRouting().routeStateUpdates(routing); } } /** - * Creates {@code StateUpdateRouting} used by the repository. - * - *

Default implementation provides {@linkplain StateUpdateRouting#newInstance() - * default instance} of the {@code StateUpdateRouting}. Overriding repository classes - * may customize the routing if the default schema does not satisfy the routing needs. + * Creates and configures the {@code StateUpdateRouting} used by this repository. */ - protected StateUpdateRouting createStateRouting() { - return StateUpdateRouting.newInstance(); + private StateUpdateRouting createStateRouting() { + ProjectionClass

cls = projectionClass(); + StateUpdateRouting routing = StateUpdateRouting.newInstance(); + setupStateRouting(routing); + routing.validate(union(cls.domesticStates(), cls.externalStates())); + return routing; } /** - * Validates routing schema for types of state messages (if any) that this repository dispatches - * to its entities. + * A callback for derived repository classes to customize routing schema for delivering + * updated state to subscribed entities, if the default schema does not satisfy + * the routing needs. * - * @throws IllegalStateException - * if a message type cannot be dispatched + * @param routing + * the routing to customize */ - private void validateStateRouting() throws IllegalStateException { - if (!projectionClass().subscribesToStates()) { - return; - } - //TODO:2019-05-13:alexander.yevsyukov: Implement + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc + protected void setupStateRouting(StateUpdateRouting routing) { + // Do nothing by default. } @VisibleForTesting diff --git a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java index 9235aaf1ad4..442acacfc51 100644 --- a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java +++ b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java @@ -20,14 +20,17 @@ package io.spine.server.route; +import com.google.common.collect.Sets; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.protobuf.Message; import io.spine.core.EventContext; import io.spine.protobuf.AnyPacker; +import io.spine.server.entity.model.StateClass; import io.spine.system.server.event.EntityStateChanged; import java.util.Set; +import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.server.route.EventRoute.noTargets; /** @@ -108,4 +111,15 @@ EventRoute eventRoute() { private static Route> defaultStateRoute() { return (message, context) -> noTargets(); } + + /** + * Validates routing schema for types of state messages. + * + * @throws IllegalStateException + * if one of the state type cannot be dispatched by the current schema configuration + */ + public void validate(Sets.SetView stateClasses) throws IllegalStateException { + checkNotNull(stateClasses); + //TODO:2019-05-15:alexander.yevsyukov: Implement + } } diff --git a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java index 257330649ae..1491ab6e5ff 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupNameProjection.java @@ -37,22 +37,20 @@ private GroupNameProjection(GroupId id) { @Subscribe(external = true) void onUpdate(Organization organization) { - builder() - .setId(id()) - .setName(organization.getName()); + builder().setId(id()) + .setName(organization.getName()); } public static final class Repository extends ProjectionRepository { @Override - protected StateUpdateRouting createStateRouting() { - return super.createStateRouting() - .route(Organization.class, (org, ctx) -> withId( - GroupId.newBuilder() - .setUuid(org.getId() - .getUuid()) - .build())); + protected void setupStateRouting(StateUpdateRouting routing) { + routing.route(Organization.class, (org, ctx) -> withId( + GroupId.newBuilder() + .setUuid(org.getId() + .getUuid()) + .build())); } } } diff --git a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java index 2dc7237a77f..19315cf2494 100644 --- a/server/src/test/java/io/spine/server/given/groups/GroupProjection.java +++ b/server/src/test/java/io/spine/server/given/groups/GroupProjection.java @@ -45,13 +45,12 @@ public static final class Repository extends ProjectionRepository { @Override - protected StateUpdateRouting createStateRouting() { - return super.createStateRouting() - .route(Organization.class, (org, eventContext) -> - withId(GroupId.newBuilder() - .setUuid(org.getHead() - .getValue()) - .build())); + protected void setupStateRouting(StateUpdateRouting routing) { + routing.route(Organization.class, (org, eventContext) -> + withId(GroupId.newBuilder() + .setUuid(org.getHead() + .getValue()) + .build())); } } } diff --git a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java index 029ea420216..273ec917b8a 100644 --- a/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java +++ b/server/src/test/java/io/spine/server/projection/given/EntitySubscriberProjection.java @@ -59,9 +59,8 @@ public static final class Repository extends ProjectionRepository { @Override - protected StateUpdateRouting createStateRouting() { - return super.createStateRouting() - .route(Project.class, (state, context) -> withId(state.getId())); + protected void setupStateRouting(StateUpdateRouting routing) { + routing.route(Project.class, (state, context) -> withId(state.getId())); } } } diff --git a/server/src/test/java/io/spine/server/route/StateUpdateRoutingTest.java b/server/src/test/java/io/spine/server/route/StateUpdateRoutingTest.java index 19c58c698be..92bd730d980 100644 --- a/server/src/test/java/io/spine/server/route/StateUpdateRoutingTest.java +++ b/server/src/test/java/io/spine/server/route/StateUpdateRoutingTest.java @@ -38,11 +38,13 @@ @DisplayName("StateUpdateRouting should") class StateUpdateRoutingTest { + private static final EventContext emptyContext = EventContext.getDefaultInstance(); + @Test @DisplayName("not accept nulls") void notAcceptNulls() { new NullPointerTester() - .setDefault(EventContext.class, EventContext.getDefaultInstance()) + .setDefault(EventContext.class, emptyContext) .testAllPublicInstanceMethods(StateUpdateRouting.newInstance()); } @@ -50,12 +52,10 @@ void notAcceptNulls() { @DisplayName("skip all messages be default") void routeNothingByDefault() { StateUpdateRouting routing = StateUpdateRouting.newInstance(); - Set emptyTargets = routing.apply(Empty.getDefaultInstance(), - EventContext.getDefaultInstance()); + Set emptyTargets = routing.apply(Empty.getDefaultInstance(), emptyContext); assertThat(emptyTargets).isEmpty(); - Set logTargets = routing.apply(LogState.getDefaultInstance(), - EventContext.getDefaultInstance()); + Set logTargets = routing.apply(LogState.getDefaultInstance(), emptyContext); assertThat(logTargets).isEmpty(); } @@ -72,7 +72,7 @@ void routeMessagesByRoutes() { .newBuilder() .putCounters(counterKey, counter) .build(); - Set targets = routing.apply(log, EventContext.getDefaultInstance()); + Set targets = routing.apply(log, emptyContext); assertThat(targets).containsExactly(counter); } @@ -95,7 +95,7 @@ void createEventRoute() { .setWhen(currentTime()) .build(); EventRoute eventRoute = routing.eventRoute(); - Set targets = eventRoute.apply(event, EventContext.getDefaultInstance()); + Set targets = eventRoute.apply(event, emptyContext); assertThat(targets).containsExactly(counter); } } From e6db5175a9a6fa7bb350bb9ed350ac3fa1b4b599 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 12:56:51 +0300 Subject: [PATCH 17/43] Consolidate repo configurations in `init()` --- .../aggregate/AggregatePartRepository.java | 10 ++++- .../server/aggregate/AggregateRepository.java | 16 +++---- .../entity/DefaultRecordBasedRepository.java | 11 +++-- .../entity/EventDispatchingRepository.java | 9 ++-- .../server/entity/RecordBasedRepository.java | 10 ++--- .../io/spine/server/entity/Repository.java | 15 ++++--- .../procman/ProcessManagerRepository.java | 27 ++++------- .../projection/ProjectionRepository.java | 45 ++++++++----------- .../aggregate/IgTestAggregateRepository.java | 9 ++-- .../procman/ProcessManagerRepositoryTest.java | 27 ++++++----- .../server/procman/ProcessManagerTest.java | 3 -- .../projection/ProjectionRepositoryTest.java | 8 ++-- .../server/route/given/switchman/Log.java | 4 +- 13 files changed, 89 insertions(+), 105 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java index c1930bc70d4..85189b3bd3d 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java @@ -48,10 +48,16 @@ protected AggregatePartRepository() { super(); } + /** + * {@inheritDoc} + * + *

Registers itself with the {@link io.spine.server.BoundedContext#aggregateRootDirectory() + * AggregateRootDirectory} of the parent {@code BoundedContext}. + */ @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); + protected void init() { + super.init(); context().aggregateRootDirectory() .register(this); } diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index b564f5893fd..6d00b935cf8 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -123,19 +123,19 @@ protected AggregateRepository() { */ @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { + protected void init() { checkNotVoid(); - super.onRegistered(); + super.init(); - BoundedContext boundedContext = context(); - boundedContext.registerCommandDispatcher(this); - boundedContext.registerEventDispatcher(this); + BoundedContext context = context(); + context.registerCommandDispatcher(this); + context.registerEventDispatcher(this); if (aggregateClass().importsEvents()) { - boundedContext.importBus() - .register(EventImportDispatcher.of(this)); + context.importBus() + .register(EventImportDispatcher.of(this)); } - this.commandErrorHandler = boundedContext.createCommandErrorHandler(); + this.commandErrorHandler = context.createCommandErrorHandler(); } /** diff --git a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java index 6bc3e65c23e..06ae750e451 100644 --- a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java +++ b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java @@ -66,14 +66,13 @@ protected StorageConverter storageConverter() { } /** - * @inheritDoc - * - *

Performs validation of the entity class and initializes the storage converter. + * Initializes the repository by performing the validation of the entity class and + * creating the storage converter. */ - @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); + @Override + protected void init() { + super.init(); storageConverter(); } } diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 64db06d568b..8fd2dd5bab0 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -60,15 +60,12 @@ protected final EventRouting eventRouting() { } /** - * {@inheritDoc} - * - *

{@linkplain io.spine.server.event.EventBus#register(io.spine.server.bus.MessageDispatcher) - * Registers} itself with the {@code EventBus} of the parent {@code BoundedContext}. + * Registers itself as an event dispatcher with the parent {@code BoundedContext}. */ @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); + protected void init() { + super.init(); context().registerEventDispatcher(this); } diff --git a/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java b/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java index a2d83c8f0b2..e5db391a942 100644 --- a/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java +++ b/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java @@ -97,15 +97,13 @@ protected RecordStorage recordStorage() { } /** - * {@inheritDoc} - * - *

Caches {@link Column} definitions of the {@link Entity} class managed by this repository. + * Initializes the repository by caching {@link Column} definitions of + * the {@link Entity} class managed by this repository. */ @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); - + protected void init() { + super.init(); cacheEntityColumns(); } diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index 80c5ac4b8a8..36a77186d14 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -195,18 +195,19 @@ public final void setBoundedContext(BoundedContext context) { } /** - * A callback for performing additional initialization of the repository during its - * {@linkplain BoundedContext#register(Repository) registration} with a {@code BoundedContext}. + * Initializes the repository during its {@linkplain BoundedContext#register(Repository) + * registration} with a {@code BoundedContext}. * *

When this method is called, the repository already has {@link #context() BoundedContext} * and the {@link #storage() Storage} {@linkplain #initStorage(StorageFactory) assigned}. * - *

Default implementation does nothing. + *

Registers itself as a type supplier with the {@link io.spine.server.stand.Stand Stand} + * of the parent {@code BoundedContext}. */ - @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc. @OverridingMethodsMustInvokeSuper protected void init() { - // Do nothing. + context().stand() + .registerTypeSupplier(this); } /** @@ -235,10 +236,10 @@ protected final BoundedContext context() { * The callback called by a {@link BoundedContext} during the {@linkplain * BoundedContext#register(Repository) registration} of the repository. */ + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc @OverridingMethodsMustInvokeSuper public void onRegistered() { - context().stand() - .registerTypeSupplier(this); + // Do nothing by default. } /** diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index 7c20635c27a..a80c46790f5 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -105,18 +105,6 @@ protected ProcessManagerRepository() { this.commandRouting = memoize(() -> CommandRouting.newInstance(idClass())); } - /** - * {@inheritDoc} - * - *

Customizes event routing to use first message field. - */ - @Override - @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); - eventRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); - } - /** * Obtains class information of process managers managed by this repository. */ @@ -133,6 +121,8 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { /** * {@inheritDoc} * + *

Customizes event routing to use first message field. + * *

Registers with the {@code CommandBus} for dispatching commands * (via {@linkplain DelegatingCommandDispatcher delegating dispatcher}). * @@ -152,17 +142,18 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { */ @Override @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); + protected void init() { + super.init(); + eventRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); - BoundedContext boundedContext = context(); - boundedContext.registerCommandDispatcher(this); + BoundedContext context = context(); + context.registerCommandDispatcher(this); checkNotDeaf(); - this.commandErrorHandler = boundedContext.createCommandErrorHandler(); + this.commandErrorHandler = context.createCommandErrorHandler(); PmSystemEventWatcher systemSubscriber = new PmSystemEventWatcher<>(this); - systemSubscriber.registerIn(boundedContext); + systemSubscriber.registerIn(context); } /** diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index fc9ac88ff8b..d2d5a730dfa 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -69,7 +69,10 @@ public abstract class ProjectionRepository, S e private RecordStorage recordStorage; /** - * Initializes the repository during its registration. + * Initializes the repository. + * + *

Ensures there is at least one event subscriber method (external or domestic) declared + * by the class of the projection. Throws an {@code IllegalStateException} otherwise. * *

If projections of this repository are {@linkplain io.spine.core.Subscribe subscribed} to * entity state updates, a routing for state updates is created and @@ -85,12 +88,26 @@ public abstract class ProjectionRepository, S e @OverridingMethodsMustInvokeSuper protected void init() throws IllegalStateException{ super.init(); + ensureDispatchesEvents(); + subscribeToSystemEvents(); if (projectionClass().subscribesToStates()) { StateUpdateRouting routing = createStateRouting(); eventRouting().routeStateUpdates(routing); } } + private void ensureDispatchesEvents() { + boolean noEventSubscriptions = !dispatchesEvents(); + if (noEventSubscriptions) { + boolean noExternalSubscriptions = !dispatchesExternalEvents(); + if (noExternalSubscriptions) { + throw newIllegalStateException( + "Projections of the repository `%s` have neither domestic nor external" + + " event subscriptions.", this); + } + } + } + /** * Creates and configures the {@code StateUpdateRouting} used by this repository. */ @@ -147,32 +164,6 @@ public P create(I id) { return projection; } - /** - * {@inheritDoc} - * - *

Ensures there is at least one event subscriber method (external or domestic) declared - * by the class of the projection. Throws an {@code IllegalStateException} otherwise. - */ - @Override - @OverridingMethodsMustInvokeSuper - public void onRegistered() { - super.onRegistered(); - ensureDispatchesEvents(); - subscribeToSystemEvents(); - } - - private void ensureDispatchesEvents() { - boolean noEventSubscriptions = !dispatchesEvents(); - if (noEventSubscriptions) { - boolean noExternalSubscriptions = !dispatchesExternalEvents(); - if (noExternalSubscriptions) { - throw newIllegalStateException( - "Projections of the repository `%s` have neither domestic nor external" + - " event subscriptions.", this); - } - } - } - private void subscribeToSystemEvents() { ProjectionSystemEventWatcher systemSubscriber = new ProjectionSystemEventWatcher<>(this); diff --git a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java index 3d5a699c42b..9899cc7cd15 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java @@ -20,6 +20,7 @@ package io.spine.server.aggregate.given.aggregate; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.event.AggProjectPaused; import io.spine.test.aggregate.event.AggTaskStarted; @@ -33,13 +34,13 @@ public class IgTestAggregateRepository extends AbstractAggregateTestRepository { + @OverridingMethodsMustInvokeSuper @Override - public void onRegistered() { - super.onRegistered(); - + public void init() { + super.init(); eventRouting().route(AggTaskStarted.class, (message, context) -> withId(message.getProjectId())) .route(AggProjectPaused.class, - (message, context) -> withId(message.getProjectId())); + (message, context) -> withId(message.getProjectId())); } } diff --git a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java index 2f317fca38d..0b0a7a78894 100644 --- a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java +++ b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java @@ -139,10 +139,11 @@ protected TestProcessManager createEntity(ProjectId id) { .newBuilder() .setId(id) .build(); - TestProcessManager result = Given.processManagerOfClass(TestProcessManager.class) - .withId(id) - .withState(state) - .build(); + TestProcessManager result = + Given.processManagerOfClass(TestProcessManager.class) + .withId(id) + .withState(state) + .build(); return result; } @@ -501,18 +502,20 @@ void postCommandRejections() { } @Test - @DisplayName("throw ISE on registering to BC if repo is not subscribed to any messages") + @DisplayName("check that its `ProcessManager` class is subscribed to at least one message") void notRegisterIfSubscribedToNothing() { SensoryDeprivedPmRepository repo = new SensoryDeprivedPmRepository(); - BoundedContext boundedContext = BoundedContext.newBuilder() - .setMultitenant(false) - .build(); - repo.setBoundedContext(boundedContext); - assertThrows(IllegalStateException.class, repo::onRegistered); + BoundedContext context = BoundedContext + .newBuilder() + .setMultitenant(false) + .build(); + + assertThrows(IllegalStateException.class, () -> + repo.setBoundedContext(context)); } @Test - @DisplayName("provide EventFilter which discards EntityStateChanged events") + @DisplayName("provide `EventFilter` which discards `EntityStateChanged` events") void discardEntityStateChangedEvents() { EventFilter filter = repository().eventFilter(); ProjectId projectId = ProjectId @@ -541,7 +544,7 @@ void discardEntityStateChangedEvents() { } @Test - @DisplayName("post all domain events through an EventFilter") + @DisplayName("post all domain events through an `EventFilter`") void postEventsThroughFilter() { ProjectId projectId = ProjectId .newBuilder() diff --git a/server/src/test/java/io/spine/server/procman/ProcessManagerTest.java b/server/src/test/java/io/spine/server/procman/ProcessManagerTest.java index 9ae310a2ebf..0d93f26dc1a 100644 --- a/server/src/test/java/io/spine/server/procman/ProcessManagerTest.java +++ b/server/src/test/java/io/spine/server/procman/ProcessManagerTest.java @@ -117,9 +117,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.spy; -@SuppressWarnings({ - "InnerClassMayBeStatic", "ClassCanBeStatic" /* JUnit nested classes cannot be static. */, - "DuplicateStringLiteralInspection" /* Common test display names. */}) @DisplayName("ProcessManager should") class ProcessManagerTest { diff --git a/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java b/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java index cd231d3d6f1..da51e95bc8b 100644 --- a/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java +++ b/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java @@ -546,15 +546,15 @@ void eventStore() { } @Test - @DisplayName("throw ISE on registering to BC if repo is not subscribed to any messages") + @DisplayName("check that its `Projection` class is subscribed to at least one message") void notRegisterIfSubscribedToNothing() { SensoryDeprivedProjectionRepository repo = new SensoryDeprivedProjectionRepository(); - BoundedContext boundedContext = BoundedContext + BoundedContext context = BoundedContext .newBuilder() .setMultitenant(false) .build(); - repo.setBoundedContext(boundedContext); - assertThrows(IllegalStateException.class, repo::onRegistered); + assertThrows(IllegalStateException.class, () -> + repo.setBoundedContext(context)); } } diff --git a/server/src/test/java/io/spine/server/route/given/switchman/Log.java b/server/src/test/java/io/spine/server/route/given/switchman/Log.java index 6ebeb5849d0..6c7c828fcb9 100644 --- a/server/src/test/java/io/spine/server/route/given/switchman/Log.java +++ b/server/src/test/java/io/spine/server/route/given/switchman/Log.java @@ -85,8 +85,8 @@ public Repository() { } @Override - public void onRegistered() { - super.onRegistered(); + public void init() { + super.init(); eventRouting().replaceDefault((message, context) -> SINGLETON_ID_SET); } } From 09074245b11a0b6300305b93f94c715e2e00b22e Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 13:08:59 +0300 Subject: [PATCH 18/43] Improve Javadoc --- .../aggregate/AggregatePartRepository.java | 4 +--- .../server/aggregate/AggregateRepository.java | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java index 85189b3bd3d..0973db0adf9 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java @@ -49,9 +49,7 @@ protected AggregatePartRepository() { } /** - * {@inheritDoc} - * - *

Registers itself with the {@link io.spine.server.BoundedContext#aggregateRootDirectory() + * Registers itself with the {@link io.spine.server.BoundedContext#aggregateRootDirectory() * AggregateRootDirectory} of the parent {@code BoundedContext}. */ @Override diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 6d00b935cf8..89fc9ae943f 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -110,16 +110,18 @@ protected AggregateRepository() { } /** - * {@inheritDoc} + * Initializes the repository during its registration with a {@code BoundedContext}. + * + *

Verifies that the class of aggregates of this repository subscribes to at least one + * type of messages. * - *

{@code AggregateRepository} also registers itself with: + *

Registers itself with {@link io.spine.server.commandbus.CommandBus CommandBus}, + * {@link io.spine.server.event.EventBus EventBus}, and + * {@link io.spine.server.aggregate.ImportBus ImportBus} of the parent {@code BoundedContext} + * for dispatching messages to its aggregates. * - *

    - *
  • {@link io.spine.server.commandbus.CommandBus CommandBus}, - *
  • {@link io.spine.server.event.EventBus EventBus}, - *
  • {@link io.spine.server.aggregate.ImportBus ImportBus} of - * the parent {@code BoundedContext} for dispatching messages to its aggregates; - *
+ * @throws IllegalStateException + * if the aggregate class does not handle any messages */ @Override @OverridingMethodsMustInvokeSuper @@ -147,7 +149,7 @@ private void checkNotVoid() { if (!handlesCommands && !reactsOnEvents) { throw newIllegalStateException( - "Aggregates of the repository %s neither handle commands" + + "Aggregates of the repository `%s` neither handle commands" + " nor react on events.", this); } } From 5b2500b00ef73560df0e809ff28ebb69f7e41625 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 14:06:29 +0300 Subject: [PATCH 19/43] Prohibit overwriting set value of a Bounded Context --- .../java/io/spine/server/BoundedContext.java | 8 ++++ .../io/spine/server/entity/Repository.java | 21 ++++++++++ .../io/spine/server/BoundedContextTest.java | 13 ++++++ .../spine/server/entity/RepositoryTest.java | 40 +++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/server/src/main/java/io/spine/server/BoundedContext.java b/server/src/main/java/io/spine/server/BoundedContext.java index 20667340132..bfcf4a5047f 100644 --- a/server/src/main/java/io/spine/server/BoundedContext.java +++ b/server/src/main/java/io/spine/server/BoundedContext.java @@ -524,4 +524,12 @@ private void shutDownRepositories() { tenantIndex.close(); } } + + /** + * Returns the name of this Bounded Context. + */ + @Override + public String toString() { + return name.getValue(); + } } diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index 36a77186d14..f12664ad47d 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -184,9 +184,30 @@ public ImmutableSet outgoingEvents() { *

If the repository does not have a storage assigned prior to this call, the storage * will be {@linkplain #initStorage(StorageFactory) initialized} from a {@code StorageFactory} * associated with the passed {@code BoundedContext}. + * + *

A context for a repository can be set only once. Passing the same second time will have + * no effect. + * + * @throws IllegalStateException + * if the repository has a context value already assigned, and the passed value is + * not equal to the assigned one */ @Internal public final void setBoundedContext(BoundedContext context) { + checkNotNull(context); + boolean sameValue = context.equals(this.boundedContext); + if (this.boundedContext != null && !sameValue) { + throw newIllegalStateException( + "The repository `%s` already has assigned BoundedContext (`%s`)." + + "This operation can be performed only once" + + " Attempted to set the context `%s`.", + this.boundedContext, this, context); + } + + if (sameValue) { + return; + } + this.boundedContext = context; if (!isStorageAssigned()) { initStorage(context.storageFactory()); diff --git a/server/src/test/java/io/spine/server/BoundedContextTest.java b/server/src/test/java/io/spine/server/BoundedContextTest.java index 0d6c541d730..ffe32ebc832 100644 --- a/server/src/test/java/io/spine/server/BoundedContextTest.java +++ b/server/src/test/java/io/spine/server/BoundedContextTest.java @@ -72,6 +72,7 @@ import static com.google.common.truth.Truth.assertThat; import static io.spine.server.event.given.EventStoreTestEnv.eventStore; +import static io.spine.testing.TestValues.randomString; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -508,4 +509,16 @@ void closeSystemWhenDomainIsClosed() throws Exception { assertThat(systemLogEvent.getMessage()).contains(systemContextName.getValue()); assertThat(systemLogEvent.getLevel()).isAtLeast(DEBUG); } + + @Test + @DisplayName("return its name in `toString()`") + void stringForm() { + String name = randomString(); + + assertThat(BoundedContext.newBuilder() + .setName(name) + .build() + .toString()) + .isEqualTo(name); + } } diff --git a/server/src/test/java/io/spine/server/entity/RepositoryTest.java b/server/src/test/java/io/spine/server/entity/RepositoryTest.java index 293b8d9e11e..14f73626da5 100644 --- a/server/src/test/java/io/spine/server/entity/RepositoryTest.java +++ b/server/src/test/java/io/spine/server/entity/RepositoryTest.java @@ -34,11 +34,13 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import java.util.Iterator; import static com.google.common.collect.Iterators.size; +import static com.google.common.truth.Truth.assertThat; import static io.spine.testing.core.given.GivenTenantId.newUuid; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -128,6 +130,44 @@ void provideDefaultEventFilter() { assertNotNull(filter); } + @Nested + @DisplayName("prohibit overwriting already set context") + class OverwritingContext { + + private BoundedContext ctx1; + private BoundedContext ctx2; + + @BeforeEach + void createContexts() { + ctx1 = BoundedContext + .newBuilder() + .setName("Context-1") + .build(); + ctx2 = BoundedContext + .newBuilder() + .setName("Context-2") + .build(); + } + + @Test + @DisplayName("throwing ISE") + void prohibit() { + repository.setBoundedContext(ctx1); + assertThrows(IllegalStateException.class, () -> + repository.setBoundedContext(ctx2)); + } + + @Test + @DisplayName("allowing passing the same value twice") + void idempotency() { + repository.setBoundedContext(ctx1); + repository.setBoundedContext(ctx1); + assertThat(repository.context()) + .isEqualTo(ctx1); + } + } + + @Test @DisplayName("close storage on close") void closeStorageOnClose() { From edbc6d8a357cd2a80f9e21641ba11bf6c3819add Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 15:26:01 +0300 Subject: [PATCH 20/43] Pass `BoundedContext` to repo init Also: * clear `boundedContext` link in a repo when closing. Primarily to make tests happy, but also to disallow activity in a context after closing. --- .../aggregate/AggregatePartRepository.java | 12 ++- .../server/aggregate/AggregateRepository.java | 9 +- .../entity/DefaultRecordBasedRepository.java | 8 +- .../entity/EventDispatchingRepository.java | 8 +- .../server/entity/RecordBasedRepository.java | 8 +- .../io/spine/server/entity/Repository.java | 25 +++-- .../procman/ProcessManagerRepository.java | 10 +- .../projection/ProjectionRepository.java | 6 +- .../spine/system/server/MirrorRepository.java | 5 +- .../spine/system/server/SystemRepository.java | 5 +- .../io/spine/server/BoundedContextTest.java | 96 ++++++++++--------- .../aggregate/AggregateRepositoryTest.java | 59 ++++++++---- .../aggregate/IgTestAggregateRepository.java | 9 +- .../aggregate/given/importado/DotSpace.java | 11 ++- .../server/route/given/switchman/Log.java | 7 +- 15 files changed, 167 insertions(+), 111 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java index 0973db0adf9..4ca07233da0 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregatePartRepository.java @@ -22,6 +22,7 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.annotation.Internal; +import io.spine.server.BoundedContext; import io.spine.server.aggregate.model.AggregatePartClass; import static io.spine.server.aggregate.model.AggregatePartClass.asAggregatePartClass; @@ -51,13 +52,16 @@ protected AggregatePartRepository() { /** * Registers itself with the {@link io.spine.server.BoundedContext#aggregateRootDirectory() * AggregateRootDirectory} of the parent {@code BoundedContext}. + * + * @param context + * the Bounded Context of this repository */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); - context().aggregateRootDirectory() - .register(this); + protected void init(BoundedContext context) { + super.init(context); + context.aggregateRootDirectory() + .register(this); } @Override diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 89fc9ae943f..41941896ae0 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -120,17 +120,18 @@ protected AggregateRepository() { * {@link io.spine.server.aggregate.ImportBus ImportBus} of the parent {@code BoundedContext} * for dispatching messages to its aggregates. * + * @param context + * the {@code BoundedContext} of this repository * @throws IllegalStateException - * if the aggregate class does not handle any messages + * if the aggregate class does not handle any messages */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { + protected void init(BoundedContext context) { checkNotVoid(); - super.init(); + super.init(context); - BoundedContext context = context(); context.registerCommandDispatcher(this); context.registerEventDispatcher(this); if (aggregateClass().importsEvents()) { diff --git a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java index 06ae750e451..32acad7a68a 100644 --- a/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java +++ b/server/src/main/java/io/spine/server/entity/DefaultRecordBasedRepository.java @@ -24,6 +24,7 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.errorprone.annotations.concurrent.LazyInit; import com.google.protobuf.Message; +import io.spine.server.BoundedContext; import io.spine.server.entity.model.EntityClass; import io.spine.type.TypeUrl; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -68,11 +69,14 @@ protected StorageConverter storageConverter() { /** * Initializes the repository by performing the validation of the entity class and * creating the storage converter. + * + * @param context + * the Bounded Context of this repository */ @OverridingMethodsMustInvokeSuper @Override - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); storageConverter(); } } diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 8fd2dd5bab0..8c92410550f 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -23,6 +23,7 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Message; import io.spine.core.Event; +import io.spine.server.BoundedContext; import io.spine.server.event.EventDispatcher; import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.ExternalMessageEnvelope; @@ -61,11 +62,14 @@ protected final EventRouting eventRouting() { /** * Registers itself as an event dispatcher with the parent {@code BoundedContext}. + * + * @param context + * the {@code BoundedContext} of this repository */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); context().registerEventDispatcher(this); } diff --git a/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java b/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java index e5db391a942..88b933a97b2 100644 --- a/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java +++ b/server/src/main/java/io/spine/server/entity/RecordBasedRepository.java @@ -30,6 +30,7 @@ import io.spine.client.OrderBy; import io.spine.client.Pagination; import io.spine.client.TargetFilters; +import io.spine.server.BoundedContext; import io.spine.server.entity.storage.Column; import io.spine.server.entity.storage.EntityColumnCache; import io.spine.server.entity.storage.EntityQueries; @@ -99,11 +100,14 @@ protected RecordStorage recordStorage() { /** * Initializes the repository by caching {@link Column} definitions of * the {@link Entity} class managed by this repository. + * + * @param context + * the Bounded Context of this repository */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); cacheEntityColumns(); } diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index f12664ad47d..92bcd05f837 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -64,9 +64,10 @@ public abstract class Repository> implements AutoClose * The {@link BoundedContext} to which the repository belongs. * *

This field is null when a repository is not {@linkplain - * BoundedContext#register(Repository) registered} yet. + * BoundedContext#register(Repository) registered} yet and + * after the repository is {@linkplain #close() closed}. */ - private @MonotonicNonNull BoundedContext boundedContext; + private @Nullable BoundedContext boundedContext; /** * Model class of entities managed by this repository. @@ -198,10 +199,10 @@ public final void setBoundedContext(BoundedContext context) { boolean sameValue = context.equals(this.boundedContext); if (this.boundedContext != null && !sameValue) { throw newIllegalStateException( - "The repository `%s` already has assigned BoundedContext (`%s`)." + - "This operation can be performed only once" + - " Attempted to set the context `%s`.", - this.boundedContext, this, context); + "The repository `%s` has the Bounded Context (`%s`) assigned." + + " This operation can be performed only once." + + " Attempted to set: `%s`.", + this, this.boundedContext, context); } if (sameValue) { @@ -212,7 +213,7 @@ public final void setBoundedContext(BoundedContext context) { if (!isStorageAssigned()) { initStorage(context.storageFactory()); } - init(); + init(context); } /** @@ -224,11 +225,14 @@ public final void setBoundedContext(BoundedContext context) { * *

Registers itself as a type supplier with the {@link io.spine.server.stand.Stand Stand} * of the parent {@code BoundedContext}. + * + * @param context + * the {@code BoundedContext} of this repository */ @OverridingMethodsMustInvokeSuper - protected void init() { - context().stand() - .registerTypeSupplier(this); + protected void init(BoundedContext context) { + context.stand() + .registerTypeSupplier(this); } /** @@ -329,6 +333,7 @@ public void close() { this.storage.close(); this.storage = null; } + this.boundedContext = null; } /** diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index a80c46790f5..a828d0dfb11 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -139,14 +139,18 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { * * *

Throws an {@code IllegalStateException} otherwise. + * @param context + * the Bounded Context of this repository + * @throws IllegalStateException + * if the Process Manager class of this repository does not declare message + * handling methods */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); eventRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); - BoundedContext context = context(); context.registerCommandDispatcher(this); checkNotDeaf(); diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index d2d5a730dfa..0b5bf714727 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -27,6 +27,7 @@ import com.google.protobuf.Timestamp; import io.spine.annotation.Internal; import io.spine.core.Event; +import io.spine.server.BoundedContext; import io.spine.server.entity.EventDispatchingRepository; import io.spine.server.entity.StorageConverter; import io.spine.server.event.EventFilter; @@ -83,11 +84,12 @@ public abstract class ProjectionRepository, S e * @throws IllegalStateException * if the state routing does not cover one of the entity state types to which * the entities are subscribed + * @param context */ @Override @OverridingMethodsMustInvokeSuper - protected void init() throws IllegalStateException{ - super.init(); + protected void init(BoundedContext context) throws IllegalStateException{ + super.init(context); ensureDispatchesEvents(); subscribeToSystemEvents(); if (projectionClass().subscribesToStates()) { diff --git a/server/src/main/java/io/spine/system/server/MirrorRepository.java b/server/src/main/java/io/spine/system/server/MirrorRepository.java index a134f264ba1..72dccae21b9 100644 --- a/server/src/main/java/io/spine/system/server/MirrorRepository.java +++ b/server/src/main/java/io/spine/system/server/MirrorRepository.java @@ -35,6 +35,7 @@ import io.spine.logging.Logging; import io.spine.option.EntityOption; import io.spine.option.EntityOption.Kind; +import io.spine.server.BoundedContext; import io.spine.server.entity.EntityVisibility; import io.spine.system.server.event.EntityArchived; import io.spine.system.server.event.EntityDeleted; @@ -79,8 +80,8 @@ final class MirrorRepository @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); prepareRouting(); } diff --git a/server/src/main/java/io/spine/system/server/SystemRepository.java b/server/src/main/java/io/spine/system/server/SystemRepository.java index 3641598bf4f..641540734e2 100644 --- a/server/src/main/java/io/spine/system/server/SystemRepository.java +++ b/server/src/main/java/io/spine/system/server/SystemRepository.java @@ -21,6 +21,7 @@ package io.spine.system.server; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.server.BoundedContext; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.entity.EventFilter; @@ -36,8 +37,8 @@ abstract class SystemRepository> @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); } diff --git a/server/src/test/java/io/spine/server/BoundedContextTest.java b/server/src/test/java/io/spine/server/BoundedContextTest.java index ffe32ebc832..ed97d32e46f 100644 --- a/server/src/test/java/io/spine/server/BoundedContextTest.java +++ b/server/src/test/java/io/spine/server/BoundedContextTest.java @@ -102,32 +102,33 @@ class BoundedContextTest { private final TestEventSubscriber subscriber = new TestEventSubscriber(); - private BoundedContext boundedContext; + private BoundedContext context; private boolean handlersRegistered = false; @BeforeEach void setUp() { ModelTests.dropAllModels(); - boundedContext = BoundedContext.newBuilder() - .setMultitenant(true) - .build(); + context = BoundedContext + .newBuilder() + .setMultitenant(true) + .build(); } @AfterEach void tearDown() throws Exception { if (handlersRegistered) { - boundedContext.eventBus() - .unregister(subscriber); + context.eventBus() + .unregister(subscriber); } - boundedContext.close(); + context.close(); } /** Registers all test repositories, handlers etc. */ private void registerAll() { - boundedContext.register(DefaultRepository.of(ProjectAggregate.class)); - boundedContext.eventBus() - .register(subscriber); + context.register(DefaultRepository.of(ProjectAggregate.class)); + context.eventBus() + .register(subscriber); handlersRegistered = true; } @@ -138,27 +139,28 @@ class Return { @Test @DisplayName("EventBus") void eventBus() { - assertNotNull(boundedContext.eventBus()); + assertNotNull(context.eventBus()); } @Test @DisplayName("IntegrationBus") void integrationBus() { - assertNotNull(boundedContext.integrationBus()); + assertNotNull(context.integrationBus()); } @Test @DisplayName("CommandDispatcher") void commandDispatcher() { - assertNotNull(boundedContext.commandBus()); + assertNotNull(context.commandBus()); } @Test @DisplayName("multitenancy state") void ifSetMultitenant() { - BoundedContext bc = BoundedContext.newBuilder() - .setMultitenant(true) - .build(); + BoundedContext bc = BoundedContext + .newBuilder() + .setMultitenant(true) + .build(); assertTrue(bc.isMultitenant()); } } @@ -186,15 +188,15 @@ void projectionRepository() { } > void registerAndAssertRepository(Class cls) { - boundedContext.register(DefaultRepository.of(cls)); - assertTrue(boundedContext.hasEntitiesOfType(cls)); + context.register(DefaultRepository.of(cls)); + assertTrue(context.hasEntitiesOfType(cls)); } @Test @DisplayName("DefaultRepository via passed entity class") void entityClass() { - boundedContext.register(ProjectAggregate.class); - assertTrue(boundedContext.hasEntitiesOfType(ProjectAggregate.class)); + context.register(ProjectAggregate.class); + assertTrue(context.hasEntitiesOfType(ProjectAggregate.class)); } } @@ -209,15 +211,15 @@ class ByEntityStateClass { @Test @DisplayName("visible entities") void visible() { - boundedContext.register(ProjectAggregate.class); - assertTrue(boundedContext.hasEntitiesWithState(Project.class)); + context.register(ProjectAggregate.class); + assertTrue(context.hasEntitiesWithState(Project.class)); } @Test @DisplayName("invisible entities") void invisible() { - boundedContext.register(new SecretProjectRepository()); - assertTrue(boundedContext.hasEntitiesWithState(SecretProject.class)); + context.register(new SecretProjectRepository()); + assertTrue(context.hasEntitiesWithState(SecretProject.class)); } } @@ -228,16 +230,16 @@ class ByEntityClass { @Test @DisplayName("visible entities") void visible() { - boundedContext.register(ProjectAggregate.class); - assertTrue(boundedContext.hasEntitiesOfType(ProjectAggregate.class)); + context.register(ProjectAggregate.class); + assertTrue(context.hasEntitiesOfType(ProjectAggregate.class)); } @Test @DisplayName("invisible entities") void invisible() { // Process Managers are invisible by default. - boundedContext.register(ProjectProcessManager.class); - assertTrue(boundedContext.hasEntitiesOfType(ProjectProcessManager.class)); + context.register(ProjectProcessManager.class); + assertTrue(context.hasEntitiesOfType(ProjectProcessManager.class)); } } } @@ -272,9 +274,10 @@ void registerStandAsEventDispatcher() { @ParameterizedTest @MethodSource("sameStateRepositories") @DisplayName("not allow two entity repositories with entities of same state") - void throwOnSameEntityState(Repository firstRepo, Repository secondRepo) { - boundedContext.register(firstRepo); - assertThrows(IllegalStateException.class, () -> boundedContext.register(secondRepo)); + void throwOnSameEntityState(Repository firstRepo, + Repository secondRepo) { + context.register(firstRepo); + assertThrows(IllegalStateException.class, () -> context.register(secondRepo)); } /** @@ -307,9 +310,9 @@ private static Stream sameStateRepositories() { Set>> cartesianProduct = Sets.cartesianProduct(repositories, sameStateRepositories); - Stream result = cartesianProduct.stream() - .map(repos -> Arguments.of(repos.get(0), - repos.get(1))); + Stream result = + cartesianProduct.stream() + .map(repos -> Arguments.of(repos.get(0), repos.get(1))); return result; } @@ -318,7 +321,7 @@ private static Stream sameStateRepositories() { void setStorageOnRegister() { Repository repository = DefaultRepository.of(ProjectAggregate.class); - boundedContext.register(repository); + context.register(repository); assertTrue(repository.isStorageAssigned()); } @@ -327,21 +330,22 @@ void setStorageOnRegister() { void notOverrideStorage() { ProjectAggregateRepository repository = new ProjectAggregateRepository(); Repository spy = spy(repository); - boundedContext.register(repository); + context.register(repository); verify(spy, never()).initStorage(any(StorageFactory.class)); } @Test - @DisplayName("set storage factory for EventBus") + @DisplayName("allow custom EventBus") void setEventBusStorageFactory() { - BoundedContext bc = BoundedContext.newBuilder() - .setEventBus(EventBus.newBuilder()) - .build(); + BoundedContext bc = BoundedContext + .newBuilder() + .setEventBus(EventBus.newBuilder()) + .build(); assertNotNull(bc.eventBus()); } @Test - @DisplayName("not set storage factory for EventBus if EventStore is set") + @DisplayName("not overwrite EventStore if already set in EventBus.Builder") void useEventStoreIfSet() { EventStore eventStore = eventStore(); BoundedContext bc = BoundedContext.newBuilder() @@ -439,12 +443,12 @@ private BoundedContext singleTenant() { @Test @DisplayName("obtain entity types by visibility") void getEntityTypesByVisibility() { - assertThat(boundedContext.entityStateTypes(EntityOption.Visibility.FULL)) + assertThat(context.entityStateTypes(EntityOption.Visibility.FULL)) .isEmpty(); registerAll(); - assertThat(boundedContext.entityStateTypes(EntityOption.Visibility.FULL)) + assertThat(context.entityStateTypes(EntityOption.Visibility.FULL)) .isNotEmpty(); } @@ -453,7 +457,7 @@ void getEntityTypesByVisibility() { void throwOnNoRepoFound() { // Attempt to get a repository without registering. assertThrows(IllegalStateException.class, - () -> boundedContext.findRepository(Project.class)); + () -> context.findRepository(Project.class)); } @Test @@ -461,9 +465,9 @@ void throwOnNoRepoFound() { void notExposeInvisibleAggregates() { ModelTests.dropAllModels(); - boundedContext.register(new SecretProjectRepository()); + context.register(new SecretProjectRepository()); - Truth8.assertThat(boundedContext.findRepository(SecretProject.class)) + Truth8.assertThat(context.findRepository(SecretProject.class)) .isEmpty(); } diff --git a/server/src/test/java/io/spine/server/aggregate/AggregateRepositoryTest.java b/server/src/test/java/io/spine/server/aggregate/AggregateRepositoryTest.java index f6d62c9e857..2e75c02dbf8 100644 --- a/server/src/test/java/io/spine/server/aggregate/AggregateRepositoryTest.java +++ b/server/src/test/java/io/spine/server/aggregate/AggregateRepositoryTest.java @@ -509,6 +509,20 @@ void onRejections() { @DisplayName("post produced events to EventBus") class PostEventsToBus { + private AggregateRepository repository; + + /** + * Create a fresh instance of the repository since this nested class uses + * {@code BlackBoxBoundedContext}. We cannot use the instance of the repository created by + * {@link AggregateRepositoryTest#setUp()} because this method registers it with another + * {@code BoundedContext}. + */ + @BeforeEach + void createAnotherRepository() { + resetRepository(); + repository = repository(); + } + @Test @DisplayName("after command dispatching") void afterCommand() { @@ -532,11 +546,12 @@ void afterCommand() { .newBuilder() .setProjectId(id) .build(); - BlackBoxBoundedContext.singleTenant() - .with(repository()) - .receivesCommands(create, addTask, start) - .assertThat(emittedEventsHadVersions(1, 2, 3)) - .close(); + BlackBoxBoundedContext + .singleTenant() + .with(repository) + .receivesCommands(create, addTask, start) + .assertThat(emittedEventsHadVersions(1, 2, 3)) + .close(); } @Test @@ -558,15 +573,16 @@ void afterEvent() { .setProjectId(parent) .addChildProjectId(id) .build(); - BlackBoxBoundedContext.singleTenant() - .with(repository()) - .receivesCommands(create, start) - .receivesEvent(archived) - .assertThat(emittedEventsHadVersions( - 1, 2, // Product creation - 3 // Event produced in response to `archived` event - )) - .close(); + BlackBoxBoundedContext + .singleTenant() + .with(repository) + .receivesCommands(create, start) + .receivesEvent(archived) + .assertThat(emittedEventsHadVersions( + 1, 2, // Product creation + 3 // Event produced in response to `archived` event + )) + .close(); } @Test @@ -588,13 +604,14 @@ void throughEventFilter() { .setProjectId(parent) .addChildProjectId(id) .build(); - BlackBoxBoundedContext.singleTenant() - .with(new EventDiscardingAggregateRepository()) - .receivesCommands(create, start) - .receivesEvent(archived) - .assertThat(emittedEvent(none())) - .assertThat(acked(thrice()).withoutErrorsOrRejections()) - .close(); + BlackBoxBoundedContext + .singleTenant() + .with(new EventDiscardingAggregateRepository()) + .receivesCommands(create, start) + .receivesEvent(archived) + .assertThat(emittedEvent(none())) + .assertThat(acked(thrice()).withoutErrorsOrRejections()) + .close(); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java index 9899cc7cd15..6318dfd34e8 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java @@ -21,6 +21,7 @@ package io.spine.server.aggregate.given.aggregate; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.server.BoundedContext; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.event.AggProjectPaused; import io.spine.test.aggregate.event.AggTaskStarted; @@ -36,11 +37,11 @@ public class IgTestAggregateRepository @OverridingMethodsMustInvokeSuper @Override - public void init() { - super.init(); + public void init(BoundedContext context) { + super.init(context); eventRouting().route(AggTaskStarted.class, - (message, context) -> withId(message.getProjectId())) + (message, ctx) -> withId(message.getProjectId())) .route(AggProjectPaused.class, - (message, context) -> withId(message.getProjectId())); + (message, ctx) -> withId(message.getProjectId())); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java index 696baab3209..fe1612a8472 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java +++ b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java @@ -21,6 +21,7 @@ package io.spine.server.aggregate.given.importado; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.server.BoundedContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; @@ -32,14 +33,16 @@ public final class DotSpace extends AggregateRepository { /** * Replaces event import routing to take first message field. * + * @param context + * the {@code BoundedContext} of this repository * @implNote Default behaviour defined in {@link AggregateRepository#eventImportRoute} - * is to take producer ID from an {@code EventContext}. We redefine this to avoid the need - * of creating {@code Event} instances. Real imports would need to create those. + * is to take producer ID from an {@code EventContext}. We redefine this to avoid the + * need of creating {@code Event} instances. Real imports would need to create those. */ @Override @OverridingMethodsMustInvokeSuper - protected void init() { - super.init(); + protected void init(BoundedContext context) { + super.init(context); eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); } } diff --git a/server/src/test/java/io/spine/server/route/given/switchman/Log.java b/server/src/test/java/io/spine/server/route/given/switchman/Log.java index 6c7c828fcb9..356b7c058f1 100644 --- a/server/src/test/java/io/spine/server/route/given/switchman/Log.java +++ b/server/src/test/java/io/spine/server/route/given/switchman/Log.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSet; import io.spine.base.Time; +import io.spine.server.BoundedContext; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.aggregate.Apply; @@ -85,9 +86,9 @@ public Repository() { } @Override - public void init() { - super.init(); - eventRouting().replaceDefault((message, context) -> SINGLETON_ID_SET); + public void init(BoundedContext context) { + super.init(context); + eventRouting().replaceDefault((event, ctx) -> SINGLETON_ID_SET); } } } From c5f382a6341b47df3aa4d3cf12c8d6fd097d27b9 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 15:28:47 +0300 Subject: [PATCH 21/43] Fix Javadoc --- .../io/spine/server/projection/ProjectionRepository.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 0b5bf714727..4bbe7c396b6 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -81,10 +81,11 @@ public abstract class ProjectionRepository, S e * If one of the states of entities cannot be routed during the created schema, * {@code IllegalStateException} will be thrown. * - * @throws IllegalStateException - * if the state routing does not cover one of the entity state types to which - * the entities are subscribed * @param context + * the {@code BoundedContext} of this repository + * @throws IllegalStateException + * if the state routing does not cover one of the entity state types to which + * the entities are subscribed */ @Override @OverridingMethodsMustInvokeSuper From fb2918542815dbce7a96ad91c7dabe14dc6a44c0 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 15:33:48 +0300 Subject: [PATCH 22/43] Fix Javadoc --- .../io/spine/server/projection/ProjectionRepository.java | 6 ++++++ .../java/io/spine/server/route/StateUpdateRouting.java | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 4bbe7c396b6..0f572bb6898 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -113,6 +113,12 @@ private void ensureDispatchesEvents() { /** * Creates and configures the {@code StateUpdateRouting} used by this repository. + * + *

This method {@linkplain StateUpdateRouting#validate(Set) validates} the created state + * routing for serving all the state classes to which projections subscribe. + * + * @throws IllegalStateException + * if one of the subscribed state classes cannot be served by the created state routing */ private StateUpdateRouting createStateRouting() { ProjectionClass

cls = projectionClass(); diff --git a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java index 442acacfc51..255d792117b 100644 --- a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java +++ b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java @@ -20,7 +20,6 @@ package io.spine.server.route; -import com.google.common.collect.Sets; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.protobuf.Message; import io.spine.core.EventContext; @@ -115,10 +114,12 @@ private static Route> defaultStateRoute() { /** * Validates routing schema for types of state messages. * + * @param stateClasses + * the set of classes that this routing is expected to serve * @throws IllegalStateException - * if one of the state type cannot be dispatched by the current schema configuration + * if one of the state type cannot be dispatched by the current schema configuration */ - public void validate(Sets.SetView stateClasses) throws IllegalStateException { + public void validate(Set stateClasses) throws IllegalStateException { checkNotNull(stateClasses); //TODO:2019-05-15:alexander.yevsyukov: Implement } From c2c1877c695a7a1f6a57194bd5e528694b90ce98 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 15:51:48 +0300 Subject: [PATCH 23/43] Add event routing callback --- .../entity/EventDispatchingRepository.java | 19 ++++++++++- .../procman/ProcessManagerRepository.java | 16 ++++++++- .../spine/system/server/MirrorRepository.java | 33 ++++++++----------- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 8c92410550f..f3a222894ae 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -70,7 +70,24 @@ protected final EventRouting eventRouting() { @OverridingMethodsMustInvokeSuper protected void init(BoundedContext context) { super.init(context); - context().registerEventDispatcher(this); + context.registerEventDispatcher(this); + setupEventRouting(eventRouting()); + } + + /** + * A callback for derived repository classes to customize routing schema for events. + * + *

Default routing returns the ID of the entity which + * {@linkplain io.spine.core.EventContext#getProducerId() produced} the event. + * This allows to “link” different kinds of entities by having the same class of IDs. + * More complex scenarios (e.g. one-to-many relationships) may require custom routing schemas. + * + * @param routing + * the routing schema to customize + */ + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc + protected void setupEventRouting(EventRouting routing) { + // Do nothing. } /** diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index a828d0dfb11..76b18c837d0 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -43,6 +43,7 @@ import io.spine.server.procman.model.ProcessManagerClass; import io.spine.server.route.CommandRouting; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.server.type.CommandClass; import io.spine.server.type.CommandEnvelope; import io.spine.server.type.EventClass; @@ -149,7 +150,6 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { @OverridingMethodsMustInvokeSuper protected void init(BoundedContext context) { super.init(context); - eventRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); context.registerCommandDispatcher(this); @@ -160,6 +160,20 @@ protected void init(BoundedContext context) { systemSubscriber.registerIn(context); } + /** + * Replaces default routing with the one which takes the target ID from the first field + * of an event message. + * + * @param routing + * the routing to customize + */ + @Override + @OverridingMethodsMustInvokeSuper + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.replaceDefault(EventRoute.byFirstMessageField(idClass())); + } + /** * Ensures the process manager class handles at least one type of messages. */ diff --git a/server/src/main/java/io/spine/system/server/MirrorRepository.java b/server/src/main/java/io/spine/system/server/MirrorRepository.java index 72dccae21b9..a7bb32f8632 100644 --- a/server/src/main/java/io/spine/system/server/MirrorRepository.java +++ b/server/src/main/java/io/spine/system/server/MirrorRepository.java @@ -21,7 +21,6 @@ package io.spine.system.server; import com.google.common.collect.ImmutableSet; -import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import com.google.protobuf.Any; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.FieldMask; @@ -35,8 +34,8 @@ import io.spine.logging.Logging; import io.spine.option.EntityOption; import io.spine.option.EntityOption.Kind; -import io.spine.server.BoundedContext; import io.spine.server.entity.EntityVisibility; +import io.spine.server.route.EventRouting; import io.spine.system.server.event.EntityArchived; import io.spine.system.server.event.EntityDeleted; import io.spine.system.server.event.EntityRestored; @@ -79,24 +78,18 @@ final class MirrorRepository ); @Override - @OverridingMethodsMustInvokeSuper - protected void init(BoundedContext context) { - super.init(context); - prepareRouting(); - } - - private void prepareRouting() { - eventRouting() - .route(EntityStateChanged.class, - (message, context) -> targetsFrom(message.getId())) - .route(EntityArchived.class, - (message, context) -> targetsFrom(message.getId())) - .route(EntityDeleted.class, - (message, context) -> targetsFrom(message.getId())) - .route(EntityUnarchived.class, - (message, context) -> targetsFrom(message.getId())) - .route(EntityRestored.class, - (message, context) -> targetsFrom(message.getId())); + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(EntityStateChanged.class, + (message, context) -> targetsFrom(message.getId())) + .route(EntityArchived.class, + (message, context) -> targetsFrom(message.getId())) + .route(EntityDeleted.class, + (message, context) -> targetsFrom(message.getId())) + .route(EntityUnarchived.class, + (message, context) -> targetsFrom(message.getId())) + .route(EntityRestored.class, + (message, context) -> targetsFrom(message.getId())); } private static Set targetsFrom(EntityHistoryId historyId) { From cdb6c4b77b420fced60b9d77f4a4fd9bf98dd497 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 16:37:00 +0300 Subject: [PATCH 24/43] Customize event routing via callback --- .../server/aggregate/AggregateRepository.java | 40 +++++++++++-- .../aggregate/IgTestAggregateRepository.java | 18 +++--- .../repo/FailingAggregateRepository.java | 21 ++++--- .../repo/ProjectAggregateRepository.java | 39 ++++++------ .../given/repo/ReactingRepository.java | 27 +++++---- .../repo/RejectionReactingRepository.java | 11 ++-- .../repo/RepoOfAggregateWithLifecycle.java | 8 ++- .../given/EventRootCommandIdTestEnv.java | 60 ++++++++++--------- .../server/route/given/switchman/Log.java | 8 +-- .../given/switchman/SwitchmanBureau.java | 12 ++-- .../blackbox/given/BbProjectRepository.java | 9 ++- .../blackbox/given/BbReportRepository.java | 7 ++- 12 files changed, 157 insertions(+), 103 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 41941896ae0..af722de2112 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -89,7 +89,7 @@ public abstract class AggregateRepository> * The routing for event import, which by default obtains the target aggregate ID as the * {@linkplain io.spine.core.EventContext#getProducerId() producer ID} of the event. */ - private final EventRouting eventImportRoute = + private final EventRouting eventImportRouting = EventRouting.withDefault(EventRoute.byProducerId()); /** @@ -132,6 +132,9 @@ protected void init(BoundedContext context) { super.init(context); + setupCommandRouting(commandRouting.get()); + setupEventRouting(eventRouting); + context.registerCommandDispatcher(this); context.registerEventDispatcher(this); if (aggregateClass().importsEvents()) { @@ -141,6 +144,35 @@ protected void init(BoundedContext context) { this.commandErrorHandler = context.createCommandErrorHandler(); } + /** + * A callback for derived repository classes to customize routing schema for commands. + * + *

Default routing returns the value of the first field of a command message. + * + * @param routing + * the routing schema to customize + */ + @SuppressWarnings("NoopMethodInAbstractClass") // See Javadoc + protected void setupCommandRouting(CommandRouting routing) { + // Do nothing. + } + + /** + * A callback for derived repository classes to customize routing schema for events. + * + *

Default routing returns the ID of the entity which + * {@linkplain io.spine.core.EventContext#getProducerId() produced} the event. + * This allows to “link” different kinds of entities by having the same class of IDs. + * More complex scenarios (e.g. one-to-many relationships) may require custom routing schemas. + * + * @param routing + * the routing schema to customize + */ + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc + protected void setupEventRouting(EventRouting routing) { + // Do nothing. + } + /** * Ensures that this repository dispatches at least one kind of messages. */ @@ -366,14 +398,14 @@ public void onError(EventEnvelope event, RuntimeException exception) { /** * Obtains command routing instance used by this repository. */ - protected final CommandRouting commandRouting() { + private CommandRouting commandRouting() { return commandRouting.get(); } /** * Obtains event routing instance used by this repository. */ - protected final EventRouting eventRouting() { + private EventRouting eventRouting() { return eventRouting; } @@ -399,7 +431,7 @@ protected final EventRouting eventRouting() { * Consider adding this code to the constructor of your {@code AggregateRepository} class. */ protected final EventRouting eventImportRouting() { - return eventImportRoute; + return eventImportRouting; } /** diff --git a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java index 6318dfd34e8..2c97bbf4d90 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/aggregate/IgTestAggregateRepository.java @@ -20,8 +20,7 @@ package io.spine.server.aggregate.given.aggregate; -import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.server.BoundedContext; +import io.spine.server.route.EventRouting; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.event.AggProjectPaused; import io.spine.test.aggregate.event.AggTaskStarted; @@ -32,16 +31,15 @@ * Test environment repository for {@linkplain io.spine.server.aggregate.IdempotencyGuardTest * IdempotencyGuard tests}. */ -public class IgTestAggregateRepository +public final class IgTestAggregateRepository extends AbstractAggregateTestRepository { - @OverridingMethodsMustInvokeSuper @Override - public void init(BoundedContext context) { - super.init(context); - eventRouting().route(AggTaskStarted.class, - (message, ctx) -> withId(message.getProjectId())) - .route(AggProjectPaused.class, - (message, ctx) -> withId(message.getProjectId())); + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(AggTaskStarted.class, + (message, ctx) -> withId(message.getProjectId())) + .route(AggProjectPaused.class, + (message, ctx) -> withId(message.getProjectId())); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/repo/FailingAggregateRepository.java b/server/src/test/java/io/spine/server/aggregate/given/repo/FailingAggregateRepository.java index 5cc65f21709..1f4420e3edb 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/repo/FailingAggregateRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/repo/FailingAggregateRepository.java @@ -27,7 +27,9 @@ import io.spine.core.EventContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.CommandRoute; +import io.spine.server.route.CommandRouting; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.server.type.MessageEnvelope; import io.spine.test.aggregate.number.FloatEncountered; import io.spine.test.aggregate.number.RejectNegativeInt; @@ -38,7 +40,7 @@ /** * The repository of {@link io.spine.server.aggregate.given.repo.FailingAggregate}s. */ -public class FailingAggregateRepository +public final class FailingAggregateRepository extends AggregateRepository { private boolean errorLogged; @@ -46,9 +48,10 @@ public class FailingAggregateRepository private @Nullable RuntimeException lastException; @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") - public FailingAggregateRepository() { - super(); - commandRouting().replaceDefault( + @Override + protected void setupCommandRouting(CommandRouting routing) { + super.setupCommandRouting(routing); + routing.replaceDefault( // Simplistic routing function that takes absolute value as ID. new CommandRoute() { private static final long serialVersionUID = 0L; @@ -61,10 +64,14 @@ public Long apply(CommandMessage message, CommandContext context) { } return 0L; } - } - ); + }); + } - eventRouting().replaceDefault( + @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.replaceDefault( new EventRoute() { private static final long serialVersionUID = 0L; diff --git a/server/src/test/java/io/spine/server/aggregate/given/repo/ProjectAggregateRepository.java b/server/src/test/java/io/spine/server/aggregate/given/repo/ProjectAggregateRepository.java index 1836ecf0154..ed2b081eb42 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/repo/ProjectAggregateRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/repo/ProjectAggregateRepository.java @@ -25,6 +25,7 @@ import io.spine.server.aggregate.AggregateRepository; import io.spine.server.aggregate.AggregateStorage; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.event.AggProjectArchived; import io.spine.test.aggregate.event.AggProjectDeleted; @@ -50,27 +51,27 @@ public class ProjectAggregateRepository .build(); @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") - public ProjectAggregateRepository() { - super(); - eventRouting() - .route(AggProjectArchived.class, - new EventRoute() { - private static final long serialVersionUID = 0L; + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(AggProjectArchived.class, + new EventRoute() { + private static final long serialVersionUID = 0L; - @Override - public Set apply(AggProjectArchived msg, EventContext ctx) { - return ImmutableSet.copyOf(msg.getChildProjectIdList()); - } - }) - .route(AggProjectDeleted.class, - new EventRoute() { - private static final long serialVersionUID = 0L; + @Override + public Set apply(AggProjectArchived msg, EventContext ctx) { + return ImmutableSet.copyOf(msg.getChildProjectIdList()); + } + }) + .route(AggProjectDeleted.class, + new EventRoute() { + private static final long serialVersionUID = 0L; - @Override - public Set apply(AggProjectDeleted msg, EventContext ctx) { - return ImmutableSet.copyOf(msg.getChildProjectIdList()); - } - }); + @Override + public Set apply(AggProjectDeleted msg, EventContext ctx) { + return ImmutableSet.copyOf(msg.getChildProjectIdList()); + } + }); } @Override diff --git a/server/src/test/java/io/spine/server/aggregate/given/repo/ReactingRepository.java b/server/src/test/java/io/spine/server/aggregate/given/repo/ReactingRepository.java index cd3ddf0ea59..e41928120e0 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/repo/ReactingRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/repo/ReactingRepository.java @@ -24,6 +24,7 @@ import io.spine.core.EventContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.event.AggProjectArchived; @@ -32,22 +33,22 @@ /** * The repository of {@link io.spine.server.aggregate.given.repo.ReactingAggregate}. */ -@SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") public class ReactingRepository extends AggregateRepository { - public ReactingRepository() { - super(); - eventRouting() - .route(AggProjectArchived.class, - new EventRoute() { - private static final long serialVersionUID = 0L; + @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(AggProjectArchived.class, + new EventRoute() { + private static final long serialVersionUID = 0L; - @Override - public Set apply(AggProjectArchived message, - EventContext context) { - return ImmutableSet.copyOf(message.getChildProjectIdList()); - } - }); + @Override + public Set apply(AggProjectArchived message, + EventContext context) { + return ImmutableSet.copyOf(message.getChildProjectIdList()); + } + }); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/repo/RejectionReactingRepository.java b/server/src/test/java/io/spine/server/aggregate/given/repo/RejectionReactingRepository.java index 7f244499999..fa593eae76e 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/repo/RejectionReactingRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/repo/RejectionReactingRepository.java @@ -24,18 +24,19 @@ import io.spine.core.EventContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.test.aggregate.ProjectId; import io.spine.test.aggregate.rejection.Rejections.AggCannotStartArchivedProject; import java.util.Set; -public class RejectionReactingRepository +public final class RejectionReactingRepository extends AggregateRepository { - public RejectionReactingRepository() { - super(); - eventRouting() - .route(AggCannotStartArchivedProject.class, routeRejection()); + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(AggCannotStartArchivedProject.class, routeRejection()); } private static EventRoute routeRejection() { diff --git a/server/src/test/java/io/spine/server/aggregate/given/repo/RepoOfAggregateWithLifecycle.java b/server/src/test/java/io/spine/server/aggregate/given/repo/RepoOfAggregateWithLifecycle.java index 2237e4fcacd..be904565e96 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/repo/RepoOfAggregateWithLifecycle.java +++ b/server/src/test/java/io/spine/server/aggregate/given/repo/RepoOfAggregateWithLifecycle.java @@ -25,6 +25,7 @@ import io.spine.core.CommandContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.CommandRoute; +import io.spine.server.route.CommandRouting; import io.spine.test.aggregate.cli.Evaluate; import io.spine.test.aggregate.cli.Evaluated; @@ -55,9 +56,10 @@ public Long apply(CommandMessage message, CommandContext context) { } }; - public RepoOfAggregateWithLifecycle() { - super(); - commandRouting().replaceDefault(parsingRoute); + @Override + protected void setupCommandRouting(CommandRouting routing) { + super.setupCommandRouting(routing); + routing.replaceDefault(parsingRoute); } /** diff --git a/server/src/test/java/io/spine/server/event/given/EventRootCommandIdTestEnv.java b/server/src/test/java/io/spine/server/event/given/EventRootCommandIdTestEnv.java index a6868e4872d..28c9e69e426 100644 --- a/server/src/test/java/io/spine/server/event/given/EventRootCommandIdTestEnv.java +++ b/server/src/test/java/io/spine/server/event/given/EventRootCommandIdTestEnv.java @@ -21,6 +21,7 @@ package io.spine.server.event.given; import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.base.CommandMessage; import io.spine.core.Command; import io.spine.core.CommandContext; @@ -38,6 +39,7 @@ import io.spine.server.procman.ProcessManager; import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.test.event.EvInvitationAccepted; import io.spine.test.event.EvMember; import io.spine.test.event.EvMemberInvitation; @@ -184,21 +186,23 @@ public static class ProjectAggregateRepository * This is done for the purposes of the * {@linkplain EventRootCommandIdTest.MatchExternalEventHandledBy#aggregate()} test. */ - @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") public static class TeamAggregateRepository extends AggregateRepository { - public TeamAggregateRepository() { - eventRouting() - .route(ProjectCreated.class, - new EventRoute() { - private static final long serialVersionUID = 0L; - - @Override - public Set apply(ProjectCreated msg, EventContext ctx) { - return singleton(msg.getTeamId()); - } - }); + @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(ProjectCreated.class, + new EventRoute() { + private static final long serialVersionUID = 0L; + + @Override + public Set apply(ProjectCreated msg, EventContext ctx) { + return singleton(msg.getTeamId()); + } + }); + } } @@ -207,23 +211,25 @@ public Set apply(ProjectCreated msg, EventContext ctx) { * created the invitation. This is done for the purposes of the * {@linkplain EventRootCommandIdTest.MatchExternalEventHandledBy#processManager()} test. */ - @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") - public static class TeamCreationRepository + public static final class TeamCreationRepository extends ProcessManagerRepository { - public TeamCreationRepository() { - eventRouting() - .route(EvInvitationAccepted.class, - new EventRoute() { - private static final long serialVersionUID = 0L; - - @Override - public Set apply(EvInvitationAccepted msg, - EventContext ctx) { - return singleton(msg.getInvitation() - .getTeamId()); - } - }); + @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") + @OverridingMethodsMustInvokeSuper + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(EvInvitationAccepted.class, + new EventRoute() { + private static final long serialVersionUID = 0L; + + @Override + public Set apply(EvInvitationAccepted msg, + EventContext ctx) { + return singleton(msg.getInvitation() + .getTeamId()); + } + }); } } diff --git a/server/src/test/java/io/spine/server/route/given/switchman/Log.java b/server/src/test/java/io/spine/server/route/given/switchman/Log.java index 356b7c058f1..9761f3b1577 100644 --- a/server/src/test/java/io/spine/server/route/given/switchman/Log.java +++ b/server/src/test/java/io/spine/server/route/given/switchman/Log.java @@ -22,11 +22,11 @@ import com.google.common.collect.ImmutableSet; import io.spine.base.Time; -import io.spine.server.BoundedContext; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.aggregate.Apply; import io.spine.server.event.React; +import io.spine.server.route.EventRouting; import io.spine.server.route.given.switchman.event.SwitchPositionConfirmed; import io.spine.server.route.given.switchman.event.SwitchWorkRecorded; import io.spine.server.route.given.switchman.event.SwitchmanAbsenceRecorded; @@ -86,9 +86,9 @@ public Repository() { } @Override - public void init(BoundedContext context) { - super.init(context); - eventRouting().replaceDefault((event, ctx) -> SINGLETON_ID_SET); + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.replaceDefault((event, ctx) -> SINGLETON_ID_SET); } } } diff --git a/server/src/test/java/io/spine/server/route/given/switchman/SwitchmanBureau.java b/server/src/test/java/io/spine/server/route/given/switchman/SwitchmanBureau.java index 8e3c3cc5013..e09ec37a0e7 100644 --- a/server/src/test/java/io/spine/server/route/given/switchman/SwitchmanBureau.java +++ b/server/src/test/java/io/spine/server/route/given/switchman/SwitchmanBureau.java @@ -23,6 +23,7 @@ import io.spine.core.CommandContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.CommandRoute; +import io.spine.server.route.CommandRouting; import io.spine.server.route.given.switchman.command.SetSwitch; import io.spine.server.route.given.switchman.rejection.SwitchmanUnavailable; @@ -30,17 +31,16 @@ * A repository which fires a rejection in response to a command with a particular value of the * target aggregate ID. */ -@SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") public final class SwitchmanBureau extends AggregateRepository { /** The ID of the aggregate for which a {@link SetSwitch command} would be rejected. */ public static final String MISSING_SWITCHMAN_NAME = "Petrovich"; - @SuppressWarnings("ResultOfMethodCallIgnored") - // Can ignore the value since we're calling own builder-like method. - public SwitchmanBureau() { - super(); - commandRouting().route(SetSwitch.class, new CommandRoute() { + @SuppressWarnings("SerializableInnerClassWithNonSerializableOuterClass") + @Override + protected void setupCommandRouting(CommandRouting routing) { + super.setupCommandRouting(routing); + routing.route(SetSwitch.class, new CommandRoute() { private static final long serialVersionUID = 0L; @Override diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectRepository.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectRepository.java index b35a05a4bf1..4d90073a2d3 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectRepository.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectRepository.java @@ -21,6 +21,7 @@ package io.spine.testing.server.blackbox.given; import io.spine.server.aggregate.AggregateRepository; +import io.spine.server.route.EventRouting; import io.spine.testing.server.blackbox.BbProjectId; import io.spine.testing.server.blackbox.event.BbUserDeleted; @@ -29,8 +30,10 @@ public final class BbProjectRepository extends AggregateRepository { - public BbProjectRepository() { - eventRouting().route(BbUserDeleted.class, - (event, context) -> new HashSet<>(event.getProjectList())); + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(BbUserDeleted.class, + (event, context) -> new HashSet<>(event.getProjectList())); } } diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbReportRepository.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbReportRepository.java index dda1b0fe318..27045d1c24e 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbReportRepository.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbReportRepository.java @@ -23,6 +23,7 @@ import io.spine.server.aggregate.AggregateRepository; import io.spine.server.entity.AbstractEntity; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.testing.server.blackbox.BbProjectId; import io.spine.testing.server.blackbox.BbReportId; import io.spine.testing.server.blackbox.event.BbTaskAdded; @@ -41,8 +42,10 @@ public final class BbReportRepository extends AggregateRepository aggregates = newArrayList(); - public BbReportRepository() { - eventRouting().route(BbTaskAdded.class, (EventRoute) + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(BbTaskAdded.class, (EventRoute) (event, context) -> getReportsContainingProject(event.getProjectId())); } From 2628629b7bd6f6fb97d93680ee20b61864049e77 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 17:40:37 +0300 Subject: [PATCH 25/43] Customize event import routing via callback --- .../server/aggregate/AggregateRepository.java | 85 +++++++++++-------- .../java/io/spine/server/aggregate/Apply.java | 2 +- .../io/spine/server/aggregate/ImportBus.java | 4 +- .../model/UnknownEntityTypeException.java | 2 +- .../spine/system/server/SystemRepository.java | 10 +-- .../aggregate/ApplyAllowImportTest.java | 30 +++---- .../aggregate/given/importado/DotSpace.java | 10 +-- 7 files changed, 76 insertions(+), 67 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index af722de2112..572ab7ae736 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -20,6 +20,7 @@ package io.spine.server.aggregate; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets.SetView; @@ -134,6 +135,7 @@ protected void init(BoundedContext context) { setupCommandRouting(commandRouting.get()); setupEventRouting(eventRouting); + setupImportRouting(eventImportRouting); context.registerCommandDispatcher(this); context.registerEventDispatcher(this); @@ -145,7 +147,21 @@ protected void init(BoundedContext context) { } /** - * A callback for derived repository classes to customize routing schema for commands. + * Ensures that this repository dispatches at least one kind of messages. + */ + private void checkNotVoid() { + boolean handlesCommands = dispatchesCommands(); + boolean reactsOnEvents = dispatchesEvents() || dispatchesExternalEvents(); + + if (!handlesCommands && !reactsOnEvents) { + throw newIllegalStateException( + "Aggregates of the repository `%s` neither handle commands" + + " nor react on events.", this); + } + } + + /** + * A callback for derived classes to customize routing schema for commands. * *

Default routing returns the value of the first field of a command message. * @@ -158,7 +174,7 @@ protected void setupCommandRouting(CommandRouting routing) { } /** - * A callback for derived repository classes to customize routing schema for events. + * A callback for derived classes to customize routing schema for events. * *

Default routing returns the ID of the entity which * {@linkplain io.spine.core.EventContext#getProducerId() produced} the event. @@ -174,17 +190,39 @@ protected void setupEventRouting(EventRouting routing) { } /** - * Ensures that this repository dispatches at least one kind of messages. + * A callback for derived classes to customize routing schema for importable events. + * + *

The default routing uses {@linkplain io.spine.core.EventContext#getProducerId() + * producer ID} of the event as the ID of the target aggregate. + * + *

This default routing requires that {@link Event Event} instances + * {@linkplain ImportBus#post(com.google.protobuf.Message, io.grpc.stub.StreamObserver) posted} + * for import must {@link io.spine.core.EventContext#getProducerId() contain} the ID of the + * target aggregate. Not providing a valid aggregate ID would result in + * {@code RuntimeException}. + * + *

Some aggregates may produce events with the aggregate ID as the first field of an event + * message. To set the default routing for repositories of such aggregates, please use the + * code below: + * + *

{@code
+     * routing.replaceDefault(EventRoute.fromFirstMessageField());
+     * }
+ * + * @param routing + * the routing schema to customize. */ - private void checkNotVoid() { - boolean handlesCommands = dispatchesCommands(); - boolean reactsOnEvents = dispatchesEvents() || dispatchesExternalEvents(); + @SuppressWarnings("NoopMethodInAbstractClass") // see Javadoc + protected void setupImportRouting(EventRouting routing) { + // Do nothing. + } - if (!handlesCommands && !reactsOnEvents) { - throw newIllegalStateException( - "Aggregates of the repository `%s` neither handle commands" + - " nor react on events.", this); - } + /** + * Obtains the event import routing used by this repository. + */ + @VisibleForTesting + protected final EventRouting eventImportRouting() { + return eventImportRouting; } @Override @@ -409,31 +447,6 @@ private EventRouting eventRouting() { return eventRouting; } - /** - * Obtains the event import routing, which by default uses - * {@linkplain io.spine.core.EventContext#getProducerId() producer ID} of the event - * as the target aggregate ID. - * - *

This default routing requires that {@link Event Event} instances - * {@linkplain ImportBus#post(com.google.protobuf.Message, io.grpc.stub.StreamObserver) posted} - * for import must {@link io.spine.core.EventContext#getProducerId() contain} the ID of the - * target aggregate. Not providing a valid aggregate ID would result in - * {@code RuntimeException}. - * - *

Some aggregates may produce events with the aggregate ID as the first field of an event - * message. To set the default routing for repositories of such aggregates, please use the - * code below: - * - *

{@code
-     * eventImportRouting().replaceDefault(EventRoute.fromFirstMessageField());
-     * }
- * - * Consider adding this code to the constructor of your {@code AggregateRepository} class. - */ - protected final EventRouting eventImportRouting() { - return eventImportRouting; - } - /** * Posts passed events to {@link EventBus}. */ diff --git a/server/src/main/java/io/spine/server/aggregate/Apply.java b/server/src/main/java/io/spine/server/aggregate/Apply.java index cd457019143..69bd27d5af1 100644 --- a/server/src/main/java/io/spine/server/aggregate/Apply.java +++ b/server/src/main/java/io/spine/server/aggregate/Apply.java @@ -56,7 +56,7 @@ * defined as the first parameter of the annotated method. * * @see ImportBus - * @see AggregateRepository#eventImportRouting() + * @see AggregateRepository#setupImportRouting(io.spine.server.route.EventRouting) */ boolean allowImport() default false; } diff --git a/server/src/main/java/io/spine/server/aggregate/ImportBus.java b/server/src/main/java/io/spine/server/aggregate/ImportBus.java index 7ad314d8964..5a9e1c6a0a4 100644 --- a/server/src/main/java/io/spine/server/aggregate/ImportBus.java +++ b/server/src/main/java/io/spine/server/aggregate/ImportBus.java @@ -60,8 +60,8 @@ * * *

{@linkplain Apply#allowImport() Marking} events and ensuring proper - * {@linkplain AggregateRepository#eventImportRouting() routing} allows to store aggregate - * events without having intermediate messages. + * {@linkplain AggregateRepository#setupImportRouting(io.spine.server.route.EventRouting) routing} + * allows to store aggregate events without having intermediate messages. * *

Temporal Logic

* diff --git a/server/src/main/java/io/spine/server/model/UnknownEntityTypeException.java b/server/src/main/java/io/spine/server/model/UnknownEntityTypeException.java index 9f54e7c16a0..6162c38f0c1 100644 --- a/server/src/main/java/io/spine/server/model/UnknownEntityTypeException.java +++ b/server/src/main/java/io/spine/server/model/UnknownEntityTypeException.java @@ -32,6 +32,6 @@ public final class UnknownEntityTypeException extends RuntimeException { private static final long serialVersionUID = 0L; public UnknownEntityTypeException(TypeUrl type) { - super(format("Type `%s` does not belong to any known bounded context.", type)); + super(format("Type `%s` does not belong to any known Bounded Context.", type)); } } diff --git a/server/src/main/java/io/spine/system/server/SystemRepository.java b/server/src/main/java/io/spine/system/server/SystemRepository.java index 641540734e2..c9c2df87468 100644 --- a/server/src/main/java/io/spine/system/server/SystemRepository.java +++ b/server/src/main/java/io/spine/system/server/SystemRepository.java @@ -20,12 +20,11 @@ package io.spine.system.server; -import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.server.BoundedContext; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.entity.EventFilter; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; /** * Abstract base for system aggregate repositories. @@ -36,10 +35,9 @@ abstract class SystemRepository> extends AggregateRepository { @Override - @OverridingMethodsMustInvokeSuper - protected void init(BoundedContext context) { - super.init(context); - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); + protected void setupImportRouting(EventRouting routing) { + super.setupImportRouting(routing); + routing.replaceDefault(EventRoute.byFirstMessageField(idClass())); } @Override diff --git a/server/src/test/java/io/spine/server/aggregate/ApplyAllowImportTest.java b/server/src/test/java/io/spine/server/aggregate/ApplyAllowImportTest.java index f388c6e31bc..09b3d4252ff 100644 --- a/server/src/test/java/io/spine/server/aggregate/ApplyAllowImportTest.java +++ b/server/src/test/java/io/spine/server/aggregate/ApplyAllowImportTest.java @@ -47,18 +47,18 @@ @DisplayName("Aggregate which supports event import should") class ApplyAllowImportTest { - private SingleTenantBlackBoxContext boundedContext; + private SingleTenantBlackBoxContext context; @BeforeEach void setUp() { - boundedContext = BlackBoxBoundedContext + context = BlackBoxBoundedContext .singleTenant() .with(new DotSpace()); } @AfterEach void tearDown() { - boundedContext.close(); + context.close(); } /** @@ -67,24 +67,24 @@ void tearDown() { @Test @DisplayName("use event appliers in a traditional way") void normalApply() { - ObjectId id = ObjectId.newBuilder() - .setValue("Луноход-1") - .build(); + ObjectId id = ObjectId + .newBuilder() + .setValue("Луноход-1") + .build(); - boundedContext - .receivesCommands(move(id, NORTH), move(id, EAST)) - .assertThat(emittedEvent(Moved.class, twice())); + context.receivesCommands(move(id, NORTH), move(id, EAST)) + .assertThat(emittedEvent(Moved.class, twice())); } @Test @DisplayName("use event appliers for import") void importingApply() { - ObjectId id = ObjectId.newBuilder() - .setValue("LRV") - .build(); + ObjectId id = ObjectId + .newBuilder() + .setValue("LRV") + .build(); - boundedContext - .importsEvents(moved(id, SOUTH), moved(id, WEST), moved(id, WEST)) - .assertThat(emittedEvent(Moved.class, thrice())); + context.importsEvents(moved(id, SOUTH), moved(id, WEST), moved(id, WEST)) + .assertThat(emittedEvent(Moved.class, thrice())); } } diff --git a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java index fe1612a8472..62a83005628 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java +++ b/server/src/test/java/io/spine/server/aggregate/given/importado/DotSpace.java @@ -20,10 +20,9 @@ package io.spine.server.aggregate.given.importado; -import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.server.BoundedContext; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; /** * A repository for {@link Dot} objects. @@ -40,9 +39,8 @@ public final class DotSpace extends AggregateRepository { * need of creating {@code Event} instances. Real imports would need to create those. */ @Override - @OverridingMethodsMustInvokeSuper - protected void init(BoundedContext context) { - super.init(context); - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); + protected void setupImportRouting(EventRouting routing) { + super.setupImportRouting(routing); + routing.replaceDefault(EventRoute.byFirstMessageField(idClass())); } } From a4dc43735e302644e7429c879e36897a38d58c5d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 19:45:52 +0300 Subject: [PATCH 26/43] Customize command routing for process managers --- license-report.md | 16 ++-- .../procman/ProcessManagerRepository.java | 20 ++++- .../procman/ProcessManagerRepositoryTest.java | 20 ++++- .../procman/given/repo/ProjectCompletion.java | 80 +++++++++++++++++++ .../spine/test/procman/cmd_routing_test.proto | 36 +++++++++ .../proto/spine/test/procman/commands.proto | 4 + 6 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java create mode 100644 server/src/test/proto/spine/test/procman/cmd_routing_test.proto diff --git a/license-report.md b/license-report.md index c24f4e777eb..47a239af267 100644 --- a/license-report.md +++ b/license-report.md @@ -431,7 +431,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:05 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -821,7 +821,7 @@ This report was generated on **Wed May 15 11:05:05 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1359,7 +1359,7 @@ This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:02 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2059,7 +2059,7 @@ This report was generated on **Wed May 15 11:05:06 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:07 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2603,7 +2603,7 @@ This report was generated on **Wed May 15 11:05:07 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:08 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3108,7 +3108,7 @@ This report was generated on **Wed May 15 11:05:08 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3621,7 +3621,7 @@ This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:15:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4234,4 +4234,4 @@ This report was generated on **Wed May 15 11:05:09 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 11:05:10 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed May 15 19:15:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java index 76b18c837d0..3eef5dc9af4 100644 --- a/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java +++ b/server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java @@ -151,10 +151,11 @@ protected final ProcessManagerClass

toModelClass(Class

cls) { protected void init(BoundedContext context) { super.init(context); - context.registerCommandDispatcher(this); - + setupCommandRouting(commandRouting()); checkNotDeaf(); + context.registerCommandDispatcher(this); + this.commandErrorHandler = context.createCommandErrorHandler(); PmSystemEventWatcher systemSubscriber = new PmSystemEventWatcher<>(this); systemSubscriber.registerIn(context); @@ -174,6 +175,19 @@ protected void setupEventRouting(EventRouting routing) { routing.replaceDefault(EventRoute.byFirstMessageField(idClass())); } + /** + * A callback for derived classes to customize routing schema for commands. + * + *

Default routing returns the value of the first field of a command message. + * + * @param routing + * the routing schema to customize + */ + @SuppressWarnings("NoopMethodInAbstractClass") // See Javadoc + protected void setupCommandRouting(CommandRouting routing) { + // Do nothing. + } + /** * Ensures the process manager class handles at least one type of messages. */ @@ -224,7 +238,7 @@ public Set commandClasses() { /** * Obtains command routing schema used by this repository. */ - protected final CommandRouting commandRouting() { + private CommandRouting commandRouting() { return commandRouting.get(); } diff --git a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java index 0b0a7a78894..5b2d7a27554 100644 --- a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java +++ b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java @@ -21,6 +21,7 @@ package io.spine.server.procman; import com.google.common.truth.Truth; +import com.google.common.truth.Truth8; import com.google.protobuf.Any; import io.spine.base.CommandMessage; import io.spine.base.EventMessage; @@ -40,6 +41,7 @@ import io.spine.server.event.DuplicateEventException; import io.spine.server.procman.given.delivery.GivenMessage; import io.spine.server.procman.given.repo.EventDiscardingProcManRepository; +import io.spine.server.procman.given.repo.ProjectCompletion; import io.spine.server.procman.given.repo.RememberingSubscriber; import io.spine.server.procman.given.repo.SensoryDeprivedPmRepository; import io.spine.server.procman.given.repo.TestProcessManager; @@ -260,6 +262,14 @@ private void dispatchEvent(Event origin) { repository().dispatch(EventEnvelope.of(event)); } + @Test + @DisplayName("allow customizing command routing") + void setupOfCommandRouting() { + ProjectCompletion.Repository repo = new ProjectCompletion.Repository(); + boundedContext.register(repo); + assertTrue(repo.callbackCalled()); + } + @Nested @DisplayName("dispatch") class Dispatch { @@ -452,7 +462,8 @@ void throwOnUnknownCommand() { ProcessManagerRepository repo = repository(); Throwable exception = assertThrows(RuntimeException.class, () -> repo.dispatchNowTo(id, request)); - assertThat(getRootCause(exception), instanceOf(IllegalStateException.class)); + Truth.assertThat(getRootCause(exception)) + .isInstanceOf(IllegalStateException.class); } @Nested @@ -526,8 +537,8 @@ void discardEntityStateChangedEvents() { .newBuilder() .setProjectId(projectId) .build(); - assertTrue(filter.filter(arbitraryEvent) - .isPresent()); + Truth8.assertThat(filter.filter(arbitraryEvent)) + .isPresent(); Any newState = pack(currentTime()); EntityHistoryId historyId = EntityHistoryId @@ -540,7 +551,8 @@ void discardEntityStateChangedEvents() { .setId(historyId) .setNewState(newState) .build(); - assertFalse(filter.filter(discardedEvent).isPresent()); + Truth8.assertThat(filter.filter(discardedEvent)) + .isEmpty(); } @Test diff --git a/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java b/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java new file mode 100644 index 00000000000..2c6aa9458c3 --- /dev/null +++ b/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.procman.given.repo; + +import io.spine.core.CommandContext; +import io.spine.server.command.Assign; +import io.spine.server.procman.ProcessManager; +import io.spine.server.procman.ProcessManagerRepository; +import io.spine.server.route.CommandRouting; +import io.spine.test.procman.ProcessId; +import io.spine.test.procman.ProcessState; +import io.spine.test.procman.ProcessStateVBuilder; +import io.spine.test.procman.ProjectId; +import io.spine.test.procman.command.PmCompleteProject; +import io.spine.test.procman.command.PmCreateProject; +import io.spine.test.procman.event.PmProjectCreated; + +import static io.spine.testdata.Sample.builderForType; + +/** + * A test environment for testing + * {@linkplain ProcessManagerRepository#setupCommandRouting(CommandRouting) custom command + * routing setup}. + * + * @see Repository#setupCommandRouting(CommandRouting) + */ +public class ProjectCompletion + extends ProcessManager { + + @Assign + PmProjectCreated handle(PmCompleteProject command, CommandContext ignored) { + PmProjectCreated.Builder event = builderForType(PmProjectCreated.class); + return event.setProjectId(command.getProjectId()) + .build(); + } + + public static class Repository + extends ProcessManagerRepository { + + private boolean callbackCalled; + + @Override + protected void setupCommandRouting(CommandRouting routing) { + super.setupCommandRouting(routing); + routing.route(PmCreateProject.class, + (command, context) -> toProcessId(command.getProjectId())); + this.callbackCalled = true; + } + + private static ProcessId toProcessId(ProjectId projectId) { + return ProcessId + .vBuilder() + .setUuid(projectId.getId()) + .build(); + } + + public boolean callbackCalled() { + return callbackCalled; + } + + } +} diff --git a/server/src/test/proto/spine/test/procman/cmd_routing_test.proto b/server/src/test/proto/spine/test/procman/cmd_routing_test.proto new file mode 100644 index 00000000000..04acf62af19 --- /dev/null +++ b/server/src/test/proto/spine/test/procman/cmd_routing_test.proto @@ -0,0 +1,36 @@ +/* + * Copyright 2019, TeamDev. 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"; + +package spine.test.procman; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io"; +option java_package="io.spine.test.procman"; +option java_multiple_files = true; + +message ProcessId { + string uuid = 1; +} + +message ProcessState { + ProcessId id = 1 [(required) = false]; +} diff --git a/server/src/test/proto/spine/test/procman/commands.proto b/server/src/test/proto/spine/test/procman/commands.proto index 713a1d64001..cf8c626caf5 100644 --- a/server/src/test/proto/spine/test/procman/commands.proto +++ b/server/src/test/proto/spine/test/procman/commands.proto @@ -80,3 +80,7 @@ message PmScheduleRetrospective { message PmPlanIteration { ProjectId project_id = 1; } + +message PmCompleteProject { + ProjectId project_id = 1; +} From 0368cae035404a7cfef4ad98269efc85f324673e Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 19:58:54 +0300 Subject: [PATCH 27/43] Hide `eventRouting()` --- license-report.md | 16 ++++++++-------- .../entity/EventDispatchingRepository.java | 2 +- .../server/projection/ProjectionRepository.java | 13 ++++++++++--- .../server/ScheduledCommandRepository.java | 6 +++--- .../procman/ProcessManagerRepositoryTest.java | 4 ++-- .../given/repo/TestProcessManagerRepository.java | 15 ++++++++------- .../java/io/spine/server/stand/given/Given.java | 12 +++++++----- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/license-report.md b/license-report.md index 47a239af267..c397280568d 100644 --- a/license-report.md +++ b/license-report.md @@ -431,7 +431,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -821,7 +821,7 @@ This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1359,7 +1359,7 @@ This report was generated on **Wed May 15 19:15:01 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:02 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2059,7 +2059,7 @@ This report was generated on **Wed May 15 19:15:02 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2603,7 +2603,7 @@ This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3108,7 +3108,7 @@ This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3621,7 +3621,7 @@ This report was generated on **Wed May 15 19:15:03 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4234,4 +4234,4 @@ This report was generated on **Wed May 15 19:15:04 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:15:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed May 15 19:57:57 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index f3a222894ae..7a4da901e9b 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -56,7 +56,7 @@ protected EventDispatchingRepository() { * Obtains the {@link EventRouting} schema used by the repository for calculating identifiers * of event targets. */ - protected final EventRouting eventRouting() { + private EventRouting eventRouting() { return eventRouting; } diff --git a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java index 0f572bb6898..fd3c64aa6fd 100644 --- a/server/src/main/java/io/spine/server/projection/ProjectionRepository.java +++ b/server/src/main/java/io/spine/server/projection/ProjectionRepository.java @@ -38,6 +38,7 @@ import io.spine.server.integration.ExternalMessageDispatcher; import io.spine.server.integration.ExternalMessageEnvelope; import io.spine.server.projection.model.ProjectionClass; +import io.spine.server.route.EventRouting; import io.spine.server.route.StateUpdateRouting; import io.spine.server.stand.Stand; import io.spine.server.storage.RecordStorage; @@ -89,13 +90,19 @@ public abstract class ProjectionRepository, S e */ @Override @OverridingMethodsMustInvokeSuper - protected void init(BoundedContext context) throws IllegalStateException{ + protected void init(BoundedContext context) throws IllegalStateException { super.init(context); ensureDispatchesEvents(); subscribeToSystemEvents(); + } + + @Override + @OverridingMethodsMustInvokeSuper + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); if (projectionClass().subscribesToStates()) { - StateUpdateRouting routing = createStateRouting(); - eventRouting().routeStateUpdates(routing); + StateUpdateRouting stateRouting = createStateRouting(); + routing.routeStateUpdates(stateRouting); } } diff --git a/server/src/main/java/io/spine/system/server/ScheduledCommandRepository.java b/server/src/main/java/io/spine/system/server/ScheduledCommandRepository.java index 5ca848971ea..d52f8f6477b 100644 --- a/server/src/main/java/io/spine/system/server/ScheduledCommandRepository.java +++ b/server/src/main/java/io/spine/system/server/ScheduledCommandRepository.java @@ -36,9 +36,9 @@ final class ScheduledCommandRepository extends SystemProjectionRepository { - ScheduledCommandRepository() { - super(); - EventRouting routing = eventRouting(); + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); routing.route(CommandDispatched.class, (message, context) -> routeToExisting(message)); } diff --git a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java index 5b2d7a27554..8ecbc091f60 100644 --- a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java +++ b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java @@ -315,7 +315,7 @@ void events() { assertTrue(TestProcessManager.processed(event.enclosedMessage())); dispatchEvent(event); - RuntimeException exception = repository().getLatestException(); + RuntimeException exception = repository().latestException(); assertNotNull(exception); assertThat(exception, instanceOf(DuplicateEventException.class)); } @@ -329,7 +329,7 @@ void commands() { assertTrue(TestProcessManager.processed(command.enclosedMessage())); dispatchCommand(command); - RuntimeException exception = repository().getLatestException(); + RuntimeException exception = repository().latestException(); assertNotNull(exception); assertThat(exception, instanceOf(DuplicateCommandException.class)); } diff --git a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java index 168334cd299..0a31158db00 100644 --- a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java +++ b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManagerRepository.java @@ -23,6 +23,7 @@ import io.spine.server.entity.EventFilter; import io.spine.server.entity.rejection.StandardRejection; import io.spine.server.procman.ProcessManagerRepository; +import io.spine.server.route.EventRouting; import io.spine.server.type.CommandEnvelope; import io.spine.server.type.EventEnvelope; import io.spine.test.procman.Project; @@ -31,16 +32,16 @@ import static io.spine.server.route.EventRoute.withId; -public class TestProcessManagerRepository +public final class TestProcessManagerRepository extends ProcessManagerRepository { private @Nullable RuntimeException latestException; - public TestProcessManagerRepository() { - super(); - eventRouting() - .route(StandardRejection.class, - (event, context) -> withId((ProjectId) event.entityId())); + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(StandardRejection.class, + (event, context) -> withId((ProjectId) event.entityId())); } @Override @@ -55,7 +56,7 @@ public void onError(CommandEnvelope cmd, RuntimeException exception) { super.onError(cmd, exception); } - public @Nullable RuntimeException getLatestException() { + public @Nullable RuntimeException latestException() { return latestException; } diff --git a/server/src/test/java/io/spine/server/stand/given/Given.java b/server/src/test/java/io/spine/server/stand/given/Given.java index e83fd01acc2..2499bde9670 100644 --- a/server/src/test/java/io/spine/server/stand/given/Given.java +++ b/server/src/test/java/io/spine/server/stand/given/Given.java @@ -27,6 +27,7 @@ import io.spine.server.projection.Projection; import io.spine.server.projection.ProjectionRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; import io.spine.test.projection.Project; import io.spine.test.projection.ProjectId; import io.spine.test.projection.ProjectVBuilder; @@ -43,7 +44,7 @@ public class Given { private Given() { } - public static class StandTestProjectionRepository + public static final class StandTestProjectionRepository extends ProjectionRepository { private static final EventRoute EVENT_TARGETS_FN = @@ -58,9 +59,10 @@ public Set apply(PrjProjectCreated message, EventContext context) { } }; - public StandTestProjectionRepository() { - super(); - eventRouting().route(PrjProjectCreated.class, EVENT_TARGETS_FN); + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(PrjProjectCreated.class, EVENT_TARGETS_FN); } @Override @@ -69,7 +71,7 @@ public EntityLifecycle lifecycleOf(ProjectId id) { } } - public static class StandTestProjection + public static final class StandTestProjection extends Projection { public StandTestProjection(ProjectId id) { From d8d08fb4249a7bc39ff55c1af55a5787e5616264 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 20:27:22 +0300 Subject: [PATCH 28/43] Split tests of event import --- .../aggregate/EventImportRoutingTest.java | 101 ++++++++++++++++++ .../server/aggregate/EventImportTest.java | 99 +++-------------- .../server/aggregate/EventImportTestBase.java | 55 ++++++++++ .../given/klasse/EngineAggregate.java | 4 +- 4 files changed, 173 insertions(+), 86 deletions(-) create mode 100644 server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java create mode 100644 server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java b/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java new file mode 100644 index 00000000000..970a0097717 --- /dev/null +++ b/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.aggregate; + +import io.spine.server.aggregate.given.klasse.EngineId; +import io.spine.server.aggregate.given.klasse.EngineRepository; +import io.spine.server.aggregate.given.klasse.event.SettingsAdjusted; +import io.spine.server.type.EventEnvelope; +import io.spine.testing.server.blackbox.BlackBoxBoundedContext; +import io.spine.testing.server.blackbox.SingleTenantBlackBoxContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static com.google.common.truth.Truth.assertThat; + +@DisplayName("For event import AggregateRepository should") +class EventImportRoutingTest extends EventImportTestBase { + + private SingleTenantBlackBoxContext context; + private EngineRepository repository; + + @BeforeEach + void setUp() { + repository = new EngineRepository(); + context = BlackBoxBoundedContext + .singleTenant() + .with(repository); + } + + @AfterEach + void tearDown() { + context.close(); + } + + @Nested + @DisplayName("route imported events") + class Routing { + + private final EngineId engineId = engineId("AFB"); + private final SettingsAdjusted eventMessage = SettingsAdjusted + .newBuilder() + .setId(engineId) + .build(); + + @Test + @DisplayName("route imported events by Producer ID by default") + void routeById() { + // Create event with the producer ID of the target aggregate. + EventEnvelope event = createEvent(eventMessage, engineId); + + // Apply routing to the generated event. + assertRouted(event); + } + + @Test + @DisplayName("route imported event by first message field, if configured") + void routeByFirstMessageField() { + repository.routeImportByFirstMessageField(); + + // Create event with the producer ID, which is NOT the target aggregate ID. + EventEnvelope event = createEvent(eventMessage, null); + + assertRouted(event); + } + + /** + * Asserts that the import routing resulted in {@link #engineId}. + */ + private void assertRouted(EventEnvelope event) { + Set targets = + repository.eventImportRouting() + .apply(event.message(), event.context()); + + assertThat(targets).hasSize(1); + assertThat(targets).containsExactly(engineId); + } + } +} diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportTest.java b/server/src/test/java/io/spine/server/aggregate/EventImportTest.java index 942c0d62f71..009991ac90a 100644 --- a/server/src/test/java/io/spine/server/aggregate/EventImportTest.java +++ b/server/src/test/java/io/spine/server/aggregate/EventImportTest.java @@ -20,18 +20,15 @@ package io.spine.server.aggregate; -import io.spine.base.EventMessage; import io.spine.server.aggregate.given.klasse.EngineId; import io.spine.server.aggregate.given.klasse.EngineRepository; import io.spine.server.aggregate.given.klasse.event.EngineStopped; -import io.spine.server.aggregate.given.klasse.event.SettingsAdjusted; import io.spine.server.aggregate.given.klasse.event.UnsupportedEngineEvent; import io.spine.server.type.EventClass; import io.spine.server.type.EventEnvelope; -import io.spine.testing.server.TestEventFactory; +import io.spine.testing.server.EventSubject; import io.spine.testing.server.blackbox.BlackBoxBoundedContext; import io.spine.testing.server.blackbox.SingleTenantBlackBoxContext; -import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -41,30 +38,28 @@ import java.util.Set; import static com.google.common.truth.Truth.assertThat; -import static io.spine.testing.client.blackbox.Count.once; import static io.spine.testing.client.blackbox.VerifyAcknowledgements.ackedWithErrors; -import static io.spine.testing.server.blackbox.VerifyEvents.emittedEvent; /** * Test support of event import in {@link AggregateRepository}. */ @DisplayName("For event import AggregateRepository should") -class EventImportTest { +class EventImportTest extends EventImportTestBase { - private SingleTenantBlackBoxContext boundedContext; + private SingleTenantBlackBoxContext context; private EngineRepository repository; @BeforeEach void setUp() { repository = new EngineRepository(); - boundedContext = BlackBoxBoundedContext + context = BlackBoxBoundedContext .singleTenant() .with(repository); } @AfterEach void tearDown() { - boundedContext.close(); + context.close(); } @Test @@ -73,51 +68,8 @@ void importableEventClasses() { Set importableEventClasses = repository.importableEvents(); Set exposedByAggregateClass = repository.aggregateClass() .importableEvents(); - assertThat(importableEventClasses).isEqualTo(exposedByAggregateClass); - } - - @Nested - @DisplayName("route imported events") - class Routing { - - private final EngineId engineId = engineId("AFB"); - private final SettingsAdjusted eventMessage = SettingsAdjusted - .newBuilder() - .setId(engineId) - .build(); - - @Test - @DisplayName("route imported events by Producer ID by default") - void routeById() { - // Create event with the producer ID of the target aggregate. - EventEnvelope event = createEvent(eventMessage, engineId); - - // Apply routing to the generated event. - assertRouted(event); - } - - @Test - @DisplayName("route imported event by first message field, if configured") - void routeByFirstMessageField() { - repository.routeImportByFirstMessageField(); - - // Create event with the producer ID, which is NOT the target aggregate ID. - EventEnvelope event = createEvent(eventMessage, null); - - assertRouted(event); - } - - /** - * Asserts that the import routing resulted in {@link #engineId}. - */ - private void assertRouted(EventEnvelope event) { - Set targets = - repository.eventImportRouting() - .apply(event.message(), event.context()); - - assertThat(targets).hasSize(1); - assertThat(targets).containsExactly(engineId); - } + assertThat(importableEventClasses) + .isEqualTo(exposedByAggregateClass); } @Nested @@ -152,8 +104,12 @@ void firstMessageField() { } private void assertImports(EventEnvelope event) { - boundedContext.importsEvent(event.outerObject()) - .assertThat(emittedEvent(EngineStopped.class, once())); + EventSubject assertEvents = + context.importsEvent(event.outerObject()) + .assertEvents() + .withType(EngineStopped.class); + + assertEvents.hasSize(1); } } @@ -167,32 +123,7 @@ void importUnsupported() { .build(); EventEnvelope unsupported = createEvent(eventMessage, id); - boundedContext.importsEvent(unsupported.outerObject()) - .assertThat(ackedWithErrors()); - } - - /** - * Creates a new event for the passed message. - * - * @param eventMessage - * the event message - * @param producerId - * the producer for the event. If {@code null}, a test class name will be the ID - * of the producer. - * @return generated event wrapped into the envelope - */ - private EventEnvelope createEvent(EventMessage eventMessage, @Nullable EngineId producerId) { - TestEventFactory eventFactory = producerId == null - ? TestEventFactory.newInstance(getClass()) - : TestEventFactory.newInstance(producerId, getClass()); - EventEnvelope result = EventEnvelope.of(eventFactory.createEvent(eventMessage)); - return result; - } - - private static EngineId engineId(String value) { - return EngineId - .newBuilder() - .setValue(value) - .build(); + context.importsEvent(unsupported.outerObject()) + .assertThat(ackedWithErrors()); } } diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java b/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java new file mode 100644 index 00000000000..1d6cef93185 --- /dev/null +++ b/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019, TeamDev. 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 io.spine.server.aggregate; + +import io.spine.base.EventMessage; +import io.spine.server.aggregate.given.klasse.EngineId; +import io.spine.server.type.EventEnvelope; +import io.spine.testing.server.TestEventFactory; +import org.checkerframework.checker.nullness.qual.Nullable; + +abstract class EventImportTestBase { + + static EngineId engineId(String value) { + return EngineId + .newBuilder() + .setValue(value) + .build(); + } + + /** + * Creates a new event for the passed message. + * + * @param eventMessage + * the event message + * @param producerId + * the producer for the event. If {@code null}, a test class name will be the ID + * of the producer. + * @return generated event wrapped into the envelope + */ + EventEnvelope createEvent(EventMessage eventMessage, @Nullable EngineId producerId) { + TestEventFactory eventFactory = producerId == null + ? TestEventFactory.newInstance(getClass()) + : TestEventFactory.newInstance(producerId, getClass()); + EventEnvelope result = EventEnvelope.of(eventFactory.createEvent(eventMessage)); + return result; + } +} diff --git a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java index 19d8c1d9da6..edbc7b79c46 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java +++ b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java @@ -115,8 +115,8 @@ Nothing on(EmissionTestStopped event) { * * Since this class reacts on own rejections (which are derived from * ThrowableMessage and have the same names as corresponding rejection - * message classes), we cannot import the outer class in which they - * are declared. + * message classes), we cannot import the nested classes because of + * the name clash. *********************************************************************/ @React From 921fca91ded7d7547b2957ca533ce5d08a6e77c5 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 15 May 2019 20:28:02 +0300 Subject: [PATCH 29/43] Revert making `final` ... to make Mockito happy :( --- server/src/test/java/io/spine/server/stand/given/Given.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/io/spine/server/stand/given/Given.java b/server/src/test/java/io/spine/server/stand/given/Given.java index 2499bde9670..f0bd0fe0bd8 100644 --- a/server/src/test/java/io/spine/server/stand/given/Given.java +++ b/server/src/test/java/io/spine/server/stand/given/Given.java @@ -44,7 +44,7 @@ public class Given { private Given() { } - public static final class StandTestProjectionRepository + public static class StandTestProjectionRepository extends ProjectionRepository { private static final EventRoute EVENT_TARGETS_FN = From 69fa8839ea0ad6d2b22052bfdd1ffdb0a070c0e7 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 16 May 2019 20:45:36 +0300 Subject: [PATCH 30/43] Hide event import routing --- .../server/aggregate/AggregateRepository.java | 21 +--- .../aggregate/EventImportRoutingTest.java | 101 --------------- .../server/aggregate/EventImportTest.java | 118 +++++++++++++++--- .../server/aggregate/EventImportTestBase.java | 55 -------- .../given/klasse/EngineAggregate.java | 2 +- .../given/klasse/EngineRepository.java | 15 ++- 6 files changed, 123 insertions(+), 189 deletions(-) delete mode 100644 server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java delete mode 100644 server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 572ab7ae736..6e90d969c17 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -20,7 +20,6 @@ package io.spine.server.aggregate; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets.SetView; @@ -217,14 +216,6 @@ protected void setupImportRouting(EventRouting routing) { // Do nothing. } - /** - * Obtains the event import routing used by this repository. - */ - @VisibleForTesting - protected final EventRouting eventImportRouting() { - return eventImportRouting; - } - @Override public A create(I id) { A aggregate = aggregateClass().create(id); @@ -387,7 +378,7 @@ private void dispatchTo(I id, EventEnvelope event) { /** * Imports the passed event into one of the aggregates. */ - I importEvent(EventEnvelope event) { + final I importEvent(EventEnvelope event) { checkNotNull(event); I target = with(event.tenantId()).evaluate(() -> doImport(event)); return target; @@ -401,7 +392,7 @@ private I doImport(EventEnvelope event) { } private I routeImport(EventEnvelope event) { - Set ids = eventImportRouting().apply(event.message(), event.context()); + Set ids = eventImportRouting.apply(event.message(), event.context()); int numberOfTargets = ids.size(); checkState( numberOfTargets > 0, @@ -450,7 +441,7 @@ private EventRouting eventRouting() { /** * Posts passed events to {@link EventBus}. */ - void postEvents(Collection events) { + final void postEvents(Collection events) { Iterable filteredEvents = eventFilter().filter(events); EventBus bus = context().eventBus(); bus.post(filteredEvents); @@ -496,7 +487,7 @@ protected AggregateStorage aggregateStorage() { * @param id the ID of the aggregate * @return loaded or created aggregate instance */ - A loadOrCreate(I id) { + final A loadOrCreate(I id) { A result = load(id).orElseGet(() -> createNew(id)); return result; } @@ -600,7 +591,7 @@ protected EntityLifecycle lifecycleOf(I id) { return super.lifecycleOf(id); } - void onDispatchEvent(I id, Event event) { + final void onDispatchEvent(I id, Event event) { lifecycleOf(id).onDispatchEventToReactor(event); } @@ -608,7 +599,7 @@ private void onCommandTargetSet(I id, CommandId commandId) { lifecycleOf(id).onTargetAssignedToCommand(commandId); } - void onEventImported(I id, Event event) { + final void onEventImported(I id, Event event) { lifecycleOf(id).onEventImported(event); } } diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java b/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java deleted file mode 100644 index 970a0097717..00000000000 --- a/server/src/test/java/io/spine/server/aggregate/EventImportRoutingTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.aggregate; - -import io.spine.server.aggregate.given.klasse.EngineId; -import io.spine.server.aggregate.given.klasse.EngineRepository; -import io.spine.server.aggregate.given.klasse.event.SettingsAdjusted; -import io.spine.server.type.EventEnvelope; -import io.spine.testing.server.blackbox.BlackBoxBoundedContext; -import io.spine.testing.server.blackbox.SingleTenantBlackBoxContext; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.util.Set; - -import static com.google.common.truth.Truth.assertThat; - -@DisplayName("For event import AggregateRepository should") -class EventImportRoutingTest extends EventImportTestBase { - - private SingleTenantBlackBoxContext context; - private EngineRepository repository; - - @BeforeEach - void setUp() { - repository = new EngineRepository(); - context = BlackBoxBoundedContext - .singleTenant() - .with(repository); - } - - @AfterEach - void tearDown() { - context.close(); - } - - @Nested - @DisplayName("route imported events") - class Routing { - - private final EngineId engineId = engineId("AFB"); - private final SettingsAdjusted eventMessage = SettingsAdjusted - .newBuilder() - .setId(engineId) - .build(); - - @Test - @DisplayName("route imported events by Producer ID by default") - void routeById() { - // Create event with the producer ID of the target aggregate. - EventEnvelope event = createEvent(eventMessage, engineId); - - // Apply routing to the generated event. - assertRouted(event); - } - - @Test - @DisplayName("route imported event by first message field, if configured") - void routeByFirstMessageField() { - repository.routeImportByFirstMessageField(); - - // Create event with the producer ID, which is NOT the target aggregate ID. - EventEnvelope event = createEvent(eventMessage, null); - - assertRouted(event); - } - - /** - * Asserts that the import routing resulted in {@link #engineId}. - */ - private void assertRouted(EventEnvelope event) { - Set targets = - repository.eventImportRouting() - .apply(event.message(), event.context()); - - assertThat(targets).hasSize(1); - assertThat(targets).containsExactly(engineId); - } - } -} diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportTest.java b/server/src/test/java/io/spine/server/aggregate/EventImportTest.java index 009991ac90a..20e0369845b 100644 --- a/server/src/test/java/io/spine/server/aggregate/EventImportTest.java +++ b/server/src/test/java/io/spine/server/aggregate/EventImportTest.java @@ -20,17 +20,22 @@ package io.spine.server.aggregate; +import io.spine.base.EventMessage; +import io.spine.server.aggregate.given.klasse.EngineAggregate; import io.spine.server.aggregate.given.klasse.EngineId; import io.spine.server.aggregate.given.klasse.EngineRepository; import io.spine.server.aggregate.given.klasse.event.EngineStopped; +import io.spine.server.aggregate.given.klasse.event.SettingsAdjusted; import io.spine.server.aggregate.given.klasse.event.UnsupportedEngineEvent; import io.spine.server.type.EventClass; import io.spine.server.type.EventEnvelope; import io.spine.testing.server.EventSubject; +import io.spine.testing.server.TestEventFactory; import io.spine.testing.server.blackbox.BlackBoxBoundedContext; import io.spine.testing.server.blackbox.SingleTenantBlackBoxContext; +import io.spine.testing.server.entity.EntitySubject; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -44,14 +49,13 @@ * Test support of event import in {@link AggregateRepository}. */ @DisplayName("For event import AggregateRepository should") -class EventImportTest extends EventImportTestBase { +class EventImportTest { - private SingleTenantBlackBoxContext context; private EngineRepository repository; + private SingleTenantBlackBoxContext context; - @BeforeEach - void setUp() { - repository = new EngineRepository(); + void createRepository(boolean routeByFirstMessageField) { + repository = new EngineRepository(routeByFirstMessageField); context = BlackBoxBoundedContext .singleTenant() .with(repository); @@ -62,12 +66,48 @@ void tearDown() { context.close(); } + static EngineId engineId(String value) { + return EngineId + .newBuilder() + .setValue(value) + .build(); + } + + protected final EngineRepository repository() { + return this.repository; + } + + protected final SingleTenantBlackBoxContext context() { + return this.context; + } + + /** + * Creates a new event for the passed message. + * + * @param eventMessage + * the event message + * @param producerId + * the producer for the event. If {@code null}, a test class name will be the ID + * of the producer. + * @return generated event wrapped into the envelope + */ + EventEnvelope createEvent(EventMessage eventMessage, @Nullable EngineId producerId) { + TestEventFactory eventFactory = producerId == null + ? TestEventFactory.newInstance(getClass()) + : TestEventFactory.newInstance(producerId, getClass()); + EventEnvelope result = EventEnvelope.of(eventFactory.createEvent(eventMessage)); + return result; + } + @Test @DisplayName("Obtain importable event classes") void importableEventClasses() { - Set importableEventClasses = repository.importableEvents(); - Set exposedByAggregateClass = repository.aggregateClass() - .importableEvents(); + createRepository(false); + Set importableEventClasses = + repository().importableEvents(); + Set exposedByAggregateClass = + repository().aggregateClass() + .importableEvents(); assertThat(importableEventClasses) .isEqualTo(exposedByAggregateClass); } @@ -86,6 +126,8 @@ class Dispatching { @Test @DisplayName("by producer ID") void producerId() { + createRepository(false); + // Create event with producer ID, which is the target aggregate ID. EventEnvelope event = createEvent(eventMessage, engineId); @@ -95,7 +137,7 @@ void producerId() { @Test @DisplayName("by first message field") void firstMessageField() { - repository.routeImportByFirstMessageField(); + createRepository(true); // Create event with producer ID, which is NOT the target aggregate ID. EventEnvelope event = createEvent(eventMessage, null); @@ -105,17 +147,63 @@ void firstMessageField() { private void assertImports(EventEnvelope event) { EventSubject assertEvents = - context.importsEvent(event.outerObject()) - .assertEvents() - .withType(EngineStopped.class); + context().importsEvent(event.outerObject()) + .assertEvents() + .withType(EngineStopped.class); assertEvents.hasSize(1); } } + @Nested + @DisplayName("route imported events by") + class Routing { + private final EngineId engineId = engineId("AFB"); + private final SettingsAdjusted eventMessage = SettingsAdjusted + .newBuilder() + .setId(engineId) + .build(); + + @Test + @DisplayName("Producer ID by default") + void routeById() { + createRepository(false); + + // Create event with the producer ID of the target aggregate. + EventEnvelope event = createEvent(eventMessage, engineId); + + // Apply routing to the generated event. + assertRouted(event); + } + + @Test + @DisplayName("first message field, if configured") + void routeByFirstMessageField() { + createRepository(true); + + // Create event with the producer ID, which is NOT the target aggregate ID. + EventEnvelope event = createEvent(eventMessage, null); + + assertRouted(event); + } + + /** + * Asserts that the import routing resulted in {@link #engineId}. + */ + private void assertRouted(EventEnvelope event) { + EntitySubject assertEntity = + context().importsEvent(event.outerObject()) + .assertEntity(EngineAggregate.class, engineId); + + assertEntity.exists(); + } + } + @Test @DisplayName("fail with exception when importing unsupported event") void importUnsupported() { + createRepository(false); + EngineId id = engineId("AGR"); UnsupportedEngineEvent eventMessage = UnsupportedEngineEvent .newBuilder() @@ -123,7 +211,7 @@ void importUnsupported() { .build(); EventEnvelope unsupported = createEvent(eventMessage, id); - context.importsEvent(unsupported.outerObject()) - .assertThat(ackedWithErrors()); + context().importsEvent(unsupported.outerObject()) + .assertThat(ackedWithErrors()); } } diff --git a/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java b/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java deleted file mode 100644 index 1d6cef93185..00000000000 --- a/server/src/test/java/io/spine/server/aggregate/EventImportTestBase.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019, TeamDev. 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 io.spine.server.aggregate; - -import io.spine.base.EventMessage; -import io.spine.server.aggregate.given.klasse.EngineId; -import io.spine.server.type.EventEnvelope; -import io.spine.testing.server.TestEventFactory; -import org.checkerframework.checker.nullness.qual.Nullable; - -abstract class EventImportTestBase { - - static EngineId engineId(String value) { - return EngineId - .newBuilder() - .setValue(value) - .build(); - } - - /** - * Creates a new event for the passed message. - * - * @param eventMessage - * the event message - * @param producerId - * the producer for the event. If {@code null}, a test class name will be the ID - * of the producer. - * @return generated event wrapped into the envelope - */ - EventEnvelope createEvent(EventMessage eventMessage, @Nullable EngineId producerId) { - TestEventFactory eventFactory = producerId == null - ? TestEventFactory.newInstance(getClass()) - : TestEventFactory.newInstance(producerId, getClass()); - EventEnvelope result = EventEnvelope.of(eventFactory.createEvent(eventMessage)); - return result; - } -} diff --git a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java index edbc7b79c46..8a2f878938e 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java +++ b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineAggregate.java @@ -84,7 +84,7 @@ private void on(EngineStopped event) { */ @Apply(allowImport = true) private void on(SettingsAdjusted event) { - // Do nothing for now. + builder().setStatus(STOPPED); } /* diff --git a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java index 47bbe885d9f..8abf391143a 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java +++ b/server/src/test/java/io/spine/server/aggregate/given/klasse/EngineRepository.java @@ -22,6 +22,7 @@ import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRoute; +import io.spine.server.route.EventRouting; /** * Test environment aggregate repository which can switch default routing of importable events. @@ -30,7 +31,17 @@ */ public class EngineRepository extends AggregateRepository { - public void routeImportByFirstMessageField() { - eventImportRouting().replaceDefault(EventRoute.byFirstMessageField(idClass())); + private final boolean routeByFirstField; + + public EngineRepository(boolean routeByFirstField) { + this.routeByFirstField = routeByFirstField; + } + + @Override + protected void setupImportRouting(EventRouting routing) { + super.setupImportRouting(routing); + if (routeByFirstField) { + routing.replaceDefault(EventRoute.byFirstMessageField(idClass())); + } } } From 70867d455bfd27d8d6e420e94f9cf03bed027695 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 16 May 2019 21:29:04 +0300 Subject: [PATCH 31/43] Test routability of a command message --- .../entity/DefaultCommandRouteTest.java | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java index c81fc979931..d53f567008f 100644 --- a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java +++ b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java @@ -20,6 +20,15 @@ package io.spine.server.entity; +import com.google.protobuf.ByteString; +import com.google.protobuf.CodedOutputStream; +import com.google.protobuf.Descriptors; +import com.google.protobuf.Empty; +import com.google.protobuf.Message; +import com.google.protobuf.Parser; +import com.google.protobuf.Timestamp; +import com.google.protobuf.UnknownFieldSet; +import io.spine.base.CommandMessage; import io.spine.core.CommandContext; import io.spine.server.route.DefaultCommandRoute; import io.spine.test.entity.command.EntCreateProject; @@ -27,6 +36,10 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; + import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -45,4 +58,140 @@ void getIdFromCommand() { .apply(msg, CommandContext.getDefaultInstance())) .isEqualTo(msg.getProjectId()); } + + @Test + @DisplayName("test if command message is routable") + void emptyOrNot() { + assertThat(DefaultCommandRoute.exists(new StubCommand(true))) + .isFalse(); + assertThat(DefaultCommandRoute.exists(new StubCommand(false))) + .isTrue(); + } + + /** + * Stub class which simulates empty command message. + */ + private static final class StubCommand implements CommandMessage { + + private static final long serialVersionUID = 0L; + private final boolean empty; + + private StubCommand(boolean empty) { + this.empty = empty; + } + + @Override + public void writeTo(CodedOutputStream output) { + // Do nothing. + } + + @Override + public int getSerializedSize() { + return 0; + } + + @Override + public Parser getParserForType() { + return null; + } + + @Override + public ByteString toByteString() { + return null; + } + + @SuppressWarnings("ZeroLengthArrayAllocation") + @Override + public byte[] toByteArray() { + return new byte[0]; + } + + @Override + public void writeTo(OutputStream output) { + // Do nothing. + } + + @Override + public void writeDelimitedTo(OutputStream output) { + // Do nothing. + } + + @Override + public Builder newBuilderForType() { + return null; + } + + @Override + public Builder toBuilder() { + return null; + } + + @Override + public Message getDefaultInstanceForType() { + return null; + } + + @Override + public boolean isInitialized() { + return false; + } + + @Override + public List findInitializationErrors() { + return null; + } + + @Override + public String getInitializationErrorString() { + return null; + } + + @Override + public Descriptors.Descriptor getDescriptorForType() { + return empty + ? Empty.getDescriptor() + : Timestamp.getDescriptor(); + } + + @Override + public Map getAllFields() { + return null; + } + + @Override + public boolean hasOneof(Descriptors.OneofDescriptor oneof) { + return false; + } + + @Override + public Descriptors.FieldDescriptor getOneofFieldDescriptor( + Descriptors.OneofDescriptor oneof) { + return null; + } + + @Override + public boolean hasField(Descriptors.FieldDescriptor field) { + return false; + } + + @Override + public Object getField(Descriptors.FieldDescriptor field) { + return null; + } + + @Override + public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { + return 0; + } + + @Override + public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) { + return null; + } + + @Override + public UnknownFieldSet getUnknownFields() { + return null; + } + } } From d32ec7d47b7eda116682d2259102ab57d89a868d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 16 May 2019 22:39:10 +0300 Subject: [PATCH 32/43] Merge remote-tracking branch 'remotes/origin/master' into more-on-state-routing # Conflicts: # server/src/test/java/io/spine/server/BoundedContextTest.java --- .../main/java/io/spine/client/CommandFactory.java | 4 ++-- client/src/main/java/io/spine/client/Queries.java | 2 +- .../src/main/java/io/spine/client/QueryBuilder.java | 4 ++-- client/src/main/java/io/spine/client/Targets.java | 7 ++++--- core/src/main/java/io/spine/core/EventMixin.java | 6 +++--- .../io/spine/system/server/MirrorProjection.java | 10 +++++----- .../io/spine/system/server/ScheduledCommand.java | 4 ++-- .../testing/client/TestActorRequestFactory.java | 8 ++++---- .../testing/core/given/GivenCommandContext.java | 12 ++++++------ version.gradle | 4 ++-- 10 files changed, 31 insertions(+), 30 deletions(-) diff --git a/client/src/main/java/io/spine/client/CommandFactory.java b/client/src/main/java/io/spine/client/CommandFactory.java index 526d2b58f80..535afea865d 100644 --- a/client/src/main/java/io/spine/client/CommandFactory.java +++ b/client/src/main/java/io/spine/client/CommandFactory.java @@ -170,11 +170,11 @@ private CommandContext createContext(int targetVersion) { private static CommandContext withCurrentTime(CommandContext value) { ActorContext withCurrentTime = value.getActorContext() - .toVBuilder() + .toBuilder() .setTimestamp(currentTime()) .build(); CommandContext result = - value.toVBuilder() + value.toBuilder() .setActorContext(withCurrentTime) .build(); return result; diff --git a/client/src/main/java/io/spine/client/Queries.java b/client/src/main/java/io/spine/client/Queries.java index e72ea403d18..c881fe7e8a4 100644 --- a/client/src/main/java/io/spine/client/Queries.java +++ b/client/src/main/java/io/spine/client/Queries.java @@ -53,7 +53,7 @@ private Queries() { public static QueryId generateId() { String formattedId = format(QUERY_ID_FORMAT, Identifier.newUuid()); - return QueryId.vBuilder() + return QueryId.newBuilder() .setValue(formattedId) .build(); } diff --git a/client/src/main/java/io/spine/client/QueryBuilder.java b/client/src/main/java/io/spine/client/QueryBuilder.java index 97ab05aeec0..6f6892fb6d8 100644 --- a/client/src/main/java/io/spine/client/QueryBuilder.java +++ b/client/src/main/java/io/spine/client/QueryBuilder.java @@ -139,7 +139,7 @@ private Optional pagination() { if (limit == 0) { return Optional.empty(); } - Pagination result = Pagination.vBuilder() + Pagination result = Pagination.newBuilder() .setPageSize(limit) .build(); return Optional.of(result); @@ -149,7 +149,7 @@ private Optional orderBy() { if (orderingColumn == null) { return Optional.empty(); } - OrderBy result = OrderBy.vBuilder() + OrderBy result = OrderBy.newBuilder() .setColumn(orderingColumn) .setDirection(direction) .build(); diff --git a/client/src/main/java/io/spine/client/Targets.java b/client/src/main/java/io/spine/client/Targets.java index 5c98e0a3dd5..953f3763660 100644 --- a/client/src/main/java/io/spine/client/Targets.java +++ b/client/src/main/java/io/spine/client/Targets.java @@ -95,6 +95,7 @@ public static Target allOf(Class targetClass) { * a set of predicates which target entity state or event message must match * @return a {@code Target} instance formed according to the provided parameters */ + @SuppressWarnings("CheckReturnValue") public static Target composeTarget(Class targetClass, @Nullable Iterable ids, @Nullable Iterable filters) { @@ -103,7 +104,7 @@ public static Target composeTarget(Class targetClass, boolean includeAll = (ids == null && filters == null); TypeUrl typeUrl = TypeUrl.of(targetClass); - TargetVBuilder builder = Target.vBuilder() + Target.Builder builder = Target.newBuilder() .setType(typeUrl.value()); if (includeAll) { builder.setIncludeAll(true); @@ -132,7 +133,7 @@ private static IdFilter composeIdFilter(Collection items) { private static IdFilter idFilter(List ids) { return IdFilter - .vBuilder() + .newBuilder() .addAllIds(ids) .build(); } @@ -154,7 +155,7 @@ private static I checkId(I item) { } private static TargetFilters targetFilters(List filters, IdFilter idFilter) { - return TargetFilters.vBuilder() + return TargetFilters.newBuilder() .setIdFilter(idFilter) .addAllFilter(filters) .build(); diff --git a/core/src/main/java/io/spine/core/EventMixin.java b/core/src/main/java/io/spine/core/EventMixin.java index 3d9c2779f79..318af835177 100644 --- a/core/src/main/java/io/spine/core/EventMixin.java +++ b/core/src/main/java/io/spine/core/EventMixin.java @@ -95,16 +95,16 @@ default boolean isRejection() { default Event clearEnrichments() { EventContext context = context(); EventContext.OriginCase originCase = context.getOriginCase(); - EventContextVBuilder resultContext = context.toVBuilder() + EventContext.Builder resultContext = context.toBuilder() .clearEnrichment(); if (originCase == EVENT_CONTEXT) { resultContext.setEventContext(context.getEventContext() - .toVBuilder() + .toBuilder() .clearEnrichment() .build()); } Event thisEvent = (Event) this; - Event result = thisEvent.toVBuilder() + Event result = thisEvent.toBuilder() .setContext(resultContext.build()) .build(); return result; diff --git a/server/src/main/java/io/spine/system/server/MirrorProjection.java b/server/src/main/java/io/spine/system/server/MirrorProjection.java index d329072b8e0..fcb9a4d8daa 100644 --- a/server/src/main/java/io/spine/system/server/MirrorProjection.java +++ b/server/src/main/java/io/spine/system/server/MirrorProjection.java @@ -84,7 +84,7 @@ void on(EntityArchived event) { MirrorVBuilder builder = builder(); LifecycleFlags flags = builder .getLifecycle() - .toVBuilder() + .toBuilder() .setArchived(true) .build(); builder.setId(id()) @@ -98,7 +98,7 @@ void on(EntityDeleted event) { MirrorVBuilder builder = builder(); LifecycleFlags flags = builder .getLifecycle() - .toVBuilder() + .toBuilder() .setDeleted(true) .build(); builder.setId(id()) @@ -112,7 +112,7 @@ void on(EntityUnarchived event) { MirrorVBuilder builder = builder(); LifecycleFlags flags = builder .getLifecycle() - .toVBuilder() + .toBuilder() .setArchived(false) .build(); builder.setId(id()) @@ -126,7 +126,7 @@ void on(EntityRestored event) { MirrorVBuilder builder = builder(); LifecycleFlags flags = builder .getLifecycle() - .toVBuilder() + .toBuilder() .setDeleted(false) .build(); builder.setId(id()) @@ -148,7 +148,7 @@ static TargetFilters buildFilters(Target target) { TargetFilters filters = target.getFilters(); CompositeFilter typeFilter = all(eq(TYPE_COLUMN_QUERY_NAME, target.getType())); TargetFilters appendedFilters = filters - .toVBuilder() + .toBuilder() .setIdFilter(idFilter) .addFilter(typeFilter) .build(); diff --git a/server/src/main/java/io/spine/system/server/ScheduledCommand.java b/server/src/main/java/io/spine/system/server/ScheduledCommand.java index 70a07dca14f..a62004e57a2 100644 --- a/server/src/main/java/io/spine/system/server/ScheduledCommand.java +++ b/server/src/main/java/io/spine/system/server/ScheduledCommand.java @@ -51,11 +51,11 @@ void on(CommandScheduled event, EventContext context) { private static Command withSchedule(Command source, CommandContext.Schedule schedule) { CommandContext updatedContext = source.context() - .toVBuilder() + .toBuilder() .setSchedule(schedule) .build(); Command updatedCommand = - source.toVBuilder() + source.toBuilder() .setContext(updatedContext) .build(); return updatedCommand; diff --git a/testutil-client/src/main/java/io/spine/testing/client/TestActorRequestFactory.java b/testutil-client/src/main/java/io/spine/testing/client/TestActorRequestFactory.java index f079f940523..a4bb59d97be 100644 --- a/testutil-client/src/main/java/io/spine/testing/client/TestActorRequestFactory.java +++ b/testutil-client/src/main/java/io/spine/testing/client/TestActorRequestFactory.java @@ -166,13 +166,13 @@ public Command createCommand(CommandMessage message, Timestamp timestamp) { private static Command withTimestamp(Command command, Timestamp timestamp) { CommandContext origin = command.context(); ActorContext withTime = origin.getActorContext() - .toVBuilder() + .toBuilder() .setTimestamp(timestamp) .build(); - CommandContext resultContext = origin.toVBuilder() + CommandContext resultContext = origin.toBuilder() .setActorContext(withTime) .build(); - Command result = command.toVBuilder() + Command result = command.toBuilder() .setContext(resultContext) .build(); return result; @@ -191,7 +191,7 @@ public Command generateCommand() { @SuppressWarnings("MagicNumber") String randomSuffix = String.format("%04d", TestValues.random(10_000)); TestCommandMessage msg = TestCommandMessage - .vBuilder() + .newBuilder() .setId("random-number-" + randomSuffix) .build(); return createCommand(msg); diff --git a/testutil-core/src/main/java/io/spine/testing/core/given/GivenCommandContext.java b/testutil-core/src/main/java/io/spine/testing/core/given/GivenCommandContext.java index 57e71782975..d86d326c0a7 100644 --- a/testutil-core/src/main/java/io/spine/testing/core/given/GivenCommandContext.java +++ b/testutil-core/src/main/java/io/spine/testing/core/given/GivenCommandContext.java @@ -25,7 +25,6 @@ import io.spine.core.ActorContext; import io.spine.core.CommandContext; import io.spine.core.CommandContext.Schedule; -import io.spine.core.CommandContextVBuilder; import io.spine.core.TenantId; import io.spine.core.UserId; @@ -59,12 +58,12 @@ public static CommandContext withRandomActor() { */ public static CommandContext withActorAndTime(UserId actor, Timestamp when) { TenantId tenantId = GivenTenantId.newUuid(); - ActorContext actorContext = ActorContext.vBuilder() + ActorContext actorContext = ActorContext.newBuilder() .setActor(actor) .setTimestamp(when) .setTenantId(tenantId) .build(); - CommandContext result = CommandContext.vBuilder() + CommandContext result = CommandContext.newBuilder() .setActorContext(actorContext) .build(); return result; @@ -78,7 +77,7 @@ public static CommandContext withActorAndTime(UserId actor, Timestamp when) { * @return a new {@code CommandContext} instance */ public static CommandContext withScheduledDelayOf(Duration delay) { - Schedule schedule = Schedule.vBuilder() + Schedule schedule = Schedule.newBuilder() .setDelay(delay) .build(); return withSchedule(schedule); @@ -92,8 +91,9 @@ public static CommandContext withScheduledDelayOf(Duration delay) { * @return a new {@code CommandContext} instance */ private static CommandContext withSchedule(Schedule schedule) { - CommandContextVBuilder builder = withRandomActor().toVBuilder() - .setSchedule(schedule); + CommandContext.Builder builder = + withRandomActor().toBuilder() + .setSchedule(schedule); return builder.build(); } } diff --git a/version.gradle b/version.gradle index 6d9ca6e231a..a50cdbe425c 100644 --- a/version.gradle +++ b/version.gradle @@ -25,11 +25,11 @@ * as we want to manage the versions in a single source. */ -def final SPINE_VERSION = '1.0.0-pre7' +def final SPINE_VERSION = '1.0.0-SNAPSHOT' ext { // The version of the modules in this project. - versionToPublish = '1.0.0-SNAPSHOT' + versionToPublish = SPINE_VERSION // Depend on `base` for the general definitions and a model compiler. spineBaseVersion = SPINE_VERSION From eaad21b21a01c27a3cbc77565ae23d1c3af5d614 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 16 May 2019 22:44:38 +0300 Subject: [PATCH 33/43] Migrate off VBuilder classes --- .../server/aggregate/VersionSequence.java | 4 +-- .../server/commandbus/CommandScheduler.java | 8 ++--- .../spine/server/entity/EntityLifecycle.java | 3 +- .../spine/server/entity/EventFieldFilter.java | 2 +- .../io/spine/server/entity/EventFilter.java | 2 +- .../io/spine/server/event/EventFactory.java | 2 +- .../spine/server/event/RejectionEnvelope.java | 2 +- .../event/model/EventSubscriberMethod.java | 2 +- .../event/model/StateSubscriberMethod.java | 2 +- .../server/event/store/QueryToFilters.java | 18 +++++------ .../server/integration/EventBusAdapter.java | 5 ++-- .../memory/InMemoryStorageFactory.java | 2 +- .../server/storage/memory/TenantRecords.java | 2 +- .../server/CommandLifecycleAggregate.java | 30 +++++++++---------- .../system/server/EntityHistoryAggregate.java | 21 +++++++------ 15 files changed, 50 insertions(+), 55 deletions(-) diff --git a/server/src/main/java/io/spine/server/aggregate/VersionSequence.java b/server/src/main/java/io/spine/server/aggregate/VersionSequence.java index edb9658b0b1..971ff89f59d 100644 --- a/server/src/main/java/io/spine/server/aggregate/VersionSequence.java +++ b/server/src/main/java/io/spine/server/aggregate/VersionSequence.java @@ -77,11 +77,11 @@ ImmutableList update(Collection originalEvents) { private static Event substituteVersion(Event event, Version newVersion) { EventContext newContext = event.context() - .toVBuilder() + .toBuilder() .setVersion(newVersion) .build(); Event result = - event.toVBuilder() + event.toBuilder() .setContext(newContext) .build(); return result; diff --git a/server/src/main/java/io/spine/server/commandbus/CommandScheduler.java b/server/src/main/java/io/spine/server/commandbus/CommandScheduler.java index 9e390c964b3..f0d21088850 100644 --- a/server/src/main/java/io/spine/server/commandbus/CommandScheduler.java +++ b/server/src/main/java/io/spine/server/commandbus/CommandScheduler.java @@ -212,18 +212,18 @@ static Command setSchedule(Command command, Duration delay, Timestamp scheduling CommandContext context = command.getContext(); CommandContext.Schedule scheduleUpdated = context.getSchedule() - .toVBuilder() + .toBuilder() .setDelay(delay) .build(); - CommandContext contextUpdated = context.toVBuilder() + CommandContext contextUpdated = context.toBuilder() .setSchedule(scheduleUpdated) .build(); Command.SystemProperties sysProps = command.getSystemProperties() - .toVBuilder() + .toBuilder() .setSchedulingTime(schedulingTime) .build(); - Command result = command.toVBuilder() + Command result = command.toBuilder() .setContext(contextUpdated) .setSystemProperties(sysProps) .build(); diff --git a/server/src/main/java/io/spine/server/entity/EntityLifecycle.java b/server/src/main/java/io/spine/server/entity/EntityLifecycle.java index c02e708f166..9b9db79b8dd 100644 --- a/server/src/main/java/io/spine/server/entity/EntityLifecycle.java +++ b/server/src/main/java/io/spine/server/entity/EntityLifecycle.java @@ -35,7 +35,6 @@ import io.spine.option.EntityOption; import io.spine.system.server.CommandTarget; import io.spine.system.server.DispatchedMessageId; -import io.spine.system.server.DispatchedMessageIdVBuilder; import io.spine.system.server.EntityHistoryId; import io.spine.system.server.SystemWriteSide; import io.spine.system.server.command.AssignTargetToCommand; @@ -402,7 +401,7 @@ protected void postCommand(CommandMessage command) { @SuppressWarnings("ChainOfInstanceofChecks") private static DispatchedMessageId dispatchedMessageId(MessageId messageId) { checkNotNull(messageId); - DispatchedMessageIdVBuilder builder = DispatchedMessageId.vBuilder(); + DispatchedMessageId.Builder builder = DispatchedMessageId.newBuilder(); if (messageId instanceof EventId) { EventId eventId = (EventId) messageId; return builder.setEventId(eventId) diff --git a/server/src/main/java/io/spine/server/entity/EventFieldFilter.java b/server/src/main/java/io/spine/server/entity/EventFieldFilter.java index 85897bb9d3e..89259dbf584 100644 --- a/server/src/main/java/io/spine/server/entity/EventFieldFilter.java +++ b/server/src/main/java/io/spine/server/entity/EventFieldFilter.java @@ -72,7 +72,7 @@ public ImmutableCollection filter(Collection events) { private Event maskEvent(Event event) { EventMessage message = event.enclosedMessage(); EventMessage masked = mask(message); - return event.toVBuilder() + return event.toBuilder() .setMessage(pack(masked)) .build(); } diff --git a/server/src/main/java/io/spine/server/entity/EventFilter.java b/server/src/main/java/io/spine/server/entity/EventFilter.java index 0822e4747ec..66b77631d94 100644 --- a/server/src/main/java/io/spine/server/entity/EventFilter.java +++ b/server/src/main/java/io/spine/server/entity/EventFilter.java @@ -88,7 +88,7 @@ default ImmutableCollection filter(Collection events) { .map(event -> { EventMessage eventMessage = event.enclosedMessage(); Optional filtered = filter(eventMessage); - Optional result = filtered.map(message -> event.toVBuilder() + Optional result = filtered.map(message -> event.toBuilder() .setMessage(pack(message)) .build()); return result; diff --git a/server/src/main/java/io/spine/server/event/EventFactory.java b/server/src/main/java/io/spine/server/event/EventFactory.java index 4c868a53470..76bf6cd6366 100644 --- a/server/src/main/java/io/spine/server/event/EventFactory.java +++ b/server/src/main/java/io/spine/server/event/EventFactory.java @@ -161,7 +161,7 @@ private static Event createEvent(EventId id, EventMessage message, EventContext checkNotNull(context); Any packed = pack(message); Event result = Event - .vBuilder() + .newBuilder() .setId(id) .setMessage(packed) .setContext(context) diff --git a/server/src/main/java/io/spine/server/event/RejectionEnvelope.java b/server/src/main/java/io/spine/server/event/RejectionEnvelope.java index 9642bee9b0a..49bb7f4334a 100644 --- a/server/src/main/java/io/spine/server/event/RejectionEnvelope.java +++ b/server/src/main/java/io/spine/server/event/RejectionEnvelope.java @@ -206,7 +206,7 @@ public DispatchedCommand getOrigin() { Any commandMessage = rejectionContext.getCommandMessage(); CommandContext commandContext = context.getCommandContext(); DispatchedCommand result = DispatchedCommand - .vBuilder() + .newBuilder() .setMessage(commandMessage) .setContext(commandContext) .build(); diff --git a/server/src/main/java/io/spine/server/event/model/EventSubscriberMethod.java b/server/src/main/java/io/spine/server/event/model/EventSubscriberMethod.java index ade69e865f4..5e1b42b0a24 100644 --- a/server/src/main/java/io/spine/server/event/model/EventSubscriberMethod.java +++ b/server/src/main/java/io/spine/server/event/model/EventSubscriberMethod.java @@ -58,7 +58,7 @@ public MessageFilter filter() { Object expectedValue = fromString(byFieldFilter.value(), fieldType); Any packedValue = toAny(expectedValue); MessageFilter messageFilter = MessageFilter - .vBuilder() + .newBuilder() .setField(fieldPath) .setValue(packedValue) .build(); diff --git a/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java b/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java index 95316df6188..409bfd1cd54 100644 --- a/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java +++ b/server/src/main/java/io/spine/server/event/model/StateSubscriberMethod.java @@ -89,7 +89,7 @@ public Class stateType() { @Override public MessageFilter filter() { return MessageFilter - .vBuilder() + .newBuilder() .setField(TYPE_URL_PATH) .setValue(typeUrlAsAny) .build(); diff --git a/server/src/main/java/io/spine/server/event/store/QueryToFilters.java b/server/src/main/java/io/spine/server/event/store/QueryToFilters.java index c89c8a3df9b..b367648dc85 100644 --- a/server/src/main/java/io/spine/server/event/store/QueryToFilters.java +++ b/server/src/main/java/io/spine/server/event/store/QueryToFilters.java @@ -22,10 +22,8 @@ import com.google.protobuf.Timestamp; import io.spine.client.CompositeFilter; -import io.spine.client.CompositeFilterVBuilder; import io.spine.client.Filter; import io.spine.client.TargetFilters; -import io.spine.client.TargetFiltersVBuilder; import io.spine.server.event.EventFilter; import io.spine.server.event.EventStreamQuery; @@ -45,7 +43,7 @@ final class QueryToFilters { private final EventStreamQuery query; - private final TargetFiltersVBuilder builder; + private final TargetFilters.Builder builder; /** * Creates an instance of {@link TargetFilters} from the given {@link EventStreamQuery}. @@ -65,7 +63,7 @@ static TargetFilters convert(EventStreamQuery query) { private QueryToFilters(EventStreamQuery query) { this.query = query; - this.builder = TargetFilters.vBuilder(); + this.builder = TargetFilters.newBuilder(); } private TargetFilters convert() { @@ -76,8 +74,8 @@ private TargetFilters convert() { @SuppressWarnings("CheckReturnValue") // calling builder private void addTimeFilter() { - CompositeFilterVBuilder timeFilter = CompositeFilter - .vBuilder() + CompositeFilter.Builder timeFilter = CompositeFilter + .newBuilder() .setOperator(ALL); String createdColumn = ColumnName.created.name(); if (query.hasAfter()) { @@ -95,8 +93,8 @@ private void addTimeFilter() { @SuppressWarnings("CheckReturnValue") // calling builder private void addTypeFilter() { - CompositeFilterVBuilder typeFilter = CompositeFilter - .vBuilder() + CompositeFilter.Builder typeFilter = CompositeFilter + .newBuilder() .setOperator(EITHER); String typeColumn = ColumnName.type.name(); for (EventFilter eventFilter : query.getFilterList()) { @@ -111,8 +109,8 @@ private void addTypeFilter() { } @SuppressWarnings("CheckReturnValue") // calling builder - private void add(CompositeFilterVBuilder filter) { - boolean filterIsEmpty = filter.getFilter() + private void add(CompositeFilter.Builder filter) { + boolean filterIsEmpty = filter.getFilterList() .isEmpty(); if (!filterIsEmpty) { builder.addFilter(filter.build()); diff --git a/server/src/main/java/io/spine/server/integration/EventBusAdapter.java b/server/src/main/java/io/spine/server/integration/EventBusAdapter.java index 28e64216e0c..aeb0a2c8912 100644 --- a/server/src/main/java/io/spine/server/integration/EventBusAdapter.java +++ b/server/src/main/java/io/spine/server/integration/EventBusAdapter.java @@ -25,7 +25,6 @@ import io.spine.core.BoundedContextName; import io.spine.core.Event; import io.spine.core.EventContext; -import io.spine.core.EventVBuilder; import io.spine.server.event.EventBus; import io.spine.server.event.EventDispatcher; import io.spine.server.type.EventClass; @@ -62,9 +61,9 @@ ExternalMessageEnvelope toExternalEnvelope(ExternalMessage message) { ExternalMessageEnvelope markExternal(ExternalMessage externalMsg) { Any packedEvent = externalMsg.getOriginalMessage(); Event event = unpack(packedEvent, Event.class); - EventVBuilder eventBuilder = event.toVBuilder(); + Event.Builder eventBuilder = event.toBuilder(); EventContext modifiedContext = eventBuilder.getContext() - .toVBuilder() + .toBuilder() .setExternal(true) .build(); diff --git a/server/src/main/java/io/spine/server/storage/memory/InMemoryStorageFactory.java b/server/src/main/java/io/spine/server/storage/memory/InMemoryStorageFactory.java index 360a1a0cdec..4b30f6e1228 100644 --- a/server/src/main/java/io/spine/server/storage/memory/InMemoryStorageFactory.java +++ b/server/src/main/java/io/spine/server/storage/memory/InMemoryStorageFactory.java @@ -73,7 +73,7 @@ InMemoryStorageFactory newInstance(BoundedContextName context, boolean multitena InMemoryStorageFactory newInstance(String boundedContextName, boolean multitenant) { checkValid(boundedContextName); BoundedContextName name = BoundedContextName - .vBuilder() + .newBuilder() .setValue(boundedContextName) .build(); return newInstance(name, multitenant); diff --git a/server/src/main/java/io/spine/server/storage/memory/TenantRecords.java b/server/src/main/java/io/spine/server/storage/memory/TenantRecords.java index 1bf91b66081..da467a56697 100644 --- a/server/src/main/java/io/spine/server/storage/memory/TenantRecords.java +++ b/server/src/main/java/io/spine/server/storage/memory/TenantRecords.java @@ -140,7 +140,7 @@ EntityRecord findAndApplyFieldMask(I targetId, FieldMask fieldMask) { EntityRecord record = recordWithColumns.getRecord(); Any recordState = record.getState(); Any maskedState = new FieldMaskApplier(fieldMask).maskAny(recordState); - EntityRecord maskedRecord = record.toVBuilder() + EntityRecord maskedRecord = record.toBuilder() .setState(maskedState) .build(); return maskedRecord; diff --git a/server/src/main/java/io/spine/system/server/CommandLifecycleAggregate.java b/server/src/main/java/io/spine/system/server/CommandLifecycleAggregate.java index 21ecf073d54..8e7b9186837 100644 --- a/server/src/main/java/io/spine/system/server/CommandLifecycleAggregate.java +++ b/server/src/main/java/io/spine/system/server/CommandLifecycleAggregate.java @@ -57,7 +57,7 @@ final class CommandLifecycleAggregate @Assign CommandScheduled handle(ScheduleCommand command) { - return CommandScheduled.vBuilder() + return CommandScheduled.newBuilder() .setId(command.getId()) .setSchedule(command.getSchedule()) .build(); @@ -65,7 +65,7 @@ CommandScheduled handle(ScheduleCommand command) { @Assign TargetAssignedToCommand handle(AssignTargetToCommand event) { - return TargetAssignedToCommand.vBuilder() + return TargetAssignedToCommand.newBuilder() .setId(event.getId()) .setTarget(event.getTarget()) .build(); @@ -81,7 +81,7 @@ TargetAssignedToCommand handle(AssignTargetToCommand event) { private void on(CommandReceived event) { ensureId(); CommandTimeline status = CommandTimeline - .vBuilder() + .newBuilder() .setWhenReceived(currentTime()) .build(); builder().setCommand(event.getPayload()) @@ -140,7 +140,7 @@ private void on(TargetAssignedToCommand event) { CommandLifecycleVBuilder builder = builder(); CommandTimeline status = builder.getStatus() - .toVBuilder() + .toBuilder() .setWhenTargetAssigned(currentTime()) .build(); builder.setStatus(status) @@ -167,7 +167,7 @@ private void on(@SuppressWarnings("unused") CommandHandled event) { private void on(CommandErrored event) { ensureId(); Status status = Status - .vBuilder() + .newBuilder() .setError(event.getError()) .build(); setStatus(status); @@ -182,7 +182,7 @@ private void on(CommandErrored event) { private void on(CommandRejected event) { ensureId(); Status status = Status - .vBuilder() + .newBuilder() .setRejection(event.getRejectionEvent()) .build(); setStatus(status); @@ -192,12 +192,12 @@ private void on(CommandRejected event) { private void on(CommandTransformed event) { ensureId(); Substituted substituted = Substituted - .vBuilder() + .newBuilder() .setCommand(event.getId()) .build(); CommandTimeline newStatus = state().getStatus() - .toVBuilder() + .toBuilder() .setSubstituted(substituted) .build(); builder().setStatus(newStatus); @@ -207,16 +207,16 @@ private void on(CommandTransformed event) { private void on(CommandSplit event) { ensureId(); Sequence sequence = Sequence - .vBuilder() + .newBuilder() .addAllItem(event.getProducedList()) .build(); Substituted substituted = Substituted - .vBuilder() + .newBuilder() .setSequence(sequence) .build(); CommandTimeline newStatus = state().getStatus() - .toVBuilder() + .toBuilder() .setSubstituted(substituted) .build(); builder().setStatus(newStatus); @@ -226,19 +226,19 @@ private Command updateSchedule(Schedule schedule) { Command command = builder().getCommand(); CommandContext updatedContext = command.context() - .toVBuilder() + .toBuilder() .setSchedule(schedule) .build(); Command updatedCommand = - command.toVBuilder() + command.toBuilder() .setContext(updatedContext) .build(); return updatedCommand; } - private CommandTimelineVBuilder statusBuilder() { + private CommandTimeline.Builder statusBuilder() { return builder().getStatus() - .toVBuilder(); + .toBuilder(); } private void setStatus(Status status) { diff --git a/server/src/main/java/io/spine/system/server/EntityHistoryAggregate.java b/server/src/main/java/io/spine/system/server/EntityHistoryAggregate.java index 09875e5f05b..b1ce42e95f6 100644 --- a/server/src/main/java/io/spine/system/server/EntityHistoryAggregate.java +++ b/server/src/main/java/io/spine/system/server/EntityHistoryAggregate.java @@ -28,7 +28,6 @@ import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; import io.spine.server.entity.LifecycleFlags; -import io.spine.server.entity.LifecycleFlagsVBuilder; import io.spine.system.server.command.DispatchCommandToHandler; import io.spine.system.server.command.DispatchEventToReactor; import io.spine.system.server.command.DispatchEventToSubscriber; @@ -195,25 +194,25 @@ private void checkNotDuplicate(Command command) throws CannotDispatchCommandTwic } } - private void updateLifecycleFlags(UnaryOperator mutation) { + private void updateLifecycleFlags(UnaryOperator mutation) { LifecycleHistory oldLifecycleHistory = builder().getLifecycle(); - LifecycleFlagsVBuilder flagsBuilder = + LifecycleFlags.Builder flagsBuilder = oldLifecycleHistory.getLifecycleFlags() - .toVBuilder(); + .toBuilder(); LifecycleFlags newFlags = mutation.apply(flagsBuilder) .build(); LifecycleHistory newLifecycleHistory = - oldLifecycleHistory.toVBuilder() + oldLifecycleHistory.toBuilder() .setLifecycleFlags(newFlags) .build(); builder().setLifecycle(newLifecycleHistory); } - private void updateLifecycleTimestamp(UnaryOperator mutation) { + private void updateLifecycleTimestamp(UnaryOperator mutation) { EntityHistoryVBuilder builder = builder(); - LifecycleHistoryVBuilder history = + LifecycleHistory.Builder history = builder.getLifecycle() - .toVBuilder(); + .toBuilder(); LifecycleHistory newHistory = mutation.apply(history) .build(); @@ -236,11 +235,11 @@ private void updateLastCommandTime(Timestamp newCommand) { } } - private void updateDispatchingHistory(UnaryOperator mutation) { + private void updateDispatchingHistory(UnaryOperator mutation) { EntityHistoryVBuilder builder = builder(); - DispatchingHistoryVBuilder history = + DispatchingHistory.Builder history = builder.getDispatching() - .toVBuilder(); + .toBuilder(); DispatchingHistory newHistory = mutation.apply(history) .build(); From ee0d0f18ba4d7e97cc28f315c0c7b0beed074b44 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 10:06:57 +0300 Subject: [PATCH 34/43] Migrate to new compiled protos --- .../src/main/java/io/spine/server/entity/AbstractEntity.java | 4 ++-- server/src/main/java/io/spine/server/entity/Transaction.java | 4 ++-- .../java/io/spine/server/event/model/SubscriberMethod.java | 2 +- .../main/java/io/spine/server/model/MessageHandlerMap.java | 2 +- .../src/main/java/io/spine/server/storage/RecordStorage.java | 2 +- server/src/main/java/io/spine/server/type/EventEnvelope.java | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/io/spine/server/entity/AbstractEntity.java b/server/src/main/java/io/spine/server/entity/AbstractEntity.java index 0735b98b25b..0dc3b8c7e19 100644 --- a/server/src/main/java/io/spine/server/entity/AbstractEntity.java +++ b/server/src/main/java/io/spine/server/entity/AbstractEntity.java @@ -333,7 +333,7 @@ public final boolean isArchived() { * Sets {@code archived} status flag to the passed value. */ protected void setArchived(boolean archived) { - setLifecycleFlags(lifecycleFlags().toVBuilder() + setLifecycleFlags(lifecycleFlags().toBuilder() .setArchived(archived) .build()); } @@ -352,7 +352,7 @@ public final boolean isDeleted() { * Sets {@code deleted} status flag to the passed value. */ protected void setDeleted(boolean deleted) { - setLifecycleFlags(lifecycleFlags().toVBuilder() + setLifecycleFlags(lifecycleFlags().toBuilder() .setDeleted(deleted) .build()); } diff --git a/server/src/main/java/io/spine/server/entity/Transaction.java b/server/src/main/java/io/spine/server/entity/Transaction.java index b6b80d9b3be..5a0122f1431 100644 --- a/server/src/main/java/io/spine/server/entity/Transaction.java +++ b/server/src/main/java/io/spine/server/entity/Transaction.java @@ -486,13 +486,13 @@ public void setListener(TransactionListener listener) { } public void setArchived(boolean archived) { - lifecycleFlags = lifecycleFlags.toVBuilder() + lifecycleFlags = lifecycleFlags.toBuilder() .setArchived(archived) .build(); } public void setDeleted(boolean deleted) { - lifecycleFlags = lifecycleFlags.toVBuilder() + lifecycleFlags = lifecycleFlags.toBuilder() .setDeleted(deleted) .build(); } diff --git a/server/src/main/java/io/spine/server/event/model/SubscriberMethod.java b/server/src/main/java/io/spine/server/event/model/SubscriberMethod.java index c40127d49ae..10b77517d0e 100644 --- a/server/src/main/java/io/spine/server/event/model/SubscriberMethod.java +++ b/server/src/main/java/io/spine/server/event/model/SubscriberMethod.java @@ -70,7 +70,7 @@ public HandlerId id() { FieldPath fieldPath = filter.getField(); return fieldPath.getFieldNameList().isEmpty() ? typeBasedToken - : typeBasedToken.toVBuilder() + : typeBasedToken.toBuilder() .setFilter(filter) .build(); } diff --git a/server/src/main/java/io/spine/server/model/MessageHandlerMap.java b/server/src/main/java/io/spine/server/model/MessageHandlerMap.java index 9ab86f01a94..6e239383aae 100644 --- a/server/src/main/java/io/spine/server/model/MessageHandlerMap.java +++ b/server/src/main/java/io/spine/server/model/MessageHandlerMap.java @@ -168,7 +168,7 @@ public ImmutableCollection handlersOf(M messageClass, MessageClass originClas .build(); HandlerTypeInfo presentKey = map.containsKey(keyWithOrigin) ? keyWithOrigin - : keyWithOrigin.toVBuilder() + : keyWithOrigin.toBuilder() .clearOriginType() .build(); return handlersOf(presentKey); diff --git a/server/src/main/java/io/spine/server/storage/RecordStorage.java b/server/src/main/java/io/spine/server/storage/RecordStorage.java index 029a6b2274a..ddf917be76f 100644 --- a/server/src/main/java/io/spine/server/storage/RecordStorage.java +++ b/server/src/main/java/io/spine/server/storage/RecordStorage.java @@ -199,7 +199,7 @@ public void writeLifecycleFlags(I id, LifecycleFlags flags) { Optional optional = read(request); if (optional.isPresent()) { EntityRecord record = optional.get(); - EntityRecord updated = record.toVBuilder() + EntityRecord updated = record.toBuilder() .setLifecycleFlags(flags) .build(); write(id, updated); diff --git a/server/src/main/java/io/spine/server/type/EventEnvelope.java b/server/src/main/java/io/spine/server/type/EventEnvelope.java index 9f8557ddd25..deac48abe66 100644 --- a/server/src/main/java/io/spine/server/type/EventEnvelope.java +++ b/server/src/main/java/io/spine/server/type/EventEnvelope.java @@ -200,11 +200,11 @@ private Enrichment enrichment() { private EventEnvelope withEnrichment(Enrichment enrichment) { EventContext context = this.context() - .toVBuilder() + .toBuilder() .setEnrichment(enrichment) .build(); Event enrichedCopy = - outerObject().toVBuilder() + outerObject().toBuilder() .setContext(context) .build(); return of(enrichedCopy); From 34d816beff2260a96e1ea982f5800d6457de76d4 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 10:18:54 +0300 Subject: [PATCH 35/43] Migrate to new compiled protos --- .../main/java/io/spine/testing/server/EventReactionTest.java | 4 ++-- .../main/java/io/spine/testing/server/TestEventFactory.java | 4 ++-- .../io/spine/testing/server/projection/ProjectionTest.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/testutil-server/src/main/java/io/spine/testing/server/EventReactionTest.java b/testutil-server/src/main/java/io/spine/testing/server/EventReactionTest.java index 6b097c58f82..d4ccddf849c 100644 --- a/testutil-server/src/main/java/io/spine/testing/server/EventReactionTest.java +++ b/testutil-server/src/main/java/io/spine/testing/server/EventReactionTest.java @@ -79,10 +79,10 @@ protected EventReactorExpected expectThat(E entity) { protected final Event createEvent(M message) { Event event = eventFactory.createEvent(message); EventContext context = event.context() - .toVBuilder() + .toBuilder() .setExternal(externalMessage()) .build(); - return event.toVBuilder() + return event.toBuilder() .setContext(context) .build(); } diff --git a/testutil-server/src/main/java/io/spine/testing/server/TestEventFactory.java b/testutil-server/src/main/java/io/spine/testing/server/TestEventFactory.java index a0bf63cbd4d..cef2f732c8d 100644 --- a/testutil-server/src/main/java/io/spine/testing/server/TestEventFactory.java +++ b/testutil-server/src/main/java/io/spine/testing/server/TestEventFactory.java @@ -93,10 +93,10 @@ public Event createEvent(EventMessage message, @Nullable Version version, Timest checkNotNull(atTime); Event event = createEvent(message, version); EventContext context = event.context() - .toVBuilder() + .toBuilder() .setTimestamp(atTime) .build(); - Event result = event.toVBuilder() + Event result = event.toBuilder() .setContext(context) .build(); return result; diff --git a/testutil-server/src/main/java/io/spine/testing/server/projection/ProjectionTest.java b/testutil-server/src/main/java/io/spine/testing/server/projection/ProjectionTest.java index 4b09b61ab3d..0eb348e5ec7 100644 --- a/testutil-server/src/main/java/io/spine/testing/server/projection/ProjectionTest.java +++ b/testutil-server/src/main/java/io/spine/testing/server/projection/ProjectionTest.java @@ -60,11 +60,11 @@ protected List dispatchTo(P entity) { Event sourceEvent = createEvent(); EventContext context = sourceEvent.context() - .toVBuilder() + .toBuilder() .setEnrichment(enrichment()) .build(); Event enrichedEvent = - sourceEvent.toVBuilder() + sourceEvent.toBuilder() .setContext(context) .build(); dispatch(entity, enrichedEvent); From d630c48e3f073e06ef2021ff81b38494d5deea43 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 10:22:45 +0300 Subject: [PATCH 36/43] Migrate to new compiled protos --- .../aggregate/AggregateStorageTest.java | 10 +++---- .../given/aggregate/TestAggregate.java | 2 +- .../server/command/AbstractCommanderTest.java | 24 ++++++++-------- .../commandbus/CommandAckMonitorTest.java | 4 +-- .../commandbus/CommandSchedulingTest.java | 4 +-- .../io/spine/server/commandbus/Given.java | 14 +++++----- .../given/CommandHandlerTestEnv.java | 8 +++--- .../given/SingleTenantCommandBusTestEnv.java | 4 +-- .../entity/TransactionalEntityTest.java | 4 +-- .../entity/storage/EntityQueriesTest.java | 10 +++---- .../spine/server/event/store/EEntityTest.java | 4 +-- .../server/event/store/EventStoreTest.java | 2 +- .../procman/given/pm/DirectQuizProcman.java | 6 ++-- .../procman/given/repo/ProjectCompletion.java | 2 +- .../given/repo/TestProcessManager.java | 8 +++--- .../e2e/ProjectionEndToEndTest.java | 2 +- .../projection/given/TestProjection.java | 4 +-- .../system/server/EntityHistoryTest.java | 20 ++++++------- .../server/given/entity/PersonAggregate.java | 8 +++--- .../server/given/entity/PersonNamePart.java | 2 +- .../server/given/entity/PersonProcman.java | 4 +-- .../given/schedule/TestCommandScheduler.java | 2 +- .../testing/server/CommandSubjectTest.java | 6 ++-- .../testing/server/EventSubjectTest.java | 6 ++-- .../blackbox/BlackBoxBoundedContextTest.java | 2 +- .../server/blackbox/given/BbInitProcess.java | 10 +++---- .../blackbox/given/BbProjectAggregate.java | 10 +++---- .../testing/server/blackbox/given/Given.java | 28 +++++++++---------- .../server/entity/EntitySubjectTest.java | 2 +- 29 files changed, 106 insertions(+), 106 deletions(-) diff --git a/server/src/test/java/io/spine/server/aggregate/AggregateStorageTest.java b/server/src/test/java/io/spine/server/aggregate/AggregateStorageTest.java index 01ff6122a9d..bdec1a3c0b5 100644 --- a/server/src/test/java/io/spine/server/aggregate/AggregateStorageTest.java +++ b/server/src/test/java/io/spine/server/aggregate/AggregateStorageTest.java @@ -546,14 +546,14 @@ class NotStoreEnrichment { @DisplayName("for EventContext") void forEventContext() { EventContext enrichedContext = EventContext - .vBuilder() + .newBuilder() .setEnrichment(withOneAttribute()) .setTimestamp(Time.currentTime()) .setProducerId(AnyPacker.pack(TestValues.newUuidValue())) .setCommandContext(GivenCommandContext.withRandomActor()) .build(); Event event = Event - .vBuilder() + .newBuilder() .setId(newEventId()) .setContext(enrichedContext) .setMessage(AnyPacker.pack(TestValues.newUuidValue())) @@ -570,20 +570,20 @@ void forEventContext() { @DisplayName("for origin of EventContext type") void forEventContextOrigin() { EventContext origin = EventContext - .vBuilder() + .newBuilder() .setEnrichment(withOneAttribute()) .setTimestamp(Time.currentTime()) .setProducerId(AnyPacker.pack(TestValues.newUuidValue())) .setCommandContext(GivenCommandContext.withRandomActor()) .build(); EventContext context = EventContext - .vBuilder() + .newBuilder() .setEventContext(origin) .setTimestamp(Time.currentTime()) .setProducerId(AnyPacker.pack(TestValues.newUuidValue())) .build(); Event event = Event - .vBuilder() + .newBuilder() .setId(newEventId()) .setContext(context) .setMessage(AnyPacker.pack(TestValues.newUuidValue())) diff --git a/server/src/test/java/io/spine/server/aggregate/given/aggregate/TestAggregate.java b/server/src/test/java/io/spine/server/aggregate/given/aggregate/TestAggregate.java index 6f9d1f3aedf..ce149a2f4ba 100644 --- a/server/src/test/java/io/spine/server/aggregate/given/aggregate/TestAggregate.java +++ b/server/src/test/java/io/spine/server/aggregate/given/aggregate/TestAggregate.java @@ -92,7 +92,7 @@ AggProjectCreated handle(AggCreateProject cmd, CommandContext ctx) { AggTaskAdded handle(AggAddTask cmd, CommandContext ctx) { isAddTaskCommandHandled = true; AggTaskAdded event = taskAdded(cmd.getProjectId()); - return event.toVBuilder() + return event.toBuilder() .setTask(cmd.getTask()) .build(); } diff --git a/server/src/test/java/io/spine/server/command/AbstractCommanderTest.java b/server/src/test/java/io/spine/server/command/AbstractCommanderTest.java index 9c9077f2e88..677a61ed928 100644 --- a/server/src/test/java/io/spine/server/command/AbstractCommanderTest.java +++ b/server/src/test/java/io/spine/server/command/AbstractCommanderTest.java @@ -84,7 +84,7 @@ void setUp() { @DisplayName("create a command in response to a command") void commandOnCommand() { CmdCreateProject commandMessage = CmdCreateProject - .vBuilder() + .newBuilder() .setProjectId(newProjectId()) .build(); createCommandAndPost(commandMessage); @@ -96,9 +96,9 @@ void commandOnCommand() { @DisplayName("create a command on an event") void commandOnEvent() { CmdTaskAdded eventMessage = CmdTaskAdded - .vBuilder() + .newBuilder() .setProjectId(newProjectId()) - .setTask(Task.vBuilder() + .setTask(Task.newBuilder() .setTaskId(newTaskId()) .build()) .build(); @@ -133,21 +133,21 @@ void createCommandPairWithNull() { private static ProjectId newProjectId() { return ProjectId - .vBuilder() + .newBuilder() .setId(newUuid()) .build(); } private static TaskId newTaskId() { return TaskId - .vBuilder() + .newBuilder() .setId(random(1, 100)) .build(); } private static UserId newUserId() { return UserId - .vBuilder() + .newBuilder() .setValue(newUuid()) .build(); @@ -169,12 +169,12 @@ private void postCreateTaskCommand(boolean startTask) { TaskId taskId = newTaskId(); UserId userId = newUserId(); Task task = Task - .vBuilder() + .newBuilder() .setTaskId(taskId) .setAssignee(userId) .build(); CmdCreateTask commandMessage = CmdCreateTask - .vBuilder() + .newBuilder() .setTaskId(taskId) .setTask(task) .setStart(startTask) @@ -194,7 +194,7 @@ private Commendatore(CommandBus commandBus, EventBus eventBus) { @Command FirstCmdCreateProject on(CmdCreateProject command) { return FirstCmdCreateProject - .vBuilder() + .newBuilder() .setId(command.getProjectId()) .build(); } @@ -202,7 +202,7 @@ FirstCmdCreateProject on(CmdCreateProject command) { @Command CmdSetTaskDescription on(CmdTaskAdded event) { return CmdSetTaskDescription - .vBuilder() + .newBuilder() .setTaskId(event.getTask() .getTaskId()) .setDescription("Testing command creation on event") @@ -215,13 +215,13 @@ Pair> on(CmdCreateTask command) { UserId assignee = command.getTask() .getAssignee(); CmdAssignTask cmdAssignTask = CmdAssignTask - .vBuilder() + .newBuilder() .setTaskId(taskId) .setAssignee(assignee) .build(); CmdStartTask cmdStartTask = command.getStart() ? CmdStartTask - .vBuilder() + .newBuilder() .setTaskId(taskId) .build() : null; diff --git a/server/src/test/java/io/spine/server/commandbus/CommandAckMonitorTest.java b/server/src/test/java/io/spine/server/commandbus/CommandAckMonitorTest.java index c22dd080a62..ce2a995a092 100644 --- a/server/src/test/java/io/spine/server/commandbus/CommandAckMonitorTest.java +++ b/server/src/test/java/io/spine/server/commandbus/CommandAckMonitorTest.java @@ -255,11 +255,11 @@ private static Ack errorAck(CommandId commandId) { private static Ack rejectionAck(CommandId commandId) { ProjectId projectId = ProjectId - .vBuilder() + .newBuilder() .setId(commandId.getUuid()) .build(); CommandMessage commandMessage = CmdBusStartProject - .vBuilder() + .newBuilder() .setProjectId(projectId) .build(); Command command = Command diff --git a/server/src/test/java/io/spine/server/commandbus/CommandSchedulingTest.java b/server/src/test/java/io/spine/server/commandbus/CommandSchedulingTest.java index 060542920f7..cb0f7776823 100644 --- a/server/src/test/java/io/spine/server/commandbus/CommandSchedulingTest.java +++ b/server/src/test/java/io/spine/server/commandbus/CommandSchedulingTest.java @@ -142,11 +142,11 @@ void schedulingTime() { private Command createCommand() { ProjectId id = ProjectId - .vBuilder() + .newBuilder() .setId(newUuid()) .build(); CmdBusStartProject command = CmdBusStartProject - .vBuilder() + .newBuilder() .setProjectId(id) .build(); CommandMessage commandMessage = toMessage(command, CommandMessage.class); diff --git a/server/src/test/java/io/spine/server/commandbus/Given.java b/server/src/test/java/io/spine/server/commandbus/Given.java index 07596e02b53..d17fb5353d5 100644 --- a/server/src/test/java/io/spine/server/commandbus/Given.java +++ b/server/src/test/java/io/spine/server/commandbus/Given.java @@ -76,7 +76,7 @@ private ACommand() { private static Command create(io.spine.base.CommandMessage command, UserId userId, Timestamp when) { TenantId generatedTenantId = TenantId - .vBuilder() + .newBuilder() .setValue(newUuid()) .build(); TestActorRequestFactory factory = @@ -176,7 +176,7 @@ static CmdBusCreateTask createTask(TaskId taskId, UserId userId, boolean startTa .setAssignee(userId) .build(); return CmdBusCreateTask - .vBuilder() + .newBuilder() .setTaskId(taskId) .setTask(task) .setStart(startTask) @@ -207,34 +207,34 @@ public static CmdBusCreateProject createProjectMessage() { static CmdBusCreateProject createProjectMessage(ProjectId id) { return CmdBusCreateProject - .vBuilder() + .newBuilder() .setProjectId(id) .build(); } static CmdBusCreateProject createProjectMessage(String projectId) { - return createProjectMessage(ProjectId.vBuilder() + return createProjectMessage(ProjectId.newBuilder() .setId(projectId) .build()); } static CmdBusStartProject startProject(ProjectId id) { return CmdBusStartProject - .vBuilder() + .newBuilder() .setProjectId(id) .build(); } static FirstCmdBusCreateProject firstCreateProject(ProjectId projectId) { return FirstCmdBusCreateProject - .vBuilder() + .newBuilder() .setId(projectId) .build(); } static SecondCmdBusStartProject secondStartProject(ProjectId projectId) { return SecondCmdBusStartProject - .vBuilder() + .newBuilder() .setId(projectId) .build(); } diff --git a/server/src/test/java/io/spine/server/commandbus/given/CommandHandlerTestEnv.java b/server/src/test/java/io/spine/server/commandbus/given/CommandHandlerTestEnv.java index 89532e10481..20aa85be2cc 100644 --- a/server/src/test/java/io/spine/server/commandbus/given/CommandHandlerTestEnv.java +++ b/server/src/test/java/io/spine/server/commandbus/given/CommandHandlerTestEnv.java @@ -180,11 +180,11 @@ public void onError(CommandEnvelope envelope, RuntimeException exception) { private ImmutableList createEventsOnStartProjectCmd() { ProjectId id = ProjectId - .vBuilder() + .newBuilder() .setId(getId()) .build(); CmdBusProjectStarted startedEvent = CmdBusProjectStarted - .vBuilder() + .newBuilder() .setProjectId(id) .build(); CmdBusProjectStarted defaultEvent = CmdBusProjectStarted.getDefaultInstance(); @@ -195,12 +195,12 @@ private ImmutableList createEventsOnStartProjectCmd() { createEventsOnCreateTaskCmd(CmdBusCreateTask msg) { TaskId taskId = msg.getTaskId(); CmdBusTaskAssigned cmdTaskAssigned = CmdBusTaskAssigned - .vBuilder() + .newBuilder() .setTaskId(taskId) .build(); CmdBusTaskStarted cmdTaskStarted = msg.getStart() ? CmdBusTaskStarted - .vBuilder() + .newBuilder() .setTaskId(taskId) .build() : null; diff --git a/server/src/test/java/io/spine/server/commandbus/given/SingleTenantCommandBusTestEnv.java b/server/src/test/java/io/spine/server/commandbus/given/SingleTenantCommandBusTestEnv.java index c5961a77bc2..22bf384bfe6 100644 --- a/server/src/test/java/io/spine/server/commandbus/given/SingleTenantCommandBusTestEnv.java +++ b/server/src/test/java/io/spine/server/commandbus/given/SingleTenantCommandBusTestEnv.java @@ -103,7 +103,7 @@ CmdBusProjectCreated handle(FirstCmdBusCreateProject command) { commandBus.post(commandToPost, noOpObserver()); handledCommands.add(command); return CmdBusProjectCreated - .vBuilder() + .newBuilder() .setProjectId(command.getId()) .build(); } @@ -112,7 +112,7 @@ CmdBusProjectCreated handle(FirstCmdBusCreateProject command) { CmdBusProjectStarted handle(SecondCmdBusStartProject command) { handledCommands.add(command); return CmdBusProjectStarted - .vBuilder() + .newBuilder() .setProjectId(command.getId()) .build(); } diff --git a/server/src/test/java/io/spine/server/entity/TransactionalEntityTest.java b/server/src/test/java/io/spine/server/entity/TransactionalEntityTest.java index 2a031153ba5..09a266981f5 100644 --- a/server/src/test/java/io/spine/server/entity/TransactionalEntityTest.java +++ b/server/src/test/java/io/spine/server/entity/TransactionalEntityTest.java @@ -187,7 +187,7 @@ void returnActiveTxFlags() { TransactionalEntity entity = entityWithInactiveTx(); LifecycleFlags originalFlags = entity.lifecycleFlags(); - LifecycleFlags modifiedFlags = originalFlags.toVBuilder() + LifecycleFlags modifiedFlags = originalFlags.toBuilder() .setDeleted(true) .build(); @@ -220,7 +220,7 @@ void reflectingCurrentState() { Message originalState = entity.builderFromState() .build(); - EmptyEntity newState = EmptyEntity.vBuilder() + EmptyEntity newState = EmptyEntity.newBuilder() .setId(newUuidValue().getValue()) .build(); assertNotEquals(originalState, newState); diff --git a/server/src/test/java/io/spine/server/entity/storage/EntityQueriesTest.java b/server/src/test/java/io/spine/server/entity/storage/EntityQueriesTest.java index 150404939ce..4447bc94a88 100644 --- a/server/src/test/java/io/spine/server/entity/storage/EntityQueriesTest.java +++ b/server/src/test/java/io/spine/server/entity/storage/EntityQueriesTest.java @@ -104,7 +104,7 @@ void checkFilterType() { Filter filter = Filters.gt(archived.name(), 42); CompositeFilter compositeFilter = Filters.all(filter); TargetFilters filters = TargetFilters - .vBuilder() + .newBuilder() .addFilter(compositeFilter) .build(); @@ -118,7 +118,7 @@ void notCreateForNonExisting() { Filter filter = Filters.eq("nonExistingColumn", 42); CompositeFilter compositeFilter = Filters.all(filter); TargetFilters filters = TargetFilters - .vBuilder() + .newBuilder() .addFilter(compositeFilter) .build(); @@ -148,7 +148,7 @@ void constructNonEmptyQueries() { Message someGenericId = Sample.messageOfType(ProjectId.class); Any entityId = AnyPacker.pack(someGenericId); IdFilter idFilter = IdFilter - .vBuilder() + .newBuilder() .addIds(entityId) .build(); BoolValue archived = BoolValue @@ -158,12 +158,12 @@ void constructNonEmptyQueries() { Filter archivedFilter = Filters .eq(LifecycleFlagField.archived.name(), archived); CompositeFilter aggregatingFilter = CompositeFilter - .vBuilder() + .newBuilder() .addFilter(archivedFilter) .setOperator(EITHER) .build(); TargetFilters filters = TargetFilters - .vBuilder() + .newBuilder() .setIdFilter(idFilter) .addFilter(aggregatingFilter) .build(); diff --git a/server/src/test/java/io/spine/server/event/store/EEntityTest.java b/server/src/test/java/io/spine/server/event/store/EEntityTest.java index e60f5a3f40b..7438ec3139c 100644 --- a/server/src/test/java/io/spine/server/event/store/EEntityTest.java +++ b/server/src/test/java/io/spine/server/event/store/EEntityTest.java @@ -20,11 +20,11 @@ void clearEnrichments() { Event event = GivenEvent.arbitrary(); EventContext contextWithEnrichment = event .getContext() - .toVBuilder() + .toBuilder() .setEnrichment(enrichment) .build(); Event eventWithEnrichment = event - .toVBuilder() + .toBuilder() .setContext(contextWithEnrichment) .build(); EEntity entity = EEntity.create(eventWithEnrichment); diff --git a/server/src/test/java/io/spine/server/event/store/EventStoreTest.java b/server/src/test/java/io/spine/server/event/store/EventStoreTest.java index 936d11a08d3..a6c5f314cb6 100644 --- a/server/src/test/java/io/spine/server/event/store/EventStoreTest.java +++ b/server/src/test/java/io/spine/server/event/store/EventStoreTest.java @@ -269,7 +269,7 @@ void eventContextOrigin() { CommandContext commandContext = event.context() .getCommandContext(); EventContext originContext = - EventContext.vBuilder() + EventContext.newBuilder() .setEnrichment(withOneAttribute()) .setCommandContext(commandContext) .setTimestamp(event.context() diff --git a/server/src/test/java/io/spine/server/procman/given/pm/DirectQuizProcman.java b/server/src/test/java/io/spine/server/procman/given/pm/DirectQuizProcman.java index 0fcb4a4e101..68b051300b4 100644 --- a/server/src/test/java/io/spine/server/procman/given/pm/DirectQuizProcman.java +++ b/server/src/test/java/io/spine/server/procman/given/pm/DirectQuizProcman.java @@ -72,7 +72,7 @@ PmQuizStarted handle(PmStartQuiz command) { if (questionIsClosed(questionId)) { PmQuestionAlreadySolved event = PmQuestionAlreadySolved - .vBuilder() + .newBuilder() .setQuizId(examId) .setQuestionId(questionId) .build(); @@ -83,7 +83,7 @@ PmQuizStarted handle(PmStartQuiz command) { if (answerIsCorrect) { PmQuestionSolved reaction = PmQuestionSolved - .vBuilder() + .newBuilder() .setQuizId(examId) .setQuestionId(questionId) .build(); @@ -91,7 +91,7 @@ PmQuizStarted handle(PmStartQuiz command) { } else { PmQuestionFailed reaction = PmQuestionFailed - .vBuilder() + .newBuilder() .setQuizId(examId) .setQuestionId(questionId) .build(); diff --git a/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java b/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java index 2c6aa9458c3..d7a7ec76519 100644 --- a/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java +++ b/server/src/test/java/io/spine/server/procman/given/repo/ProjectCompletion.java @@ -67,7 +67,7 @@ protected void setupCommandRouting(CommandRouting routing) { private static ProcessId toProcessId(ProjectId projectId) { return ProcessId - .vBuilder() + .newBuilder() .setUuid(projectId.getId()) .build(); } diff --git a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java index 29bdc2ab85f..3894454f600 100644 --- a/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java +++ b/server/src/test/java/io/spine/server/procman/given/repo/TestProcessManager.java @@ -85,7 +85,7 @@ private void keep(Message commandOrEventMsg) { } private void handleProjectCreated(ProjectId projectId) { - Project newState = state().toVBuilder() + Project newState = state().toBuilder() .setId(projectId) .setStatus(Project.Status.CREATED) .build(); @@ -93,14 +93,14 @@ private void handleProjectCreated(ProjectId projectId) { } private void handleTaskAdded(Task task) { - Project newState = state().toVBuilder() + Project newState = state().toBuilder() .addTask(task) .build(); builder().mergeFrom(newState); } private void handleProjectStarted() { - Project newState = state().toVBuilder() + Project newState = state().toBuilder() .setStatus(Project.Status.STARTED) .build(); builder().mergeFrom(newState); @@ -170,7 +170,7 @@ PmProjectDeleted handle(PmDeleteProject command) { PmNothingDone handle(PmDoNothing command, CommandContext ignored) { keep(command); return PmNothingDone - .vBuilder() + .newBuilder() .setProjectId(command.getProjectId()) .build(); } diff --git a/server/src/test/java/io/spine/server/projection/e2e/ProjectionEndToEndTest.java b/server/src/test/java/io/spine/server/projection/e2e/ProjectionEndToEndTest.java index 578d0aaec4e..7023bf79095 100644 --- a/server/src/test/java/io/spine/server/projection/e2e/ProjectionEndToEndTest.java +++ b/server/src/test/java/io/spine/server/projection/e2e/ProjectionEndToEndTest.java @@ -109,7 +109,7 @@ void receiveExternal() { OrganizationId producerId = established.getId(); sender.receivesEventsProducedBy(producerId, established); GroupId groupId = GroupId - .vBuilder() + .newBuilder() .setUuid(producerId.getUuid()) .build(); receiver.assertEntityWithState(GroupName.class, groupId) diff --git a/server/src/test/java/io/spine/server/projection/given/TestProjection.java b/server/src/test/java/io/spine/server/projection/given/TestProjection.java index 100651fe918..513aa49309a 100644 --- a/server/src/test/java/io/spine/server/projection/given/TestProjection.java +++ b/server/src/test/java/io/spine/server/projection/given/TestProjection.java @@ -87,7 +87,7 @@ void on(PrjProjectCreated event) { // Keep the event message for further inspection in tests. keep(event); - Project newState = state().toVBuilder() + Project newState = state().toBuilder() .setId(event.getProjectId()) .setStatus(Project.Status.CREATED) .setName(event.getName()) @@ -114,7 +114,7 @@ void on(PrjTaskAdded event) { void on(PrjProjectStarted event, @SuppressWarnings("UnusedParameters") EventContext ignored) { keep(event); - Project newState = state().toVBuilder() + Project newState = state().toBuilder() .setStatus(Project.Status.STARTED) .build(); builder().mergeFrom(newState); diff --git a/server/src/test/java/io/spine/system/server/EntityHistoryTest.java b/server/src/test/java/io/spine/system/server/EntityHistoryTest.java index d912169edcf..50e78d496d9 100644 --- a/server/src/test/java/io/spine/system/server/EntityHistoryTest.java +++ b/server/src/test/java/io/spine/system/server/EntityHistoryTest.java @@ -77,7 +77,7 @@ class EntityHistoryTest { @BeforeEach void setUp() { BoundedContextName contextName = BoundedContextName - .vBuilder() + .newBuilder() .setValue(EntityHistoryTest.class.getSimpleName()) .build(); context = BoundedContext @@ -116,13 +116,13 @@ void entityCreated() { checkCommandDispatchedToAggregateHandler(); checkEntityCreated(AGGREGATE, PersonAggregate.TYPE); - checkEntityStateChanged(Person.vBuilder() + checkEntityStateChanged(Person.newBuilder() .setId(id) .setName(PersonName.getDefaultInstance()) .build()); checkEventDispatchedToSubscriber(); checkEntityCreated(PROJECTION, PersonProjection.TYPE); - checkEntityStateChanged(PersonDetails.vBuilder() + checkEntityStateChanged(PersonDetails.newBuilder() .setId(id) .setName(PersonName.getDefaultInstance()) .build()); @@ -152,7 +152,7 @@ void unArchivedAndUnDeleted() { eventAccumulator.forgetEvents(); ExposePerson command = ExposePerson - .vBuilder() + .newBuilder() .setId(id) .build(); postCommand(command); @@ -190,7 +190,7 @@ void commandToPart() { @DisplayName("command is dispatched to handler in procman") void commandToPm() { CommandMessage startCommand = StartPersonCreation - .vBuilder() + .newBuilder() .setId(id) .build(); postCommand(startCommand); @@ -206,7 +206,7 @@ void commandToPm() { eventAccumulator.forgetEvents(); CommandMessage domainCommand = CompletePersonCreation - .vBuilder() + .newBuilder() .setId(id) .build(); postCommand(domainCommand); @@ -256,7 +256,7 @@ void eventToReactorInAggregate() { eventAccumulator.forgetEvents(); RenamePerson domainCommand = RenamePerson - .vBuilder() + .newBuilder() .setId(id) .setNewFirstName("Paul") .build(); @@ -276,7 +276,7 @@ void eventToReactorInAggregate() { private void createPerson() { CreatePerson command = CreatePerson - .vBuilder() + .newBuilder() .setId(id) .build(); postCommand(command); @@ -285,7 +285,7 @@ private void createPerson() { @CanIgnoreReturnValue private HidePerson hidePerson() { HidePerson command = HidePerson - .vBuilder() + .newBuilder() .setId(id) .build(); postCommand(command); @@ -295,7 +295,7 @@ private HidePerson hidePerson() { @CanIgnoreReturnValue private CreatePersonName createPersonName() { CreatePersonName domainCommand = CreatePersonName - .vBuilder() + .newBuilder() .setId(id) .setFirstName("Ringo") .build(); diff --git a/server/src/test/java/io/spine/system/server/given/entity/PersonAggregate.java b/server/src/test/java/io/spine/system/server/given/entity/PersonAggregate.java index 27953c55d89..17d77be4c89 100644 --- a/server/src/test/java/io/spine/system/server/given/entity/PersonAggregate.java +++ b/server/src/test/java/io/spine/system/server/given/entity/PersonAggregate.java @@ -51,7 +51,7 @@ protected PersonAggregate(PersonId id) { @Assign PersonCreated handle(CreatePerson command) { return PersonCreated - .vBuilder() + .newBuilder() .setId(command.getId()) .setName(command.getName()) .build(); @@ -60,7 +60,7 @@ PersonCreated handle(CreatePerson command) { @Assign PersonHidden handle(HidePerson command) { return PersonHidden - .vBuilder() + .newBuilder() .setId(command.getId()) .build(); } @@ -68,7 +68,7 @@ PersonHidden handle(HidePerson command) { @Assign PersonExposed handle(ExposePerson command) { return PersonExposed - .vBuilder() + .newBuilder() .setId(command.getId()) .build(); } @@ -76,7 +76,7 @@ PersonExposed handle(ExposePerson command) { @Assign PersonRenamed handle(RenamePerson command) { return PersonRenamed - .vBuilder() + .newBuilder() .setId(command.getId()) .setNewFirstName(command.getNewFirstName()) .build(); diff --git a/server/src/test/java/io/spine/system/server/given/entity/PersonNamePart.java b/server/src/test/java/io/spine/system/server/given/entity/PersonNamePart.java index 639d7850aa1..2dbf8a24a69 100644 --- a/server/src/test/java/io/spine/system/server/given/entity/PersonNamePart.java +++ b/server/src/test/java/io/spine/system/server/given/entity/PersonNamePart.java @@ -53,7 +53,7 @@ Nothing reactOn(PersonRenamed event) { @Assign PersonNameCreated handle(CreatePersonName command) { return PersonNameCreated - .vBuilder() + .newBuilder() .setId(command.getId()) .setFirstName(command.getFirstName()) .build(); diff --git a/server/src/test/java/io/spine/system/server/given/entity/PersonProcman.java b/server/src/test/java/io/spine/system/server/given/entity/PersonProcman.java index dadf1e1ad0e..08219d46a3f 100644 --- a/server/src/test/java/io/spine/system/server/given/entity/PersonProcman.java +++ b/server/src/test/java/io/spine/system/server/given/entity/PersonProcman.java @@ -50,7 +50,7 @@ public final class PersonProcman PersonCreationStarted handle(StartPersonCreation command) { builder().setId(command.getId()); return PersonCreationStarted - .vBuilder() + .newBuilder() .setId(command.getId()) .build(); } @@ -60,7 +60,7 @@ PersonCreationCompleted handle(CompletePersonCreation command) { builder().setId(command.getId()) .setCreated(true); return PersonCreationCompleted - .vBuilder() + .newBuilder() .setId(command.getId()) .build(); } diff --git a/server/src/test/java/io/spine/system/server/given/schedule/TestCommandScheduler.java b/server/src/test/java/io/spine/system/server/given/schedule/TestCommandScheduler.java index 4f7ac84b0f1..5fc08bd8efc 100644 --- a/server/src/test/java/io/spine/system/server/given/schedule/TestCommandScheduler.java +++ b/server/src/test/java/io/spine/system/server/given/schedule/TestCommandScheduler.java @@ -43,7 +43,7 @@ protected void doSchedule(Command command) { public void assertScheduled(Command command) { // System properties are modified by the framework. boolean found = scheduledCommands.stream() - .map(cmd -> cmd.toVBuilder() + .map(cmd -> cmd.toBuilder() .clearSystemProperties() .build()) .anyMatch(command::equals); diff --git a/testutil-server/src/test/java/io/spine/testing/server/CommandSubjectTest.java b/testutil-server/src/test/java/io/spine/testing/server/CommandSubjectTest.java index 04bf4f4969b..f203ee2b952 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/CommandSubjectTest.java +++ b/testutil-server/src/test/java/io/spine/testing/server/CommandSubjectTest.java @@ -54,7 +54,7 @@ CommandSubject assertWithSubjectThat(Iterable messages) { Command createMessage() { return newCommand( TuAddComment - .vBuilder() + .newBuilder() .setId(generateTaskId()) .build() ); @@ -64,7 +64,7 @@ Command createMessage() { Command createAnotherMessage() { return newCommand( TuCreateTask - .vBuilder() + .newBuilder() .setId(generateTaskId()) .build() ); @@ -76,7 +76,7 @@ private static Command newCommand(CommandMessage msg) { private static TuTaskId generateTaskId() { return TuTaskId - .vBuilder() + .newBuilder() .setValue(newUuid()) .build(); } diff --git a/testutil-server/src/test/java/io/spine/testing/server/EventSubjectTest.java b/testutil-server/src/test/java/io/spine/testing/server/EventSubjectTest.java index b6dff063ff9..3914ccc4056 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/EventSubjectTest.java +++ b/testutil-server/src/test/java/io/spine/testing/server/EventSubjectTest.java @@ -51,7 +51,7 @@ EventSubject assertWithSubjectThat(Iterable messages) { Event createMessage() { TuTaskId taskId = generateTaskId(); TuCommentAdded event = TuCommentAdded - .vBuilder() + .newBuilder() .setId(taskId) .build(); return newEvent(event); @@ -61,7 +61,7 @@ Event createMessage() { Event createAnotherMessage() { TuTaskId taskId = generateTaskId(); TuTaskCreated event = TuTaskCreated - .vBuilder() + .newBuilder() .setId(taskId) .build(); return newEvent(event); @@ -73,7 +73,7 @@ private static Event newEvent(EventMessage msg) { private static TuTaskId generateTaskId() { return TuTaskId - .vBuilder() + .newBuilder() .setValue(newUuid()) .build(); } diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/BlackBoxBoundedContextTest.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/BlackBoxBoundedContextTest.java index bb3bd220d5d..94ebe246b3a 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/BlackBoxBoundedContextTest.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/BlackBoxBoundedContextTest.java @@ -494,7 +494,7 @@ void deletedFlag() { @DisplayName("state subject") void stateSubject() { BbInit expectedState = BbInit - .vBuilder() + .newBuilder() .setId(id) .setInitialized(true) .build(); diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbInitProcess.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbInitProcess.java index f8ac35551b6..777529735eb 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbInitProcess.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbInitProcess.java @@ -51,14 +51,14 @@ public final class BbInitProcess extends ProcessManager> on(BbInitProject cmd) { builder().setId(cmd.getProjectId()); BbAssignTeam assignTeam = BbAssignTeam - .vBuilder() + .newBuilder() .setProjectId(cmd.getProjectId()) .addAllMember(cmd.getMemberList()) .build(); @Nullable BbAssignScrumMaster assignScrumMaster = cmd.hasScrumMaster() ? BbAssignScrumMaster - .vBuilder() + .newBuilder() .setProjectId(cmd.getProjectId()) .setScrumMaster(cmd.getScrumMaster()) .build() @@ -74,12 +74,12 @@ Pair on(BbAssignTeam cmd) { setDeleted(true); return Pair.of( BbTeamAssigned - .vBuilder() + .newBuilder() .setProjectId(cmd.getProjectId()) .addAllMember(cmd.getMemberList()) .build(), BbProjectInitialized - .vBuilder() + .newBuilder() .setProjectId(cmd.getProjectId()) .build() ); @@ -88,7 +88,7 @@ Pair on(BbAssignTeam cmd) { @Assign BbScrumMasterAssigned on(BbAssignScrumMaster cmd) { return BbScrumMasterAssigned - .vBuilder() + .newBuilder() .setProjectId(cmd.getProjectId()) .setScrumMaster(cmd.getScrumMaster()) .build(); diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectAggregate.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectAggregate.java index f3a1534703b..67f840891e3 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectAggregate.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/BbProjectAggregate.java @@ -55,7 +55,7 @@ final class BbProjectAggregate extends Aggregate on(BbUserDeleted event) { private BbAssigneeRemoved userUnassigned(UserId user) { return BbAssigneeRemoved - .vBuilder() + .newBuilder() .setId(id()) .setUserId(user) .build(); diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java index 731650ffcc8..1ff1ecfe7ec 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java @@ -57,7 +57,7 @@ public static BbProjectId newProjectId() { public static BbAddTask addTask(BbProjectId projectId) { return BbAddTask - .vBuilder() + .newBuilder() .setProjectId(projectId) .setTask(newTask()) .build(); @@ -65,7 +65,7 @@ public static BbAddTask addTask(BbProjectId projectId) { public static BbTaskAdded taskAdded(BbProjectId projectId) { return BbTaskAdded - .vBuilder() + .newBuilder() .setProjectId(projectId) .setTask(newTask()) .build(); @@ -73,14 +73,14 @@ public static BbTaskAdded taskAdded(BbProjectId projectId) { private static BbTask newTask() { return BbTask - .vBuilder() + .newBuilder() .setTitle(newUuid()) .build(); } public static BbCreateReport createReport(BbProjectId projectId) { return BbCreateReport - .vBuilder() + .newBuilder() .setReportId(newReportId()) .addProjectId(projectId) .build(); @@ -88,7 +88,7 @@ public static BbCreateReport createReport(BbProjectId projectId) { private static BbReportId newReportId() { return BbReportId - .vBuilder() + .newBuilder() .setId(newUuid()) .build(); } @@ -96,7 +96,7 @@ private static BbReportId newReportId() { public static BbRegisterCommandDispatcher registerCommandDispatcher(Class dispatcherName) { return BbRegisterCommandDispatcher - .vBuilder() + .newBuilder() .setDispatcherName(dispatcherName.getName()) .build(); } @@ -105,7 +105,7 @@ private static BbReportId newReportId() { eventDispatcherRegistered(Class dispatcherClass) { String name = dispatcherClass.getName(); BbEventDispatcherRegistered result = BbEventDispatcherRegistered - .vBuilder() + .newBuilder() .setDispatcherName(name) .build(); return result; @@ -116,21 +116,21 @@ public static BbCreateProject createProject() { } private static UserId generateUserId() { - return UserId.vBuilder() + return UserId.newBuilder() .setValue(TestValues.randomString()) .build(); } public static BbCreateProject createProject(BbProjectId id) { return BbCreateProject - .vBuilder() + .newBuilder() .setProjectId(id) .build(); } public static BbInitProject initProject(BbProjectId id, boolean scrum) { BbInitProjectVBuilder builder = BbInitProject - .vBuilder() + .newBuilder() .setProjectId(id); // Generate a random team. IntStream.range(0, TestValues.random(1, 10)) @@ -143,14 +143,14 @@ public static BbInitProject initProject(BbProjectId id, boolean scrum) { public static BbStartProject startProject(BbProjectId id) { return BbStartProject - .vBuilder() + .newBuilder() .setProjectId(id) .build(); } public static BbProject createdProjectState(BbCreateProject createProject) { return BbProject - .vBuilder() + .newBuilder() .setId(createProject.getProjectId()) .setStatus(BbProject.Status.CREATED) .build(); @@ -158,7 +158,7 @@ public static BbProject createdProjectState(BbCreateProject createProject) { public static BbAssignProject addProjectAssignee(BbProjectId projectId, UserId id) { return BbAssignProject - .vBuilder() + .newBuilder() .setId(projectId) .setUserId(id) .build(); @@ -166,7 +166,7 @@ public static BbAssignProject addProjectAssignee(BbProjectId projectId, UserId i public static BbUserDeleted userDeleted(UserId id, BbProjectId... projectIds) { return BbUserDeleted - .vBuilder() + .newBuilder() .setId(id) .addAllProject(newArrayList(projectIds)) .build(); diff --git a/testutil-server/src/test/java/io/spine/testing/server/entity/EntitySubjectTest.java b/testutil-server/src/test/java/io/spine/testing/server/entity/EntitySubjectTest.java index 0841c961294..033c79036b1 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/entity/EntitySubjectTest.java +++ b/testutil-server/src/test/java/io/spine/testing/server/entity/EntitySubjectTest.java @@ -51,7 +51,7 @@ class EntitySubjectTest extends SubjectTest> { void setUp() { BbProjectId id = BbProjectId.generate(); BbProjectView state = BbProjectView - .vBuilder() + .newBuilder() .setId(id) .build(); entity = Given.projectionOfClass(ProjectView.class) From ad726df5ca9209bc8e2d7e932c6a62a5892c40fb Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 10:33:06 +0300 Subject: [PATCH 37/43] Annotate stub class immutable --- .../java/io/spine/server/entity/DefaultCommandRouteTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java index d53f567008f..eaff4a08f78 100644 --- a/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java +++ b/server/src/test/java/io/spine/server/entity/DefaultCommandRouteTest.java @@ -20,6 +20,7 @@ package io.spine.server.entity; +import com.google.errorprone.annotations.Immutable; import com.google.protobuf.ByteString; import com.google.protobuf.CodedOutputStream; import com.google.protobuf.Descriptors; @@ -71,6 +72,7 @@ void emptyOrNot() { /** * Stub class which simulates empty command message. */ + @Immutable private static final class StubCommand implements CommandMessage { private static final long serialVersionUID = 0L; From 51baaf6eb738e3d8ade4ed9a9c942d086b6ba833 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 10:41:27 +0300 Subject: [PATCH 38/43] Extract common default event routing def. --- license-report.md | 16 ++++++++-------- .../server/aggregate/AggregateRepository.java | 10 +++------- .../entity/EventDispatchingRepository.java | 3 +-- .../java/io/spine/server/route/EventRouting.java | 10 ++++++++++ .../testing/server/blackbox/given/Given.java | 3 +-- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/license-report.md b/license-report.md index c397280568d..790b3b98242 100644 --- a/license-report.md +++ b/license-report.md @@ -431,7 +431,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:26 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -821,7 +821,7 @@ This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:27 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1359,7 +1359,7 @@ This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:28 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2059,7 +2059,7 @@ This report was generated on **Wed May 15 19:57:54 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:29 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2603,7 +2603,7 @@ This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:30 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3108,7 +3108,7 @@ This report was generated on **Wed May 15 19:57:55 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3621,7 +3621,7 @@ This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4234,4 +4234,4 @@ This report was generated on **Wed May 15 19:57:56 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 15 19:57:57 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Fri May 17 10:39:32 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java index 6e90d969c17..72a94361178 100644 --- a/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java +++ b/server/src/main/java/io/spine/server/aggregate/AggregateRepository.java @@ -35,7 +35,6 @@ import io.spine.server.event.EventBus; import io.spine.server.event.EventDispatcherDelegate; import io.spine.server.route.CommandRouting; -import io.spine.server.route.EventRoute; import io.spine.server.route.EventRouting; import io.spine.server.storage.Storage; import io.spine.server.storage.StorageFactory; @@ -72,8 +71,7 @@ @SuppressWarnings("ClassWithTooManyMethods") public abstract class AggregateRepository> extends Repository - implements CommandDispatcher, - EventDispatcherDelegate { + implements CommandDispatcher, EventDispatcherDelegate { /** The default number of events to be stored before a next snapshot is made. */ static final int DEFAULT_SNAPSHOT_TRIGGER = 100; @@ -82,15 +80,13 @@ public abstract class AggregateRepository> private final Supplier> commandRouting; /** The routing schema for events to which aggregates react. */ - private final EventRouting eventRouting = - EventRouting.withDefault(EventRoute.byProducerId()); + private final EventRouting eventRouting = EventRouting.withDefaultByProducerId(); /** * The routing for event import, which by default obtains the target aggregate ID as the * {@linkplain io.spine.core.EventContext#getProducerId() producer ID} of the event. */ - private final EventRouting eventImportRouting = - EventRouting.withDefault(EventRoute.byProducerId()); + private final EventRouting eventImportRouting = EventRouting.withDefaultByProducerId(); /** * The {@link CommandErrorHandler} tackling the dispatching errors. diff --git a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java index 7a4da901e9b..041d9a243a7 100644 --- a/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java +++ b/server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java @@ -33,7 +33,6 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.server.route.EventRoute.byProducerId; import static io.spine.server.tenant.TenantAwareRunner.with; /** @@ -49,7 +48,7 @@ public abstract class EventDispatchingRepository EventRouting withDefault(EventRoute defaul return new EventRouting<>(defaultRoute); } + /** + * Creates a new event routing with the default one by event producer ID. + * + * @see #withDefault(EventRoute) + * @see EventRoute#byProducerId() + */ + public static EventRouting withDefaultByProducerId() { + return withDefault(EventRoute.byProducerId()); + } + /** * {@inheritDoc} * diff --git a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java index 1ff1ecfe7ec..6e780fb4cc4 100644 --- a/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java +++ b/testutil-server/src/test/java/io/spine/testing/server/blackbox/given/Given.java @@ -33,7 +33,6 @@ import io.spine.testing.server.blackbox.command.BbCreateProject; import io.spine.testing.server.blackbox.command.BbCreateReport; import io.spine.testing.server.blackbox.command.BbInitProject; -import io.spine.testing.server.blackbox.command.BbInitProjectVBuilder; import io.spine.testing.server.blackbox.command.BbRegisterCommandDispatcher; import io.spine.testing.server.blackbox.command.BbStartProject; import io.spine.testing.server.blackbox.event.BbEventDispatcherRegistered; @@ -129,7 +128,7 @@ public static BbCreateProject createProject(BbProjectId id) { } public static BbInitProject initProject(BbProjectId id, boolean scrum) { - BbInitProjectVBuilder builder = BbInitProject + BbInitProject.Builder builder = BbInitProject .newBuilder() .setProjectId(id); // Generate a random team. From 800a73e2588ac66ba9fedf7c6ca78b0915c944be Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 17 May 2019 11:27:41 +0300 Subject: [PATCH 39/43] Test empty command validation --- license-report.md | 16 +++---- .../server/commandbus/CommandValidator.java | 1 + .../CommandValidatorViolationCheckTest.java | 47 +++++++++++++++---- .../proto/spine/test/command/commands.proto | 4 ++ 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/license-report.md b/license-report.md index 790b3b98242..6e4f456017b 100644 --- a/license-report.md +++ b/license-report.md @@ -431,7 +431,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:26 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -821,7 +821,7 @@ This report was generated on **Fri May 17 10:39:26 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:27 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:03 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1359,7 +1359,7 @@ This report was generated on **Fri May 17 10:39:27 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:28 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2059,7 +2059,7 @@ This report was generated on **Fri May 17 10:39:28 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:29 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:04 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2603,7 +2603,7 @@ This report was generated on **Fri May 17 10:39:29 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:30 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:05 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3108,7 +3108,7 @@ This report was generated on **Fri May 17 10:39:30 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:05 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3621,7 +3621,7 @@ This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri May 17 11:12:05 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4234,4 +4234,4 @@ This report was generated on **Fri May 17 10:39:31 EEST 2019** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 17 10:39:32 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Fri May 17 11:12:06 EEST 2019** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/server/src/main/java/io/spine/server/commandbus/CommandValidator.java b/server/src/main/java/io/spine/server/commandbus/CommandValidator.java index 1afd4af68ed..f69896a76be 100644 --- a/server/src/main/java/io/spine/server/commandbus/CommandValidator.java +++ b/server/src/main/java/io/spine/server/commandbus/CommandValidator.java @@ -188,6 +188,7 @@ private void validateTargetId() { CommandMessage message = command.message(); if (!DefaultCommandRoute.exists(message)) { addViolation("The command message does not have a field with a command target ID."); + return; } Object target = defaultRoute.apply(message, CommandContext.getDefaultInstance()); diff --git a/server/src/test/java/io/spine/server/commandbus/CommandValidatorViolationCheckTest.java b/server/src/test/java/io/spine/server/commandbus/CommandValidatorViolationCheckTest.java index d05541ee70a..571b2beb0de 100644 --- a/server/src/test/java/io/spine/server/commandbus/CommandValidatorViolationCheckTest.java +++ b/server/src/test/java/io/spine/server/commandbus/CommandValidatorViolationCheckTest.java @@ -27,6 +27,7 @@ import io.spine.core.CommandId; import io.spine.protobuf.AnyPacker; import io.spine.server.type.CommandEnvelope; +import io.spine.test.command.CmdEmpty; import io.spine.test.commandbus.command.CmdBusCreateProject; import io.spine.testing.client.TestActorRequestFactory; import io.spine.validate.ConstraintViolation; @@ -35,10 +36,11 @@ import java.util.List; +import static com.google.common.truth.Truth.assertThat; import static io.spine.server.commandbus.CommandValidator.inspect; import static io.spine.server.commandbus.Given.CommandMessage.createProjectMessage; import static io.spine.testing.core.given.GivenCommandContext.withRandomActor; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static java.util.stream.Collectors.toList; @DisplayName("CommandValidator violation check should") class CommandValidatorViolationCheckTest { @@ -48,9 +50,10 @@ class CommandValidatorViolationCheckTest { void returnNothingForValidCmd() { Command cmd = Given.ACommand.createProject(); - List violations = inspect(CommandEnvelope.of(cmd)); + List violations = inspectCommand(cmd); - assertEquals(0, violations.size()); + assertThat(violations) + .isEmpty(); } @Test @@ -61,9 +64,10 @@ void notAllowDefaultId() { .toBuilder() .setId(CommandId.getDefaultInstance()) .build(); - List violations = inspect(CommandEnvelope.of(unidentifiableCommand)); + List violations = inspectCommand(unidentifiableCommand); - assertEquals(1, violations.size()); + assertThat(violations) + .hasSize(1); } @Test @@ -77,9 +81,10 @@ void notAllowInvalidMessage() { .setContext(withRandomActor()) .build(); - List violations = inspect(CommandEnvelope.of(commandWithEmptyMessage)); + List violations = inspectCommand(commandWithEmptyMessage); - assertEquals(3, violations.size()); + assertThat(violations) + .hasSize(3); } @Test @@ -92,8 +97,32 @@ void notAllowInvalidContext() { .setContext(CommandContext.getDefaultInstance()) .build(); - List violations = inspect(CommandEnvelope.of(commandWithoutContext)); + List violations = inspectCommand(commandWithoutContext); - assertEquals(1, violations.size()); + assertThat(violations) + .hasSize(1); + } + + @Test + @DisplayName("return violation for an empty command message") + void emptyMessage() { + TestActorRequestFactory factory = new TestActorRequestFactory(getClass()); + Command emptyCommand = factory.createCommand(CmdEmpty.newBuilder().build()); + + List violations = inspectCommand(emptyCommand); + + boolean hasViolationOnCommandTargetId = + !(violations.stream() + .filter(v -> v.getMsgFormat() + .contains("command target ID")) + .collect(toList()) + .isEmpty()); + + assertThat(hasViolationOnCommandTargetId) + .isTrue(); + } + + private static List inspectCommand(Command command) { + return inspect(CommandEnvelope.of(command)); } } diff --git a/server/src/test/proto/spine/test/command/commands.proto b/server/src/test/proto/spine/test/command/commands.proto index 4898bb2c757..9769013cfca 100644 --- a/server/src/test/proto/spine/test/command/commands.proto +++ b/server/src/test/proto/spine/test/command/commands.proto @@ -94,3 +94,7 @@ message CmdSetTaskDescription { TaskId task_id = 1; string description = 3; } + +// Invalid command message which does not contain any fields. +message CmdEmpty { +} From 1a7d2712f17fb69903098c4359abfc86bbc10d1f Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 17 May 2019 13:23:59 +0300 Subject: [PATCH 40/43] Improve names --- .../java/io/spine/server/BoundedContext.java | 2 +- .../io/spine/server/entity/Repository.java | 20 +++++++++---------- .../spine/server/entity/RepositoryTest.java | 8 ++++---- .../procman/ProcessManagerRepositoryTest.java | 2 +- .../projection/ProjectionRepositoryTest.java | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/server/src/main/java/io/spine/server/BoundedContext.java b/server/src/main/java/io/spine/server/BoundedContext.java index 044b5a273bc..fd199e9d451 100644 --- a/server/src/main/java/io/spine/server/BoundedContext.java +++ b/server/src/main/java/io/spine/server/BoundedContext.java @@ -218,7 +218,7 @@ public static BoundedContextBuilder newBuilder() { */ public > void register(Repository repository) { checkNotNull(repository); - repository.setBoundedContext(this); + repository.setContext(this); guard.register(repository); repository.onRegistered(); registerEventDispatcher(stand()); diff --git a/server/src/main/java/io/spine/server/entity/Repository.java b/server/src/main/java/io/spine/server/entity/Repository.java index 92bcd05f837..887592cafbc 100644 --- a/server/src/main/java/io/spine/server/entity/Repository.java +++ b/server/src/main/java/io/spine/server/entity/Repository.java @@ -67,7 +67,7 @@ public abstract class Repository> implements AutoClose * BoundedContext#register(Repository) registered} yet and * after the repository is {@linkplain #close() closed}. */ - private @Nullable BoundedContext boundedContext; + private @Nullable BoundedContext context; /** * Model class of entities managed by this repository. @@ -194,22 +194,22 @@ public ImmutableSet outgoingEvents() { * not equal to the assigned one */ @Internal - public final void setBoundedContext(BoundedContext context) { + public final void setContext(BoundedContext context) { checkNotNull(context); - boolean sameValue = context.equals(this.boundedContext); - if (this.boundedContext != null && !sameValue) { + boolean sameValue = context.equals(this.context); + if (this.context != null && !sameValue) { throw newIllegalStateException( "The repository `%s` has the Bounded Context (`%s`) assigned." + " This operation can be performed only once." + " Attempted to set: `%s`.", - this, this.boundedContext, context); + this, this.context, context); } if (sameValue) { return; } - this.boundedContext = context; + this.context = context; if (!isStorageAssigned()) { initStorage(context.storageFactory()); } @@ -239,7 +239,7 @@ protected void init(BoundedContext context) { * Verifies whether the repository is registered with a {@code BoundedContext}. */ protected final boolean isRegistered() { - return boundedContext != null; + return context != null; } /** @@ -251,10 +251,10 @@ protected final boolean isRegistered() { * registered} yet */ protected final BoundedContext context() { - checkState(boundedContext != null, + checkState(context != null, "The repository (class: `%s`) is not registered with a `BoundedContext`.", getClass().getName()); - return boundedContext; + return context; } /** @@ -333,7 +333,7 @@ public void close() { this.storage.close(); this.storage = null; } - this.boundedContext = null; + this.context = null; } /** diff --git a/server/src/test/java/io/spine/server/entity/RepositoryTest.java b/server/src/test/java/io/spine/server/entity/RepositoryTest.java index 14f73626da5..de7a3cbd3b3 100644 --- a/server/src/test/java/io/spine/server/entity/RepositoryTest.java +++ b/server/src/test/java/io/spine/server/entity/RepositoryTest.java @@ -152,16 +152,16 @@ void createContexts() { @Test @DisplayName("throwing ISE") void prohibit() { - repository.setBoundedContext(ctx1); + repository.setContext(ctx1); assertThrows(IllegalStateException.class, () -> - repository.setBoundedContext(ctx2)); + repository.setContext(ctx2)); } @Test @DisplayName("allowing passing the same value twice") void idempotency() { - repository.setBoundedContext(ctx1); - repository.setBoundedContext(ctx1); + repository.setContext(ctx1); + repository.setContext(ctx1); assertThat(repository.context()) .isEqualTo(ctx1); } diff --git a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java index 8ecbc091f60..96709169da9 100644 --- a/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java +++ b/server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java @@ -522,7 +522,7 @@ void notRegisterIfSubscribedToNothing() { .build(); assertThrows(IllegalStateException.class, () -> - repo.setBoundedContext(context)); + repo.setContext(context)); } @Test diff --git a/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java b/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java index da51e95bc8b..a7339267af8 100644 --- a/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java +++ b/server/src/test/java/io/spine/server/projection/ProjectionRepositoryTest.java @@ -555,6 +555,6 @@ void notRegisterIfSubscribedToNothing() { .build(); assertThrows(IllegalStateException.class, () -> - repo.setBoundedContext(context)); + repo.setContext(context)); } } From 018d707e19e1ff1b74516628d52371e712eb8840 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 17 May 2019 13:33:00 +0300 Subject: [PATCH 41/43] Improve Javadoc --- .../io/spine/server/entity/rejection/StandardRejection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java b/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java index 4c908789376..6905b110f8e 100644 --- a/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java +++ b/server/src/main/java/io/spine/server/entity/rejection/StandardRejection.java @@ -27,12 +27,15 @@ import io.spine.protobuf.AnyPacker; /** - * Interface common for {@link StandardRejections}. + * Interface common for standard rejections which is used during routing. */ @Immutable @GeneratedMixin public interface StandardRejection extends RejectionMessage { + /** + * Obtains the packed version of ID of the entity which caused the rejection. + */ Any getEntityId(); /** From 44a96e6260fc48cdabbf19731bf3e948270d3a62 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 17 May 2019 13:34:23 +0300 Subject: [PATCH 42/43] Improve Javadoc --- server/src/main/java/io/spine/server/route/FirstField.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/spine/server/route/FirstField.java b/server/src/main/java/io/spine/server/route/FirstField.java index 60c82914077..4af71c194bc 100644 --- a/server/src/main/java/io/spine/server/route/FirstField.java +++ b/server/src/main/java/io/spine/server/route/FirstField.java @@ -30,8 +30,10 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * Obtains the first field from multiple messages expecting each field - * being the identifier of the same type. + * Routes messages to a single target, which ID is the same as the first field of + * the routed message. + * + *

It is expected that the types of the first field and the identifier are the same. * * @param * the type of the identifiers From 621ca32b511dfd7cdd2afe470e4573caee9c9c5a Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Fri, 17 May 2019 13:37:04 +0300 Subject: [PATCH 43/43] Reference issue in todo --- .../src/main/java/io/spine/server/route/StateUpdateRouting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java index 255d792117b..99393baeb30 100644 --- a/server/src/main/java/io/spine/server/route/StateUpdateRouting.java +++ b/server/src/main/java/io/spine/server/route/StateUpdateRouting.java @@ -121,6 +121,6 @@ private static Route> defaultStateRoute() { */ public void validate(Set stateClasses) throws IllegalStateException { checkNotNull(stateClasses); - //TODO:2019-05-15:alexander.yevsyukov: Implement + //TODO:2019-05-15:alexander.yevsyukov: See https://github.com/SpineEventEngine/core-java/issues/1067 } }