You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/09/19 17:18:52 UTC

(maven-project-info-reports-plugin) branch master updated: Replace the Jetty 6 test server with the JDK HTTP server

This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-project-info-reports-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 59dea5d  Replace the Jetty 6 test server with the JDK HTTP server
59dea5d is described below

commit 59dea5df90c7296bacf9389ec71b9b0b616992c6
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Sat Sep 19 18:42:33 2026 +0200

    Replace the Jetty 6 test server with the JDK HTTP server
    
    org.mortbay.jetty:jetty:6.1.26 (2010) is the last release of that
    coordinate and has no upgrade path (#652). The only consumer is the
    fixture in ProjectInfoReportUtilsTest, which needs plain HTTP, HTTPS and
    basic auth; com.sun.net.httpserver covers all three on Java 8.
---
 pom.xml                                            |   8 +-
 .../projectinfo/ProjectInfoReportUtilsTest.java    | 159 +++++++++++----------
 src/test/resources/realm.properties                |  19 ---
 3 files changed, 84 insertions(+), 102 deletions(-)

diff --git a/pom.xml b/pom.xml
index a7fa81b..96f4012 100644
--- a/pom.xml
+++ b/pom.xml
@@ -323,12 +323,6 @@ under the License.
       <version>4.11.0</version>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.mortbay.jetty</groupId>
-      <artifactId>jetty</artifactId>
-      <version>6.1.26</version>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.apache.maven.resolver</groupId>
       <artifactId>maven-resolver-impl</artifactId>
@@ -401,7 +395,7 @@ under the License.
       </plugins>
     </pluginManagement>
     <plugins>
-      <!-- To use Jetty SSL in tests -->
+      <!-- Key pair for the HTTPS server in ProjectInfoReportUtilsTest -->
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>keytool-maven-plugin</artifactId>
diff --git a/src/test/java/org/apache/maven/report/projectinfo/ProjectInfoReportUtilsTest.java b/src/test/java/org/apache/maven/report/projectinfo/ProjectInfoReportUtilsTest.java
index 244f8c1..8cc9c10 100644
--- a/src/test/java/org/apache/maven/report/projectinfo/ProjectInfoReportUtilsTest.java
+++ b/src/test/java/org/apache/maven/report/projectinfo/ProjectInfoReportUtilsTest.java
@@ -18,9 +18,26 @@
  */
 package org.apache.maven.report.projectinfo;
 
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
 import java.net.URL;
-
+import java.nio.file.Files;
+import java.security.KeyStore;
+
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
 import org.apache.maven.model.DeploymentRepository;
 import org.apache.maven.model.DistributionManagement;
 import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
@@ -28,17 +45,6 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.settings.Settings;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.mortbay.jetty.Connector;
-import org.mortbay.jetty.Handler;
-import org.mortbay.jetty.Server;
-import org.mortbay.jetty.handler.DefaultHandler;
-import org.mortbay.jetty.nio.SelectChannelConnector;
-import org.mortbay.jetty.security.Constraint;
-import org.mortbay.jetty.security.ConstraintMapping;
-import org.mortbay.jetty.security.HashUserRealm;
-import org.mortbay.jetty.security.SecurityHandler;
-import org.mortbay.jetty.security.SslSocketConnector;
-import org.mortbay.jetty.webapp.WebAppContext;
 
 import static org.apache.maven.api.plugin.testing.MojoExtension.getBasedir;
 import static org.apache.maven.report.projectinfo.ProjectInfoReportUtils.getArchiveServer;
@@ -52,13 +58,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
  * @version $Id$
  */
 class ProjectInfoReportUtilsTest {
-    private static final int MAX_IDLE_TIME = 30000;
-
     private int port = -1;
 
     private Settings settingsStub;
 
-    private Server jettyServer;
+    private HttpServer httpServer;
 
     @BeforeEach
     void setUp() throws Exception {
@@ -108,7 +112,7 @@ class ProjectInfoReportUtilsTest {
         assertTrue(content.contains("Свобода всем народам!"));
 
         // http + no auth
-        startJetty(false, false);
+        startServer(false, false);
 
         url = new URL("http://localhost:" + port + "/project-info-reports.properties");
 
@@ -116,10 +120,10 @@ class ProjectInfoReportUtilsTest {
         assertNotNull(content);
         assertTrue(content.contains("Licensed to the Apache Software Foundation"));
 
-        stopJetty();
+        stopServer();
 
         // http + auth
-        startJetty(false, true);
+        startServer(false, true);
 
         url = new URL("http://localhost:" + port + "/project-info-reports.properties");
 
@@ -127,10 +131,10 @@ class ProjectInfoReportUtilsTest {
         assertNotNull(content);
         assertTrue(content.contains("Licensed to the Apache Software Foundation"));
 
-        stopJetty();
+        stopServer();
 
         // https + no auth
-        startJetty(true, false);
+        startServer(true, false);
 
         url = new URL("https://localhost:" + port + "/project-info-reports.properties");
 
@@ -138,10 +142,10 @@ class ProjectInfoReportUtilsTest {
         assertNotNull(content);
         assertTrue(content.contains("Licensed to the Apache Software Foundation"));
 
-        stopJetty();
+        stopServer();
 
         // https + auth
-        startJetty(true, true);
+        startServer(true, true);
 
         url = new URL("https://localhost:" + port + "/project-info-reports.properties");
 
@@ -149,7 +153,7 @@ class ProjectInfoReportUtilsTest {
         assertNotNull(content);
         assertTrue(content.contains("Licensed to the Apache Software Foundation"));
 
-        stopJetty();
+        stopServer();
 
         // TODO need to test with a proxy
     }
@@ -191,72 +195,75 @@ class ProjectInfoReportUtilsTest {
         assertEquals("maven.announce.markmail.org", getArchiveServer("http://maven.announce.markmail.org"));
     }
 
-    private void startJetty(boolean isSSL, boolean withAuth) throws Exception {
-        jettyServer = new Server();
-        jettyServer.setStopAtShutdown(true);
-
-        Connector connector = (isSSL ? getSSLConnector() : getDefaultConnector());
-        jettyServer.setConnectors(new Connector[] {connector});
-
-        WebAppContext webapp = new WebAppContext();
-        webapp.setContextPath("/");
-        webapp.setResourceBase(getBasedir() + "/target/classes/");
+    /**
+     * Starts a local server on an ephemeral port that serves the files under {@code target/classes}, the same
+     * document root the Jetty fixture used before, optionally over TLS with the key pair that
+     * {@code keytool-maven-plugin} generates at {@code target/jetty.jks} and optionally behind basic auth for
+     * the {@code admin} user that {@link #setUp()} puts into the settings stub.
+     */
+    private void startServer(boolean isSSL, boolean withAuth) throws Exception {
+        InetSocketAddress address = new InetSocketAddress("localhost", 0);
+        if (isSSL) {
+            HttpsServer httpsServer = HttpsServer.create(address, 0);
+            httpsServer.setHttpsConfigurator(new HttpsConfigurator(createSslContext()));
+            httpServer = httpsServer;
+        } else {
+            httpServer = HttpServer.create(address, 0);
+        }
 
-        webapp.setServer(jettyServer);
+        final File documentRoot = new File(getBasedir(), "target/classes");
+        HttpHandler handler = new HttpHandler() {
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                File file = new File(documentRoot, exchange.getRequestURI().getPath());
+                if (!file.isFile()) {
+                    exchange.sendResponseHeaders(404, -1);
+                    exchange.close();
+                    return;
+                }
+                byte[] body = Files.readAllBytes(file.toPath());
+                exchange.sendResponseHeaders(200, body.length);
+                try (OutputStream out = exchange.getResponseBody()) {
+                    out.write(body);
+                }
+            }
+        };
+        HttpContext context = httpServer.createContext("/", handler);
 
         if (withAuth) {
-            Constraint constraint = new Constraint();
-            constraint.setName(Constraint.__BASIC_AUTH);
-            constraint.setRoles(new String[] {"user", "admin"});
-            constraint.setAuthenticate(true);
-
-            ConstraintMapping cm = new ConstraintMapping();
-            cm.setConstraint(constraint);
-            cm.setPathSpec("/*");
-
-            SecurityHandler sh = new SecurityHandler();
-            sh.setUserRealm(new HashUserRealm("MyRealm", getBasedir() + "/src/test/resources/realm.properties"));
-            sh.setConstraintMappings(new ConstraintMapping[] {cm});
-
-            webapp.addHandler(sh);
+            context.setAuthenticator(new BasicAuthenticator("MyRealm") {
+                @Override
+                public boolean checkCredentials(String username, String password) {
+                    return "admin".equals(username) && "admin".equals(password);
+                }
+            });
         }
 
-        DefaultHandler defaultHandler = new DefaultHandler();
-        defaultHandler.setServer(jettyServer);
-
-        Handler[] handlers = new Handler[2];
-        handlers[0] = webapp;
-        handlers[1] = defaultHandler;
-        jettyServer.setHandlers(handlers);
+        httpServer.start();
 
-        jettyServer.start();
-
-        port = connector.getLocalPort();
+        port = httpServer.getAddress().getPort();
     }
 
-    private void stopJetty() throws Exception {
-        if (jettyServer != null) {
-            jettyServer.stop();
+    private void stopServer() {
+        if (httpServer != null) {
+            httpServer.stop(0);
 
-            jettyServer = null;
+            httpServer = null;
 
             port = -1;
         }
     }
 
-    private Connector getDefaultConnector() {
-        Connector connector = new SelectChannelConnector();
-        connector.setMaxIdleTime(MAX_IDLE_TIME);
-        return connector;
-    }
-
-    private Connector getSSLConnector() {
-        SslSocketConnector connector = new SslSocketConnector();
-        connector.setKeystore(getBasedir() + "/target/jetty.jks");
-        connector.setPassword("apache");
-        connector.setKeyPassword("apache");
-        connector.setTruststore(getBasedir() + "/target/jetty.jks");
-        connector.setTrustPassword("apache");
-        return connector;
+    private SSLContext createSslContext() throws Exception {
+        char[] password = "apache".toCharArray();
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        try (InputStream in = new FileInputStream(new File(getBasedir(), "target/jetty.jks"))) {
+            keyStore.load(in, password);
+        }
+        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        keyManagerFactory.init(keyStore, password);
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
+        return sslContext;
     }
 }
diff --git a/src/test/resources/realm.properties b/src/test/resources/realm.properties
deleted file mode 100644
index 5eca8a5..0000000
--- a/src/test/resources/realm.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-admin: admin,admin
-user: user,read-only