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

cshannon pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq.git

commit bb5ccb4aaf4e5dee98186936eedef4433e56737c
Author: Matt Pavlovich <[email protected]>
AuthorDate: Tue Jul 14 08:52:22 2026 -0500

    [AMQ-9359] Migrate Jetty EE9 -> EE11
    
    - BOM: jetty-ee9-bom -> jetty-ee11-bom
    - Dropped artifacts with no EE11 equiv
    - WebSocket: the legacy WebSocketListener API is gone in EE11
    - Security/TRACE: ee9.nested.ServletConstraint is gone; 
configureTraceMethod now uses
      the core immutable Constraint (FORBIDDEN/ALLOWED) via 
ee11.servlet.security.
    - ServletContextHandler: EE11 dropped the (Server, path, options) 
constructor
    - XML: WebAppContext ee9.webapp -> ee11.webapp
---
 activemq-amqp/pom.xml                              |  4 +-
 activemq-http/pom.xml                              | 12 ++---
 .../transport/WebTransportServerSupport.java       | 42 +++++++---------
 .../discovery/http/EmbeddedJettyServer.java        |  4 +-
 .../transport/http/HttpTransportServer.java        | 11 +++--
 .../activemq/transport/ws/WSTransportProxy.java    | 31 +++++++-----
 .../activemq/transport/ws/WSTransportServer.java   | 16 +++---
 .../transport/ws/{jetty12 => ee11}/MQTTSocket.java | 26 ++++++----
 .../ws/{jetty12 => ee11}/StompSocket.java          | 22 +++++----
 .../transport/ws/{jetty12 => ee11}/WSServlet.java  | 18 +++----
 .../apache/activemq/transport/ws/SocketTest.java   |  8 +--
 .../transport/ws/WSTransportProxyTest.java         | 34 +++++++------
 .../activemq/transport/ws/WSTransportTest.java     |  4 +-
 activemq-web-console/pom.xml                       | 18 +++----
 .../java/org/apache/activemq/web/tool/Main.java    |  2 +-
 .../resources/jetty/jetty-activemq-console.xml     |  2 +-
 .../src/test/resources/jetty/jetty-webapps.xml     |  8 +--
 activemq-web-demo/pom.xml                          |  8 +--
 .../java/org/apache/activemq/web/JettyServer.java  |  2 +-
 .../org/apache/activemq/web/JettyTestSupport.java  |  2 +-
 activemq-web/pom.xml                               |  8 +--
 .../org/apache/activemq/web/MessageServlet.java    | 12 +++--
 .../activemq/web/async/AsyncServletRequest.java    |  7 ++-
 .../apache/activemq/web/config/JspConfigurer.java  |  2 +-
 assembly/pom.xml                                   | 57 ++++++++++------------
 assembly/src/main/descriptors/common-bin.xml       | 30 ++++++------
 assembly/src/release/conf/jetty/jetty-webapps.xml  | 20 ++++++--
 pom.xml                                            | 16 +++---
 28 files changed, 228 insertions(+), 198 deletions(-)

diff --git a/activemq-amqp/pom.xml b/activemq-amqp/pom.xml
index 91d06892e0..cba8c17d54 100644
--- a/activemq-amqp/pom.xml
+++ b/activemq-amqp/pom.xml
@@ -124,8 +124,8 @@
     <!-- activemq-http's WSTransportServer uses the Jetty EE9 websocket 
ServletContainerInitializer;
          activemq-http declares it provided+optional, so the ws transport 
needs it at test runtime here. -->
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-server</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jetty-server</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/activemq-http/pom.xml b/activemq-http/pom.xml
index cc578ca713..09780d541f 100644
--- a/activemq-http/pom.xml
+++ b/activemq-http/pom.xml
@@ -65,8 +65,8 @@
       <artifactId>jetty-xml</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-webapp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-webapp</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
@@ -138,14 +138,14 @@
       <optional>true</optional>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jakarta-client</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jakarta-client</artifactId>
       <scope>provided</scope>
       <optional>true</optional>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-server</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jetty-server</artifactId>
       <scope>provided</scope>
       <optional>true</optional>
     </dependency>
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/WebTransportServerSupport.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/WebTransportServerSupport.java
index be54eb1793..3fe4373ec3 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/WebTransportServerSupport.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/WebTransportServerSupport.java
@@ -23,9 +23,9 @@ import java.util.Map;
 
 import org.apache.activemq.util.InetAddressUtil;
 import org.apache.activemq.util.IntrospectionSupport;
-import org.eclipse.jetty.ee9.nested.ServletConstraint;
-import org.eclipse.jetty.ee9.security.ConstraintMapping;
-import org.eclipse.jetty.ee9.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintMapping;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.security.Constraint;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.resource.ResourceFactory;
@@ -111,27 +111,21 @@ abstract public class WebTransportServerSupport extends 
TransportServerSupport {
     protected void configureTraceMethod(ConstraintSecurityHandler 
securityHandler,
             boolean enableTrace) {
 
-        ServletConstraint servletConstraint = new ServletConstraint();
-        servletConstraint.setName("trace-security");
-        // If enableTrace is true we set authenticate=false so TRACE is 
permitted; otherwise
-        // authenticate=true forces authentication which - with no login 
service configured on this
-        // handler - forbids TRACE (403). Using the (name, role) constructor 
instead leaves
-        // authenticate=false, so the constraint would enforce nothing and 
TRACE would always pass.
-        servletConstraint.setAuthenticate(!enableTrace);
-
-        ConstraintMapping mapping = new ConstraintMapping();
-        mapping.setConstraint(servletConstraint);
-        mapping.setMethod("TRACE");
-        mapping.setPathSpec("/");
-        securityHandler.addConstraintMapping(mapping);
-
-        servletConstraint = new ServletConstraint();
-        servletConstraint.setName("allow");
-        mapping = new ConstraintMapping();
-        mapping.setConstraint(servletConstraint);
-        mapping.setMethodOmissions(new String[]{ "TRACE" });
-        mapping.setPathSpec("/");
-        securityHandler.addConstraintMapping(mapping);
+        // TRACE is disabled by default (Cross-Site Tracing protection). In 
EE11 the servlet-spec
+        // ServletConstraint is gone; ConstraintMapping takes the core 
immutable Constraint. A
+        // FORBIDDEN constraint on TRACE yields 403; ALLOWED serves it when 
explicitly enabled.
+        ConstraintMapping traceMapping = new ConstraintMapping();
+        traceMapping.setConstraint(enableTrace ? Constraint.ALLOWED : 
Constraint.FORBIDDEN);
+        traceMapping.setMethod("TRACE");
+        traceMapping.setPathSpec("/");
+        securityHandler.addConstraintMapping(traceMapping);
+
+        // All other methods are allowed.
+        ConstraintMapping allowMapping = new ConstraintMapping();
+        allowMapping.setConstraint(Constraint.ALLOWED);
+        allowMapping.setMethodOmissions(new String[]{ "TRACE" });
+        allowMapping.setPathSpec("/");
+        securityHandler.addConstraintMapping(allowMapping);
     }
 
     public void setHttpOptions(Map<String, Object> options) {
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/discovery/http/EmbeddedJettyServer.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/discovery/http/EmbeddedJettyServer.java
index 0c996292cf..0becd7fd70 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/discovery/http/EmbeddedJettyServer.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/discovery/http/EmbeddedJettyServer.java
@@ -19,8 +19,8 @@ package org.apache.activemq.transport.discovery.http;
 import java.net.URI;
 
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee9.servlet.ServletHolder;
+import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee11.servlet.ServletHolder;
 
 public class EmbeddedJettyServer implements org.apache.activemq.Service {
 
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/http/HttpTransportServer.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/http/HttpTransportServer.java
index 4b354ceb76..97f6d9e65a 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/http/HttpTransportServer.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/http/HttpTransportServer.java
@@ -27,15 +27,15 @@ import 
org.apache.activemq.transport.WebTransportServerSupport;
 import org.apache.activemq.transport.util.TextWireFormat;
 import org.apache.activemq.transport.xstream.XStreamWireFormat;
 import org.apache.activemq.util.ServiceStopper;
-import org.eclipse.jetty.ee9.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.server.ConnectionFactory;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.Handler.Wrapper;
-import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee9.servlet.ServletHolder;
+import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee11.servlet.ServletHolder;
 
 public class HttpTransportServer extends WebTransportServerSupport {
 
@@ -92,8 +92,11 @@ public class HttpTransportServer extends 
WebTransportServerSupport {
 
         URI boundTo = bind();
 
+        // EE11 dropped the (Server, contextPath, options) constructor (no 
nested layer); create the
+        // context then set it as the server handler explicitly.
         ServletContextHandler contextHandler =
-            new ServletContextHandler(server, "/", 
ServletContextHandler.SECURITY);
+            new ServletContextHandler("/", ServletContextHandler.SECURITY);
+        server.setHandler(contextHandler);
 
         ServletHolder holder = new ServletHolder();
         holder.setServlet(new HttpTunnelServlet());
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportProxy.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportProxy.java
index c981c72d98..90588588fa 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportProxy.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportProxy.java
@@ -34,8 +34,8 @@ import org.apache.activemq.util.IOExceptionSupport;
 import org.apache.activemq.util.IntrospectionSupport;
 import org.apache.activemq.util.ServiceStopper;
 import org.apache.activemq.wireformat.WireFormat;
-import org.eclipse.jetty.ee9.websocket.api.Session;
-import org.eclipse.jetty.ee9.websocket.api.WebSocketListener;
+import org.eclipse.jetty.websocket.api.Callback;
+import org.eclipse.jetty.websocket.api.Session;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory;
  * A proxy class that manages sending WebSocket events to the wrapped protocol 
level
  * WebSocket Transport.
  */
-public final class WSTransportProxy extends TransportSupport implements 
Transport, WebSocketListener, BrokerServiceAware, WSTransportSink {
+public final class WSTransportProxy extends TransportSupport implements 
Transport, Session.Listener.AutoDemanding, BrokerServiceAware, WSTransportSink {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(WSTransportProxy.class);
 
@@ -159,7 +159,7 @@ public final class WSTransportProxy extends 
TransportSupport implements Transpor
     //----- WebSocket methods being proxied to the WS Transport 
--------------//
 
     @Override
-    public void onWebSocketBinary(byte[] payload, int offset, int length) {
+    public void onWebSocketBinary(ByteBuffer payload, Callback callback) {
         if (!transportStartedAtLeastOnce()) {
             LOG.debug("Waiting for WebSocket to be properly started...");
             try {
@@ -171,8 +171,13 @@ public final class WSTransportProxy extends 
TransportSupport implements Transpor
 
         protocolLock.lock();
         try {
-            wsTransport.onWebSocketBinary(ByteBuffer.wrap(payload, offset, 
length));
+            // Copy the frame: Jetty may reuse the pooled buffer once the 
callback succeeds.
+            ByteBuffer copy = ByteBuffer.allocate(payload.remaining());
+            copy.put(payload).flip();
+            wsTransport.onWebSocketBinary(copy);
+            callback.succeed();
         } catch (Exception e) {
+            callback.fail(e);
             onException(IOExceptionSupport.create(e));
         } finally {
             protocolLock.unlock();
@@ -217,7 +222,7 @@ public final class WSTransportProxy extends 
TransportSupport implements Transpor
     }
 
     @Override
-    public void onWebSocketConnect(Session session) {
+    public void onWebSocketOpen(Session session) {
         this.session = session;
         this.session.setIdleTimeout(Duration.ZERO);
 
@@ -245,10 +250,11 @@ public final class WSTransportProxy extends 
TransportSupport implements Transpor
 
         LOG.trace("WS Proxy sending string of size {} out", data.length());
         try {
-            // FIXME: Convert to async API w/ tiemeout 
getDefaultSendTimeOut(), TimeUnit.SECONDS);
-            // Outbound text must be sent as a WebSocket TEXT frame 
(sendString), not a binary
-            // frame; sendString also encodes as UTF-8 per the WebSocket spec.
-            session.getRemote().sendString(data);
+            // Outbound text must be sent as a WebSocket TEXT frame 
(sendText), not a binary frame;
+            // sendText also encodes as UTF-8 per the WebSocket spec. Block 
with a timeout.
+            Callback.Completable callback = new Callback.Completable();
+            session.sendText(data, callback);
+            callback.get(getDefaultSendTimeOut(), TimeUnit.SECONDS);
         } catch (Exception e) {
             throw IOExceptionSupport.create(e);
         }
@@ -268,8 +274,9 @@ public final class WSTransportProxy extends 
TransportSupport implements Transpor
         LOG.trace("WS Proxy sending {} bytes out", data.remaining());
         int limit = data.limit();
         try {
-            // FIXME: Convert to async API w/ tiemeout 
getDefaultSendTimeOut(), TimeUnit.SECONDS);
-            session.getRemote().sendBytes(data);
+            Callback.Completable callback = new Callback.Completable();
+            session.sendBinary(data, callback);
+            callback.get(getDefaultSendTimeOut(), TimeUnit.SECONDS);
         } catch (Exception e) {
             throw IOExceptionSupport.create(e);
         }
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportServer.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportServer.java
index 4c7357a711..5b99a5f57c 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportServer.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/WSTransportServer.java
@@ -26,17 +26,17 @@ import org.apache.activemq.broker.BrokerServiceAware;
 import org.apache.activemq.command.BrokerInfo;
 import org.apache.activemq.transport.SocketConnectorFactory;
 import org.apache.activemq.transport.WebTransportServerSupport;
-import org.apache.activemq.transport.ws.jetty12.WSServlet;
+import org.apache.activemq.transport.ws.ee11.WSServlet;
 import org.apache.activemq.util.IntrospectionSupport;
 import org.apache.activemq.util.ServiceStopper;
 import org.eclipse.jetty.server.ConnectionFactory;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.ee9.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee9.servlet.ServletHolder;
-import 
org.eclipse.jetty.ee9.websocket.server.config.JettyWebSocketServletContainerInitializer;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee11.servlet.ServletHolder;
+import 
org.eclipse.jetty.ee11.websocket.server.config.JettyWebSocketServletContainerInitializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,9 +73,11 @@ public class WSTransportServer extends 
WebTransportServerSupport implements Brok
 
         URI boundTo = bind();
 
+        // EE11 dropped the (Server, contextPath, options) constructor (no 
nested layer); create the
+        // context then set it as the server handler explicitly.
         ServletContextHandler contextHandler =
-                new ServletContextHandler(server, "/", 
ServletContextHandler.SECURITY);
-        // server.setHandler(contextHandler); Future: Jetty 12 EE10 API change
+                new ServletContextHandler("/", ServletContextHandler.SECURITY);
+        server.setHandler(contextHandler);
 
         ServletHolder holder = new ServletHolder();
         JettyWebSocketServletContainerInitializer.configure(contextHandler, 
null);
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/MQTTSocket.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/MQTTSocket.java
similarity index 84%
rename from 
activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/MQTTSocket.java
rename to 
activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/MQTTSocket.java
index 6e14b9ec37..64cfc5a1ea 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/MQTTSocket.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/MQTTSocket.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.activemq.transport.ws.jetty12;
+package org.apache.activemq.transport.ws.ee11;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -26,8 +26,8 @@ import org.apache.activemq.transport.mqtt.MQTTCodec;
 import org.apache.activemq.transport.ws.AbstractMQTTSocket;
 import org.apache.activemq.util.ByteSequence;
 import org.apache.activemq.util.IOExceptionSupport;
-import org.eclipse.jetty.ee9.websocket.api.WebSocketListener;
-import org.eclipse.jetty.ee9.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.Callback;
+import org.eclipse.jetty.websocket.api.Session;
 import org.fusesource.hawtbuf.Buffer;
 import org.fusesource.hawtbuf.DataByteArrayInputStream;
 import org.fusesource.mqtt.codec.DISCONNECT;
@@ -35,7 +35,7 @@ import org.fusesource.mqtt.codec.MQTTFrame;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class MQTTSocket extends AbstractMQTTSocket implements 
MQTTCodec.MQTTFrameSink, WebSocketListener {
+public class MQTTSocket extends AbstractMQTTSocket implements 
MQTTCodec.MQTTFrameSink, Session.Listener.AutoDemanding {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(MQTTSocket.class);
 
@@ -55,9 +55,10 @@ public class MQTTSocket extends AbstractMQTTSocket 
implements MQTTCodec.MQTTFram
     public void sendToMQTT(MQTTFrame command) throws IOException {
         ByteSequence bytes = wireFormat.marshal(command);
         try {
-            //timeout after a period of time so we don't wait forever and hold 
the protocol lock
-            // FIXME: convert to async .get(getDefaultSendTimeOut(), 
TimeUnit.SECONDS)
-            session.getRemote().sendBytes(ByteBuffer.wrap(bytes.getData(), 0, 
bytes.getLength()));
+            // Block on the async send but time out so we don't wait forever 
holding the protocol lock.
+            Callback.Completable callback = new Callback.Completable();
+            session.sendBinary(ByteBuffer.wrap(bytes.getData(), 0, 
bytes.getLength()), callback);
+            callback.get(getDefaultSendTimeOut(), TimeUnit.SECONDS);
         } catch (Exception e) {
             throw IOExceptionSupport.create(e);
         }
@@ -73,7 +74,7 @@ public class MQTTSocket extends AbstractMQTTSocket implements 
MQTTCodec.MQTTFram
     //----- WebSocket.OnTextMessage callback handlers 
------------------------//
 
     @Override
-    public void onWebSocketBinary(byte[] bytes, int offset, int length) {
+    public void onWebSocketBinary(ByteBuffer payload, Callback callback) {
         if (!transportStartedAtLeastOnce()) {
             LOG.debug("Waiting for MQTTSocket to be properly started...");
             try {
@@ -85,9 +86,14 @@ public class MQTTSocket extends AbstractMQTTSocket 
implements MQTTCodec.MQTTFram
 
         protocolLock.lock();
         try {
+            int length = payload.remaining();
+            byte[] bytes = new byte[length];
+            payload.get(bytes);
             receiveCounter += length;
-            codec.parse(new DataByteArrayInputStream(new Buffer(bytes, offset, 
length)), length);
+            codec.parse(new DataByteArrayInputStream(new Buffer(bytes, 0, 
length)), length);
+            callback.succeed();
         } catch (Exception e) {
+            callback.fail(e);
             onException(IOExceptionSupport.create(e));
         } finally {
             protocolLock.unlock();
@@ -115,7 +121,7 @@ public class MQTTSocket extends AbstractMQTTSocket 
implements MQTTCodec.MQTTFram
     }
 
     @Override
-    public void onWebSocketConnect(Session session) {
+    public void onWebSocketOpen(Session session) {
         this.session = session;
         this.session.setIdleTimeout(Duration.ZERO);
     }
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/StompSocket.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/StompSocket.java
similarity index 80%
rename from 
activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/StompSocket.java
rename to 
activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/StompSocket.java
index 2a47a5156c..c486dd35f8 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/StompSocket.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/StompSocket.java
@@ -14,9 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.activemq.transport.ws.jetty12;
+package org.apache.activemq.transport.ws.ee11;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
 
@@ -24,15 +25,15 @@ import org.apache.activemq.transport.stomp.Stomp;
 import org.apache.activemq.transport.stomp.StompFrame;
 import org.apache.activemq.transport.ws.AbstractStompSocket;
 import org.apache.activemq.util.IOExceptionSupport;
-import org.eclipse.jetty.ee9.websocket.api.Session;
-import org.eclipse.jetty.ee9.websocket.api.WebSocketListener;
+import org.eclipse.jetty.websocket.api.Callback;
+import org.eclipse.jetty.websocket.api.Session;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Implements web socket and mediates between servlet and the broker
  */
-public class StompSocket extends AbstractStompSocket implements 
WebSocketListener {
+public class StompSocket extends AbstractStompSocket implements 
Session.Listener.AutoDemanding {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(StompSocket.class);
 
@@ -47,9 +48,10 @@ public class StompSocket extends AbstractStompSocket 
implements WebSocketListene
     @Override
     public void sendToStomp(StompFrame command) throws IOException {
         try {
-            //timeout after a period of time so we don't wait forever and hold 
the protocol lock
-            // FIXME: convert to timeout async get(getDefaultSendTimeOut(), 
TimeUnit.SECONDS)
-            
session.getRemote().sendString(getWireFormat().marshalToString(command));
+            // Block on the async send but time out so we don't wait forever 
holding the protocol lock.
+            Callback.Completable callback = new Callback.Completable();
+            session.sendText(getWireFormat().marshalToString(command), 
callback);
+            callback.get(getDefaultSendTimeOut(), TimeUnit.SECONDS);
         } catch (Exception e) {
             throw IOExceptionSupport.create(e);
         }
@@ -65,7 +67,9 @@ public class StompSocket extends AbstractStompSocket 
implements WebSocketListene
     //----- WebSocketListener event callbacks 
--------------------------------//
 
     @Override
-    public void onWebSocketBinary(byte[] arg0, int arg1, int arg2) {
+    public void onWebSocketBinary(ByteBuffer payload, Callback callback) {
+        // STOMP over WebSocket uses text frames; ignore binary but release 
the frame.
+        callback.succeed();
     }
 
     @Override
@@ -85,7 +89,7 @@ public class StompSocket extends AbstractStompSocket 
implements WebSocketListene
     }
 
     @Override
-    public void onWebSocketConnect(Session session) {
+    public void onWebSocketOpen(Session session) {
         this.session = session;
         this.session.setIdleTimeout(Duration.ZERO);
     }
diff --git 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/WSServlet.java
 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/WSServlet.java
similarity index 92%
rename from 
activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/WSServlet.java
rename to 
activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/WSServlet.java
index 86183c8c4f..f39432143a 100644
--- 
a/activemq-http/src/main/java/org/apache/activemq/transport/ws/jetty12/WSServlet.java
+++ 
b/activemq-http/src/main/java/org/apache/activemq/transport/ws/ee11/WSServlet.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.activemq.transport.ws.jetty12;
+package org.apache.activemq.transport.ws.ee11;
 
 import java.io.IOException;
 import java.net.URI;
@@ -38,12 +38,12 @@ import 
org.apache.activemq.transport.TransportAcceptListener;
 import org.apache.activemq.transport.TransportFactory;
 import org.apache.activemq.transport.util.HttpTransportUtils;
 import org.apache.activemq.transport.ws.WSTransportProxy;
-import org.eclipse.jetty.ee9.websocket.api.WebSocketListener;
-import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeRequest;
-import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeResponse;
-import org.eclipse.jetty.ee9.websocket.server.JettyWebSocketCreator;
-import org.eclipse.jetty.ee9.websocket.server.JettyWebSocketServlet;
-import org.eclipse.jetty.ee9.websocket.server.JettyWebSocketServletFactory;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.ee11.websocket.server.JettyServerUpgradeRequest;
+import org.eclipse.jetty.ee11.websocket.server.JettyServerUpgradeResponse;
+import org.eclipse.jetty.ee11.websocket.server.JettyWebSocketCreator;
+import org.eclipse.jetty.ee11.websocket.server.JettyWebSocketServlet;
+import org.eclipse.jetty.ee11.websocket.server.JettyWebSocketServletFactory;
 
 /**
  * Handle connection upgrade requests and creates web sockets
@@ -93,7 +93,7 @@ public class WSServlet extends JettyWebSocketServlet 
implements BrokerServiceAwa
         factory.setCreator(new JettyWebSocketCreator() {
             @Override
             public Object createWebSocket(JettyServerUpgradeRequest req, 
JettyServerUpgradeResponse resp) {
-                WebSocketListener socket;
+                Session.Listener socket;
                 Protocol requestedProtocol = Protocol.UNKNOWN;
 
                 // When no sub-protocol is requested we default to STOMP for 
legacy reasons.
@@ -141,7 +141,7 @@ public class WSServlet extends JettyWebSocketServlet 
implements BrokerServiceAwa
         });
     }
 
-    private WebSocketListener findWSTransport(JettyServerUpgradeRequest 
request, JettyServerUpgradeResponse response) {
+    private Session.Listener findWSTransport(JettyServerUpgradeRequest 
request, JettyServerUpgradeResponse response) {
         WSTransportProxy proxy = null;
 
         for (String subProtocol : request.getSubProtocols()) {
diff --git 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/SocketTest.java 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/SocketTest.java
index 9f2aecfc84..bc36c6347a 100644
--- 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/SocketTest.java
+++ 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/SocketTest.java
@@ -18,8 +18,8 @@ package org.apache.activemq.transport.ws;
 
 import static org.junit.Assert.assertEquals;
 
-import org.apache.activemq.transport.ws.jetty12.MQTTSocket;
-import org.apache.activemq.transport.ws.jetty12.StompSocket;
+import org.apache.activemq.transport.ws.ee11.MQTTSocket;
+import org.apache.activemq.transport.ws.ee11.StompSocket;
 import org.junit.Test;
 
 public class SocketTest {
@@ -31,8 +31,8 @@ public class SocketTest {
 
         assertEquals("ws://localhost:8080", 
stompSocketJetty8.getRemoteAddress());
 
-        org.apache.activemq.transport.ws.jetty12.StompSocket 
stompSocketJetty11 =
-                new 
org.apache.activemq.transport.ws.jetty12.StompSocket("ws://localhost:8080");
+        org.apache.activemq.transport.ws.ee11.StompSocket stompSocketJetty11 =
+                new 
org.apache.activemq.transport.ws.ee11.StompSocket("ws://localhost:8080");
 
         assertEquals("ws://localhost:8080", 
stompSocketJetty11.getRemoteAddress());
     }
diff --git 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportProxyTest.java
 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportProxyTest.java
index 1fa58538ac..4ed505eccd 100644
--- 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportProxyTest.java
+++ 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportProxyTest.java
@@ -17,7 +17,8 @@
 package org.apache.activemq.transport.ws;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -29,14 +30,14 @@ import java.nio.charset.StandardCharsets;
 
 import org.apache.activemq.transport.Transport;
 import org.apache.activemq.transport.TransportListener;
-import org.eclipse.jetty.ee9.websocket.api.RemoteEndpoint;
-import org.eclipse.jetty.ee9.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.Callback;
+import org.eclipse.jetty.websocket.api.Session;
 import org.junit.Test;
 
 /**
  * Unit tests for {@link WSTransportProxy} frame handling. In particular that 
outbound
  * text is emitted as a WebSocket TEXT frame and outbound binary as a BINARY 
frame -
- * a regression guard: outbound text was previously sent via sendBytes (a 
binary frame).
+ * a regression guard: outbound text was previously sent as a binary frame.
  */
 public class WSTransportProxyTest {
 
@@ -46,8 +47,8 @@ public class WSTransportProxyTest {
 
         WSTransportProxy proxy = new WSTransportProxy("ws://localhost:61614", 
transport);
         proxy.setTransportListener(mock(TransportListener.class));
-        proxy.start();                     // counts down the "started" latch 
so sends don't block
-        proxy.onWebSocketConnect(session); // installs the session used by the 
outbound sends
+        proxy.start();                  // counts down the "started" latch so 
sends don't block
+        proxy.onWebSocketOpen(session); // installs the session used by the 
outbound sends
         return proxy;
     }
 
@@ -55,32 +56,33 @@ public class WSTransportProxyTest {
     public void testOutboundTextIsSentAsTextFrame() throws Exception {
         WSTransport wsTransport = mock(WSTransport.class);
         Session session = mock(Session.class);
-        RemoteEndpoint remote = mock(RemoteEndpoint.class);
-        when(session.getRemote()).thenReturn(remote);
+        // The proxy blocks on the send callback, so complete it when sendText 
is invoked.
+        doAnswer(inv -> { inv.getArgument(1, Callback.class).succeed(); return 
null; })
+            .when(session).sendText(any(), any(Callback.class));
 
         WSTransportProxy proxy = startedProxy(wsTransport, session);
 
         proxy.onSocketOutboundText("CONNECTED\n");
 
-        // Must be a WebSocket TEXT frame (sendString), never a binary frame.
-        verify(remote, times(1)).sendString("CONNECTED\n");
-        verify(remote, never()).sendBytes(any(ByteBuffer.class));
+        // Must be a WebSocket TEXT frame (sendText), never a binary frame.
+        verify(session, times(1)).sendText(eq("CONNECTED\n"), 
any(Callback.class));
+        verify(session, never()).sendBinary(any(ByteBuffer.class), 
any(Callback.class));
     }
 
     @Test
     public void testOutboundBinaryIsSentAsBinaryFrame() throws Exception {
         WSTransport wsTransport = mock(WSTransport.class);
         Session session = mock(Session.class);
-        RemoteEndpoint remote = mock(RemoteEndpoint.class);
-        when(session.getRemote()).thenReturn(remote);
+        doAnswer(inv -> { inv.getArgument(1, Callback.class).succeed(); return 
null; })
+            .when(session).sendBinary(any(ByteBuffer.class), 
any(Callback.class));
 
         WSTransportProxy proxy = startedProxy(wsTransport, session);
 
         ByteBuffer payload = 
ByteBuffer.wrap("frame-bytes".getBytes(StandardCharsets.UTF_8));
         proxy.onSocketOutboundBinary(payload);
 
-        // Must be a WebSocket BINARY frame (sendBytes), never a text frame.
-        verify(remote, times(1)).sendBytes(any(ByteBuffer.class));
-        verify(remote, never()).sendString(anyString());
+        // Must be a WebSocket BINARY frame (sendBinary), never a text frame.
+        verify(session, times(1)).sendBinary(any(ByteBuffer.class), 
any(Callback.class));
+        verify(session, never()).sendText(any(), any(Callback.class));
     }
 }
diff --git 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportTest.java
 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportTest.java
index 870f35c930..af13166afd 100644
--- 
a/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportTest.java
+++ 
b/activemq-http/src/test/java/org/apache/activemq/transport/ws/WSTransportTest.java
@@ -42,7 +42,7 @@ import org.eclipse.jetty.io.ClientConnector;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.ee9.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -74,7 +74,7 @@ public class WSTransportTest extends WSTransportTestSupport {
         Connector connector = createJettyConnector(server);
 
         WebAppContext context = new WebAppContext();
-        context.setResourceBase("src/test/webapp");
+        context.setBaseResourceAsString("src/test/webapp");
         context.setContextPath("/");
         context.setServer(server);
 
diff --git a/activemq-web-console/pom.xml b/activemq-web-console/pom.xml
index fe74be93aa..65f2e6f7ec 100644
--- a/activemq-web-console/pom.xml
+++ b/activemq-web-console/pom.xml
@@ -52,8 +52,8 @@
         </configuration>
       </plugin>
       <plugin>
-        <groupId>org.eclipse.jetty.ee9</groupId>
-        <artifactId>jetty-ee9-maven-plugin</artifactId>
+        <groupId>org.eclipse.jetty.ee11</groupId>
+        <artifactId>jetty-ee11-maven-plugin</artifactId>
         <version>${jetty-version}</version>
         <configuration>
           <httpConnector>
@@ -242,8 +242,8 @@
 
     <!-- web container -->
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-webapp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-webapp</artifactId>
       <scope>provided</scope>
     </dependency>
     <dependency>
@@ -280,15 +280,15 @@
     <!-- JSTL support -->
     
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-glassfish-jstl</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-glassfish-jstl</artifactId>
       <scope>provided</scope>
     </dependency>
     
     <!-- Tag Libs -->
     <!--
       These two should be available either in the WAR itself or from the 
container. We can't configure
-      jetty-ee9-maven-plugin with <useProvidedScope>true</useProvidedScope> 
because we don't need ALL provided
+      jetty-ee11-maven-plugin with <useProvidedScope>true</useProvidedScope> 
because we don't need ALL provided
       dependencies. But we shouldn't build the WAR with these two included 
either, because _full_ web container
       may provide own taglibs... Not me to decide ;)
     -->
@@ -338,8 +338,8 @@
     </dependency>
     
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-apache-jsp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-apache-jsp</artifactId>
       <scope>provided</scope>
       <exclusions>
           <exclusion>
diff --git 
a/activemq-web-console/src/test/java/org/apache/activemq/web/tool/Main.java 
b/activemq-web-console/src/test/java/org/apache/activemq/web/tool/Main.java
index 1f06c789ad..d95a6ffb81 100644
--- a/activemq-web-console/src/test/java/org/apache/activemq/web/tool/Main.java
+++ b/activemq-web-console/src/test/java/org/apache/activemq/web/tool/Main.java
@@ -22,7 +22,7 @@ import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.util.resource.ResourceFactory;
-import org.eclipse.jetty.ee9.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 
 /**
  * A simple bootstrap class for starting Jetty in your IDE using the local web
diff --git 
a/activemq-web-console/src/test/resources/jetty/jetty-activemq-console.xml 
b/activemq-web-console/src/test/resources/jetty/jetty-activemq-console.xml
index 05512ba298..8e138b9e79 100644
--- a/activemq-web-console/src/test/resources/jetty/jetty-activemq-console.xml
+++ b/activemq-web-console/src/test/resources/jetty/jetty-activemq-console.xml
@@ -16,7 +16,7 @@
     limitations under the License.
 -->
 <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" 
"https://www.eclipse.org/jetty/configure_12_0.dtd";>
-<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
+<Configure class="org.eclipse.jetty.ee11.webapp.WebAppContext">
   <Set name="contextPath">/console</Set>
   <Set name="resourceBase">webapps/admin</Set>
 </Configure>
\ No newline at end of file
diff --git a/activemq-web-console/src/test/resources/jetty/jetty-webapps.xml 
b/activemq-web-console/src/test/resources/jetty/jetty-webapps.xml
index c1ccff6965..03b9f29241 100644
--- a/activemq-web-console/src/test/resources/jetty/jetty-webapps.xml
+++ b/activemq-web-console/src/test/resources/jetty/jetty-webapps.xml
@@ -86,7 +86,7 @@
   <!-- Admin Web Application -->
   <Call name="addHandler">
     <Arg>
-      <New class="org.eclipse.jetty.ee9.webapp.WebAppContext">
+      <New class="org.eclipse.jetty.ee11.webapp.WebAppContext">
         <Set name="contextPath">/admin</Set>
         <Set name="baseResourceAsString">src/test/resources/webapps/admin</Set>
         <Set name="logUrlOnStart">true</Set>
@@ -94,7 +94,7 @@
              runs and TLDs are discovered (otherwise JSP compilation fails 
with a null TldCache). -->
         <Call name="setAttribute">
           <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
-          
<Arg>.*/jetty-ee9-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+          
<Arg>.*/jetty-ee11-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
         </Call>
       </New>
     </Arg>
@@ -103,7 +103,7 @@
   <!-- API Web Application -->
   <Call name="addHandler">
     <Arg>
-      <New class="org.eclipse.jetty.ee9.webapp.WebAppContext">
+      <New class="org.eclipse.jetty.ee11.webapp.WebAppContext">
         <Set name="contextPath">/api</Set>
         <Set name="baseResourceAsString">src/test/resources/webapps/api</Set>
         <Set name="logUrlOnStart">true</Set>
@@ -111,7 +111,7 @@
              runs and TLDs are discovered (otherwise JSP compilation fails 
with a null TldCache). -->
         <Call name="setAttribute">
           <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
-          
<Arg>.*/jetty-ee9-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+          
<Arg>.*/jetty-ee11-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
         </Call>
       </New>
     </Arg>
diff --git a/activemq-web-demo/pom.xml b/activemq-web-demo/pom.xml
index d8c59dc766..378c2d5d84 100644
--- a/activemq-web-demo/pom.xml
+++ b/activemq-web-demo/pom.xml
@@ -33,8 +33,8 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.eclipse.jetty.ee9</groupId>
-        <artifactId>jetty-ee9-maven-plugin</artifactId>
+        <groupId>org.eclipse.jetty.ee11</groupId>
+        <artifactId>jetty-ee11-maven-plugin</artifactId>
         <configuration>
           <httpConnector>
             <port>${jetty.port}</port>
@@ -188,8 +188,8 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-webapp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-webapp</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git 
a/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyServer.java 
b/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyServer.java
index eb5602eb04..50b074e78d 100644
--- a/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyServer.java
+++ b/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyServer.java
@@ -23,7 +23,7 @@ import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.util.resource.ResourceFactory;
-import org.eclipse.jetty.ee9.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 
 /**
  * A simple bootstrap class for starting Jetty in your IDE using the local web
diff --git 
a/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyTestSupport.java 
b/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyTestSupport.java
index 7fd016d15e..f5efc2e8e8 100644
--- 
a/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyTestSupport.java
+++ 
b/activemq-web-demo/src/test/java/org/apache/activemq/web/JettyTestSupport.java
@@ -37,7 +37,7 @@ import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.util.resource.ResourceFactory;
-import org.eclipse.jetty.ee9.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 import org.junit.After;
 import org.junit.Before;
 import org.slf4j.Logger;
diff --git a/activemq-web/pom.xml b/activemq-web/pom.xml
index 4f67b91687..17303133b9 100644
--- a/activemq-web/pom.xml
+++ b/activemq-web/pom.xml
@@ -79,12 +79,12 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-webapp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-webapp</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-server</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jetty-server</artifactId>
     </dependency>
 
     <!-- Just used for testing -->
diff --git 
a/activemq-web/src/main/java/org/apache/activemq/web/MessageServlet.java 
b/activemq-web/src/main/java/org/apache/activemq/web/MessageServlet.java
index 10675a7cf2..dd1ac3ee4b 100644
--- a/activemq-web/src/main/java/org/apache/activemq/web/MessageServlet.java
+++ b/activemq-web/src/main/java/org/apache/activemq/web/MessageServlet.java
@@ -18,6 +18,7 @@
 package org.apache.activemq.web;
 
 import jakarta.jms.*;
+import jakarta.servlet.DispatcherType;
 import jakarta.servlet.ServletConfig;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
@@ -189,11 +190,12 @@ public class MessageServlet extends MessageServletSupport 
{
                 throw new NoDestinationSuppliedException();
             }
             consumer = (MessageAvailableConsumer) 
client.getConsumer(destination, request.getHeader(WebClient.selectorName));
-            final AsyncServletRequest asyncRequest = 
AsyncServletRequest.getAsyncRequest(request);
-
-            // Don't allow concurrent use of the consumer. Do make sure to 
allow
-            // subsequent calls on asyncRequest to use the consumer.
-            if (asyncRequest.isInitial() && !activeConsumers.add(consumer)) {
+            // Don't allow concurrent use of the consumer on the initial 
dispatch. Subsequent async
+            // re-dispatches (DispatcherType.ASYNC) reuse the 
already-registered consumer. Determine
+            // "initial" from the CURRENT request: EE11 does not update the 
stored original request's
+            // dispatcher type on an async re-dispatch (EE9 reused the same 
request object), so
+            // AsyncServletRequest.isInitial() would wrongly report true on 
re-dispatch.
+            if (request.getDispatcherType() != DispatcherType.ASYNC && 
!activeConsumers.add(consumer)) {
                 throw new ServletException("Concurrent access to consumer is 
not supported");
             }
 
diff --git 
a/activemq-web/src/main/java/org/apache/activemq/web/async/AsyncServletRequest.java
 
b/activemq-web/src/main/java/org/apache/activemq/web/async/AsyncServletRequest.java
index 4ba158b456..9a207a79a9 100644
--- 
a/activemq-web/src/main/java/org/apache/activemq/web/async/AsyncServletRequest.java
+++ 
b/activemq-web/src/main/java/org/apache/activemq/web/async/AsyncServletRequest.java
@@ -114,9 +114,12 @@ public class AsyncServletRequest implements AsyncListener  
{
             LOG.debug("ActiveMQAsyncRequest " + event + " timeout.");
         }
 
+        // Use the context's request/response rather than 
event.getSuppliedRequest(): the listener
+        // is registered via addListener(this) (no supplied request/response), 
so getSuppliedRequest()
+        // is null under EE11's spec-compliant behavior (EE9 happened to 
populate it).
         final AsyncContext context = event.getAsyncContext();
-        if (context != null && event.getSuppliedRequest().isAsyncStarted()) {
-            // We must call dispatch to finish the request on timeout.
+        if (context != null && context.getRequest().isAsyncStarted()) {
+            // We must call dispatch to finish the request on timeout,
             // then set the status code to prevent a 500 error.
             context.dispatch();
             final ServletResponse response = context.getResponse();
diff --git 
a/activemq-web/src/main/java/org/apache/activemq/web/config/JspConfigurer.java 
b/activemq-web/src/main/java/org/apache/activemq/web/config/JspConfigurer.java
index 6fe6d53779..290925e893 100644
--- 
a/activemq-web/src/main/java/org/apache/activemq/web/config/JspConfigurer.java
+++ 
b/activemq-web/src/main/java/org/apache/activemq/web/config/JspConfigurer.java
@@ -19,7 +19,7 @@ package org.apache.activemq.web.config;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.Handler.Sequence;
-import org.eclipse.jetty.ee9.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 
 /**
  *
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 42785a7f94..c84c62a473 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -379,24 +379,16 @@
       <artifactId>jettison</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-webapp</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-webapp</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-annotations</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-annotations</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-nested</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-security</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.ee9</groupId>
-      <artifactId>jetty-ee9-servlet</artifactId>
+      <groupId>org.eclipse.jetty.ee11</groupId>
+      <artifactId>jetty-ee11-servlet</artifactId>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty.ee</groupId>
@@ -454,24 +446,20 @@
       <artifactId>jetty-websocket-jetty-api</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jakarta-client</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-api</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jakarta-client</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-common</artifactId>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>jetty-websocket-jetty-common</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-jetty-server</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-jetty-server</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.ee9.websocket</groupId>
-      <artifactId>jetty-ee9-websocket-servlet</artifactId>
+      <groupId>org.eclipse.jetty.ee11.websocket</groupId>
+      <artifactId>jetty-ee11-websocket-servlet</artifactId>
     </dependency>
 <!--
 o  'org.eclipse.jetty.websocket:websocket-core-common'
@@ -527,18 +515,27 @@ o  'org.eclipse.jetty:apache-jsp'
     </dependency>
 
     <dependency>
-        <groupId>org.eclipse.jetty.ee9</groupId>
-        <artifactId>jetty-ee9-apache-jsp</artifactId>
+        <groupId>org.eclipse.jetty.ee11</groupId>
+        <artifactId>jetty-ee11-apache-jsp</artifactId>
     </dependency>
     <dependency>
-        <groupId>org.eclipse.jetty.ee9</groupId>
-        <artifactId>jetty-ee9-glassfish-jstl</artifactId>
+        <groupId>org.eclipse.jetty.ee11</groupId>
+        <artifactId>jetty-ee11-glassfish-jstl</artifactId>
     </dependency>
     <dependency>
       <groupId>jakarta.servlet.jsp.jstl</groupId>
       <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
       <version>3.0.2</version>
     </dependency>
+    <dependency>
+      <groupId>jakarta.el</groupId>
+      <artifactId>jakarta.el-api</artifactId>
+      <version>6.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>jakarta.servlet.jsp</groupId>
+      <artifactId>jakarta.servlet.jsp-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.glassfish.web</groupId>
       <artifactId>jakarta.servlet.jsp.jstl</artifactId>
diff --git a/assembly/src/main/descriptors/common-bin.xml 
b/assembly/src/main/descriptors/common-bin.xml
index e99cba79bb..d6a945e4ba 100644
--- a/assembly/src/main/descriptors/common-bin.xml
+++ b/assembly/src/main/descriptors/common-bin.xml
@@ -272,38 +272,36 @@
         <include>org.eclipse.jetty:jetty-plus</include>
         <include>org.eclipse.jetty:jetty-security</include>
         <include>org.eclipse.jetty:jetty-rewrite</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-nested</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-security</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-servlet</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-webapp</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-servlet</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-webapp</include>
         <!-- plus + annotations enable ServletContainerInitializer/TLD 
scanning (JSP/JSTL) -->
-        <include>org.eclipse.jetty.ee9:jetty-ee9-plus</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-plus</include>
         <include>org.eclipse.jetty:jetty-annotations</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-annotations</include>
-        <include>org.eclipse.jetty.ee9:jetty-ee9-apache-jsp</include>
-        
<include>org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-annotations</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-apache-jsp</include>
+        <include>jakarta.servlet:jakarta.servlet-api</include>
         
<include>org.eclipse.jetty.websocket:jetty-websocket-core-client</include>
         
<include>org.eclipse.jetty.websocket:jetty-websocket-core-common</include>
         
<include>org.eclipse.jetty.websocket:jetty-websocket-core-server</include>
         
<include>org.eclipse.jetty.websocket:jetty-websocket-jetty-client</include>
         
<include>org.eclipse.jetty.websocket:jetty-websocket-jetty-api</include>
         <include>org.eclipse.jetty.orbit:javax.security.auth.message</include>
-        
<include>org.eclipse.jetty.ee9.websocket:jetty-ee9-websocket-jakarta-client</include>
-        
<include>org.eclipse.jetty.ee9.websocket:jetty-ee9-websocket-jetty-api</include>
-        
<include>org.eclipse.jetty.ee9.websocket:jetty-ee9-websocket-jetty-common</include>
-        
<include>org.eclipse.jetty.ee9.websocket:jetty-ee9-websocket-jetty-server</include>
-        
<include>org.eclipse.jetty.ee9.websocket:jetty-ee9-websocket-servlet</include>
-        <!-- include>jakarta.servlet:jakarta.servlet-api</include -->
+        
<include>org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-client</include>
+        
<include>org.eclipse.jetty.websocket:jetty-websocket-jetty-common</include>
+        
<include>org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jetty-server</include>
+        
<include>org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-servlet</include>
         <include>jakarta.websocket:jakarta.websocket-api</include>
         <!-- JSP support -->
-        <!-- Jetty JSP impl (pulled in via jetty-ee9-apache-jsp) -->
+        <!-- Jetty JSP impl (pulled in via jetty-ee11-apache-jsp) -->
+        <include>jakarta.servlet.jsp:jakarta.servlet.jsp-api</include>
         <include>org.mortbay.jasper:mortbay-apache-jsp</include>
         <!-- jstl and el api -->
-        <include>org.eclipse.jetty.ee9:jetty-ee9-glassfish-jstl</include>
+        <include>org.eclipse.jetty.ee11:jetty-ee11-glassfish-jstl</include>
         
<include>jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api</include>
         <include>org.glassfish.web:jakarta.servlet.jsp.jstl</include>
         <!-- include>org.apache.taglibs:taglibs-standard-spec</include -->
         <!-- jstl and el impl -->
+        <include>jakarta.el:jakarta.el-api</include>
         <include>org.mortbay.jasper:mortbay-apache-el</include>
         <!-- include>org.apache.taglibs:taglibs-standard-impl</include -->
 
diff --git a/assembly/src/release/conf/jetty/jetty-webapps.xml 
b/assembly/src/release/conf/jetty/jetty-webapps.xml
index 52e94fc08c..f4bd9603d3 100644
--- a/assembly/src/release/conf/jetty/jetty-webapps.xml
+++ b/assembly/src/release/conf/jetty/jetty-webapps.xml
@@ -134,7 +134,7 @@
   <!-- Admin Web Application -->
   <Call name="addHandler">
     <Arg>
-      <New class="org.eclipse.jetty.ee9.webapp.WebAppContext">
+      <New class="org.eclipse.jetty.ee11.webapp.WebAppContext">
         <Set name="contextPath">/admin</Set>
         <Set name="baseResourceAsString"><Property name="activemq.home" 
default="."/>/webapps/admin</Set>
         <Set name="logUrlOnStart">true</Set>
@@ -142,7 +142,13 @@
              runs and TLDs are discovered (otherwise JSP compilation fails 
with a null TldCache). -->
         <Call name="setAttribute">
           <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
-          
<Arg>.*/jetty-ee9-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+          
<Arg>.*/jetty-ee11-[^/]*\.jar$|.*/jakarta\.servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+        </Call>
+        <!-- Jasper needs an InstanceManager in the ServletContext to 
instantiate JSP/tag classes.
+             EE11 no longer wires one for a plain exploded WebAppContext, so 
set a simple one. -->
+        <Call name="setAttribute">
+          <Arg>org.apache.tomcat.InstanceManager</Arg>
+          <Arg><New class="org.apache.tomcat.SimpleInstanceManager"/></Arg>
         </Call>
       </New>
     </Arg>
@@ -151,7 +157,7 @@
   <!-- API Web Application -->
   <Call name="addHandler">
     <Arg>
-      <New class="org.eclipse.jetty.ee9.webapp.WebAppContext">
+      <New class="org.eclipse.jetty.ee11.webapp.WebAppContext">
         <Set name="contextPath">/api</Set>
         <Set name="baseResourceAsString"><Property name="activemq.home" 
default="."/>/webapps/api</Set>
         <Set name="logUrlOnStart">true</Set>
@@ -159,7 +165,13 @@
              runs and TLDs are discovered (otherwise JSP compilation fails 
with a null TldCache). -->
         <Call name="setAttribute">
           <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
-          
<Arg>.*/jetty-ee9-[^/]*\.jar$|.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+          
<Arg>.*/jetty-ee11-[^/]*\.jar$|.*/jakarta\.servlet-api-[^/]*\.jar$|.*/jakarta\.servlet\.jsp\.jstl.*\.jar$</Arg>
+        </Call>
+        <!-- Jasper needs an InstanceManager in the ServletContext to 
instantiate JSP/tag classes.
+             EE11 no longer wires one for a plain exploded WebAppContext, so 
set a simple one. -->
+        <Call name="setAttribute">
+          <Arg>org.apache.tomcat.InstanceManager</Arg>
+          <Arg><New class="org.apache.tomcat.SimpleInstanceManager"/></Arg>
         </Call>
       </New>
     </Arg>
diff --git a/pom.xml b/pom.xml
index 03aaeabea7..9d65caac3d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -450,16 +450,16 @@
         <version>9.10.1</version>
       </dependency>
 
-     <!-- Servlet 5.0 and JSP -->
+     <!-- Servlet 6.1 and JSP (Jakarta EE 11) -->
      <dependency>
        <groupId>jakarta.servlet.jsp</groupId>
        <artifactId>jakarta.servlet.jsp-api</artifactId>
-       <version>3.1.1</version>
+       <version>4.0.0</version>
      </dependency>
      <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
-       <version>5.0.0</version>
+       <version>6.1.0</version>
      </dependency>
      <dependency>
        <groupId>jakarta.websocket</groupId>
@@ -831,8 +831,8 @@
       </dependency>
 
       <dependency>
-        <groupId>org.eclipse.jetty.ee9</groupId>
-        <artifactId>jetty-ee9-bom</artifactId>
+        <groupId>org.eclipse.jetty.ee11</groupId>
+        <artifactId>jetty-ee11-bom</artifactId>
         <version>${jetty-version}</version>
         <type>pom</type>
         <scope>import</scope>
@@ -939,7 +939,7 @@
       <dependency>
         <groupId>jakarta.annotation</groupId>
         <artifactId>jakarta.annotation-api</artifactId>
-        <version>2.1.1</version>
+        <version>3.0.0</version>
       </dependency>
 
     </dependencies>
@@ -1024,8 +1024,8 @@
           <version>${javacc-maven-plugin-version}</version>
         </plugin>
         <plugin>
-          <groupId>org.eclipse.jetty.ee9</groupId>
-          <artifactId>jetty-ee9-maven-plugin</artifactId>
+          <groupId>org.eclipse.jetty.ee11</groupId>
+          <artifactId>jetty-ee11-maven-plugin</artifactId>
           <version>${jetty-version}</version>
         </plugin>
         <plugin>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact


Reply via email to