From 5e55001cfbec31b697c1e9ee8dc9d03dbcd8dc28 Mon Sep 17 00:00:00 2001 From: Ludwig Richter Date: Tue, 29 Mar 2022 21:06:19 +0200 Subject: [PATCH 1/4] feat(images): Add message structure diagram --- .../vertx/message-structure.drawio.svg | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 static/img/drawio-diagrams/vertx/message-structure.drawio.svg diff --git a/static/img/drawio-diagrams/vertx/message-structure.drawio.svg b/static/img/drawio-diagrams/vertx/message-structure.drawio.svg new file mode 100644 index 00000000..505dd0d5 --- /dev/null +++ b/static/img/drawio-diagrams/vertx/message-structure.drawio.svg @@ -0,0 +1,84 @@ + + + + + + + + +
+
+
+ Vert.x Message +
+
+
+
+ + Vert.x Message + +
+
+ + + + +
+
+
+ Meta information +
+
+
+
+ + Meta information + +
+
+ + + + +
+
+
+ Optional headers +
+
+
+
+ + Optional headers + +
+
+ + + + +
+
+
+ Message Body +
+ (Content) +
+
+
+
+ + Message Body... + +
+
+
+ + + + + Viewer does not support full SVG 1.1 + + + +
\ No newline at end of file From 653ce2d1272d68ea4c2e7ebfe7747b7ad43f0325 Mon Sep 17 00:00:00 2001 From: Ludwig Richter Date: Tue, 29 Mar 2022 21:07:11 +0200 Subject: [PATCH 2/4] feat(docs/application): Add message headers concept --- .../concepts/120-message-headers.mdx | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 docs/application/concepts/120-message-headers.mdx diff --git a/docs/application/concepts/120-message-headers.mdx b/docs/application/concepts/120-message-headers.mdx new file mode 100644 index 00000000..af12c0e8 --- /dev/null +++ b/docs/application/concepts/120-message-headers.mdx @@ -0,0 +1,176 @@ +--- +title: Message headers +description: Additional information attached to Vert.x messages +--- + + + + + +import { Reference, Image } from '/components'; + + + +Message headers are additional information that can be attached to Vert.x messages. +These information are like [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) and completely optional. + +Vert.x provides basic functionality for header information via +[MultiMaps](https://javadoc.io/static/io.vertx/vertx-core/4.2.6/index.html?io/vertx/core/MultiMap.html). +Telestion takes this approach and extends the MultiMap's functionality via the +[HeaderInformation](https://javadoc.io/doc/de.wuespace.telestion/telestion-api/latest/de/wuespace/telestion/api/message/HeaderInformation.html) +class. + +## Vert.x Multi Map + +Vert.x Multi Maps store basic string type information in a key-value list format. + +Take a look at the following example: + +```java +// create new and empty multi map +var map = MultiMap.caseInsensitiveMultiMap(); + +// add some values +map.add("key1", "value1_1"); +map.add("key2", "value2_1"); + +// later +map.add("key1", "value1_2"); +logger.debug("Values on key1: {}", map.getAll("key1")); // Values on key1: ["value1_1", "value1_2"] +logger.debug("Values on key2: {}", map.getAll("key2")); // Values on key2: ["value2_1"] + +// set a value (-> removes existing information) +map.set("key1", "value1_3"); +logger.debug("Values on key1: {}", map.getAll("key1")); // Values on key1: ["value1_3"] +``` + +As you can see, a multi map can store multiple strings in one keyslot. + +## Telestion Header Information + +Telestion uses the same approach as the Vert.x Multi Map and provides a similar interface but with support +for all primitive data types in Java. + +Look at the following example: + +```java +// create new and empty header information +var information = new HeaderInformation(); + +// add some values +information.add("key1", true).add("key2", 42); + +// and extract them again +logger.debug("Boolean value on key1: {}", information.getBoolean("key1")); +logger.debug("Integer value on key2: {}", information.getInteger("key2")); +``` + +As you can see, the Telestion Header Information API follows the Vert.x Multi Map API +and also provides support for other data types, e.g. booleans or integers. + +## Headers and messages + +Headers can be attached to message before they pass the event bus and can be extracted +on the the receiving side. + +The attached headers aren't part of the body and reside next to the content. + + + +Take a look at the following example: + +```java title="PublishVerticle.java" +public class PublishVerticle extends TelestionVerticle implements WithEventBus { + @Override + public void onStart() { + var information = new HeaderInformation().add("send-time", System.currentTimeInMillis()); + // attach information to event bus message + publish("some-address", "Important information", information); + } +} +``` + +```java title="ReceiveVerticle.java" +public class ReceiveVerticle extends TelestionVerticle implements WithEventBus { + @Override + public void onStart() { + register("some-address", message -> { + // extract information from received message + var receivedInformation = HeaderInformation.from(message); + logger.debug("Received content: {}", message.body()); + logger.debug("Send time: {}", receivedInformation.getLong("send-time")); + }); + } +} +``` + +As you can see, Telestion provides excellent support for Vert.x Multi Maps +and Telestion Header Information especially in verticles. + +## See also + + + HTTP Headers + + + + MultiMap API reference + + + + HeaderInformation API reference + + + + Traits concept + + + + WithEventBus API reference + + + From a3eecd1241d697fad8484b978437e7a4e6803e42 Mon Sep 17 00:00:00 2001 From: Ludwig Richter Date: Wed, 27 Jul 2022 00:05:58 +0200 Subject: [PATCH 3/4] feat(docs/application): Add header information guide --- .../concepts/120-message-headers.mdx | 12 +- .../guides/210-using-header-information.mdx | 462 ++++++++++++++++++ .../header-information/add.drawio.svg | 128 +++++ .../header-information/set.drawio.svg | 130 +++++ 4 files changed, 728 insertions(+), 4 deletions(-) create mode 100644 docs/application/guides/210-using-header-information.mdx create mode 100644 static/img/drawio-diagrams/header-information/add.drawio.svg create mode 100644 static/img/drawio-diagrams/header-information/set.drawio.svg diff --git a/docs/application/concepts/120-message-headers.mdx b/docs/application/concepts/120-message-headers.mdx index af12c0e8..a8ca47e4 100644 --- a/docs/application/concepts/120-message-headers.mdx +++ b/docs/application/concepts/120-message-headers.mdx @@ -142,6 +142,14 @@ and Telestion Header Information especially in verticles. ## See also + + Traits concept + + + + Using Header Information + + HTTP Headers @@ -154,10 +162,6 @@ and Telestion Header Information especially in verticles. HeaderInformation API reference - - Traits concept - - WithEventBus API reference diff --git a/docs/application/guides/210-using-header-information.mdx b/docs/application/guides/210-using-header-information.mdx new file mode 100644 index 00000000..87f0c675 --- /dev/null +++ b/docs/application/guides/210-using-header-information.mdx @@ -0,0 +1,462 @@ +--- +title: Using Header Information +# e.g., "Working with the Event Bus" or "Managing dependencies with npm" + +description: + Header Information are an additional way to transmit information. + Learn how to use Telestion Header Information in your project + and how to create your own custom Header Information. +--- + + + + + +import { Reference, Image } from '/components'; + + + +This guide teaches you how to use the Telestion Header Information in your project +and how to write your own custom Header Information. + + + +:::tip Is this the right guide for you? + +This guide primarily targets Backend Developers +and anyone who wants to learn how to use the Telestion Header Information. + +To best understand the topics covered here, you should be familiar with the +following concepts before reading this article: + + + +- [Message headers](/application/concepts/message-headers) +- [Using traits in Verticles](/application/tutorials/using-traits-in-verticles) + +::: + +## Using Header Information in your project + +### Create and extract Header Information from different sources + +Header Information are nothing more than meta information storage. + +You can create empty Header Information or extract the metadata from different sources. +These can be Vert.x messages, delivery options or Vert.x MultiMaps. + +For example, create new and empty Header Information: + +```java +var information = new HeaderInformation(); +logger.debug(information.size()); // 0 +``` + +Or from different sources: + +```java +// your sources +Message vertxMessage; +DeliveryOptions options; +MultiMap vertxMultiMap; + +// using the suitable constructor +var infos1 = new HeaderInformation(vertxMessage); +var infos2 = new HeaderInformation(options); +var infos3 = new HeaderInformation(vertxMultiMap); + +// using the from utility method +var infos4 = HeaderInformation.from(vertxMessage); +var infos5 = HeaderInformation.from(options); +var infos6 = HeaderInformation.from(vertxMultiMap); +``` + +### Add and manipulate metadata + +Then you can manipulate the metadata inside the Header Information. + +For example, adding more metadata: + +```java +var information = new HeaderInformation(); + +// adds an additional value to already existing ones +information.add("key1", "value1"); +information.add("key1", "value2"); + +logger.debug("Values: {}", information.getAll("key1")); // Values: ["value1", "value2"] +``` + +:::info + +If there are already existing information on the specified keyslot, +the `add` method appends the new information to the list of already existing information. + + + +::: + +Or replacing existing information: + +```java +var information = new HeaderInformation(); + +// adds an additional value to already existing ones +information.set("key1", "value1"); +information.set("key1", "value2"); + +logger.debug("Values: {}", information.getAll("key1")); // Values: ["value2"] +``` + +:::info + +The `set` method **overwrites** the current content in the specified keyslot. + + + +::: + +You can also delete existing information: + +```java +var information = new HeaderInformation(); + +// adds an additional value to already existing ones +information.set("key1", "value1"); +information.remove("key1"); + +logger.debug("Values: {}", information.getAll("key1")); // Values: [] +``` + +### Publish the results + +Once you're happy with your changes, it's time to publish them. +Telestion provides multiple convenience functions to make this step easier. + +For example, the `WithEventBus` trait accepts Header Information, +merge them and attach the result to the outgoing message: + +```java +// some information +var infos1 = new HeaderInformation().add("key1", "value1"); +var infos2 = new HeaderInformation().add("key2", "value2"); + +// attach to publish message +publish("some-address", "Ping", infos1, infos2); + +register("some-address", message -> { + // extract attached information + var infos = HeaderInformation.from(message); + + logger.debug("Key 1: {}", infos.get("key1", "default1")); // Key 1: value1 + logger.debug("Key 2: {}", infos.get("key2", "default2")); // Key 2: value2 +}); +``` + +If you have a more complex use case, you can use one of the export methods: + +```java +var information = new HeaderInformation().set("key1", "value1"); + +// to delivery options +var deliveryOptions = information.toOptions(); +// to Vert.x MultiMap +var multiMap = information.getHeaders(); +``` + +Or you have multiple Header Information and your target only accept one, you can merge them: + +```java +var infos1 = new HeaderInformation().add("key1", "value1"); +var infos2 = new HeaderInformation().add("key2", "value2"); + +var merged = HeaderInformation.merge(infos1, infos2); + +logger.debug("Key 1: {}", merged.get("key1", "default1")); // Key 1: value1 +logger.debug("Key 2: {}", merged.get("key2", "default2")); // Key 2: value2 +``` + +## Writing custom Header Information + +If you plan to distribute a collection of verticles and you use headers to spread information, +you can extend the Header Information class to specify attributes. +This gives you and other users outside of your collection access to bundled Header Information +in a well-defined way. + +### Extending Header Information + +To kick off you new Header Information, all you need to do, is extending the `HeaderInformation` class: + +````java +import de.wuespace.telestion.api.message.HeaderInformation; + +public class CounterInformation extends HeaderInformation { +} +```` + +:::tip + +All custom Header Information class names should end with `Information`. + +::: + +In this abstraction we want to store and access a counter value. Lets add a getter and setter method: + +````java +import de.wuespace.telestion.api.message.HeaderInformation; + +public class CounterInformation extends HeaderInformation { + + public CounterInformation() { + this(-1); + } + + public CounterInformation(int counter) { + setCounter(counter); + } + + public CounterInformation(CounterInformation other) { + this(other.getCounter()); + } + + public CounterInformation setCounter(int counter) { + add("counter", counter); + return this; + } + + public int getCounter() { + return getInt("counter", -1); + } +} +```` + +:::tip + +Add a constructor for: + +- default values (the default constructor) +- other custom Header Information + +Add a setter and getter method for every property you want to control. + +::: + +### Merge duplicates and add sane defaults + +As you can see, we have some redundant parts. Lets merge and move them up: + +````java +import de.wuespace.telestion.api.message.HeaderInformation; + +public class CounterInformation extends HeaderInformation { + + // highlight-next-line + public static final String COUNTER_KEY = "counter"; + + // highlight-next-line + public static final int COUNTER_DEFAULT = -1; + + public CounterInformation() { + // highlight-next-line + this(COUNTER_DEFAULT); + } + + public CounterInformation(int counter) { + setCounter(counter); + } + + public CounterInformation(CounterInformation other) { + this(other.getCounter()); + } + + public CounterInformation setCounter(int counter) { + // highlight-next-line + add(COUNTER_KEY, counter); + return this; + } + + public int getCounter() { + // highlight-next-line + return getInt(COUNTER_KEY, COUNTER_DEFAULT); + } +} +```` + +:::tip + +Key names and default values should be class constants. +Specifiers for key names should end with `_KEY`. +Specifiers for default values should end with `_DEFAULT`. + +::: + +:::caution + +Always think and add sane defaults to your stored values. +Header Information are always completely optional and the user expects good default values. + +::: + +### Add convenience methods + +Currently the user needs to cast the header information to get access to your counter methods. +Lets simplify that and add methods to parse MultiMaps, messages and delivery options: + +````java +import de.wuespace.telestion.api.message.HeaderInformation; +// highlight-start +import io.vertx.core.MultiMap; +import io.vertx.core.eventbus.DeliveryOptions; +import io.vertx.core.eventbus.Message; +// highlight-end + +public class CounterInformation extends HeaderInformation { + + public static final String COUNTER_KEY = "counter"; + + public static final int COUNTER_DEFAULT = -1; + + // highlight-start + public static CounterInformation from(MultiMap headers) { + return new CounterInformation(headers); + } + // highlight-end + + // highlight-start + public static CounterInformation from(Message message) { + return new CounterInformation(message); + } + // highlight-end + + // highlight-start + public static CounterInformation from(DeliveryOptions options) { + return new CounterInformation(options); + } + // highlight-end + + public CounterInformation() { + this(COUNTER_DEFAULT); + } + + public CounterInformation(int counter) { + setCounter(counter); + } + + public CounterInformation(CounterInformation other) { + this(other.getCounter()); + } + + // highlight-start + public CounterInformation(MultiMap headers) { + super(headers); + } + // highlight-end + + // highlight-start + public CounterInformation(Message message) { + super(message); + } + // highlight-end + + // highlight-start + public CounterInformation(DeliveryOptions options) { + super(options); + } + // highlight-end + + public CounterInformation setCounter(int counter) { + add(COUNTER_KEY, counter); + return this; + } + + public int getCounter() { + return getInt(COUNTER_KEY, COUNTER_DEFAULT); + } +} +```` + +:::tip + +Custom header information should provide constructors to parse: + +- multimaps +- messages +- delivery options + +and an overloaded method named `from` that passes through all listed items mentioned above +and returns a new header information object. + +::: + +That's it! You've written your first custom header information. + +### Wrap up + +If you want to write custom Header Information, consider the following things: + +- your class name should with `Information` +- add a setter and getter method for every property you want to control +- provide class constants for key names and default values +- add sane defaults +- specifiers for key names should end with `_KEY` +- specifiers for default values should end with `_DEFAULT` +- add a default constructor +- add a constructor that accepts other custom Header Information +- add constructors that accept multimaps, messages and delivery options +- add an overloaded static method `from` that accepts the arguments from above and returns a new instance + +## See also + + + Message Headers concept + + + + Using traits in Verticles + + + diff --git a/static/img/drawio-diagrams/header-information/add.drawio.svg b/static/img/drawio-diagrams/header-information/add.drawio.svg new file mode 100644 index 00000000..bbdfcc3e --- /dev/null +++ b/static/img/drawio-diagrams/header-information/add.drawio.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + +
+
+
+ existing +
+ value +
+
+
+
+ + existing... + +
+
+ + + + +
+
+
+ [empty] +
+
+
+
+ + [empty] + +
+
+ + + + + + +
+
+
+ Key +
+
+
+
+ + Key + +
+
+ + + + + + +
+
+
+ new value +
+
+
+
+ + new value + +
+
+ + + + + + +
+
+
+ get() +
+
+
+
+ + get() + +
+
+ + + + +
+
+
+ [empty] +
+
+
+
+ + [empty] + +
+
+
+ + + + + Viewer does not support full SVG 1.1 + + + +
\ No newline at end of file diff --git a/static/img/drawio-diagrams/header-information/set.drawio.svg b/static/img/drawio-diagrams/header-information/set.drawio.svg new file mode 100644 index 00000000..a97355f2 --- /dev/null +++ b/static/img/drawio-diagrams/header-information/set.drawio.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + +
+
+
+ existing +
+ value +
+
+
+
+ + existing... + +
+
+ + + + +
+
+
+ [empty] +
+
+
+
+ + [empty] + +
+
+ + + + + + +
+
+
+ Key +
+
+
+
+ + Key + +
+
+ + + + + + +
+
+
+ new value +
+
+
+
+ + new value + +
+
+ + + + + + +
+
+
+ get() +
+
+
+
+ + get() + +
+
+ + + + +
+
+
+ [empty] +
+
+
+
+ + [empty] + +
+
+
+ + + + + Viewer does not support full SVG 1.1 + + + +
\ No newline at end of file From 125caab1f7c4e03a9108b00e58633b4857827c5e Mon Sep 17 00:00:00 2001 From: Ludwig Richter Date: Thu, 28 Jul 2022 12:31:01 +0200 Subject: [PATCH 4/4] feat(docs/application): Add get metadata section in user guide --- docs/application/guides/210-using-header-information.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/application/guides/210-using-header-information.mdx b/docs/application/guides/210-using-header-information.mdx index 87f0c675..145d1617 100644 --- a/docs/application/guides/210-using-header-information.mdx +++ b/docs/application/guides/210-using-header-information.mdx @@ -104,6 +104,10 @@ var infos5 = HeaderInformation.from(options); var infos6 = HeaderInformation.from(vertxMultiMap); ``` +### Get metadata + +Coming soon + ### Add and manipulate metadata Then you can manipulate the metadata inside the Header Information.