diff --git a/extensions/common/http/jetty-core/README.md b/extensions/common/http/jetty-core/README.md index 515834b852..bd5bb09142 100644 --- a/extensions/common/http/jetty-core/README.md +++ b/extensions/common/http/jetty-core/README.md @@ -34,8 +34,6 @@ web.http.path=/api That will expose any resource under `http://:8181/api/*`. -_Please note that under the hood `web.http.*` gets expanded to `web.http.default.*`_ - In some situations it is required to expose a part of the public API under another port or path, which can be achieved by using port mappings. First, a "named" property group needs to be created using the following configuration. The example will create a port mapping with the @@ -75,4 +73,4 @@ port mapping's context alias and have the controllers themselves handle any sub- implicit default values - Attempting to register two port mappings with the same path will raise an exception, even if different ports are used. This has to do with the way how servlet - contexts are mapped internally and may change in future releases. \ No newline at end of file + contexts are mapped internally and may change in future releases. diff --git a/extensions/common/http/jetty-core/build.gradle.kts b/extensions/common/http/jetty-core/build.gradle.kts index 9681ad1590..4c0b63ee5f 100644 --- a/extensions/common/http/jetty-core/build.gradle.kts +++ b/extensions/common/http/jetty-core/build.gradle.kts @@ -17,16 +17,13 @@ plugins { `java-library` } - dependencies { - implementation(libs.jetty.websocket) - api(project(":spi:common:core-spi")) api(project(":spi:common:web-spi")) + implementation(libs.jetty.websocket) + testImplementation(libs.restAssured) - testImplementation(project(":tests:junit-base")); + testImplementation(project(":core:common:junit")); } - - diff --git a/extensions/common/http/jetty-core/src/main/java/org/eclipse/edc/web/jetty/JettyExtension.java b/extensions/common/http/jetty-core/src/main/java/org/eclipse/edc/web/jetty/JettyExtension.java index 7c8322c33e..bd1ab00185 100644 --- a/extensions/common/http/jetty-core/src/main/java/org/eclipse/edc/web/jetty/JettyExtension.java +++ b/extensions/common/http/jetty-core/src/main/java/org/eclipse/edc/web/jetty/JettyExtension.java @@ -37,27 +37,28 @@ @Provides({ WebServer.class, JettyService.class }) public class JettyExtension implements ServiceExtension { - private static final String DEFAULT_PATH = "/api"; private static final String DEFAULT_CONTEXT_NAME = "default"; private static final int DEFAULT_PORT = 8181; - @Setting - private static final String KEYSTORE_PATH_SETTING = "edc.web.https.keystore.path"; - @Setting - private static final String KEYSTORE_TYPE_SETTING = "edc.web.https.keystore.type"; - - private JettyService jettyService; - private final PortMappingRegistryImpl portMappings = new PortMappingRegistryImpl(); + @Deprecated(since = "0.11.0") + private static final String DEPRECATED_SETTING_PATH = "web.http.default"; @Configuration private JettyConfiguration jettyConfiguration; @Configuration private DefaultApiConfiguration apiConfiguration; - @Setting(key = KEYSTORE_PATH_SETTING, description = "Keystore path", required = false) + @Deprecated(since = "0.11.0") + @Configuration + private DeprecatedDefaultApiConfiguration deprecatedApiConfiguration; + + @Setting(key = "edc.web.https.keystore.path", description = "Keystore path", required = false) private String keystorePath; - @Setting(key = KEYSTORE_TYPE_SETTING, description = "Keystore type", defaultValue = "PKCS12") + @Setting(key = "edc.web.https.keystore.type", description = "Keystore type", defaultValue = "PKCS12") private String keystoreType; + private JettyService jettyService; + private final PortMappingRegistry portMappingRegistry = new PortMappingRegistryImpl(); + @Override public String name() { return "Jetty Service"; @@ -65,10 +66,16 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - var defaultPortMapping = new PortMapping(DEFAULT_CONTEXT_NAME, apiConfiguration.port(), apiConfiguration.path()); - portMappings.register(defaultPortMapping); - var monitor = context.getMonitor(); + + var deprecatedConfig = context.getConfig().getConfig(DEPRECATED_SETTING_PATH); + if (deprecatedConfig.getRelativeEntries().isEmpty()) { + portMappingRegistry.register(new PortMapping(DEFAULT_CONTEXT_NAME, apiConfiguration.port(), apiConfiguration.path())); + } else { + monitor.warning("Config group %s has been deprecated, please configure the default api context under web.http".formatted(DEPRECATED_SETTING_PATH)); + portMappingRegistry.register(new PortMapping(DEFAULT_CONTEXT_NAME, deprecatedApiConfiguration.port(), deprecatedApiConfiguration.path())); + } + KeyStore ks = null; if (keystorePath != null) { @@ -82,7 +89,7 @@ public void initialize(ServiceExtensionContext context) { } } - jettyService = new JettyService(jettyConfiguration, ks, monitor, portMappings); + jettyService = new JettyService(jettyConfiguration, ks, monitor, portMappingRegistry); context.registerService(JettyService.class, jettyService); context.registerService(WebServer.class, jettyService); } @@ -102,12 +109,12 @@ public void shutdown() { @Provider @Deprecated(since = "0.11.0") public WebServiceConfigurer webServiceContextConfigurator(ServiceExtensionContext context) { - return new WebServiceConfigurerImpl(context.getMonitor(), portMappings); + return new WebServiceConfigurerImpl(context.getMonitor(), portMappingRegistry); } @Provider public PortMappingRegistry portMappings() { - return portMappings; + return portMappingRegistry; } @Settings @@ -120,4 +127,17 @@ record DefaultApiConfiguration( } + @Settings + @Deprecated(since = "0.11.0") + record DeprecatedDefaultApiConfiguration( + @Deprecated(since = "0.11.0") + @Setting(key = "web.http.default.port", description = "Port for default api context", defaultValue = DEFAULT_PORT + "") + int port, + @Deprecated(since = "0.11.0") + @Setting(key = "web.http.default.path", description = "Path for default api context", defaultValue = DEFAULT_PATH) + String path + ) { + + } + } diff --git a/extensions/common/http/jetty-core/src/test/java/org/eclipse/edc/web/jetty/JettyExtensionTest.java b/extensions/common/http/jetty-core/src/test/java/org/eclipse/edc/web/jetty/JettyExtensionTest.java new file mode 100644 index 0000000000..f8e78d30f5 --- /dev/null +++ b/extensions/common/http/jetty-core/src/test/java/org/eclipse/edc/web/jetty/JettyExtensionTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.web.jetty; + +import org.eclipse.edc.boot.system.injection.ObjectFactory; +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; +import org.eclipse.edc.web.spi.configuration.PortMapping; +import org.eclipse.edc.web.spi.configuration.PortMappingRegistry; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.type; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +class JettyExtensionTest { + + private final Monitor monitor = mock(); + + @Test + void setup(ServiceExtensionContext context) { + context.registerService(Monitor.class, monitor); + } + + @Test + void shouldRegisterPortMapping(ServiceExtensionContext context, ObjectFactory objectFactory) { + var settings = Map.of("web.http.port", "11111", "web.http.path", "/path"); + when(context.getConfig()).thenReturn(ConfigFactory.fromMap(settings)); + + var extension = objectFactory.constructInstance(JettyExtension.class); + + extension.initialize(context); + + assertThat(extension).extracting("portMappingRegistry", type(PortMappingRegistry.class)).satisfies(portMappingRegistry -> { + assertThat(portMappingRegistry.getAll()).containsOnly(new PortMapping("default", 11111, "/path")); + }); + verify(context.getMonitor(), never()).warning(contains("web.http")); + } + + @Deprecated(since = "0.11.0") + @Test + void shouldRegisterDeprecatedPortMapping(ServiceExtensionContext context, ObjectFactory objectFactory) { + var settings = Map.of("web.http.default.port", "11111", "web.http.default.path", "/path"); + when(context.getConfig()).thenReturn(ConfigFactory.fromMap(settings)); + + var extension = objectFactory.constructInstance(JettyExtension.class); + + extension.initialize(context); + + assertThat(extension).extracting("portMappingRegistry", type(PortMappingRegistry.class)).satisfies(portMappingRegistry -> { + assertThat(portMappingRegistry.getAll()).containsOnly(new PortMapping("default", 11111, "/path")); + }); + verify(context.getMonitor()).warning(contains("web.http.default")); + } +}