Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mp ws services #1073

Merged
merged 8 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/src/main/docs/microprofile/02_server-configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,82 @@ metrics:
health:
routing: "admin"
----

== Assigning JAX-RS applications to ports
Since 1.3.2

Helidon has the concept of named routings. These correspond to the named ports
we have described in the previous section.

You can assign a JAX-RS application to a named routing (and as a result to a named port) using
either an annotation or configuration (or both to override the value from annotation).

=== Annotation `@RoutingName`
You can annotate an application with this annotation to assign it to a specific named routing,
that is (most likely) going to be bound to a specific port.

The annotation has two attributes:
- `value` that defines the routing name
- `required` to mark that the routing name MUST be configured in Helidon server

Example:
----
@ApplicationScoped
@ApplicationPath("/admin")
@RoutingName(value="admin", required="true")
public class AdminApplication extends Application {
//....
}
----

The example above will be bound to `admin` routing (and port) and will fail if such a port
is not configured.

=== Configuration override of routing name
For each application class you can define the routing name and its required flag by specifying a configuration
option `class-name.routing-name.name` and `class-name.routing-name.required`.

Example (YAML) configuration for a class `io.helidon.examples.AdminApplication` that changes the
routing name to `management` and its required flag to `false`:

----
io.helidon.examples.AdminApplication:
routing-name:
name: "management"
required: false
----

== Overriding JAX-RS application path
Since Helidon 1.3.2
In JAX-RS we can use `@ApplicationPath` to configure a path the JAX-RS application is available on.
As this is compiled into the source code, Helidon provides a way to override this using configuration.

For each application class you can define the routing path by specifying a configuration
option `class-name.routing-path.path`.

Example (YAML) configuration for a class `io.helidon.example.AdminApplication` that changes the
routing path to `/management`:

----
io.helidon.examples.AdminApplication:
routing-path:
path: "/management"
----

== Example configuration of JAX-RS application
A full configuration example (YAML):

----
server:
port: 8080
sockets:
management:
port: 8090

io.helidon.examples.AdminApplication:
routing-name:
name: "management"
required: true
routing-path:
path: "/management"
----
124 changes: 124 additions & 0 deletions docs/src/main/docs/microprofile/10_reactive-routing.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

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.

///////////////////////////////////////////////////////////////////////////////

= Reactive routing in Helidon MP
:description: Helidon MP reactive routing
= :keywords: helidon, rest, reactive, WebServer, route, routing

Since Helidon 1.3.2

== Configuring a reactive route in Helidon MP
Helidon MP Server will pick up CDI beans that implement the `io.helidon.webserver.Service`
interface and configure them with the underlying WebServer.

This allows configuration of reactive routes to run alongside a JAX-RS application.

The bean is expected to be either `ApplicationScoped` or `Dependent` and will be requested
only once during the boot of the `Server`.

The bean will support injection of `ApplicationScoped` and `Dependent` scoped beans.
You cannot inject `RequestScoped` beans. Please use WebServer features to handle request
related objects.

=== Customizing the reactive service
The service can be customized using annotations and/or configuration to be

- registered on a specific path
- registered with a named routing

==== Assigning a reactive service to named ports
Helidon has the concept of named routings. These correspond to the named ports
configured with WebServer.

You can assign a reactive service to a named routing (and as a result to a named port) using
either an annotation or configuration (or both to override the value from annotation).

===== Annotation `@RoutingName`
You can annotated a service with this annotation to assign it to a specific named routing,
that is (most likely) going to be bound to a specific port.

The annotation has two attributes:
- `value` that defines the routing name
- `required` to mark that the routing name MUST be configured in Helidon server

Example:
----
@ApplicationScoped
@RoutingName(value="admin", required="true")
@RoutingPath("/admin")
public class AdminService implements Service {
//....
}
----

The example above will be bound to `admin` routing (and port) and will fail if such a port
is not configured.

===== Configuration override of routing name
For each service class you can define the routing name and its required flag by specifying a configuration
option `class-name.routing-name.name` and `class-name.routing-name.required`.

Example (YAML) configuration for a class `io.helidon.examples.AdminService` that changes the
routing name to `management` and its required flag to `false`:

----
io.helidon.examples.AdminService:
routing-name:
name: "management"
required: false
----

==== Configuring a reactive service path
Each service is registered on a path. If none is configured, then the service would be
configured on the root path.

You can configure service path using an annotation or configuration (or both to override value from annotation)

===== Annotation `@RoutingPath`
You can configure `@RoutingPath` to define the path a service is registered on.

===== Configuration override of routing path
For each reactive service class you can define the routing path by specifying a configuration
option `class-name.routing-path.path`.

Example (YAML) configuration for a class `io.helidon.example.AdminService` that changes the
routing path to `/management`:

----
io.helidon.examples.AdminService:
routing-path:
path: "/management"
----

=== Example configuration of reactive service
A full configuration example (YAML):

----
server:
port: 8080
sockets:
management:
port: 8090

io.helidon.examples.AdminService:
routing-name:
name: "management"
required: true
routing-path:
path: "/management"
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
*
* 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.examples.quickstart.mp;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import io.helidon.microprofile.server.RoutingPath;
import io.helidon.security.SecurityContext;
import io.helidon.webserver.Routing;
import io.helidon.webserver.Service;

/**
* TODO javadoc.
*/
@ApplicationScoped
@RoutingPath("/reactive")
public class ReactiveService implements Service {
@Inject
private SecurityContext securityContext;

@Override
public void update(Routing.Rules rules) {
rules.get("/", (req, res) -> res.send("Context: " + securityContext));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,6 +37,9 @@ public final class JaxRsApplication {
private final String contextRoot;
private final ResourceConfig config;
private final ExecutorService executorService;
private final String appClassName;
private final String routingName;
private final boolean routingNameRequired;

/**
* Create a new instance based on an JAX-RS Application class.
Expand Down Expand Up @@ -71,10 +74,13 @@ public static Builder builder() {
return new Builder();
}

private JaxRsApplication(String contextRoot, ResourceConfig config, ExecutorService executorService) {
this.contextRoot = contextRoot;
this.config = config;
this.executorService = executorService;
private JaxRsApplication(Builder builder) {
this.contextRoot = builder.contextRoot;
this.config = builder.config;
this.executorService = builder.executorService;
this.appClassName = builder.appClassName;
this.routingName = builder.routingName;
this.routingNameRequired = builder.routingNameRequired;
}

String contextRoot() {
Expand All @@ -89,6 +95,18 @@ Optional<ExecutorService> executorService() {
return Optional.ofNullable(executorService);
}

String appClassName() {
return appClassName;
}

String routingName() {
return routingName;
}

boolean routingNameRequired() {
return routingNameRequired;
}

/**
* Fluent API builder to create {@link JaxRsApplication} instances.
*/
Expand All @@ -97,6 +115,9 @@ public static class Builder {
private String contextRoot;
private ResourceConfig config;
private ExecutorService executorService;
private String appClassName;
private String routingName;
private boolean routingNameRequired;

/**
* Configure an explicit context root for this application.
Expand Down Expand Up @@ -135,9 +156,11 @@ public Builder config(ResourceConfig config) {
public Builder application(Application app) {
this.config = toConfig(app);

if (null == this.contextRoot) {
this.contextRoot = getContextRoot(app.getClass());
}
Class<?> clazz = app.getClass();
contextRoot(clazz);
routingName(clazz);
appClassName = clazz.getName();

return this;
}

Expand All @@ -152,9 +175,11 @@ public Builder application(Application app) {
*/
public Builder application(Class<? extends Application> appClass) {
config = ResourceConfig.forApplicationClass(appClass);
if (null == this.contextRoot) {
this.contextRoot = getContextRoot(appClass);
}

contextRoot(appClass);
routingName(appClass);
appClassName = appClass.getName();

return this;
}

Expand All @@ -180,7 +205,7 @@ public JaxRsApplication build() {
contextRoot = DEFAULT_CONTEXT_ROOT;
}

return new JaxRsApplication(contextRoot, config, executorService);
return new JaxRsApplication(this);
}

private static ResourceConfig toConfig(Application application) {
Expand All @@ -191,12 +216,25 @@ private static ResourceConfig toConfig(Application application) {
return ResourceConfig.forApplication(application);
}

private static String getContextRoot(Class<? extends Application> application) {
ApplicationPath path = application.getAnnotation(ApplicationPath.class);
if (null == path) {
return null;
private void contextRoot(Class<?> clazz) {
if (null != contextRoot) {
return;
}
ApplicationPath path = clazz.getAnnotation(ApplicationPath.class);
if (null != path) {
contextRoot = path.value();
}
}

private void routingName(Class<?> clazz) {
if (null != routingName) {
return;
}
RoutingName rn = clazz.getAnnotation(RoutingName.class);
if (null != rn) {
this.routingName = rn.value();
this.routingNameRequired = rn.required();
}
return path.value();
}
}
}
Loading