diff --git a/vlingo-schemata-integration/README.adoc b/vlingo-schemata-integration/README.adoc new file mode 100644 index 00000000..f351de82 --- /dev/null +++ b/vlingo-schemata-integration/README.adoc @@ -0,0 +1,141 @@ += Integration w/ vlingo/schemata + +ifdef::env-github[] +:tip-caption: :bulb: +:note-caption: :information_source: +:important-caption: :heavy_exclamation_mark: +:caution-caption: :fire: +:warning-caption: :warning: +endif::[] + +`vlingo/schemata` allows for managing schemata for events and commands that +to be consumed by other bounded contexts, thus implementing the published language pattern. + +`vlingo/schemata` can be run as standalone service and comes with a user interface +and an HTTP API that lets you manage master data and schemata. Using `vlingo-build-plugins`, +you can also interact with schemata as part of your build process. + +In projects, you'll typically consume and/or publish schemata to be able to integrate +with other bounded contexts in a type safe and versioned manner. + +In this example, you'll see how to ... + +* ... build an run `vlingo/schemata` +* ... manage schemata and schemata meta data using the UI and the HTTP API. +* ... push schemata to the registry from maven builds and +* ... consume schemata stored in the registry as part of the build. + + +NOTE: This is the first iteration of the example. We're already working on updates showing +version validation and the schemata lifecycle. + +== Prerequisites + +To be able to follow along, you'll need: + +* JDK 8 +* Maven 3.3.x +* A running instance of `vlingo/schemata` (see <<Set up vlingo/schemata>>) +* Some master data (see <<Provision schemata master data>>) + +=== Set up vlingo/schemata + +* Clone https://github.com/vlingo/vlingo-schemata +* Make sure your JDK is set to a 1.8 version in the shell you're building in footnote:[If you're juggling JDKs, https://sdkman.io/ might help you.] +* Run `mvn package -Pfrontend` in the project root +* Run `java -jar target/vlingo-schemata-<version>-jar-with-dependencies.jar dev`. This starts a schemata instance listening on port 9019 running on an embedded in memory database. +* Open http://localhost:9019/. If you see something with `vlingo/schemata` in the the title bar, you're good to go. + +NOTE: To run against a persistent database, please have a look at https://github.com/vlingo/vlingo-schemata/ + +TIP: We'll provide a working docker image soon, please bear with us and build schemata yourself in the meantime. + +=== Provision schemata master data + +To be able to integrate your projects with the schema registry, you need to +make your organization structure and available published languages known first. +You can do this either via the HTTP API or the UI. + +Schemata are structured in a hierarchical manner: +`Organisation -> Units -> Contexts -> Schemas -> Schema Versions`. +We'll push new schema versions using the maven plugin. +Before running the build, you need to have at least one of each other entity prepared. + +==== Using the UI + +From the navigation drawer to the left, open the editor for each of these entities and create one. +The build assumes the following structure: + +* Organisation: `Vlingo` +** Unit: `examples` +***** Context Namepace: `io.vlingo.examples.schemata` +****** Schema: `SchemaDefined` +****** Schema: `SchemaPublished` + +.Create context using the UI +image::doc/ui-context.png[] + +.The result should look like this +image::doc/ui-browse.png[] + +==== Using the API + +In case you are using IntelliJ, you can just run the requests in `masterdata.http` directly; +`masterdata.sh` is a bash script doing the same footnote:[Requires `curl` and `jq`]. +Otherwise, deriving the `wget` footnote:[`PostMan`, `HTTPie`, `Insomnia`, `Invoke-WebRequest` pick your flavor.] +calls from the snippets should be a simple exercise. + +== Run + +Now that we have the master data in place, we can publish some schemata from +`vlingo-schemata-producer`. The schema sources live in `src/main/vlingo/schemata` +in that project. To publish them, simply run `mvn install` in the project root. +The build output should contain <<output-producer>>, the <<ui-schema-version>> should look like +the screenshot below. You can also have a look at the generated code (`Specification -> Source`) and description using the +and the generated description (`Description -> Preview`) + + +Next, hop over to `vlingo-schemata-consumer` and open `SchemataUsageTest` in your IDE. +You'll notice that it does not compile, as the schema class is missing. +Now run `mvn generate-sources` and verify that the code generated from schemata is +pulled and written to `target/generated-sources/vlingo` as shown in <<output-consumer>>. +The test relying on schemata sources will now compile and execute as expected. + +NOTE: This is just for illustration purposes. Typically, you'll rely on maven's default lifecycle binding + and not call `generate-sources` explicitly. Simply running `mvn install` will determine + that `vlingo-build-plugin` is bound to `generate-sources` and run it before. + + +[[output-producer]] +.producer build output +[source] +--- +[INFO] --- vlingo-build-plugins:0.9.3-RC4:push-schemata (default) @ vlingo-schemata-producer --- +[INFO] vlingo/maven: Pushing project schemata to vlingo-schemata registry. +[INFO] Pushing Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1 to http://localhost:9019/versions/Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1. +[INFO] Successfully pushed http://localhost:9019/versions/Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1 +[INFO] Setting source to SchemaPublished.vss for Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 +[INFO] Pushing Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 to http://localhost:9019/versions/Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1. +[INFO] Successfully pushed http://localhost:9019/versions/Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 +--- + +[[ui-schema-version]] +.schema version in the UI +image::doc/ui-schema-version.png[] + +[[output-consumer]] +.consumer build output +[source] +--- +[INFO] --- vlingo-build-plugins:0.9.3-RC4:pull-schemata (pullSchemata) @ vlingo-schemata-consumer --- +[INFO] vlingo/maven: Pulling code generated from vlingo/schemata registry. +[INFO] SchemataService{url=http://localhost:9019, clientOrganization='Vlingo', clientUnit='examples'} +[INFO] Pulling Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1 from http://localhost:9019/code/Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1/java +[INFO] Pulled Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1 +[INFO] Writing Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1 to /Users/wwerner/Projects/vlingo/vlingo-examples/vlingo-schemata-integration/vlingo-schemata-consumer/target/classes/generated-sources/vlingo/io/vlingo/examples/schemata/event/SchemaDefined.java +[INFO] Wrote /Users/wwerner/Projects/vlingo/vlingo-examples/vlingo-schemata-integration/vlingo-schemata-consumer/target/classes/generated-sources/vlingo/io/vlingo/examples/schemata/event/SchemaDefined.java +[INFO] Pulling Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 from http://localhost:9019/code/Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1/java +[INFO] Pulled Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 +[INFO] Writing Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1 to /Users/wwerner/Projects/vlingo/vlingo-examples/vlingo-schemata-integration/vlingo-schemata-consumer/target/classes/generated-sources/vlingo/io/vlingo/examples/schemata/event/SchemaPublished.java +[INFO] Wrote /Users/wwerner/Projects/vlingo/vlingo-examples/vlingo-schemata-integration/vlingo-schemata-consumer/target/classes/generated-sources/vlingo/io/vlingo/examples/schemata/event/SchemaPublished.java +--- diff --git a/vlingo-schemata-integration/doc/ui-browse.png b/vlingo-schemata-integration/doc/ui-browse.png new file mode 100644 index 00000000..ca0ca994 Binary files /dev/null and b/vlingo-schemata-integration/doc/ui-browse.png differ diff --git a/vlingo-schemata-integration/doc/ui-context.png b/vlingo-schemata-integration/doc/ui-context.png new file mode 100644 index 00000000..a04a3ff5 Binary files /dev/null and b/vlingo-schemata-integration/doc/ui-context.png differ diff --git a/vlingo-schemata-integration/doc/ui-schema-version.png b/vlingo-schemata-integration/doc/ui-schema-version.png new file mode 100644 index 00000000..3e053586 Binary files /dev/null and b/vlingo-schemata-integration/doc/ui-schema-version.png differ diff --git a/vlingo-schemata-integration/masterdata.http b/vlingo-schemata-integration/masterdata.http new file mode 100644 index 00000000..2c77eb79 --- /dev/null +++ b/vlingo-schemata-integration/masterdata.http @@ -0,0 +1,75 @@ +### Create Organization +POST http://localhost:9019/organizations +Content-Type: application/json + +{ + "organizationId": "", + "name": "Vlingo", + "description": "Vlingo Organization" +} + +> {% client.global.set('orgId', response.body.organizationId) %} + + +### Create Unit +POST http://localhost:9019/organizations/{{orgId}}/units +Content-Type: application/json + +{ + "organizationId": "{{orgId}}", + "unitId": "", + "name": "examples", + "description": "Examples for vlingo/schemata" +} + +> {% client.global.set('unitId', response.body.unitId) %} + +### Create Context +POST http://localhost:9019/organizations/{{orgId}}/units/{{unitId}}/contexts +Content-Type: application/json + +{ + "organizationId": "{{orgId}}", + "unitId": "{{unitId}}", + "contextId": "", + "namespace": "io.vlingo.examples.schemata", + "description": "Bounded context for vlingo/schemata examples" +} + +> {% client.global.set('contextId', response.body.contextId) %} + +### Create SchemaDefined schema +POST http://localhost:9019/organizations/{{orgId}}/units/{{unitId}}/contexts/{{contextId}}/schemas +Content-Type: application/json + +{ + "organizationId": "{{orgId}}", + "unitId": "{{unitId}}", + "contextId": "{{contextId}}", + "schemaId": "", + "category": "Event", + "name": "SchemaDefined", + "scope": "Public", + "description": "Fired whenever a new schema is defined." +} + +> {% client.global.set('schemaId', response.body.schemaId) %} + +### Create SchematPublished schema +POST http://localhost:9019/organizations/{{orgId}}/units/{{unitId}}/contexts/{{contextId}}/schemas +Content-Type: application/json + +{ + "organizationId": "{{orgId}}", + "unitId": "{{unitId}}", + "contextId": "{{contextId}}", + "schemaId": "", + "category": "Event", + "name": "SchemaPublished", + "scope": "Public", + "description": "Fired whenever a schema version is published." +} + +> {% client.global.set('schemaId', response.body.schemaId) %} + +### diff --git a/vlingo-schemata-integration/masterdata.sh b/vlingo-schemata-integration/masterdata.sh new file mode 100755 index 00000000..f15f0b52 --- /dev/null +++ b/vlingo-schemata-integration/masterdata.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Small utility script to add master data required for the example to a schemata instance +# Requires curl and jq to be on the path. +# Set the port to the port the schemata server is listening on + +PORT=9039 +ORG_ID=$(curl -s -d '{ "organizationId": "", "name": "Vlingo", "description": "Vlingo Organization" }' -H 'Content-Type: application/json' -X POST http://localhost:${PORT}/organizations | jq -r '.organizationId') +UNIT_ID=$(curl -s -d '{ "organizationId": "'${ORG_ID}'", "unitId": "", "name": "examples", "description": "Examples for vlingo/schemata" }' -X POST -H 'Content-Type: application/json' http://localhost:${PORT}/organizations/${ORG_ID}/units | jq -r '.unitId') +CONTEXT_ID=$(curl -s -X POST -H 'Content-Type: application/json' -d '{ "organizationId": "'${ORG_ID}'", "unitId": "'${UNIT_ID}'", "contextId": "", "namespace": "io.vlingo.examples.schemata", "description": "Bounded context for vlingo/schemata examples" }' http://localhost:${PORT}/organizations/${ORG_ID}/units/${UNIT_ID}/contexts | jq -r '.contextId') +curl -s -X POST -H 'Content-Type: application/json' -d '{ "organizationId": "'${ORG_ID}'", "unitId": "'${UNIT_ID}'", "contextId": "'${CONTEXT_ID}'", "schemaId": "", "category": "Event", "name": "SchemaDefined", "scope": "Public", "description": "Fired whenever a new schema is defined." }' http://localhost:${PORT}/organizations/${ORG_ID}/units/${UNIT_ID}/contexts/${CONTEXT_ID}/schemas +curl -s -X POST -H 'Content-Type: application/json' -d '{ "organizationId": "'${ORG_ID}'", "unitId": "'${UNIT_ID}'", "contextId": "'${CONTEXT_ID}'", "schemaId": "", "category": "Event", "name": "SchemaPublished", "scope": "Public", "description": "Fired whenever a schema version is published." }' http://localhost:${PORT}/organizations/${ORG_ID}/units/${UNIT_ID}/contexts/${CONTEXT_ID}/schemas diff --git a/vlingo-schemata-integration/vlingo-schemata-consumer/pom.xml b/vlingo-schemata-integration/vlingo-schemata-consumer/pom.xml new file mode 100644 index 00000000..c66617a3 --- /dev/null +++ b/vlingo-schemata-integration/vlingo-schemata-consumer/pom.xml @@ -0,0 +1,68 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <groupId>io.vlingo</groupId> + <artifactId>vlingo-schemata-consumer</artifactId> + <version>0.9.3-RC4</version> + <name>vlingo-schemata-consumer</name> + <description>Example of a project consuming schemas from vlingo/schemata.</description> + <url>https://github.com/vlingo/vlingo-examples</url> + <licenses> + <license> + <name>Mozilla Public License 2.0</name> + <url>https://mozilla.org/MPL/2.0/</url> + </license> + </licenses> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <vlingo.build.plugins.version>${project.version}</vlingo.build.plugins.version> + </properties> + <build> + <plugins> + <plugin> + <groupId>io.vlingo</groupId> + <artifactId>vlingo-build-plugins</artifactId> + <version>${vlingo.build.plugins.version}</version> + <executions> + <execution> + <id>pullSchemata</id> + <goals> + <goal>pull-schemata</goal> + </goals> + <configuration> + <schemataService> + <url>http://localhost:9019</url> + <clientOrganization>Vlingo</clientOrganization> + <clientUnit>examples</clientUnit> + </schemataService> + <outputDirectory>${project.build.directory}/generated-sources/vlingo</outputDirectory> + <schemata> + <schema> + <ref>Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1</ref> + </schema> + <schema> + <ref>Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1</ref> + </schema> + </schemata> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + <dependencies> + <!-- required to have access to schemata base classes --> + <dependency> + <groupId>io.vlingo</groupId> + <artifactId>vlingo-lattice</artifactId> + <version>0.9.3-RC4</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/vlingo-schemata-integration/vlingo-schemata-consumer/src/test/java/SchemataUsageTest.java b/vlingo-schemata-integration/vlingo-schemata-consumer/src/test/java/SchemataUsageTest.java new file mode 100644 index 00000000..ddfadaf2 --- /dev/null +++ b/vlingo-schemata-integration/vlingo-schemata-consumer/src/test/java/SchemataUsageTest.java @@ -0,0 +1,19 @@ +// Copyright © 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +import io.vlingo.examples.schemata.event.SchemaDefined; +import io.vlingo.examples.schemata.event.SchemaPublished; +import org.junit.Test; + +public class SchemataUsageTest { + + @Test + public void testThatSchemaIsPulledAndCompiledTest() { + new SchemaDefined(); + new SchemaPublished(); + } +} diff --git a/vlingo-schemata-integration/vlingo-schemata-producer/pom.xml b/vlingo-schemata-integration/vlingo-schemata-producer/pom.xml new file mode 100644 index 00000000..5255f47d --- /dev/null +++ b/vlingo-schemata-integration/vlingo-schemata-producer/pom.xml @@ -0,0 +1,57 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <groupId>io.vlingo</groupId> + <artifactId>vlingo-schemata-producer</artifactId> + <version>0.9.3-RC4</version> + <name>vlingo-schemata-producer</name> + <description>Example of a project pushing schemas to vlingo/schemata.</description> + <url>https://github.com/vlingo/vlingo-examples</url> + <licenses> + <license> + <name>Mozilla Public License 2.0</name> + <url>https://mozilla.org/MPL/2.0/</url> + </license> + </licenses> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <vlingo.build.plugins.version>${project.version}</vlingo.build.plugins.version> + </properties> + <build> + <plugins> + <plugin> + <groupId>io.vlingo</groupId> + <artifactId>vlingo-build-plugins</artifactId> + <version>${vlingo.build.plugins.version}</version> + <executions> + <execution> + <goals> + <goal>push-schemata</goal> + </goals> + <configuration> + <srcDirectory>${basedir}/src/main/vlingo/schemata</srcDirectory> + <schemataService> + <url>http://localhost:9019</url> + <clientOrganization>Vlingo</clientOrganization> + <clientUnit>examples</clientUnit> + </schemataService> + <schemata> + <schema> + <ref>Vlingo:examples:io.vlingo.examples.schemata:SchemaDefined:0.0.1</ref> + <src>SchemaDefined.vss</src> + <previousVersion>0.0.0</previousVersion> + </schema> + <schema> + <ref>Vlingo:examples:io.vlingo.examples.schemata:SchemaPublished:0.0.1</ref> + <!-- src defaults to the name part of the reference --> + <!-- previousVersion defaults to 0.0.0 --> + </schema> + </schemata> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaDefined.vss b/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaDefined.vss new file mode 100644 index 00000000..e269b2f3 --- /dev/null +++ b/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaDefined.vss @@ -0,0 +1,5 @@ +event SchemaDefined { + type eventType + timestamp occurredOn + version eventVersion +} \ No newline at end of file diff --git a/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaPublished.vss b/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaPublished.vss new file mode 100644 index 00000000..f7ec60ba --- /dev/null +++ b/vlingo-schemata-integration/vlingo-schemata-producer/src/main/vlingo/schemata/SchemaPublished.vss @@ -0,0 +1,4 @@ +event SchemaPublished { + timestamp publishedOn + version publishedVersion +} \ No newline at end of file