Skip to content

Commit

Permalink
Updated documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
miere committed Mar 6, 2022
1 parent e798592 commit 16293d4
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 62 deletions.
5 changes: 5 additions & 0 deletions docs_src/manual/architecture/implementation-loaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ They are responsible to perform two basic tasks the Kos needs all the time:
1. Load an object implementing a given Interface - or extending a given class
2. Load all objects implementing a given Interface - or extending a given class

Bear in mind that dependencies are lazy loaded, once a dependency for a given type is loaded
you can't override it. This means that you can safely read any injected dependency using KosContext.
However, the only place you should be able to deterministically modify these dependencies
is within a [Plugin](../kos-plugins/) scope.

## Types of Implementation Loaders
The next topics will cover all DI mechanism provided out-of-box with Kos.

Expand Down
18 changes: 18 additions & 0 deletions docs_src/manual/architecture/kos-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# The Kos Context
`kos.api.KosContext` is the backbone of the system, containing all the basic components
in which Kos will interact with. To avoid misconfiguration, there will be
only one instance of this object (managed by Kos) in the whole application. The
only way to mutate its content is by creating a [Plugin](../kos-plugins/).

## Things you can do with it
- **Programmatically access injectable dependencies** - By invoking `KosContext.getImplementationLoader()` you will be able to directly interact
with all [injectable dependencies found at compile time](../implementation-loaders/). If you have access to a `MutableKosContext`
instance, you will also be able to define a customised dependency injection framework - replacing _Injector_ completely.
- **Use a different serialization strategy** - By default, just as any other web server, Kos will always respect the HTTP Headers to infer which
type of serialization to use when handling a Http Request. You can change this by passing your own `PayloadSerialisationStrategy`
implementation to `MutableKosContext.setPayloadSerializationStrategy`.
- **Change the default payload serializer** - When using the default serialization strategy, Kos will use JSON as default serializer whenever the response Content-Type is
not defined or the Context-Type header is not present in the request. You can use the `MutableKosContext.setDefaultSerializer`
to modify the serialization type.

For more details, check the `KosContext` and `MutableKosContext` javadoc.
11 changes: 4 additions & 7 deletions docs_src/manual/architecture/kos-plugins.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# Kos Plugins
Kos Plugins are useful to change how any internal component
will work on Kos, being it provided by Kos itself or a Vert.x one.
Kos Plugins are useful to change how any internal component will work, being it provided
by Kos itself or a Vert.x one. Plugins are the only entrypoint that allows developers to
mutate `kos.api.KosContext` (through `kos.api.MutableKosContext`).

## The Kos Context
`kos.api.KosContext` is the backbone of the system, contains all basic components
in which Kos will interact with. Thus, to avoid misconfiguration, there will be
only one instance of this object (managed by Kos) in the whole application. The
only way to mutate its content is by creating a `kos.api.Plugin` implementation.
To learn more about KosContext, check [this page](../kos-context/).

## Creating a Plugin
Creating a plugin is easy. All it's needed is exposing an implementation of
Expand Down
29 changes: 14 additions & 15 deletions docs_src/manual/developer/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,10 @@ class Server : AbstractVerticle() {
```

For this small example, it doesn't worth the effort: the `Server` class is a bit more complex, and the business logic
is a just a single line. In the real world, though, this design actually pays off. The current design certainly increased
clarity of the business layer, the one which is more likely to expand as the time passes by.

If we expand this example ever further, this simple would become unmaintainable. Imagine what would happen if try to
persist users, parse input parameters, deserialize request payload or externalize the server configuration through to a
configuration file. Unless you have strong discipline, it's fairly likely that this project would soon become a big
ball of mud on its early stages.
is a just a single line. If we expand this example ever further, though, it would become unmaintainable. Imagine what would happen if we try to
persist users, parse input parameters, deserialize request payload or use a configuration file to define the web server
port. Unless you have strong discipline, it's fairly likely that this project would soon become a big
ball of mud.

## Annotation Processors
Vert.x is rather powerful though. It was designed as a toolkit, and can be used to design almost everything. Kos helps
Expand All @@ -81,11 +78,11 @@ Whenever the server is initialised, Kos will ask Injector for Web Routes, Valida
Vert.x components that might have been created during the compilation process.

!!! info
You can check the [Dependency Injection](../../architecture/dependency-injection/) guide in case you want to
You can check the [Dependency Injection](../../architecture/implementation-loaders/) guide in case you want to
a different DI library as a replacement for Injector.

### Implementation Discovery
Most of the Kos components are trivial to be configured. However, you might be asked to "Expose" an implementation
Most of the Kos components are trivial to be configured. In the process, you might be asked to _"Expose"_ an implementation
of a given interface, so Kos can find it during the bootstrap process. There are two annotations that can be used
to make an interface implementation discoverable (or exposed): `injector.Exposed` and `injector.ExposedAs`.

Expand All @@ -98,17 +95,19 @@ As the annotation process takes place, a few classes will be generated making th
exposed on the Class Path. Classes (or classes which methods are) annotated with the following Kos annotations
will be automatically exposed:

- `@RestApi`
- `@Listener`
- `@Validates`
- `@RestApi` - automatically exposes [Rest endpoints](../rest-apis/)
- `@RestClient` - automatically exposes [Rest clients](../rest-clients/)
- `@Listener` - automatically listens for Vert.x's Event-Loop internal events
- `@Validates` - turns a method into an object validator for Event listeners and Rest endpoints

## The Launcher
Kos has a small bootstrap class called `kos.core.Launcher` that will automatically spin up the server. With a little
help from our DI, it will read the Vert.x configuration and deploy all verticles found on the class path. So, make
sure you set this class as your `Main-Class` and your application good to go.
help from [the Implementation Loader](../../architecture/implementation-loaders/), it will read the Vert.x configuration and deploy all verticles found on the class path. So, make
sure you set this class as your `Main-Class`.

## Kos Context
The `kos.api.KosContext` object contains all the internal components managed by Kos. This includes:
The `kos.api.KosContext` object contains all the internal components managed by Kos. Among many other features, it holds:

- `io.vertx.core.Vertx` instance - used whenever interacting with Vert.x components
- Log configuration
- Serialization mechanisms (for both Rest API and Clients)
Expand Down
93 changes: 54 additions & 39 deletions docs_src/manual/developer/config-files.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,64 @@
# Reading Configuration File
Kos will use Vert.x's core api to read Yaml configuration files available in the class path.
Once the configuration is read, you will have a `JsonObject` which you can interact with
and read the desired configuration property.
As stated by its [documentation](https://vertx.io/docs/vertx-config/java/), Vert.x provides the
`vertx-config` module to efficiently interact with configuration files. Internally,
this module relies on the **Config Retriever** and **Configuration store** concepts, defining
"a location from where the configuration data is read and also a format (JSON by default)."

By default, Kos will for a file called `application.yml` in the classpath. In case
more than one is found, all `application.yml` found in the classpath will be merged
before being used.
As an attempt to simplify this process, Kos made the following design choices:

## Reading the configuration object
Reading the configuration file and transforming it into an object that can be accessed
globally in the application is a common pattern nowadays. Kos provides a different approach
to tackle this problem: event-driven configuration.

All you will need do is to expose an implementation of the `ConfigurationLoadedListener.Event` interface.
- it only looks after files named `application.yml` in the classpath. In case
more than one is found, they will be merged before being used.
- it fully executes the above by default, but allows one to change the default behaviour (e.g. using a
different _Configuration Retriever_)
- Once the configuration is read, you will have access to an `JsonObject` - just like you'd have on a
typical Vert.x application.

!!! note
As your class is annotated with `@Exposed` annotation, you can inject other components.
Check the [Injector](https://skullabs.github.io/injector) for more details.
## Reading the configuration object
The easiest way to interaction with the read configuration would be through Dependency Injection.
You will have full access to [Kos Context](../../architecture/kos-context/), which will expose the
read configuration file (Vert.x's `JsonObject`).

=== "Kotlin"
```kotlin
@Exposed
class MyAppConfigPlugin: ConfigurationLoadedEventListener {

fun on(event: ConfigurationLoadedEvent) {
val vertxConf = event.applicationConfig
val remoteUrl = URL(vertxConf.getString("myapp.remote.url"))
// do something with the `remoteUrl`
```kotlin
@Singleton
class MyServerConfiguration(
private val kosContext: KosContext
) {

val dbHost = kosContext.applicationConfig.getString("db.host", "localhost")
val dbPort = kosContext.applicationConfig.getString("db.port", "5432")
val dbUser = kosContext.applicationConfig.getString("db.user", "postgres")
val dbPass = kosContext.applicationConfig.getString("db.pass", "postgres")
}
}
```
```java
@Exposed
class MyAppConfigPlugin implements ConfigurationLoadedEventListener {

@Override
public void on(ConfigurationLoadedEvent event) {
try {
JsonObject vertxConf = event.getApplicationConfig();
URL remoteUrl = new URL(vertxConf.getString("myapp.remote.url"));
// do something with the `remoteUrl`
} catch (MalformedURLException cause) {
cause.printStackTrace();
```

=== "Java"
```java
@Singleton
class MyServerConfiguration {

private final KosContext kosContext;

public MyServerConfiguration(KosContext kosContext){
this.kosContext = kosContext;
}

public String getDbHost() {
return kosContext.getApplicationConfig().getString("db.host", "localhost");
}

public String getDbPort() {
return kosContext.getApplicationConfig().getString("db.port", "5432");
}

public String getDbUser() {
return kosContext.getApplicationConfig().getString("db.user", "postgres");
}

public String getDbPass() {
return kosContext.getApplicationConfig().getString("db.pass", "postgres");
}
}
}
```

```
Another option would be listening to Kos' [internal events](../architecture/internal-events/).
22 changes: 22 additions & 0 deletions docs_src/manual/developer/event-listeners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Event Listeners
The [event bus](https://vertx.io/docs/vertx-core/java/#event_bus) is the nervous system of Vert.x.
It acts as broker, where **messages** are sent on the event bus to an **address**. Listeners on
these addresses can react to the incoming messages and perform bespoke code (the so-called **handlers**).

Vert.x supports the following messaging patterns:

- [Publish/Subscribe](https://vertx.io/docs/vertx-core/java/#_publish_subscribe_messaging) -
This notification pattern allows one to have multiple listeners for each subscription address.
The communication happens in uni-directionally from the publisher to all the listeners.
- [Point-to-point](https://vertx.io/docs/vertx-core/java/#_point_to_point_and_request_response_messaging) -
Here messages will be delivered to only one subscriber per address. If multiple listeners are registered,
_"one will be chosen using a non-strict round-robin algorithm. When a message is received by a
recipient, and has been handled, the recipient can optionally decide to reply to the message.
If they do so, the reply handler will be called._

It is clear from the description above that the communication coordinated by the topic producer. Listeners
can send replies to producers, even though they will only receive the reply

## How Kos Listeners work?
Kos abstracts this workflow using the `@Listener` annotation on a listener method. The method signature
will define how the communication will be performed between
4 changes: 3 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ nav:
- Basic Concepts: manual/developer/basic-concepts.md
- Rest API: manual/developer/rest-apis.md
- Rest Clients: manual/developer/rest-clients.md
- Event Listeners: manual/developer/event-listeners.md
- Logging: manual/developer/logging.md
- Configuration File: manual/developer/config-files.md
- Extending Kos:
- Internal Events: manual/architecture/internal-events.md
- Plugins: manual/architecture/kos-plugins.md
- Kos Context: manual/architecture/kos-context.md
- Implementation Loaders: manual/architecture/implementation-loaders.md
- Internal Events: manual/architecture/internal-events.md
- License: license.md

0 comments on commit 16293d4

Please sign in to comment.