diff --git a/Gemfile.lock b/Gemfile.lock index 3456b589..6cb0c553 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,8 +23,8 @@ GEM commonmarker (0.17.13) ruby-enum (~> 0.5) concurrent-ruby (1.1.6) - dnsruby (1.61.3) - addressable (~> 2.5) + dnsruby (1.61.4) + simpleidn (~> 0.1) em-websocket (0.5.1) eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) @@ -37,9 +37,9 @@ GEM ffi (1.13.1) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (206) + github-pages (207) github-pages-health-check (= 1.16.1) - jekyll (= 3.8.7) + jekyll (= 3.9.0) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) jekyll-commonmark-ghpages (= 0.1.6) @@ -73,7 +73,8 @@ GEM jekyll-theme-time-machine (= 0.1.1) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.11.1) - kramdown (= 1.17.0) + kramdown (= 2.3.0) + kramdown-parser-gfm (= 1.1.0) liquid (= 4.0.3) mercenary (~> 0.3) minima (= 2.5.1) @@ -100,14 +101,14 @@ GEM http_parser.rb (0.6.0) i18n (0.9.5) concurrent-ruby (~> 1.0) - jekyll (3.8.7) + jekyll (3.9.0) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) i18n (~> 0.7) jekyll-sass-converter (~> 1.0) jekyll-watch (~> 2.0) - kramdown (~> 1.14) + kramdown (>= 1.17, < 3) liquid (~> 4.0) mercenary (~> 0.3.3) pathutil (~> 0.9) @@ -206,7 +207,10 @@ GEM gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) - kramdown (1.17.0) + kramdown (2.3.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) liquid (4.0.3) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) @@ -234,6 +238,7 @@ GEM rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) + rexml (3.2.4) rouge (3.19.0) ruby-enum (0.8.0) i18n @@ -247,6 +252,8 @@ GEM sawyer (0.8.2) addressable (>= 2.3.5) faraday (> 0.8, < 2.0) + simpleidn (0.1.1) + unf (~> 0.1.4) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) @@ -254,6 +261,9 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.7) unicode-display_width (1.7.0) yell (2.2.2) zeitwerk (2.4.0) diff --git a/docs/guides/integration.md b/docs/guides/integration.md index 65846ab8..b216a64a 100644 --- a/docs/guides/integration.md +++ b/docs/guides/integration.md @@ -91,9 +91,9 @@ The Event Consumer, as depicted above, implements the Event transformation logic establish this communication channel, the **Airplane Supplies** system declares a [gRPC](https://grpc.io/) service. In [`supplies_service.proto`](https://github.com/spine-examples/airport/blob/master/airplane-supplies/src/main/proto/spine/example/airport/supplies/supplies_service.proto): - +[//]: # ```proto message Subscription { @@ -102,9 +102,9 @@ message Subscription { google.protobuf.Timestamp starting_from = 3; } ``` - +[//]: # ```proto enum EventType { ALL = 0; @@ -117,8 +117,8 @@ enum EventType { The **Airplane Supplies** system [implements](https://github.com/spine-examples/airport/blob/master/airplane-supplies/src/main/java/io/spine/example/airport/supplies/SuppliesEventProducer.java) the service and exposes it on an endpoint available to the **Takeoffs and Landings** system: - +[//]: # ```java public final class SuppliesEventProducer extends SuppliesEventProducerImplBase { ... @@ -145,8 +145,8 @@ an [event consumer](https://github.com/spine-examples/airport/blob/master/t which constructs a subscription and maintains it as long as the system needs to receive more events. The consumer broadcasts the received Events via an instance of [`ThirdPartyContext`](https://spine.io/core-java/reference/server/io/spine/server/integration/ThirdPartyContext.html): - +[//]: # ```java @Override public void onNext(SuppliesEvent event) { @@ -168,9 +168,9 @@ The [`AircraftAggregate`](https://github.com/spine-examples/airport/blob/master/ reacts on those events. Note that all the events published through `ThirdPartyContext` are always `external`, so should be the subscriber and reactor methods. - +[//]: # ```java @React AircraftPreparedForFlight on(@External PreflightCheckComplete event) { @@ -201,9 +201,9 @@ The Consumer consists of two parts: [`WeatherUpdateClient`](https://github.com/s and [`WeatherUpdateEndpoint`](https://github.com/spine-examples/airport/blob/master/takeoffs-and-landings/src/main/java/io/spine/example/airport/tl/weather/WeatherUpdateEndpoint.java). The client polls the pull-style API of the **Weather** system. - +[//]: # ```java private void fetchWeatherUpdates() { Instant lastEvent = lastEventTime; @@ -230,9 +230,9 @@ private void fetchWeatherUpdates() { The endpoint handles the polled measurements and publishes them as Events in the **Takeoffs and Landings** context: - +[//]: # ```java public void receiveNew(WeatherMeasurement measurement) { checkNotNull(measurement); @@ -255,8 +255,9 @@ public void receiveNew(WeatherMeasurement measurement) { ``` The [`FlightAggregate`](https://github.com/spine-examples/airport/blob/master/takeoffs-and-landings/src/main/java/io/spine/example/airport/tl/FlightAggregate.java) reacts on those events and changes its state as the result: - + +[//]: # ```java @React EitherOf2 on(@External TemperatureChanged event) { @@ -302,8 +303,9 @@ for the [Boarding process](https://github.com/spine-examples/airport/blob/master The **Security Checks** API provides data for each passenger independently. The client polls the data and publishes many intermediate `PassengerBoarded` or `PassengerDeniedBoarding` external events via [`ThirdPartyContext`](https://spine.io/core-java/reference/server/io/spine/server/integration/ThirdPartyContext.html): - + +[//]: # ```java public void start() { while (active) { @@ -332,8 +334,8 @@ The [Process Manager](https://github.com/spine-examples/airport/blob/master/take accumulates the Events and, once the whole *Flight* is boarded, emits a `BoardingComplete` event, which is later consumed by the [*Flight* Aggregate](https://github.com/spine-examples/airport/blob/master/takeoffs-and-landings/src/main/java/io/spine/example/airport/tl/FlightAggregate.java). - +[//]: # ```java @React EitherOf2 on(@External PassengerBoarded event) { diff --git a/docs/quick-start/index.md b/docs/quick-start/index.md index dc44f0aa..725fa2ae 100644 --- a/docs/quick-start/index.md +++ b/docs/quick-start/index.md @@ -132,9 +132,9 @@ Now, let's review the code in details, starting with how to add Spine to a Gradl Let's open `build.gradle` from the root of the project. The simplest and recommended way for adding Spine dependencies to a project is the Bootstrap plugin: - +[//]: # ```groovy plugins { id 'io.spine.tools.gradle.bootstrap' version '1.5.24' @@ -143,9 +143,9 @@ plugins { Once the plugin is added, we can use its features: - +[//]: # ```groovy spine.enableJava().server() ``` @@ -221,18 +221,18 @@ syntax = "proto3"; Then follows the import statement for custom options used when defining data types. This import is required for all proto files of a Spine-based project. - +[//]: # ```proto import "spine/options.proto"; ``` The following file-wide option defines the prefix for type names used in this file. - +[//]: # ```proto option (type_url_prefix) = "type.spine.io"; ``` @@ -242,9 +242,9 @@ in a system would use the same prefix. Then we see the standard Protobuf option for defining a Java package for the generated code: - +[//]: # ```proto option java_package="io.spine.helloworld.hello.command"; ``` @@ -263,9 +263,9 @@ There are three parts of interest in this package name: The following standard proto file option defines the name for the outer class generated by Protobuf Compiler for this `.proto` file: - +[//]: # ```proto option java_outer_classname = "CommandsProto"; ``` @@ -280,17 +280,18 @@ The next standard option instructs the Protobuf Compiler to put each generated J a separate file. This way it would be easier to analyze dependencies of the code which uses these generated types. - +[//]: # ```proto option java_multiple_files = true; ``` The command for printing a text in a console is defined this way: - +[//]: # ```proto message Print { @@ -350,9 +351,9 @@ The sole event in this project is declared this way: The command for printing a text in a console is defined this way: - +[//]: # ```proto message Printed { @@ -386,9 +387,9 @@ server-only is not used by the client code. This file defines a single data type. It is the state of the entity handling the `Print` command: - +[//]: # ```proto message Output { option (entity) = { kind: PROCESS_MANAGER }; @@ -412,8 +413,8 @@ Now, let's see how this data is used at the server-side. The class is declared this way: - +[//]: # ```java final class Console extends ProcessManager { ``` @@ -431,9 +432,9 @@ of the first field of the `Print` command? The command is handled by this method: - +[//]: # ```java @Assign Printed handle(Print command) { @@ -458,9 +459,9 @@ The following code obtains the name of the user and the text to print from the r and then applies them to the state of the Process Manager. Instances of the `Console` class store the text printed for each user. - +[//]: # ```java String username = command.getUsername(); String text = command.getText(); @@ -469,18 +470,19 @@ builder().setUsername(username) ``` Then we print the text to `System.out` so that it becomes visible on the screen: - + +[//]: # ```java println(username, text); ``` This is done by the method the `Console` class declares: - +[//]: # ```java private void println(String userName, String text) { String output = format("[%s] %s", userName, text); @@ -490,9 +492,9 @@ private void println(String userName, String text) { Then, the command-handling method concludes by producing the event message: - +[//]: # ```java return Printed.newBuilder() .setUsername(username) @@ -515,8 +517,9 @@ receive commands. Let's open the `HelloContext` class. The first thing of interest in this class is the declaration of the name of the Bounded Context: - +[//]: # ```java static final String NAME = "Hello"; ``` @@ -525,9 +528,9 @@ This constant is used for creating the context (we will review it in a minute) a the server-side code which belongs to the Hello context. This is done in `package-info.java` using the `@BoundedContext` annotation: - +[//]: # ```java @BoundedContext(HelloContext.NAME) package io.spine.helloworld.server.hello; @@ -539,9 +542,9 @@ This arrangement is needed for routing events.

The second thing the `HelloContext` does is creating a Builder for the Bounded Context: - +[//]: # ```java public static BoundedContextBuilder newBuilder() { return BoundedContext @@ -569,9 +572,9 @@ you enable Spine in your project using `spine.enableJava().server()`. So, we're The class of the test suite extends the abstract base called `ContextAwareTest`: - +[//]: # ```java @DisplayName("Hello context should") class HelloContextTest extends ContextAwareTest { @@ -584,9 +587,9 @@ the `context()` method. We pass the Hello Context for testing using its builder by implementing the abstract method `contextBuilder()` inherited from `ContextAwareTest`: - +[//]: # ```java @Override protected BoundedContextBuilder contextBuilder() { @@ -597,9 +600,9 @@ Now we can get down to the tests. The suite verifiers the outcome of the `Print` The test methods are gathered under the nested class called `PrintCommand`. The class holds the reference to the command as its field: - +[//]: # ```java @Nested @DisplayName("handle the `Print` command") @@ -612,9 +615,9 @@ class PrintCommand { The command is created and sent to the test fixture before each test method: - +[//]: # ```java @BeforeEach void sendCommand() { @@ -639,9 +642,9 @@ its state. Testing that an event was generated is quite simple. We create the expected event and assert it with the test fixture: - +[//]: # ```java @Test @DisplayName("emitting the `Printed` event") void event() { @@ -658,9 +661,9 @@ void event() { For testing the state of the `Console` Process Manager was updated, we construct the expected state and pass it to the `assertState()` method of the test fixture: - +[//]: # ```java @Test @DisplayName("updating the `Console` entity") void entity() { @@ -684,9 +687,9 @@ the server-side application. Let's open the `Server` class of our example application suite. The static initialization of the class configures the server environment: - +[//]: # ```java static { configureEnvironment(); @@ -698,9 +701,9 @@ static { The `configureEnvironment()` method initializes the `Production` environment of this example with the settings that are normally used for testing: - +[//]: # ```java private static void configureEnvironment() { Class prod = Production.class; @@ -720,9 +723,9 @@ The implementation of the `Server` class wraps around the class `io.spine.server by the framework. This API is for exposing `BoundedContext`s in a server-side application. This is what our `Server` class does in the constructor: - +[//]: # ```java public Server(String serverName) { this.server = inProcess(serverName) @@ -754,9 +757,9 @@ Now we have the server, but how does the client side look like? Similarly to `Server`, the `Client` class of our example application wraps around the `io.spine.client.Client` API provided by the `spine-client` library: - +[//]: # ```java public final class Client { @@ -771,8 +774,9 @@ the `io.spine:spine-server` library, which is added to the project when you do Then, the `Client` class declares a field for keeping subscriptions to the results of a command execution. We'll see how this field is used in a minute. - +[//]: # ```java private @Nullable ImmutableSet subscriptions; ``` @@ -781,9 +785,9 @@ First of all, let's see how the `Client` instances are created. ### The constructor - +[//]: # ```java public Client(String serverName) { this.client = inProcess(serverName) @@ -800,9 +804,9 @@ Now, let's review the main thing the `Client` class does, sending the `Print` co ### Sending the command - +[//]: # ```java public void sendCommand() { String userName = System.getProperty("user.name"); @@ -846,9 +850,9 @@ the subscription. When the client code receives the `Printed` event, it prints its data and then cancels the subscription: - +[//]: # ```java private void onPrinted(Printed event) { printEvent(event); @@ -858,9 +862,9 @@ private void onPrinted(Printed event) { There's not much exciting about the printing part. - +[//]: # ```java private void printEvent(EventMessage e) { String out = format( @@ -880,9 +884,9 @@ all Protobuf types available in the project. Cancelling the subscription, if any, iterates through the set passing each of them to the `Client.subscriptions()` API for the cancellation: - +[//]: # ```java private void cancelSubscriptions() { if (subscriptions != null) { @@ -900,9 +904,9 @@ The `close()` method simply delegates to the method of the `io.spine.client.Clie We also need to tell the calling code if the client has finished its job. This is what the `isDone()` method is for: - +[//]: # ```java public boolean isDone() { return client.subscriptions() @@ -920,9 +924,9 @@ Now, let's put it all together. Let's review the `Example` class and its `main()` method. It simulates client-server communication scenario. - +[//]: # ```java public static void main(String[] args) { String serverName = UUID.randomUUID().toString();