Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
How to contribute
==================
Thank you for wanting to contribute to Spine. The following links will help you get started:
* [Wiki home][wiki-home] — the home of the developer's documentation.
* [Wiki home][wiki-home] — the home of the framework developer's documentation.
* [Getting started with Spine in Java][quick-start] — this guide will walk you through
a minimal client-server “Hello World!” application in Java.
* [Introduction][docs-intro] — this section of the Spine Documentation will help you understand
the foundation of the framework.

Pull requests
-------------
A work on an improvement starts from creating an issue which describes a bug or a feature you
intend to fix. The issue will be used for communications on the proposed improvements. If code
changes are going to be introduced, the issue would also have a link to corresponding Pull Request.
The work on an improvement starts with creating an issue that describes a bug or a feature. The issue will be used for communications on the proposed improvements.
If code changes are going to be introduced, the issue should also have a link to the corresponding Pull Request.

Code contributions should:
* Be accompanied by tests.
* Be licensed Apache 2.0 with the appropriate copyright header for each file.
* Be licensed under the Apache v2.0 license with the appropriate copyright header for each file.
* Formatted according to the code style. See [Wiki home][wiki-home] for the links to
style guides of the programming languages used in the framework.

Contributor License Agreement
-----------------------------
Contributions to the code of Spine Event Engine framework and its libraries must be accompanied by
Contributor License Agreement.
Contributor License Agreement (CLA).

* If you are an individual writing original source code and you're sure you own
the intellectual property, then you'll need to sign an individual CLA.
Expand Down
58 changes: 48 additions & 10 deletions client/src/main/java/io/spine/client/CommandRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,27 @@ public CommandRequest onServerError(ServerErrorHandler handler) {
* client code "knows" how many of them it expects. Also, some events may not arrive
* because of communication or business logic reasons. That's why the returned
* subscriptions should be cancelled by the client code when it no longer needs it.
* @see #postAndForget()
*/
@CanIgnoreReturnValue
public ImmutableSet<Subscription> post() {
PostOperation op = new PostOperation();
return op.perform();
}

/**
* Posts the command without subscribing to events that may be generated during
* the command handling.
*
* @throws IllegalStateException
* if {@link #observe(Class, EventConsumer)} or {@link #observe(Class, Consumer)} were
* called in the command request configuration chain before calling this method
* @see #post()
*/
public void postAndForget() throws IllegalStateException {
PostOperation op = new PostOperation();
op.performWithoutSubscriptions();
}

@VisibleForTesting
CommandMessage message() {
return message;
Expand All @@ -201,9 +215,41 @@ private PostOperation() {
}

private ImmutableSet<Subscription> perform() {
if (consumers.isEmpty()) {
throw newIllegalStateException(
"No event subscriptions were requested prior to calling `post()`." +
" If you intend to receive events please call `observe()`" +
" before `post()`." +
" Or, if you subscribe to events or projections elsewhere," +
" please use `postAndForget()`."
);
}
subscribeToEvents();
Ack ack = client().post(command);
Status status = ack.getStatus();
return handleStatus(status);
}

private void performWithoutSubscriptions() {
if (!consumers.isEmpty()) {
throw newIllegalStateException(
"Subscriptions to events were requested. Please call `post()` instead."
);
}
Ack ack = client().post(command);
Status status = ack.getStatus();
handleStatus(status);
}

private void subscribeToEvents() {
Client client = client();
this.subscriptions = subscribe(client, command, consumers, streamingErrorHandler());
client.subscriptions()
.addAll(subscriptions);
}

@CanIgnoreReturnValue
private ImmutableSet<Subscription> handleStatus(Status status) {
switch (status.getStatusCase()) {
case OK:
return Optional.ofNullable(subscriptions)
Expand All @@ -224,21 +270,13 @@ private ImmutableSet<Subscription> perform() {
}
}

private void subscribeToEvents() {
Client client = client();
this.subscriptions = subscribe(client, command, consumers, streamingErrorHandler());
checkNotNull(subscriptions);
client.subscriptions()
.addAll(subscriptions);
}

/**
* Cancels the passed subscriptions to events because the command could not be posted.
*
*/
private void cancelVoidSubscriptions() {
Subscriptions activeSubscriptions = client().subscriptions();
if (subscriptions != null) {
Subscriptions activeSubscriptions = client().subscriptions();
subscriptions.forEach(activeSubscriptions::cancel);
}
}
Expand Down
3 changes: 2 additions & 1 deletion client/src/main/java/io/spine/client/EventsAfterCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.spine.core.EventContext;
import io.spine.core.UserId;
import io.spine.logging.Logging;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import static com.google.common.base.Preconditions.checkNotNull;
Expand All @@ -47,7 +48,7 @@ final class EventsAfterCommand implements Logging {
private final Command command;
private final MultiEventConsumers consumers;

static ImmutableSet<Subscription>
static @NonNull ImmutableSet<Subscription>
subscribe(Client client,
Command command,
MultiEventConsumers consumers,
Expand Down
9 changes: 9 additions & 0 deletions client/src/main/java/io/spine/client/MultiEventConsumers.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,17 @@ ImmutableSet<Class<? extends EventMessage>> eventTypes() {
return map.keySet();
}

/**
* Returns {@code true} if no event consumers were collected, {@code false} otherwise.
*/
boolean isEmpty() {
boolean result = eventTypes().isEmpty();
return result;
}

/** Obtains all the consumers grouped by type of consumed events. */
ImmutableMap<Class<? extends EventMessage>, StreamObserver<Event>> toObservers() {
@SuppressWarnings("ConstantConditions") // `null` values are prevented when gathering.
Map<Class<? extends EventMessage>, StreamObserver<Event>> observers =
Maps.transformValues(map, EventConsumers::toObserver);
return ImmutableMap.copyOf(observers);
Expand Down
5 changes: 3 additions & 2 deletions client/src/main/java/io/spine/client/Subscriptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.protobuf.Message;
import io.grpc.ManagedChannel;
import io.grpc.stub.StreamObserver;
Expand All @@ -34,7 +35,6 @@
import io.spine.logging.Logging;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -172,7 +172,7 @@ <M extends Message> Subscription subscribeTo(Topic topic, StreamObserver<M> obse
}

/** Adds all the passed subscriptions. */
void addAll(Collection<Subscription> newSubscriptions) {
void addAll(Iterable<Subscription> newSubscriptions) {
newSubscriptions.forEach(this::add);
}

Expand All @@ -188,6 +188,7 @@ private void add(Subscription s) {
*
* @return {@code true} if the subscription was previously made
*/
@CanIgnoreReturnValue
public boolean cancel(Subscription s) {
checkNotNull(s);
boolean isActive = items.contains(s);
Expand Down
Loading