Skip to content

Commit

Permalink
Support for @ApplicationPath in SE
Browse files Browse the repository at this point in the history
Signed-off-by: jansupol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed Sep 21, 2021
1 parent 4da89d6 commit e92e025
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 47 deletions.
Expand Up @@ -252,7 +252,9 @@ public static HttpServer createHttpServer(final URI uri,
// Map the path to the processor.
final ServerConfiguration config = server.getServerConfiguration();
if (handler != null) {
final String path = uri.getPath().replaceAll("/{2,}", "/");
final String appPath = handler.getApplicationHandler().getConfiguration().getApplicationPath();
final String uriPath = appPath == null ? uri.getPath() : uri.getPath() + "/" + appPath;
final String path = uriPath.replaceAll("/{2,}", "/");

final String contextPath = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
config.addHttpHandler(handler, HttpHandlerRegistration.bulder().contextPath(contextPath).build());
Expand Down
Expand Up @@ -228,15 +228,19 @@ public final void configure(final HttpsParameters httpsParameters) {
throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_SCHEME_UNKNOWN(uri));
}

final String path = uri.getPath();
if (path == null) {
final String _path = uri.getPath();
if (_path == null) {
throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_PATH_NULL(uri));
} else if (path.isEmpty()) {
} else if (_path.isEmpty()) {
throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_PATH_EMPTY(uri));
} else if (path.charAt(0) != '/') {
} else if (_path.charAt(0) != '/') {
throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_PATH_START(uri));
}

final String appPath = handler.getApplicationHandler().getConfiguration().getApplicationPath();
final String uriPath = appPath == null ? _path : _path + "/" + appPath;
final String path = uriPath.replaceAll("/{2,}", "/");

final int port = (uri.getPort() == -1)
? (isHttp ? Container.DEFAULT_HTTP_PORT : Container.DEFAULT_HTTPS_PORT)
: uri.getPort();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -51,6 +51,7 @@
class JerseyServerHandler extends ChannelInboundHandlerAdapter {

private final URI baseUri;
private final String applicationPath;
private final NettyInputStream nettyInputStream = new NettyInputStream();
private final NettyHttpContainer container;
private final ResourceConfig resourceConfig;
Expand All @@ -65,9 +66,20 @@ class JerseyServerHandler extends ChannelInboundHandlerAdapter {
* @param container Netty container implementation.
*/
public JerseyServerHandler(URI baseUri, NettyHttpContainer container, ResourceConfig resourceConfig) {
this(baseUri, null, container, resourceConfig);
}

/**
* Constructor.
*
* @param baseUri base {@link URI} of the container (includes context path, if any).
* @param container Netty container implementation.
*/
public JerseyServerHandler(URI baseUri, String applicationPath, NettyHttpContainer container, ResourceConfig resourceConfig) {
this.baseUri = baseUri;
this.container = container;
this.resourceConfig = resourceConfig;
this.applicationPath = applicationPath;
}

@Override
Expand Down Expand Up @@ -145,7 +157,11 @@ public void run() {
private ContainerRequest createContainerRequest(ChannelHandlerContext ctx, HttpRequest req) {

String s = req.uri().startsWith("/") ? req.uri().substring(1) : req.uri();
URI requestUri = URI.create(baseUri + ContainerUtils.encodeUnsafeCharacters(s));
final String baseUriStr = baseUri.toString();
final String base = applicationPath == null || applicationPath.isEmpty()
? baseUriStr
: baseUriStr.substring(0, baseUriStr.length() - applicationPath.length() - 1);
final URI requestUri = URI.create(base + ContainerUtils.encodeUnsafeCharacters(s));

ContainerRequest requestContext = new ContainerRequest(
baseUri, requestUri, req.method().name(), getSecurityContext(ctx),
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -44,6 +44,7 @@
class JerseyServerInitializer extends ChannelInitializer<SocketChannel> {

private final URI baseUri;
private final String applicationPath;
private final SslContext sslCtx;
private final NettyHttpContainer container;
private final boolean http2;
Expand Down Expand Up @@ -72,7 +73,14 @@ public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContaine
*/
public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContainer container, ResourceConfig resourceConfig,
boolean http2) {
this.baseUri = baseUri;
applicationPath = container.getApplicationHandler().getConfiguration().getApplicationPath();
final String uriPath = applicationPath == null
? baseUri.toString()
: baseUri.toString() + "/" + applicationPath + "/";
final int doubleSlash = uriPath.indexOf("/") + 2;
final String path = uriPath.substring(0, doubleSlash) + uriPath.substring(doubleSlash).replaceAll("/{2,}", "/");

this.baseUri = URI.create(path);
this.sslCtx = sslCtx;
this.container = container;
this.resourceConfig = resourceConfig;
Expand All @@ -96,7 +104,7 @@ public void initChannel(SocketChannel ch) {
}
p.addLast(new HttpServerCodec());
p.addLast(new ChunkedWriteHandler());
p.addLast(new JerseyServerHandler(baseUri, container, resourceConfig));
p.addLast(new JerseyServerHandler(baseUri, applicationPath, container, resourceConfig));
}
}

Expand Down
Expand Up @@ -136,7 +136,7 @@ public static final class Builder implements SeBootstrap.Configuration.Builder {
private final Map<String, Object> properties = new HashMap<>();

private Builder() {
this.properties.put(SeBootstrap.Configuration.PROTOCOL, "http");
this.properties.put(SeBootstrap.Configuration.PROTOCOL, "HTTP"); // upper case mandated by javadoc
this.properties.put(SeBootstrap.Configuration.HOST, "localhost");
this.properties.put(SeBootstrap.Configuration.PORT, -1); // Auto-select port 80 for HTTP or 443 for HTTPS
this.properties.put(SeBootstrap.Configuration.ROOT_PATH, "/");
Expand Down
Expand Up @@ -25,11 +25,13 @@
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.RuntimeType;
import jakarta.ws.rs.core.Application;
Expand Down Expand Up @@ -57,6 +59,7 @@
import org.glassfish.jersey.server.internal.scanning.FilesScanner;
import org.glassfish.jersey.server.internal.scanning.PackageNamesScanner;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.uri.UriComponent;


/**
Expand Down Expand Up @@ -997,6 +1000,32 @@ public final Application getApplication() {
return _getApplication();
}

/**
* Returns encoded value of {@link ApplicationPath} annotation of the Application corresponding
* with this ResourceConfig or {@code null} when the annotation is not present.
*
* @return Returns encoded value of {@link ApplicationPath} annotation of the Application
* corresponding with this ResourceConfig.
*/
public final String getApplicationPath() {
final Application application;
if (ResourceConfig.class.isInstance(_getApplication())) {
final Application unwrap = unwrapCustomRootApplication((ResourceConfig) _getApplication());
application = unwrap != null ? unwrap : _getApplication();
} else {
application = _getApplication();
}
final ApplicationPath appPath = application.getClass().getAnnotation(ApplicationPath.class);
final String value;
if (appPath != null && !appPath.value().isEmpty() && !appPath.value().trim().equals("/")) {
final String val = appPath.value().trim();
value = UriComponent.encode(val.startsWith("/") ? val.substring(1) : val, UriComponent.Type.PATH);
} else {
value = null;
}
return value;
}

/**
* Allows overriding the {@link #getApplication()} method functionality in {@link WrappingResourceConfig}.
*
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand All @@ -13,15 +13,13 @@
import java.util.HashSet;
import java.util.Set;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

/**
* JAX-RS application.
*
* @author Jonathan Benoit
*/
@ApplicationPath("/*")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -35,7 +35,7 @@ protected Application configure() {
*/
@Test
public void testDefaultMethods() {
final WebTarget defaultMethodTarget = target("default-method");
final WebTarget defaultMethodTarget = target("j8").path("default-method");

// test default method with no @Path annotation
String response = defaultMethodTarget.request().get(String.class);
Expand All @@ -51,7 +51,7 @@ public void testDefaultMethods() {
*/
@Test
public void testImplementingClass() throws Exception {
final String response = target("default-method").path("class").request().get(String.class);
final String response = target("j8").path("default-method").path("class").request().get(String.class);
assertEquals("class", response);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -36,7 +36,7 @@ protected Application configure() {
*/
@Test
public void testLambdas() {
final WebTarget target = target("lambdas/{p}");
final WebTarget target = target("j8").path("lambdas/{p}");

// test default method with no @Path annotation
String response = target.resolveTemplate("p", "test").request().get(String.class);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -45,7 +45,7 @@ protected URI getBaseUri() {

@Test
public void testManagedClientSimple() throws Exception {
final WebTarget resource = target().path("client");
final WebTarget resource = target("app").path("client");
Response response;

response = resource.path("animals").request(MediaType.TEXT_PLAIN).get();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -125,7 +125,7 @@ protected URI getBaseUri() {
@Test
public void testItemsStore() throws Exception {
final List<String> items = Collections.unmodifiableList(Arrays.asList("foo", "bar", "baz"));
final WebTarget itemsTarget = target("items");
final WebTarget itemsTarget = target("resources").path("items");
final CountDownLatch latch = new CountDownLatch(items.size() * MAX_LISTENERS * 2); // countdown on all events
final List<Queue<Integer>> indexQueues = new ArrayList<>(MAX_LISTENERS);
final SseEventSource[] sources = new SseEventSource[MAX_LISTENERS];
Expand Down Expand Up @@ -193,7 +193,7 @@ public void testItemsStore() throws Exception {
*/
@Test
public void testEventSourceReconnect() throws Exception {
final WebTarget itemsTarget = target("items");
final WebTarget itemsTarget = target("resources").path("items");
final CountDownLatch latch = new CountDownLatch(MAX_ITEMS * MAX_LISTENERS * 2); // countdown only on new item events
final List<Queue<String>> receivedQueues = new ArrayList<>(MAX_LISTENERS);
final SseEventSource[] sources = new SseEventSource[MAX_LISTENERS];
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -101,7 +101,7 @@ public void testItemsStore() throws Exception {
"foo",
"bar",
"baz"));
final WebTarget itemsTarget = target("items");
final WebTarget itemsTarget = target("resources").path("items");
final CountDownLatch latch = new CountDownLatch(items.size() * MAX_LISTENERS * 2); // countdown on all events
final List<Queue<Integer>> indexQueues = new ArrayList<>(MAX_LISTENERS);
final EventSource[] sources = new EventSource[MAX_LISTENERS];
Expand Down Expand Up @@ -174,9 +174,8 @@ public void testItemsStore() throws Exception {
* @throws Exception in case of a test failure.
*/
@Test
@Ignore //TODO - remove after jacartification
public void testEventSourceReconnect() throws Exception {
final WebTarget itemsTarget = target("items");
final WebTarget itemsTarget = target("resources").path("items");
final CountDownLatch latch = new CountDownLatch(MAX_ITEMS * MAX_LISTENERS * 2); // countdown only on new item events
final List<Queue<String>> receivedQueues = new ArrayList<>(MAX_LISTENERS);
final EventSource[] sources = new EventSource[MAX_LISTENERS];
Expand Down

0 comments on commit e92e025

Please sign in to comment.