Skip to content

Commit

Permalink
Add Global Config
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Aleksandrov <dmitry.aleksandrov@oracle.com>
  • Loading branch information
dalexandrov committed Oct 17, 2023
1 parent cf37191 commit 50ecaa6
Showing 1 changed file with 239 additions and 3 deletions.
242 changes: 239 additions & 3 deletions docs/se/guides/migration_4x.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2024 Oracle and/or its affiliates.
Copyright (c) 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -21,7 +21,7 @@
:keywords: helidon, porting, migration, upgrade, incompatibilities
:rootdir: {docdir}/../..
In Helidon 4.x we have made some major changes to Helidon. Reactive engine has been removed. APIS and implementations rewritten in "blocking" paradigm.. This guide will help you upgrade a Helidon MP 3.x application to 4.x.
In Helidon 4.x we have made some major changes to Helidon. Reactive engine has been removed. APIS and implementations are rewritten in "blocking" paradigm. This guide will help you upgrade a Helidon MP 3.x application to 4.x.
== Java 21 Runtime
Expand All @@ -31,5 +31,241 @@ Java 17 is no longer supported in Helidon 4. Java 21 or newer is required. Pleas
Helidon 4 no more uses Netty. Helidon SE is now running on Helidon WebServer which is based on Virtual threads technology, available in Java 21.
== Deprecations
== Programming paradigm
Helidon SE has changed from an asynchronous style API to an imperative/blocking style API that is optimized for use with virtual threads. Currently, there is no compatibility API available
== Server initialization and start up
In Helidon 1.x-3.x to star a server, the following actions should be done:
[source, java]
.Start Helidon SE 3.x Server
----
static Single<WebServer> startServer() {
Config config = Config.create();
WebServer server = WebServer.builder(createRouting(config))
.config(config.get("server"))
.addMediaSupport(JsonpSupport.create())
.build();
Single<WebServer> webserver = server.start(); <1>
webserver.thenAccept(ws -> { <2>
System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet");
ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!"));
})
.exceptionallyAccept(t -> { <3>
System.err.println("Startup failed: " + t.getMessage());
t.printStackTrace(System.err);
});
return webserver;
}
----
<1> Server is started in an asynchronous way. A `Single` object is returned.
<2> Wait for the Server to start and print the message in an asynchronous way.
<3> Gracefully handle exceptions if they occur during the initialization process.
Since Helidon SE in 3.x was reactive, during the start a `Single` object is returned, the server has been started in asynchronous way. We have to use reactive methods like `thenAccept` to wait for the server to start and then to perform the desired action. The exception handling should also be done in reactive way using the corresponding method.
In Helidon 4.x there are no more Reactive APIs, so the Server startup is much simpler:
[source, java]
.Start Helidon SE 4.x Server
----
public static void main(String[] args) {
Config config = Config.create();
Config.global(config);
WebServer server = WebServer.builder() <1>
.config(config.get("server"))
.routing(Main::routing)
.build()
.start(); <2>
System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); <3>
}
----
<1> Configure the Server.
<2> Start the Server. No reactive objects returned.
<3> Print a message when the Server is started.
Just create it, configure it, and wait for it to start. If any exceptions happen, they are handled the traditional way using available language constructions.
== Routing configuration
In Helidon 1.x-3.x the routing config was done the following way:
[source, java]
.Routing in Helidon SE 3.x Server
----
private static Routing createRouting(Config config) {
MetricsSupport metrics = MetricsSupport.create(); <1>
HealthSupport health = HealthSupport.builder()
.addLiveness(HealthChecks.healthChecks())
.build();
GreetService greetService = new GreetService(config); <2>
return Routing.builder()
.register(health) <3>
.register(metrics)
.register("/greet", greetService) <4>
.build();
}
----
<1> Create and configure `Metrics` and `Heath` support.
<2> Create a regular Helidon Service.
<3> Register `Metrics` and `Heath` support as Helidon Services.
<4> Register the regular Greeting service.
Services are created and assigned to the desired path. Observability and other features are being created as usual Helidon `services`, available as part of the framework. Uses defined services are also registered the same way.
In Helidon 4, the routing is configured the following way:
[source, java]
.Start Helidon SE 4.x Server
----
static void routing(HttpRouting.Builder routing) {
Config config = Config.global();
routing.register("/greet", new GreetService()) <1>
.addFeature(OpenApiFeature.create(config.get("openapi"))) <2>
.addFeature(ObserveFeature.create(config.get("observe")));
}
----
<1> Register Greeting service as in previous versions of Helidon.
<2> Add `Feature` for Observability and OpenAPI.
`Feature` encapsulates a set of endpoints, services and/or filters. It is similar to `HttpService` but gives more freedom in setup. Main difference is that a feature can add `Filters` and it cannot be registered on a path. Features are not registered immediately—each feature can define a `Weight` or implement `Weighted` to order features according to their weight. Higher-weighted features are registered first. This is to allow ordering of features in a meaningful way (e.g. Context should be first, Tracing second, Security third etc.).
== Services
There are also significant changes in Helidon `Service`.
In prior versions, a service looks this way:
[source, java]
.Helidon SE 3.x Service
----
public class GreetService implements Service {
@Override
public void update(Routing.Rules rules) { <1>
rules
.get("/", this::getDefaultMessageHandler)
.get("/{name}", this::getMessageHandler)
.put("/greeting", this::updateGreetingHandler);
}
private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { <2>
sendResponse(response, "World");
}
// other methods omitted
}
----
<1> Use `update()` method to set up routing.
<2> Handle a `Request` and return a `Responce`.
In Helidon 4, the same service:
[source, java]
.Helidon SE 4.x Service
----
public class GreetService implements HttpService { <1>
@Override
public void routing(HttpRules rules) { <2>
rules.get("/", this::getDefaultMessageHandler)
.get("/{name}", this::getMessageHandler)
.put("/greeting", this::updateGreetingHandler);
}
private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { <3>
sendResponse(response, "World");
}
// other methods omitted
}
----
<1> Implement `HttpService` for the `GreetingService`.
<2> Use `routing(HttpRules rules)` to set up routing.
<3> Handle a `Request` and return a `Responce`.
Helidon 4 introduced `HttpService` that should be implemented in order to process HTTP requests. To set up routing, the method `routing(HttpRules rules)` should now be used. It receives `HttpRules` object with routes description.
These changes make Helidon 4 incompatible with previous versions.
Learn more about `HttpService` and `Routing` at xref:../webserver.adoc[Helidon SE WebServer]
=== Significant changes
==== Testing
There is a new testing framework for Helidon SE.
[source, xml]
----
<dependency>
<groupId>io.helidon.microprofile.testing</groupId>
<artifactId>helidon-microprofile-testing-junit5</artifactId>
<scope>test</scope>
</dependency>
----
Find more information proceed to xref:../introduction.adoc[Helidon SE testing]
==== Observability
Observability features of Helidon have now moved to different package. For `Heath` and `Metrics` please use:
[source, xml]
----
<dependency>
<groupId>io.helidon.webserver.observe</groupId>
<artifactId>helidon-webserver-observe-health</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver.observe</groupId>
<artifactId>helidon-webserver-observe-metrics</artifactId>
</dependency>
----
Observability has new endpoints.
For System Metrics, please use:
[source, xml]
----
<dependency>
<groupId>io.helidon.metrics</groupId>
<artifactId>helidon-metrics-system-meters</artifactId>
</dependency>
----
=== Global Configuration
The global configuration represents a single instance of the `Config` class, which is implicitly employed by certain Helidon components. Furthermore, it offers a handy approach for your application to access configuration information from any part of your code.
You can utilize the global configuration for easy retrieval of your application's configuration:
```
Config config = Config.global();
```
More information at xref:../config/introduction.adoc[Helidon SE Config].
== Conclusion
Please proceed to xref:../introduction.adoc[Helidon SE Introduction] to find more information and documentation about each module.

0 comments on commit 50ecaa6

Please sign in to comment.