Skip to content

Commit

Permalink
Add a simple way to register routing for a named socket. (#7705)
Browse files Browse the repository at this point in the history
- Update WebServerConfigBlueprint and LoomServer
- Update multiport example to use the new API
- Fix multiport example README.md and dependencies (/observe and dependencies)

Fixes #7702
  • Loading branch information
romain-grecourt committed Oct 3, 2023
1 parent fd84ce5 commit bf22456
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 13 deletions.
8 changes: 4 additions & 4 deletions examples/webserver/multiport/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

It is common when deploying a microservice to run your service on
multiple ports so that you can control the visibility of your
service's endpoints. For example you might want to use three ports:
service's endpoints. For example, you might want to use three ports:

- 8080: public REST endpoints of application
- 8081: private REST endpoints of application
Expand All @@ -16,7 +16,7 @@ as described above.

The ports are configured in `application.yaml` by using named sockets.

Seperate routing is defined for each named socket in `Main.java`
Separate routing is defined for each named socket in `Main.java`

## Build and run

Expand All @@ -32,7 +32,7 @@ curl -X GET http://localhost:8080/hello
curl -X GET http://localhost:8081/private/hello
curl -X GET http://localhost:8082/health
curl -X GET http://localhost:8082/observe/health
curl -X GET http://localhost:8082/metrics
curl -X GET http://localhost:8082/observe/metrics
```
6 changes: 4 additions & 2 deletions examples/webserver/multiport/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,21 @@
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver.observe</groupId>
<artifactId>helidon-webserver-observe-health</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.health</groupId>
<artifactId>helidon-health-checks</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver.observe</groupId>
<artifactId>helidon-webserver-observe-metrics</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.metrics</groupId>
<artifactId>helidon-metrics-system-meters</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.webserver.testing.junit5</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,8 @@ static void setup(WebServerConfig.Builder server) {
// Build server using three ports:
// default public port, admin port, private port
server.routing(Main::publicRouting)
// Add a set of routes on the named socket "admin"
.putSocket("admin", socket -> socket.from(server.sockets().get("admin"))
.routing(Main::adminSocket))
// Add a set of routes on the named socket "private"
.putSocket("private", socket -> socket.from(server.sockets().get("admin"))
.routing(Main::privateSocket));
.routing("admin", Main::adminSocket)
.routing("private", Main::privateSocket);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,24 @@ class LoomServer implements WebServer, Startable {
if (routing.isEmpty() && routings.isEmpty()) {
routerBuilder.addRouting(HttpRouting.create());
}
Router router = routerBuilder.build();

Timer idleConnectionTimer = new Timer("helidon-idle-connection-timer", true);
Map<String, ServerListener> listenerMap = new HashMap<>();
sockets.forEach((name, socketConfig) -> {
List<Routing> socketRoutings = serverConfig.namedRoutings().get(name);
Router socketRouter;
if (socketRoutings != null) {
socketRouter = Router.builder()
.update(b -> socketRoutings.forEach(b::addRouting))
.build();
} else {
socketRouter = router;
}
listenerMap.put(name,
new ServerListener(name,
socketConfig,
routerBuilder.build(),
socketRouter,
context,
idleConnectionTimer,
serverConfig.mediaContext().orElseGet(MediaContext::create),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.helidon.webserver;

import java.util.List;
import java.util.Map;
import java.util.Optional;

Expand All @@ -32,6 +33,7 @@
* See {@link WebServer#create(java.util.function.Consumer)}.
*/
@Prototype.Blueprint(decorator = WebServerConfigBlueprint.ServerConfigDecorator.class)
@Prototype.CustomMethods(WebServerConfigSupport.CustomMethods.class)
@Configured(root = true, prefix = "server")
@ConfigBean(wantDefault = true)
interface WebServerConfigBlueprint extends ListenerConfigBlueprint, Prototype.Factory<WebServer> {
Expand All @@ -56,6 +58,17 @@ interface WebServerConfigBlueprint extends ListenerConfigBlueprint, Prototype.Fa
@Option.Singular
Map<String, ListenerConfig> sockets();

/**
* Routing for additional sockets.
* Note that socket named {@value WebServer#DEFAULT_SOCKET_NAME} cannot be used,
* configure the routing on the server directly.
*
* @return map of routing
*/
@Option.Singular
@Option.Access("")
Map<String, List<Routing>> namedRoutings();

/**
* Context for the WebServer, if none defined, a new one will be created with global context as the root.
*
Expand All @@ -70,6 +83,10 @@ public void decorate(WebServerConfig.BuilderBase<?, ?> target) {
throw new ConfigException("Default socket must be configured directly on server config node, or through"
+ " \"ServerConfig.Builder\", not as a separated socket.");
}
if (target.namedRoutings().containsKey(WebServer.DEFAULT_SOCKET_NAME)) {
throw new ConfigException("Default routing must be configured directly on server config node, or through"
+ " \"ServerConfig.Builder\", not as a named routing.");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.webserver;

import java.util.function.Consumer;

import io.helidon.builder.api.Prototype;
import io.helidon.webserver.http.HttpRouting;

class WebServerConfigSupport {

static class CustomMethods {

/**
* Add Http routing for an additional socket.
*
* @param builder builder to update
* @param socket name of the socket
* @param consumer HTTP Routing for the given socket name
*/
@Prototype.BuilderMethod
static void routing(WebServerConfig.BuilderBase<?, ?> builder,
String socket,
Consumer<HttpRouting.Builder> consumer) {
HttpRouting.Builder routingBuilder = HttpRouting.builder();
consumer.accept(routingBuilder);
builder.addNamedRouting(socket, routingBuilder.build());
}

/**
* Add Http routing for an additional socket.
*
* @param builder builder to update
* @param socket name of the socket
* @param routing HTTP Routing for the given socket name
*/
@Prototype.BuilderMethod
static void routing(WebServerConfig.BuilderBase<?, ?> builder,
String socket,
HttpRouting routing) {
builder.addNamedRouting(socket, routing);
}
}
}

0 comments on commit bf22456

Please sign in to comment.