Skip to content

Commit

Permalink
Port to Nima of enhancement to allow different WebSocket applications…
Browse files Browse the repository at this point in the history
… to be registered on different ports. Due to a restriction in Tyrus, you cannot share the same path even if registered on different ports, so this is a restriction on this enhancement. WebSocket unit tests re-structured to use @HelidonTest. For more info see issue helidon-io#5643 and WebSocketEndpointAppTest.
  • Loading branch information
spericas committed Jan 30, 2023
1 parent 39b0c39 commit 30298d1
Show file tree
Hide file tree
Showing 15 changed files with 391 additions and 408 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.helidon.microprofile.tyrus;

import java.lang.System.Logger.Level;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
Expand All @@ -30,13 +31,13 @@
*/
public final class TyrusApplication {

private final Class<? extends ServerApplicationConfig> applicationClass;
private Set<Class<? extends ServerApplicationConfig>> applicationClasses;
private final Set<Class<?>> annotatedEndpoints;
private final Set<Class<? extends Endpoint>> programmaticEndpoints;
private final Set<Extension> extensions;

private TyrusApplication(Builder builder) {
this.applicationClass = builder.applicationClass;
this.applicationClasses = builder.applicationClasses;
this.annotatedEndpoints = builder.annotatedEndpoints;
this.programmaticEndpoints = builder.programmaticEndpoints;
this.extensions = builder.extensions;
Expand All @@ -57,7 +58,16 @@ public static Builder builder() {
* @return Application class optional.
*/
public Optional<Class<? extends ServerApplicationConfig>> applicationClass() {
return Optional.ofNullable(applicationClass);
return applicationClasses.isEmpty() ? Optional.empty() : Optional.of(applicationClasses.iterator().next());
}

/**
* Get access to all application classes. Possibly an empty set.
*
* @return Immutable set of application classes.
*/
public Set<Class<? extends ServerApplicationConfig>> applicationClasses() {
return Collections.unmodifiableSet(applicationClasses);
}

/**
Expand Down Expand Up @@ -93,7 +103,7 @@ public Set<Extension> extensions() {
public static class Builder {
private static final System.Logger LOGGER = System.getLogger(TyrusApplication.Builder.class.getName());

private Class<? extends ServerApplicationConfig> applicationClass;
private final Set<Class<? extends ServerApplicationConfig>> applicationClasses = new HashSet<>();
private final Set<Class<?>> annotatedEndpoints = new HashSet<>();
private final Set<Class<? extends Endpoint>> programmaticEndpoints = new HashSet<>();
private final Set<Extension> extensions = new HashSet<>();
Expand All @@ -105,10 +115,11 @@ public static class Builder {
* @return The builder.
*/
Builder updateApplicationClass(Class<? extends ServerApplicationConfig> applicationClass) {
if (this.applicationClass != null) {
LOGGER.log(Level.DEBUG, () -> "Overriding websocket application using " + applicationClass);
if (!applicationClasses.isEmpty()) {
LOGGER.log(Level.DEBUG, () -> "Overriding websocket applications using " + applicationClass);
}
this.applicationClass = applicationClass;
applicationClasses.clear();
applicationClasses.add(applicationClass);
return this;
}

Expand All @@ -119,10 +130,7 @@ Builder updateApplicationClass(Class<? extends ServerApplicationConfig> applicat
* @return The builder.
*/
public Builder applicationClass(Class<? extends ServerApplicationConfig> applicationClass) {
if (this.applicationClass != null) {
throw new IllegalStateException("At most one subclass of ServerApplicationConfig is permitted");
}
this.applicationClass = applicationClass;
applicationClasses.add(applicationClass);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,59 +133,54 @@ TyrusRouting tyrusRouting() {
private void registerWebSockets() {
try {
TyrusApplication app = appBuilder.build();

// If application present call its methods
TyrusRouting.Builder tyrusRoutingBuilder = TyrusRouting.builder();
Optional<Class<? extends ServerApplicationConfig>> appClass = app.applicationClass();

Optional<String> contextRoot = appClass.flatMap(c -> findContextRoot(config, c));
Optional<String> namedRouting = appClass.flatMap(c -> findNamedRouting(config, c));
boolean routingNameRequired = appClass.map(c -> isNamedRoutingRequired(config, c)).orElse(false);

String rootPath = contextRoot.orElse(DEFAULT_WEBSOCKET_PATH);

LOGGER.log(Level.INFO, "Registering websocket application at " + rootPath);

if (appClass.isPresent()) {
Class<? extends ServerApplicationConfig> c = appClass.get();

// Attempt to instantiate via CDI
ServerApplicationConfig instance = null;
try {
instance = CDI.current().select(c).get();
} catch (UnsatisfiedResolutionException e) {
// falls through
}
Set<Class<? extends ServerApplicationConfig>> appClasses = app.applicationClasses();
if (appClasses.isEmpty()) {
// Direct registration without calling application class
app.annotatedEndpoints().forEach(aClass -> tyrusRoutingBuilder.endpoint(DEFAULT_WEBSOCKET_PATH, aClass));
app.programmaticEndpoints().forEach(wsCfg -> tyrusRoutingBuilder.endpoint(DEFAULT_WEBSOCKET_PATH, wsCfg));
app.extensions().forEach(tyrusRoutingBuilder::extension);

// Otherwise, we create instance directly
if (instance == null) {
// Create routing
tyrusRouting = tyrusRoutingBuilder.build();
serverCdiExtension.serverBuilder().addRouting(tyrusRouting);
} else {
appClasses.forEach(appClass -> {
Optional<String> contextRoot = findContextRoot(config, appClass);
String rootPath = contextRoot.orElse(DEFAULT_WEBSOCKET_PATH);
Optional<String> namedRouting = findNamedRouting(config, appClass);
boolean routingNameRequired = isNamedRoutingRequired(config, appClass);

// Attempt to instantiate via CDI
ServerApplicationConfig instance = null;
try {
instance = c.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Unable to instantiate websocket application " + c, e);
instance = CDI.current().select(appClass).get();
} catch (UnsatisfiedResolutionException e) {
// falls through
}
}

// Call methods in application class
Set<ServerEndpointConfig> endpointConfigs = instance.getEndpointConfigs(app.programmaticEndpoints());
Set<Class<?>> endpointClasses = instance.getAnnotatedEndpointClasses(app.annotatedEndpoints());
// Otherwise, we create instance directly
if (instance == null) {
try {
instance = appClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Unable to instantiate websocket application " + appClass, e);
}
}

// Register classes and configs
endpointClasses.forEach(cl -> tyrusRoutingBuilder.endpoint(rootPath, cl));
endpointConfigs.forEach(cf -> tyrusRoutingBuilder.endpoint(rootPath, cf));
// Call methods in application class
Set<ServerEndpointConfig> endpointConfigs = instance.getEndpointConfigs(app.programmaticEndpoints());
Set<Class<?>> endpointClasses = instance.getAnnotatedEndpointClasses(app.annotatedEndpoints());

// Create routing wsRoutingBuilder
tyrusRouting = tyrusRoutingBuilder.build();
addWsRouting(tyrusRouting, namedRouting, routingNameRequired, c.getName());
} else {
// Direct registration without calling application class
app.annotatedEndpoints().forEach(cl -> tyrusRoutingBuilder.endpoint(rootPath, cl));
app.programmaticEndpoints().forEach(ep -> tyrusRoutingBuilder.endpoint(rootPath, ep));
app.extensions().forEach(tyrusRoutingBuilder::extension);
// Register classes and configs
endpointClasses.forEach(aClass -> tyrusRoutingBuilder.endpoint(rootPath, aClass));
endpointConfigs.forEach(wsCfg -> tyrusRoutingBuilder.endpoint(rootPath, wsCfg));

// Create routing wsRoutingBuilder
tyrusRouting = tyrusRoutingBuilder.build();
serverCdiExtension.serverBuilder().addRouting(tyrusRouting);
// Create routing
tyrusRouting = tyrusRoutingBuilder.build();
addWsRouting(tyrusRouting, namedRouting, routingNameRequired, appClass.getName());
});
}
} catch (IllegalArgumentException e) {
throw new RuntimeException("Unable to load WebSocket extension", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class TyrusUpgrader extends WsUpgrader {
super(origins);
TyrusCdiExtension extension = CDI.current().select(TyrusCdiExtension.class).get();
Objects.requireNonNull(extension);
this.tyrusRouting = extension.tyrusRouting();
this.tyrusRouting = extension.tyrusRouting(); // TODO which port?
TyrusServerContainer tyrusServerContainer = initializeTyrus();
this.engine = tyrusServerContainer.getWebSocketEngine();
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 30298d1

Please sign in to comment.