From 4d11ff58e9b07b60c341e8973d1b3320b8859f2f Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Fri, 13 Oct 2023 11:53:31 +0200 Subject: [PATCH] 8.0.x : Abstract out CometD from Servlet API (#1385) * Decoupled cometd from Servlet APIs. * Moved Servlet specific code to different modules. Signed-off-by: Ludovic Orban Signed-off-by: Simone Bordet Co-authored-by: Simone Bordet --- cometd-demo/pom.xml | 32 +- .../demo/auction/AuctionChatService.java | 6 +- .../webtide/demo/auction/AuctionService.java | 6 +- .../java/org/webtide/demo/auction/Bidder.java | 2 +- .../java/org/webtide/demo/auction/Item.java | 2 +- .../webapp/WEB-INF/jetty-logging.properties | 3 + .../src/main/webapp/WEB-INF/log4j2.properties | 16 - cometd-demo/src/main/webapp/WEB-INF/web.xml | 6 +- .../src/test/java/org/cometd/demo/Demo.java | 2 +- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 16 - cometd-documentation/pom.xml | 2 +- .../src/main/asciidoc/java_json.adoc | 2 +- .../src/main/asciidoc/java_oort.adoc | 16 +- .../src/main/asciidoc/java_oort_object.adoc | 2 +- .../src/main/asciidoc/java_oort_seti.adoc | 6 +- .../asciidoc/java_server_configuration.adoc | 12 +- .../java_server_services_integration.adoc | 4 +- ...va_server_services_integration_spring.adoc | 8 +- .../main/asciidoc/java_server_transports.adoc | 8 +- .../src/main/asciidoc/migration.adoc | 4 +- .../org/cometd/documentation/JSONDocs.java | 4 +- .../documentation/oort/OortObjectDocs.java | 3 +- .../server/ServerContextDocs.java | 6 +- .../server/ServerServiceDocs.java | 3 +- .../src/main/java/module-info.java | 2 +- .../cometd-java-annotation-server/pom.xml | 2 +- .../src/main/java/module-info.java | 4 +- .../server/AnnotationCometDServlet.java | 7 +- .../cometd/annotation/server/Configure.java | 1 - .../cometd-java-annotation-tests/pom.xml | 12 - .../annotation/AbstractClientServerTest.java | 5 +- .../test/resources/jetty-logging.properties | 4 + .../src/test/resources/log4j2-test.properties | 19 - .../main/java/org/cometd/bayeux/Bayeux.java | 5 +- .../main/java/org/cometd/bayeux/Promise.java | 38 +- .../cometd/bayeux/server/BayeuxContext.java | 120 +-- .../cometd/bayeux/server/BayeuxServer.java | 4 + .../cometd-java-benchmark-client/pom.xml | 9 +- .../benchmark/client/CometDLoadClient.java | 4 +- .../main/resources/jetty-logging.properties | 3 + .../src/main/resources/log4j2.properties | 24 - .../java/org/cometd/benchmark/Config.java | 2 +- .../cometd-java-benchmark-server/pom.xml | 19 +- .../benchmark/server/CometDLoadServer.java | 202 +++-- .../src/main/resources/log4j2.properties | 27 +- .../java/org/cometd/client/BayeuxClient.java | 19 +- .../client/transport/HttpClientTransport.java | 79 +- .../src/main/java/module-info.java | 2 +- .../cometd-java-client-http-tests/pom.xml | 18 +- .../http/BayeuxClientCallbacksTest.java | 2 +- .../cometd/client/http/ClientServerTest.java | 5 +- .../cometd/client/http/JSONContextTest.java | 4 +- .../http/JacksonCustomSerializationTest.java | 1 + .../http/JettyHttpClientTransportTest.java | 2 +- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 16 - .../pom.xml | 2 +- .../jetty/JettyWebSocketTransport.java | 4 +- .../src/main/java/module-info.java | 2 +- cometd-java/cometd-java-common/pom.xml | 13 - .../java/org/cometd/common/AsyncFoldLeft.java | 4 +- .../java/org/cometd/common/JSONContext.java | 1 + .../test/java/org/cometd/common/Z85Test.java | 1 - .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 16 - .../java/org/cometd/examples/CometDDemo.java | 3 +- cometd-java/cometd-java-examples/pom.xml | 2 + .../cometd-java-oort-common/pom.xml | 41 + .../src/main/java/module-info.java | 0 .../src/main/java/org/cometd/oort/Oort.java | 9 +- .../main/java/org/cometd/oort/OortComet.java | 1 + .../java/org/cometd/oort/OortContainer.java | 1 + .../main/java/org/cometd/oort/OortList.java | 0 .../main/java/org/cometd/oort/OortLong.java | 1 + .../java/org/cometd/oort/OortLongMap.java | 0 .../main/java/org/cometd/oort/OortMap.java | 0 .../java/org/cometd/oort/OortMembership.java | 0 .../cometd/oort/OortMulticastConfigurer.java | 0 .../main/java/org/cometd/oort/OortObject.java | 0 .../org/cometd/oort/OortObjectFactories.java | 0 .../org/cometd/oort/OortObjectMergers.java | 0 .../java/org/cometd/oort/OortPrimaryLong.java | 0 .../org/cometd/oort/OortPrimaryService.java | 0 .../java/org/cometd/oort/OortService.java | 1 + .../java/org/cometd/oort/OortStringMap.java | 0 .../src/main/java/org/cometd/oort/Seti.java | 2 - .../java/org/cometd/oort/jmx/OortMBean.java | 1 + .../cometd-java-oort-jakarta/pom.xml | 30 + .../src/main/java/module-info.java | 22 + .../oort/jakarta}/OortConfigServlet.java | 7 +- .../jakarta}/OortMulticastConfigServlet.java | 5 +- .../jakarta}/OortStaticConfigServlet.java | 8 +- .../org/cometd/oort/jakarta}/SetiServlet.java | 5 +- cometd-java/cometd-java-oort/pom.xml | 43 +- .../cometd-java-server-common/pom.xml | 27 - .../src/main/java/module-info.java | 3 +- .../server/AbstractServerTransport.java | 40 +- .../org/cometd/server/AbstractService.java | 6 +- .../org/cometd/server/BayeuxServerImpl.java | 171 ++-- .../java/org/cometd/server/CometDRequest.java | 151 ++++ .../org/cometd/server/CometDResponse.java | 58 ++ .../java/org/cometd/server/HttpException.java | 29 + .../org/cometd/server/ServerSessionImpl.java | 8 +- .../AcknowledgedMessagesSessionExtension.java | 2 +- .../server/http/AbstractHttpScheduler.java | 128 +++ .../server/http/AbstractHttpTransport.java | 635 +++++++-------- .../http/AbstractStreamHttpTransport.java | 254 ------ .../server/http/AsyncJSONTransport.java | 481 ----------- .../cometd/server/http/JSONHttpTransport.java | 232 ++++++ .../server/http/JSONPHttpTransport.java | 139 ++++ .../cometd/server/http/JSONPTransport.java | 90 --- .../org/cometd/server/http/JSONTransport.java | 77 -- .../cometd/server/http/TransportContext.java | 134 +++ .../server/AbstractBayeuxServerTest.java | 91 --- .../org/cometd/server/BayeuxContextTest.java | 225 ------ .../cometd/server/BayeuxServerJMXTest.java | 166 ---- .../org/cometd/server/IdleLongPollTest.java | 123 --- .../org/cometd/server/SlowConnectionTest.java | 347 -------- ...PTransportCallbackParamValidationTest.java | 95 --- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 16 - .../cometd-java-server-http-jakarta/pom.xml | 85 ++ .../src/main/java/module-info.java | 28 + .../server/http/jakarta}/CometDServlet.java | 95 ++- .../http/jakarta/JakartaBayeuxContext.java | 140 ++++ .../http/jakarta/JakartaCometDRequest.java | 188 +++++ .../http/jakarta/JakartaCometDResponse.java | 106 +++ .../cometd-java-server-http-jetty/pom.xml | 67 ++ .../src/main/java/module-info.java | 28 + .../server/http/jetty/CometDHandler.java | 171 ++++ .../server/http/jetty/JettyBayeuxContext.java | 126 +++ .../server/http/jetty/JettyCometDRequest.java | 140 ++++ .../http/jetty/JettyCometDResponse.java | 75 ++ .../cometd-java-server-http-tests/pom.xml | 47 ++ .../http}/AbstractBayeuxClientServerTest.java | 2 +- .../server/http/AbstractBayeuxServerTest.java | 109 +++ .../org/cometd/server/http}/BadJSONTest.java | 116 ++- .../cometd/server/http/BayeuxContextTest.java | 116 +++ .../http}/BayeuxServerCreationTest.java | 21 +- .../cometd/server/http}/BayeuxServerTest.java | 22 +- .../server/http/BrowserMappingTest.java | 227 +++--- .../org/cometd/server/http}/CharsetTest.java | 58 +- .../CometDServiceMetaNotificationsTest.java | 48 +- .../server/http}/CometDServiceTest.java | 64 +- .../CometDServiceWithThreadPoolTest.java | 34 +- .../ConcurrentConnectDisconnectTest.java | 118 ++- ...currentDisconnectSubscribePublishTest.java | 92 +-- ...tHandshakeFailureSubscribePublishTest.java | 46 +- .../cometd/server/http}/CustomAdviceTest.java | 126 +-- ...ustomResponseOnSecurityPolicyDenyTest.java | 66 +- .../cometd/server/http}/DisconnectTest.java | 44 +- .../JSONTransportMetaConnectDeliveryTest.java | 47 +- .../cometd/server/http}/MaxQueuedTest.java | 25 +- .../http}/MessageProcessingOrderTest.java | 4 +- .../MetaConnectWithOtherMessagesTest.java | 30 +- .../server/http}/ServerChannelTest.java | 10 +- .../server/http}/ServerRedeployTest.java | 46 +- .../server/http}/ServerShutdownTest.java | 46 +- .../http}/ServiceWithCustomDataClassTest.java | 33 +- .../server/http}/SessionHijackingTest.java | 31 +- .../server/http/SlowConnectionTest.java | 182 +++++ ...SubscriptionsWithMultipleChannelsTest.java | 54 +- .../org/cometd/server/http}/SweepTest.java | 6 +- .../http}/authorizer/AuthorizerTest.java | 147 ++-- .../http}/ext/AcknowledgeExtensionTest.java | 136 ++-- .../server/http}/ext/BayeuxExtensionTest.java | 96 +-- .../http}/ext/ExtensionConnectTest.java | 26 +- .../http}/ext/ExtensionDisconnectTest.java | 24 +- .../http}/ext/ExtensionHandshakeTest.java | 18 +- .../ext/ExtensionPublishReceivedTest.java | 26 +- .../http}/ext/ExtensionPublishSentTest.java | 26 +- .../http}/ext/ExtensionSubscribeTest.java | 26 +- .../http}/ext/ExtensionUnsubscribeTest.java | 34 +- .../http}/filter/JSONDataFilterTest.java | 46 +- .../test/resources/jetty-logging.properties | 3 + .../cometd-java-server-http/pom.xml | 19 + .../pom.xml | 17 - .../common/AbstractBayeuxContext.java | 57 +- .../common/AbstractWebSocketEndPoint.java | 39 +- .../pom.xml | 2 +- .../src/main/java/module-info.java | 1 + .../websocket/jakarta/WebSocketEndPoint.java | 7 +- .../websocket/jakarta/WebSocketTransport.java | 67 +- .../pom.xml | 5 +- .../src/main/java/module-info.java | 2 +- .../jetty/JettyWebSocketEndPoint.java | 8 +- .../jetty/JettyWebSocketTransport.java | 105 ++- .../pom.xml | 24 +- .../BatchedRepliesWebSocketTest.java | 5 +- .../server/websocket/BayeuxClientTest.java | 116 ++- .../websocket/BayeuxClientWebSocketTest.java | 161 ++-- .../server/websocket/BayeuxContextTest.java | 140 ++-- .../websocket/ClientServerWebSocketTest.java | 140 ++-- .../websocket/ConcurrentAbortPublishTest.java | 4 +- .../websocket/ExtensionNegotiationTest.java | 8 +- .../websocket/MultipleURLMappingsTest.java | 139 ---- .../server/websocket/SlowConnectionTest.java | 37 +- .../server/websocket/URLMappingTest.java | 55 +- .../websocket/WebSocketTransportTest.java | 2 +- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 16 - cometd-java/cometd-java-server/pom.xml | 1 + .../cometd-java-tests-common/pom.xml | 24 +- .../tests/AbstractClientServerTest.java | 99 +-- .../org/cometd/tests/AckExtensionTest.java | 5 +- .../org/cometd/tests/BayeuxClientTest.java | 7 + .../tests/DuplicateMetaConnectTest.java | 3 +- .../cometd/tests/HandshakeReconnectTest.java | 3 +- .../HandshakeWithExpiredSessionTest.java | 5 +- .../org/cometd/tests/MaxMessageSizeTest.java | 5 +- .../MessageDeliveryDuringHandshakeTest.java | 13 +- .../tests/MetaConnectDeliverOnlyTest.java | 7 +- .../cometd/tests/MetaConnectFailureTest.java | 5 +- ...etaConnectFailureWithAckExtensionTest.java | 20 +- ...aConnectOvertakenWithAckExtensionTest.java | 7 +- .../tests/NetworkDelayListenerTest.java | 4 +- .../org/cometd/tests/OrphanedSessionTest.java | 3 +- .../test/java/org/cometd/tests/ProxyTest.java | 7 +- .../cometd/tests/ServerSendMessageTest.java | 3 +- .../test/java/org/cometd/tests/SweepTest.java | 2 +- .../cometd/tests/TransportFailureTest.java | 3 +- .../java/org/cometd/tests/WebAppService.java | 2 +- .../java/org/cometd/tests/WebAppTest.java | 35 +- .../src/test/resources/http-web.xml | 4 +- .../src/test/resources/jakarta-ws-web.xml | 2 +- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/jetty-ws-web.xml | 51 -- .../src/test/resources/log4j2-test.properties | 16 - .../cometd-java-tests-oort/pom.xml | 26 +- .../cometd/oort/AbstractOortObjectTest.java | 13 +- .../{OortTest.java => AbstractOortTest.java} | 94 ++- .../test/java/org/cometd/oort/JMXTest.java | 12 +- .../cometd/oort/JacksonOortObjectTest.java | 4 +- .../cometd/oort/OortAuthenticationTest.java | 8 +- .../test/java/org/cometd/oort/OortDemo.java | 5 +- .../java/org/cometd/oort/OortListTest.java | 20 +- .../java/org/cometd/oort/OortLongMapTest.java | 8 +- .../oort/OortMulticastConfigurerTest.java | 22 +- .../cometd/oort/OortObjectStartupTest.java | 6 +- .../java/org/cometd/oort/OortObjectTest.java | 48 +- .../cometd/oort/OortObserveChannelTest.java | 28 +- .../org/cometd/oort/OortObserveCometTest.java | 159 ++-- .../org/cometd/oort/OortPrimaryLongTest.java | 4 +- .../java/org/cometd/oort/OortServiceTest.java | 28 +- .../java/org/cometd/oort/OortStartupTest.java | 26 +- .../oort/OortStringMapDisconnectTest.java | 10 +- .../org/cometd/oort/OortStringMapTest.java | 40 +- .../java/org/cometd/oort/SetiStartupTest.java | 6 +- .../test/java/org/cometd/oort/SetiTest.java | 760 +++++++++--------- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 19 - .../cometd-java-tests-spring/pom.xml | 18 +- .../SpringFrameworkConfigurationTest.java | 6 +- .../tests/spring/annotation/Configurator.java | 5 +- ...ngFrameworkWebSocketConfigurationTest.java | 15 +- ...server.xml => applicationContext-http.xml} | 2 +- .../applicationContext-jakarta-websocket.xml | 4 +- .../applicationContext-jetty-websocket.xml | 4 +- .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/log4j2-test.properties | 19 - cometd-javascript/tests/pom.xml | 12 - .../cometd/javascript/AbstractCometDTest.java | 10 +- .../cometd/javascript/CometDAdviceTest.java | 7 +- .../javascript/CometDCallbackPollingTest.java | 1 - .../CometDCrossOriginReHandshakeTest.java | 3 +- .../cometd/javascript/CometDDeliverTest.java | 4 +- .../CometDHandshakeDynamicPropsTest.java | 3 +- .../javascript/CometDRemoteCallTest.java | 9 +- ...CometDTransportNegotiationFailureTest.java | 7 +- .../CometDAckAndReloadExtensionsTest.java | 4 +- .../extension/CometDAckExtensionTest.java | 4 +- .../test/resources/jetty-logging.properties | 4 + .../src/test/resources/log4j2-test.properties | 19 - pom.xml | 28 +- 275 files changed, 5898 insertions(+), 5684 deletions(-) create mode 100644 cometd-demo/src/main/webapp/WEB-INF/jetty-logging.properties delete mode 100644 cometd-demo/src/main/webapp/WEB-INF/log4j2.properties create mode 100644 cometd-demo/src/test/resources/jetty-logging.properties delete mode 100644 cometd-demo/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/log4j2.properties create mode 100644 cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-common/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-common/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-oort/cometd-java-oort-common/pom.xml rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/module-info.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/Oort.java (98%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortComet.java (99%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortContainer.java (99%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortList.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortLong.java (99%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortLongMap.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortMap.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortMembership.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortMulticastConfigurer.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortObject.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortObjectFactories.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortObjectMergers.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortPrimaryLong.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortPrimaryService.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortService.java (99%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/OortStringMap.java (100%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/Seti.java (99%) rename cometd-java/cometd-java-oort/{ => cometd-java-oort-common}/src/main/java/org/cometd/oort/jmx/OortMBean.java (99%) create mode 100644 cometd-java/cometd-java-oort/cometd-java-oort-jakarta/pom.xml create mode 100644 cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/module-info.java rename cometd-java/cometd-java-oort/{src/main/java/org/cometd/oort => cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta}/OortConfigServlet.java (98%) rename cometd-java/cometd-java-oort/{src/main/java/org/cometd/oort => cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta}/OortMulticastConfigServlet.java (98%) rename cometd-java/cometd-java-oort/{src/main/java/org/cometd/oort => cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta}/OortStaticConfigServlet.java (91%) rename cometd-java/cometd-java-oort/{src/main/java/org/cometd/oort => cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta}/SetiServlet.java (96%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDRequest.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDResponse.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/HttpException.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpScheduler.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractStreamHttpTransport.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AsyncJSONTransport.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONHttpTransport.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPHttpTransport.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPTransport.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONTransport.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/TransportContext.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxServerTest.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxContextTest.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxServerJMXTest.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/IdleLongPollTest.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/SlowConnectionTest.java delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/http/JSONPTransportCallbackParamValidationTest.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/pom.xml create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/module-info.java rename cometd-java/cometd-java-server/{cometd-java-server-common/src/main/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta}/CometDServlet.java (53%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaBayeuxContext.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDRequest.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDResponse.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/pom.xml create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/module-info.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/CometDHandler.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyBayeuxContext.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDRequest.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDResponse.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/pom.xml rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/AbstractBayeuxClientServerTest.java (98%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxServerTest.java rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/BadJSONTest.java (51%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/BayeuxContextTest.java rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/BayeuxServerCreationTest.java (78%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/BayeuxServerTest.java (97%) rename cometd-java/cometd-java-server/{cometd-java-server-common => cometd-java-server-http/cometd-java-server-http-tests}/src/test/java/org/cometd/server/http/BrowserMappingTest.java (60%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CharsetTest.java (65%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CometDServiceMetaNotificationsTest.java (72%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CometDServiceTest.java (66%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CometDServiceWithThreadPoolTest.java (73%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ConcurrentConnectDisconnectTest.java (60%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ConcurrentDisconnectSubscribePublishTest.java (59%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ConcurrentHandshakeFailureSubscribePublishTest.java (50%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CustomAdviceTest.java (61%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/CustomResponseOnSecurityPolicyDenyTest.java (74%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/DisconnectTest.java (63%) rename cometd-java/cometd-java-server/{cometd-java-server-common => cometd-java-server-http/cometd-java-server-http-tests}/src/test/java/org/cometd/server/http/JSONTransportMetaConnectDeliveryTest.java (61%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/MaxQueuedTest.java (74%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/MessageProcessingOrderTest.java (99%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/MetaConnectWithOtherMessagesTest.java (68%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ServerChannelTest.java (98%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ServerRedeployTest.java (58%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ServerShutdownTest.java (55%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ServiceWithCustomDataClassTest.java (76%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/SessionHijackingTest.java (74%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/SlowConnectionTest.java rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/SubscriptionsWithMultipleChannelsTest.java (60%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/SweepTest.java (97%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/authorizer/AuthorizerTest.java (62%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/AcknowledgeExtensionTest.java (61%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/BayeuxExtensionTest.java (77%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionConnectTest.java (78%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionDisconnectTest.java (79%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionHandshakeTest.java (83%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionPublishReceivedTest.java (80%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionPublishSentTest.java (77%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionSubscribeTest.java (78%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/ext/ExtensionUnsubscribeTest.java (73%) rename cometd-java/cometd-java-server/{cometd-java-server-common/src/test/java/org/cometd/server => cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http}/filter/JSONDataFilterTest.java (62%) create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/resources/jetty-logging.properties create mode 100644 cometd-java/cometd-java-server/cometd-java-server-http/pom.xml delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/MultipleURLMappingsTest.java create mode 100644 cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/log4j2-test.properties create mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-ws-web.xml delete mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/log4j2-test.properties rename cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/{OortTest.java => AbstractOortTest.java} (72%) create mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/log4j2-test.properties rename cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/{applicationContext-server.xml => applicationContext-http.xml} (91%) create mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/jetty-logging.properties delete mode 100644 cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/log4j2-test.properties create mode 100644 cometd-javascript/tests/src/test/resources/jetty-logging.properties delete mode 100644 cometd-javascript/tests/src/test/resources/log4j2-test.properties diff --git a/cometd-demo/pom.xml b/cometd-demo/pom.xml index 749549df93..609c6444de 100644 --- a/cometd-demo/pom.xml +++ b/cometd-demo/pom.xml @@ -101,14 +101,9 @@ ${jetty-version} - org.apache.logging.log4j - log4j-core - ${log4j2-version} - - - org.apache.logging.log4j - log4j-slf4j2-impl - ${log4j2-version} + org.eclipse.jetty + jetty-slf4j-impl + ${jetty-version} @@ -169,7 +164,7 @@ org.cometd.java - cometd-java-oort + cometd-java-oort-jakarta ${project.version} @@ -213,26 +208,11 @@ ${jetty-version} - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - org.apache.logging.log4j - log4j-web - ${log4j2-version} + org.eclipse.jetty + jetty-slf4j-impl runtime - - org.junit.jupiter - junit-jupiter - org.cometd.java cometd-java-client-websocket-jetty diff --git a/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionChatService.java b/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionChatService.java index 3fe0672170..e09e6b2457 100644 --- a/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionChatService.java +++ b/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionChatService.java @@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import jakarta.servlet.ServletContext; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerChannel; @@ -29,7 +30,6 @@ import org.cometd.bayeux.server.ServerSession; import org.cometd.oort.Oort; import org.cometd.oort.Seti; -import org.cometd.oort.SetiServlet; import org.cometd.server.AbstractService; import org.cometd.server.authorizer.GrantAuthorizer; import org.slf4j.Logger; @@ -49,12 +49,12 @@ public AuctionChatService(ServletContext context) { _oort = (Oort)context.getAttribute(Oort.OORT_ATTRIBUTE); if (_oort == null) { throw new RuntimeException("Missing " + Oort.OORT_ATTRIBUTE + " from " + ServletContext.class.getSimpleName() + "; " + - "is an Oort servlet declared in web.xml ?"); + "is an Oort Servlet declared in web.xml?"); } _seti = (Seti)context.getAttribute(Seti.SETI_ATTRIBUTE); if (_seti == null) { throw new RuntimeException("Missing " + Seti.SETI_ATTRIBUTE + " from " + ServletContext.class.getSimpleName() + "; " + - "is " + SetiServlet.class.getSimpleName() + " declared in web.xml ?"); + "is a Seti Servlet declared in web.xml?"); } getBayeux().createChannelIfAbsent("/auction/chat/**", channel -> channel.addAuthorizer(GrantAuthorizer.GRANT_ALL)); diff --git a/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionService.java b/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionService.java index 25fd343afe..1d326ff057 100644 --- a/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionService.java +++ b/cometd-demo/src/main/java/org/webtide/demo/auction/AuctionService.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import jakarta.servlet.ServletContext; + import org.cometd.bayeux.Message; import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSessionChannel; @@ -29,7 +30,6 @@ import org.cometd.bayeux.server.ServerSession; import org.cometd.oort.Oort; import org.cometd.oort.Seti; -import org.cometd.oort.SetiServlet; import org.cometd.server.AbstractService; import org.cometd.server.authorizer.GrantAuthorizer; import org.eclipse.jetty.util.thread.AutoLock; @@ -53,12 +53,12 @@ public AuctionService(ServletContext context) { Oort oort = (Oort)context.getAttribute(Oort.OORT_ATTRIBUTE); if (oort == null) { throw new RuntimeException("Missing " + Oort.OORT_ATTRIBUTE + " from " + ServletContext.class.getSimpleName() + "; " + - "is an Oort servlet declared in web.xml ?"); + "is an Oort Servlet declared in web.xml?"); } _seti = (Seti)context.getAttribute(Seti.SETI_ATTRIBUTE); if (_seti == null) { throw new RuntimeException("Missing " + Seti.SETI_ATTRIBUTE + " from " + ServletContext.class.getSimpleName() + "; " + - "is " + SetiServlet.class.getSimpleName() + " declared in web.xml ?"); + "is a Seti Servlet declared in web.xml?"); } oort.observeChannel(AUCTION_ROOT + "**"); diff --git a/cometd-demo/src/main/java/org/webtide/demo/auction/Bidder.java b/cometd-demo/src/main/java/org/webtide/demo/auction/Bidder.java index 9826b31f64..666b74b3c1 100644 --- a/cometd-demo/src/main/java/org/webtide/demo/auction/Bidder.java +++ b/cometd-demo/src/main/java/org/webtide/demo/auction/Bidder.java @@ -16,6 +16,7 @@ package org.webtide.demo.auction; import java.util.Map; + import org.eclipse.jetty.util.ajax.JSON; import org.eclipse.jetty.util.ajax.JSON.Output; @@ -47,7 +48,6 @@ public void setUsername(String aUsername) { username = aUsername; } - @Override public boolean equals(Object obj) { if (obj == this) { diff --git a/cometd-demo/src/main/java/org/webtide/demo/auction/Item.java b/cometd-demo/src/main/java/org/webtide/demo/auction/Item.java index e065ef060a..e21b270395 100644 --- a/cometd-demo/src/main/java/org/webtide/demo/auction/Item.java +++ b/cometd-demo/src/main/java/org/webtide/demo/auction/Item.java @@ -16,6 +16,7 @@ package org.webtide.demo.auction; import java.util.Map; + import org.eclipse.jetty.util.ajax.JSON; import org.eclipse.jetty.util.ajax.JSON.Output; @@ -101,7 +102,6 @@ public int hashCode() { return id.hashCode(); } - @Override public Item clone() { try { diff --git a/cometd-demo/src/main/webapp/WEB-INF/jetty-logging.properties b/cometd-demo/src/main/webapp/WEB-INF/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-demo/src/main/webapp/WEB-INF/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-demo/src/main/webapp/WEB-INF/log4j2.properties b/cometd-demo/src/main/webapp/WEB-INF/log4j2.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-demo/src/main/webapp/WEB-INF/log4j2.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-demo/src/main/webapp/WEB-INF/web.xml b/cometd-demo/src/main/webapp/WEB-INF/web.xml index abf43cba89..f60618c482 100644 --- a/cometd-demo/src/main/webapp/WEB-INF/web.xml +++ b/cometd-demo/src/main/webapp/WEB-INF/web.xml @@ -15,7 +15,7 @@ cross-origin - org.eclipse.jetty.servlets.CrossOriginFilter + org.eclipse.jetty.ee10.servlets.CrossOriginFilter true @@ -76,7 +76,7 @@ oort - org.cometd.oort.OortMulticastConfigServlet + org.cometd.oort.jakarta.OortMulticastConfigServlet oort.url http://localhost:8080/cometd @@ -87,7 +87,7 @@ seti - org.cometd.oort.SetiServlet + org.cometd.oort.jakarta.SetiServlet 4 diff --git a/cometd-demo/src/test/java/org/cometd/demo/Demo.java b/cometd-demo/src/test/java/org/cometd/demo/Demo.java index 20fb48d128..0075862afb 100644 --- a/cometd-demo/src/test/java/org/cometd/demo/Demo.java +++ b/cometd-demo/src/test/java/org/cometd/demo/Demo.java @@ -18,7 +18,7 @@ import java.lang.management.ManagementFactory; import org.cometd.bayeux.server.BayeuxServer; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.ee10.servlet.DefaultServlet; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; diff --git a/cometd-demo/src/test/resources/jetty-logging.properties b/cometd-demo/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-demo/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-demo/src/test/resources/log4j2-test.properties b/cometd-demo/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-demo/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-documentation/pom.xml b/cometd-documentation/pom.xml index 5ea9ba72f3..15dfe6d5b1 100644 --- a/cometd-documentation/pom.xml +++ b/cometd-documentation/pom.xml @@ -83,7 +83,7 @@ org.cometd.java - cometd-java-oort + cometd-java-oort-common ${project.version} diff --git a/cometd-documentation/src/main/asciidoc/java_json.adoc b/cometd-documentation/src/main/asciidoc/java_json.adoc index feae3089fe..c867e27e03 100644 --- a/cometd-documentation/src/main/asciidoc/java_json.adoc +++ b/cometd-documentation/src/main/asciidoc/java_json.adoc @@ -79,7 +79,7 @@ For example: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet jsonContext diff --git a/cometd-documentation/src/main/asciidoc/java_oort.adoc b/cometd-documentation/src/main/asciidoc/java_oort.adoc index 4ed973366a..8e19f4b05d 100644 --- a/cometd-documentation/src/main/asciidoc/java_oort.adoc +++ b/cometd-documentation/src/main/asciidoc/java_oort.adoc @@ -108,7 +108,7 @@ You can configure the automatic discovery mechanism either via code, or by confi cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -119,7 +119,7 @@ You can configure the automatic discovery mechanism either via code, or by confi oort - org.cometd.oort.OortMulticastConfigServlet + org.cometd.oort.jakarta.OortMulticastConfigServletorg.cometd.oort.jakarta.OortMulticastConfigServlet 2 oort.url @@ -227,7 +227,7 @@ You can accomplish the static discovery configuration either via code, or by con cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -238,7 +238,7 @@ You can accomplish the static discovery configuration either via code, or by con oort - org.cometd.oort.OortStaticConfigServlet + org.cometd.oort.jakarta.OortStaticConfigServletorg.cometd.oort.jakarta.OortStaticConfigServlet 2 oort.url @@ -279,7 +279,7 @@ To make the Oort node part of the Oort cluster, you can configure the `oort.clou cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -290,7 +290,7 @@ To make the Oort node part of the Oort cluster, you can configure the `oort.clou oort - org.cometd.oort.OortStaticConfigServlet + org.cometd.oort.jakarta.OortStaticConfigServletorg.cometd.oort.jakarta.OortStaticConfigServlet 2 oort.url @@ -414,7 +414,7 @@ You accomplish this by configuring the Oort configuration servlets to set the `o cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -425,7 +425,7 @@ You accomplish this by configuring the Oort configuration servlets to set the `o oort - org.cometd.oort.OortMulticastConfigServlet + org.cometd.oort.jakarta.OortMulticastConfigServletorg.cometd.oort.jakarta.OortMulticastConfigServlet 2 oort.url diff --git a/cometd-documentation/src/main/asciidoc/java_oort_object.adoc b/cometd-documentation/src/main/asciidoc/java_oort_object.adoc index cf9ffd22d6..368761db8f 100644 --- a/cometd-documentation/src/main/asciidoc/java_oort_object.adoc +++ b/cometd-documentation/src/main/asciidoc/java_oort_object.adoc @@ -189,7 +189,7 @@ Finally, you must specify class `MyCustomJSONContextClient` as the `jsonContext` ... oort-config - org.cometd.oort.OortMulticastConfigServlet + org.cometd.oort.jakarta.OortMulticastConfigServlet oort.url http://localhost:8080/cometd diff --git a/cometd-documentation/src/main/asciidoc/java_oort_seti.adoc b/cometd-documentation/src/main/asciidoc/java_oort_seti.adoc index ce76f1c4d8..fab10bbd69 100644 --- a/cometd-documentation/src/main/asciidoc/java_oort_seti.adoc +++ b/cometd-documentation/src/main/asciidoc/java_oort_seti.adoc @@ -25,7 +25,7 @@ A configuration example follows: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -36,7 +36,7 @@ A configuration example follows: oort - org.cometd.oort.OortStaticConfigServlet + org.cometd.oort.jakarta.OortStaticConfigServlet oort.url http://host:port/context/cometd @@ -46,7 +46,7 @@ A configuration example follows: seti - org.cometd.oort.SetiServlet + org.cometd.oort.jakarta.SetiServletorg.cometd.oort.jakarta.SetiServlet 3 diff --git a/cometd-documentation/src/main/asciidoc/java_server_configuration.adoc b/cometd-documentation/src/main/asciidoc/java_server_configuration.adoc index 8325b45072..57f1e64402 100644 --- a/cometd-documentation/src/main/asciidoc/java_server_configuration.adoc +++ b/cometd-documentation/src/main/asciidoc/java_server_configuration.adoc @@ -17,7 +17,7 @@ If you followed xref:_primer[the primer], Maven has configured the `web.xml` fil cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet timeout 60000 @@ -255,7 +255,7 @@ Furthermore, a cross-domain deployment may require a more advanced configuration [[_java_server_configuration_advanced_cross_origin_filter]] ====== Configuring the `CrossOriginFilter` -Independently of the Servlet Container you are using, Jetty provides a standard, portable, `org.eclipse.jetty.servlets.CrossOriginFilter`. +Independently of the Servlet Container you are using, Jetty provides a standard, portable, `org.eclipse.jetty.ee10.servlets.CrossOriginFilter`. This filter implements the https://www.w3.org/TR/access-control/[Cross-Origin Resource Sharing] specification, and allows recent browsers that implement it to perform cross-domain JavaScript requests (see also xref:_javascript_transports[the JavaScript transports section]). Here is an example of `web.xml` configuration for the `CrossOriginFilter`: @@ -270,7 +270,7 @@ Here is an example of `web.xml` configuration for the `CrossOriginFilter`: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet timeout 60000 @@ -285,7 +285,7 @@ Here is an example of `web.xml` configuration for the `CrossOriginFilter`: cross-origin - org.eclipse.jetty.servlets.CrossOriginFilter + org.eclipse.jetty.ee10.servlets.CrossOriginFilter true @@ -336,7 +336,7 @@ For example: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true <2> @@ -347,7 +347,7 @@ For example: cross-origin - org.eclipse.jetty.servlets.CrossOriginFilter + org.eclipse.jetty.ee10.servlets.CrossOriginFilter true <2> diff --git a/cometd-documentation/src/main/asciidoc/java_server_services_integration.adoc b/cometd-documentation/src/main/asciidoc/java_server_services_integration.adoc index 1648d39783..4b85a1353b 100644 --- a/cometd-documentation/src/main/asciidoc/java_server_services_integration.adoc +++ b/cometd-documentation/src/main/asciidoc/java_server_services_integration.adoc @@ -22,7 +22,7 @@ Here is a sample `web.xml`: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true @@ -70,7 +70,7 @@ Here is a sample `web.xml` file: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 true diff --git a/cometd-documentation/src/main/asciidoc/java_server_services_integration_spring.adoc b/cometd-documentation/src/main/asciidoc/java_server_services_integration_spring.adoc index f34397126f..e4c9e6e9b1 100644 --- a/cometd-documentation/src/main/asciidoc/java_server_services_integration_spring.adoc +++ b/cometd-documentation/src/main/asciidoc/java_server_services_integration_spring.adoc @@ -24,7 +24,7 @@ The `web.xml` file is as follows: cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet true @@ -103,10 +103,10 @@ Below you can find a Spring's `applicationContext.xml` that configures the `Baye - + - + @@ -121,7 +121,7 @@ Below you can find a Spring's `applicationContext.xml` that configures the `Baye [NOTE] ==== When configuring the `BayeuxServer` transports, you need to explicitly specify all the transports you want, included the default transports that you do not need to specify when configuring a `BayeuxServer` using the `CometDServlet`. -The order of the transports is important, and you want the `WebSocketTransport` to be the first of the list, followed by at least the `JSONTransport` (also known as the "long-polling" transport) as a fallback. +The order of the transports is important, and you want the `WebSocketTransport` to be the first of the list, followed by at least the `ServletJSONTransport` (also known as the "long-polling" transport) as a fallback. ==== ===== Annotation Based Spring Configuration diff --git a/cometd-documentation/src/main/asciidoc/java_server_transports.adoc b/cometd-documentation/src/main/asciidoc/java_server_transports.adoc index 82b0fb2a78..0ac3f24438 100644 --- a/cometd-documentation/src/main/asciidoc/java_server_transports.adoc +++ b/cometd-documentation/src/main/asciidoc/java_server_transports.adoc @@ -20,10 +20,12 @@ These two transports are automatically configured in the `BayeuxServer` instance For the `long-polling` transport there exist two implementations: -* `org.cometd.server.http.AsyncJSONTransport`, which uses Servlet 3.1 non-blocking I/O and it is only available when the CometD web application is deployed to Servlet Containers that support Servlet 3.1 -* `org.cometd.server.http.JSONTransport`, which depends on Servlet 3.0 and uses blocking I/O +* `org.cometd.server.servlet.transport.AsyncJSONTransport`, which uses Servlet 3.1 non-blocking I/O and it is only available when the CometD web application is deployed to Servlet Containers that support Servlet 3.1 +// TODO: fix this referring to Jetty Handlers. +* `org.cometd.server.handler.transport.AsyncJSONTransport`, which depends on Servlet 3.0 and uses blocking I/O -The CometD server tries to lookup the presence of Servlet 3.1 via reflection on startup; if it is available, then `AsyncJSONTransport` is preferred over `JSONTransport`, as it is more scalable in the case of a large number of clients because it uses non-blocking I/O. +// TODO: fix this paragraph. +The CometD server tries to lookup the presence of Servlet 3.1 via reflection on startup; if it is available, then `ServletJSONTransport` is preferred over `JSONTransport`, as it is more scalable in the case of a large number of clients because it uses non-blocking I/O. For the `callback-polling` transport the implementation class is `org.cometd.server.http.JSONPTransport`. This transport uses blocking I/O and it is the least efficient; the CometD server only uses it when all other transports cannot be used. diff --git a/cometd-documentation/src/main/asciidoc/migration.adoc b/cometd-documentation/src/main/asciidoc/migration.adoc index 0991835867..42e9da9ab5 100644 --- a/cometd-documentation/src/main/asciidoc/migration.adoc +++ b/cometd-documentation/src/main/asciidoc/migration.adoc @@ -82,7 +82,7 @@ Only the WebSocket artifacts have changed. ... cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet 1 <3> true <4> @@ -535,7 +535,7 @@ API method name changes and parameter list changes. In CometD 5.0.x a new, more performant, non-blocking, JSON parser has been introduced with class `JSONContext.AsyncParser`. -`JSONContext.AsyncParser` is the default parser on the client when using `JettyHttpClientTransport`, and the default parser on the server when using `AsyncJSONTransport`. +`JSONContext.AsyncParser` is the default parser on the client when using `JettyHttpClientTransport`, and the default parser on the server when using `ServletJSONTransport`. If you are using the Jetty `JSONContext` implementation, and you have custom ``JSON.Convertor``s to convert your application classes to/from JSON, use the new APIs indicated in the following table. diff --git a/cometd-documentation/src/main/java/org/cometd/documentation/JSONDocs.java b/cometd-documentation/src/main/java/org/cometd/documentation/JSONDocs.java index e599ce5c78..e44080e029 100644 --- a/cometd-documentation/src/main/java/org/cometd/documentation/JSONDocs.java +++ b/cometd-documentation/src/main/java/org/cometd/documentation/JSONDocs.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.client.BayeuxClient; @@ -85,7 +86,6 @@ public static void portability(ServerMessage message) { Object field = data.get("array"); Object[] array = field instanceof List ? ((List)field).toArray() : (Object[])field; - // Expecting a long // WRONG @@ -130,7 +130,7 @@ public void toJSON(Object obj, JSON.Output out) { } @Override - public Object fromJSON(Map map) { + public Object fromJSON(Map map) { String id = (String)map.get("id"); String echo = (String)map.get("echo"); return new EchoInfo(id, echo); diff --git a/cometd-documentation/src/main/java/org/cometd/documentation/oort/OortObjectDocs.java b/cometd-documentation/src/main/java/org/cometd/documentation/oort/OortObjectDocs.java index 740c214d8a..bdc4150691 100644 --- a/cometd-documentation/src/main/java/org/cometd/documentation/oort/OortObjectDocs.java +++ b/cometd-documentation/src/main/java/org/cometd/documentation/oort/OortObjectDocs.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.common.JettyJSONContextClient; @@ -113,7 +114,7 @@ public void toJSON(Object obj, JSON.Output out) { } @Override - public Object fromJSON(Map object) { + public Object fromJSON(Map object) { String id = (String)object.get("id"); return new UserInfo(id); } diff --git a/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerContextDocs.java b/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerContextDocs.java index 1f6cb596b4..65569923d0 100644 --- a/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerContextDocs.java +++ b/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerContextDocs.java @@ -15,8 +15,11 @@ */ package org.cometd.documentation.server; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.HashSet; import java.util.Set; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxContext; import org.cometd.bayeux.server.BayeuxServer; @@ -36,7 +39,8 @@ public void canHandshake(BayeuxServer bayeuxServer, ServerSession session, Serve BayeuxContext context = message.getBayeuxContext(); // Get the remote address of the client. - String remoteAddress = context.getRemoteAddress().getHostString(); + SocketAddress remoteSocketAddress = context.getRemoteAddress(); + String remoteAddress = remoteSocketAddress instanceof InetSocketAddress inet ? inet.getHostName() : null; // Only allow clients from different remote addresses. diff --git a/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerServiceDocs.java b/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerServiceDocs.java index 1458a48334..8969121ca7 100644 --- a/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerServiceDocs.java +++ b/cometd-documentation/src/main/java/org/cometd/documentation/server/ServerServiceDocs.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import jakarta.inject.Inject; + import org.cometd.annotation.Listener; import org.cometd.annotation.Param; import org.cometd.annotation.Service; @@ -118,7 +119,6 @@ public void processGame(ServerSession remote, ServerMessage message) { } // end::dynamic[] - @SuppressWarnings("InnerClassMayBeStatic") // tag::annotatedService[] @org.cometd.annotation.Service("echoService") @@ -137,7 +137,6 @@ public InheritedEchoService(BayeuxServer bayeux) { } // end::inheritedService[] - @SuppressWarnings("InnerClassMayBeStatic") // tag::annotatedConfigure[] @Service("echoService") diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-common/src/main/java/module-info.java b/cometd-java/cometd-java-annotation/cometd-java-annotation-common/src/main/java/module-info.java index 59a81d1df4..00d3f8ed50 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-common/src/main/java/module-info.java +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-common/src/main/java/module-info.java @@ -17,6 +17,6 @@ exports org.cometd.annotation; requires jakarta.annotation; - requires jakarta.inject; + requires transitive jakarta.inject; requires org.slf4j; } diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/pom.xml b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/pom.xml index a93fcb078c..0044b1882c 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/pom.xml +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/pom.xml @@ -22,7 +22,7 @@ org.cometd.java - cometd-java-server-common + cometd-java-server-http-jakarta ${project.version} diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/module-info.java b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/module-info.java index 0b697b1249..af98871e38 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/module-info.java +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/module-info.java @@ -18,7 +18,9 @@ requires jakarta.annotation; requires jakarta.inject; + requires transitive jakarta.servlet; requires transitive org.cometd.annotation; - requires transitive org.cometd.server; + requires transitive org.cometd.api.server; + requires transitive org.cometd.server.http.jakarta; requires org.slf4j; } diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/AnnotationCometDServlet.java b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/AnnotationCometDServlet.java index 8ab88bf7d1..a55f3cf858 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/AnnotationCometDServlet.java +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/AnnotationCometDServlet.java @@ -20,8 +20,7 @@ import jakarta.servlet.ServletException; import org.cometd.bayeux.server.BayeuxServer; -import org.cometd.server.CometDServlet; -import org.eclipse.jetty.util.Loader; +import org.cometd.server.http.jakarta.CometDServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,7 +53,7 @@ public class AnnotationCometDServlet extends CometDServlet { public void init() throws ServletException { super.init(); - processor = newServerAnnotationProcessor(getBayeux()); + processor = newServerAnnotationProcessor(getBayeuxServer()); String servicesParam = getInitParameter("services"); if (servicesParam != null && servicesParam.length() > 0) { @@ -86,7 +85,7 @@ protected Object processService(ServerAnnotationProcessor processor, String serv } protected Object newService(String serviceClassName) throws Exception { - Class serviceClass = Loader.loadClass(getClass(), serviceClassName); + Class serviceClass = Thread.currentThread().getContextClassLoader().loadClass(serviceClassName); return serviceClass.getConstructor().newInstance(); } diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/Configure.java b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/Configure.java index 34e1d9a989..161127b3e6 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/Configure.java +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-server/src/main/java/org/cometd/annotation/server/Configure.java @@ -47,5 +47,4 @@ * @return if true, then the configuration method is called even if it already exists */ boolean configureIfExists() default false; - } diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/pom.xml b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/pom.xml index 3cd07ece7a..fbdba25a32 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/pom.xml +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/pom.xml @@ -29,18 +29,6 @@ - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - org.cometd.java cometd-java-annotation-client diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/java/org/cometd/annotation/AbstractClientServerTest.java b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/java/org/cometd/annotation/AbstractClientServerTest.java index 5b92d476f8..99e246a0c0 100644 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/java/org/cometd/annotation/AbstractClientServerTest.java +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/java/org/cometd/annotation/AbstractClientServerTest.java @@ -19,7 +19,7 @@ import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -32,7 +32,7 @@ public abstract class AbstractClientServerTest { @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); protected Server server; protected String cometdURL; @@ -50,7 +50,6 @@ public void prepare() throws Exception { ServletContextHandler context = new ServletContextHandler("/"); server.setHandler(context); - // CometD servlet ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); cometdServletHolder.setInitParameter("timeout", "10000"); cometdServletHolder.setInitOrder(1); diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..0f46df10b8 --- /dev/null +++ b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,4 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG +#com.google.inject.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/log4j2-test.properties deleted file mode 100644 index 2265552fe2..0000000000 --- a/cometd-java/cometd-java-annotation/cometd-java-annotation-tests/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,19 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info - -logger.guice.name=com.google.inject -logger.guice.level=info diff --git a/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Bayeux.java b/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Bayeux.java index 7eadb45471..198b3b80ab 100644 --- a/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Bayeux.java +++ b/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Bayeux.java @@ -98,7 +98,7 @@ public static boolean isValidChannelId(String channelId) { } public static boolean isValidMessageId(String messageId) { - if (messageId.length() < 1) { + if (messageId.isEmpty()) { return false; } for (int i = 0; i < messageId.length(); ++i) { @@ -128,5 +128,8 @@ private static boolean isAllowed(char c) { default -> false; }; } + + private Validator() { + } } } diff --git a/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Promise.java b/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Promise.java index 882cb91e6f..9bbd665180 100644 --- a/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Promise.java +++ b/cometd-java/cometd-java-api/cometd-java-api-common/src/main/java/org/cometd/bayeux/Promise.java @@ -15,6 +15,7 @@ */ package org.cometd.bayeux; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -30,15 +31,7 @@ public interface Promise { *

Shared instance whose methods are implemented empty,

*

use {@link #noop()} to ease type inference.

*/ - static final Promise NOOP = new Promise<>() { - @Override - public void succeed(Object result) { - } - - @Override - public void fail(Throwable failure) { - } - }; + Promise NOOP = new Promise<>() {}; /** *

Callback to invoke when the operation succeeds.

@@ -146,4 +139,31 @@ public void fail(Throwable failure) { completeExceptionally(failure); } } + + /** + *

A wrapper for {@link Promise} instances.

+ * + * @param the type of the result value + */ + class Wrapper implements Promise { + private final Promise wrapped; + + public Wrapper(Promise wrapped) { + this.wrapped = Objects.requireNonNull(wrapped); + } + + public Promise getWrapped() { + return wrapped; + } + + @Override + public void succeed(W result) { + getWrapped().succeed(result); + } + + @Override + public void fail(Throwable failure) { + getWrapped().fail(failure); + } + } } diff --git a/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxContext.java b/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxContext.java index e4ba658ed2..acf3f69996 100644 --- a/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxContext.java +++ b/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxContext.java @@ -15,157 +15,103 @@ */ package org.cometd.bayeux.server; -import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.security.Principal; import java.util.List; import java.util.Locale; /** *

The Bayeux Context provides information about the current context of a Bayeux message.

- *

This information may be from an associated HTTP request, or a HTTP request used to - * originally establish the connection (for example in a websocket handshake).

+ *

This information may be from an associated HTTP request, or from a HTTP request originally + * used to establish the connection to the server (for example in a WebSocket upgrade).

*/ public interface BayeuxContext { /** - * @return The user Principal (if any) + * @return the user {@link Principal} (if any) */ Principal getUserPrincipal(); /** * @param role the role to check whether the user belongs to - * @return true if there is a known user and they are in the given role. + * @return true if there is a known user and they are in the given role */ boolean isUserInRole(String role); /** * @return the remote socket address */ - InetSocketAddress getRemoteAddress(); + SocketAddress getRemoteAddress(); /** * @return the local socket address */ - InetSocketAddress getLocalAddress(); + SocketAddress getLocalAddress(); /** - * Get a transport header.

- * Get a header for any current transport mechanism (eg HTTP request). - * For transports like websocket, the header may be from the initial handshake. - * - * @param name The name of the header - * @return The header value or null if no current transport mechanism or no such header. + * @param name the name of the request header + * @return the value of the header, or {@code null} if there is no such header */ String getHeader(String name); /** - * Get a multi valued transport header.

- * Get a header for any current transport mechanism (eg HTTP request). - * For transports like websocket, the header may be from the initial handshake. - * - * @param name The name of the header - * @return The header value or null if no current transport mechanism or no such header. + * @param name the name of the request header + * @return the values of the header, or {@code null} if no such header */ List getHeaderValues(String name); /** - * Get a transport parameter.

- * Get a parameter for any current transport mechanism (eg HTTP request). - * For transports like websocket, the parameter may be from the initial handshake. - * - * @param name The name of the parameter - * @return The parameter value or null if no current transport mechanism or no such parameter. + * @param name the name of the query parameter + * @return the value of the query parameter, or {@code null} if no such parameter */ String getParameter(String name); /** - * Get a multi valued transport parameter.

- * Get a parameter for any current transport mechanism (eg HTTP request). - * For transports like websocket, the parameter may be from the initial handshake. - * - * @param name The name of the parameter - * @return The parameter value or null if no current transport mechanism or no such parameter. + * @param name the name of the query parameter + * @return the values of the query parameter, or {@code null} if no such parameter */ List getParameterValues(String name); /** - * Get a transport cookie.

- * Get a cookie for any current transport mechanism (eg HTTP request). - * For transports like websocket, the cookie may be from the initial handshake. - * - * @param name The name of the cookie - * @return The cookie value or null if no current transport mechanism or no such cookie. + * @param name the name of the cookie + * @return the value of the cookie value, or {@code null} if no such cookie */ String getCookie(String name); /** - * Access the HTTP Session (if any) ID. - * The {@link ServerSession#getId()} should be used in preference to the HTTP Session. - * - * @return HTTP session ID or null - */ - String getHttpSessionId(); - - /** - * Access the HTTP Session (if any) attributes. - * The {@link ServerSession#getAttribute(String)} should be used in preference to the HTTP Session. - * - * @param name the attribute name - * @return The attribute value - */ - Object getHttpSessionAttribute(String name); - - /** - * Access the HTTP Session (if any) attributes. - * The {@link ServerSession#setAttribute(String, Object)} should be used in preference to the HTTP Session. - * - * @param name the attribute name - * @param value the attribute value - */ - void setHttpSessionAttribute(String name, Object value); - - /** - * Invalidate the HTTP Session. - * The {@link ServerSession#getId()} should be used in preference to the HTTP Session. + * @param name the context attribute name + * @return the context attribute value, or {@code null} if no such attribute */ - void invalidateHttpSession(); + Object getContextAttribute(String name); /** - * Access the Request (if any) attributes. - * - * @param name the attribute name - * @return The attribute value + * @param name the request attribute name + * @return the request attribute value, or {@code null} if no such attribute */ Object getRequestAttribute(String name); /** - * Access the ServletContext (if any) attributes. - * - * @param name the attribute name - * @return The attribute value - */ - Object getContextAttribute(String name); - - /** - * Access the ServletContext (if any) init parameter. + *

Returns an HTTP session attribute value.

+ *

{@link ServerSession#getAttribute(String)} should be used to retrieve + * attribute values in session scope.

* - * @param name the init parameter name - * @return The attribute value + * @param name the HTTP session attribute name + * @return the HTTP session attribute value, or {@code null} if no such attribute */ - String getContextInitParameter(String name); + Object getSessionAttribute(String name); /** - * @return the application context path + * @return the web application context path */ String getContextPath(); /** - * @return the full request URI complete with query string if present. + * @return the full request URI complete with query string if present */ String getURL(); /** - * @return the request Locales, in order of preference, or the default - * server Locale if the request Locales are missing. + * @return the request {@link Locale}s, in order of preference, or the default + * server {@link Locale} if the request does not specify locales */ List getLocales(); @@ -175,7 +121,7 @@ public interface BayeuxContext { String getProtocol(); /** - * @return whether the request was made over a secure channel + * @return whether the request was made over a secure transport */ boolean isSecure(); } diff --git a/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxServer.java b/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxServer.java index 87d00aadb8..2f95823723 100644 --- a/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxServer.java +++ b/cometd-java/cometd-java-api/cometd-java-api-server/src/main/java/org/cometd/bayeux/server/BayeuxServer.java @@ -16,6 +16,7 @@ package org.cometd.bayeux.server; import java.util.List; + import org.cometd.bayeux.Bayeux; import org.cometd.bayeux.MarkedReference; import org.cometd.bayeux.Promise; @@ -42,6 +43,9 @@ * like a client-side Bayeux session.

*/ public interface BayeuxServer extends Bayeux { + @Override + ServerTransport getTransport(String transport); + /** * ServletContext attribute name used to obtain the Bayeux object */ diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/pom.xml b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/pom.xml index ea11711d0c..8d377c8ced 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/pom.xml +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/pom.xml @@ -150,13 +150,8 @@ ${jackson-version}
- org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl + org.eclipse.jetty + jetty-slf4j-impl runtime
diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/java/org/cometd/benchmark/client/CometDLoadClient.java b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/java/org/cometd/benchmark/client/CometDLoadClient.java index 1b6836c5c5..57f0dbc96b 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/java/org/cometd/benchmark/client/CometDLoadClient.java +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/java/org/cometd/benchmark/client/CometDLoadClient.java @@ -66,7 +66,6 @@ import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; -import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.ee10.websocket.jakarta.client.JakartaWebSocketClientContainerProvider; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; @@ -83,6 +82,7 @@ import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.websocket.client.WebSocketClient; public class CometDLoadClient implements MeasureConverter { private static final String START_FIELD = "start"; @@ -305,7 +305,7 @@ public void run() throws Exception { } contextPath = value; } - String url = (tls ? "https" : "http") + "://" + host + ":" + port + contextPath + Config.SERVLET_PATH; + String url = (tls ? "https" : "http") + "://" + host + ":" + port + contextPath + Config.COMETD_PATH; String channel = this.channel; if (interactive) { diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/jetty-logging.properties b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/log4j2.properties b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/log4j2.properties deleted file mode 100644 index a4a001ec1c..0000000000 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-client/src/main/resources/log4j2.properties +++ /dev/null @@ -1,24 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -#appender.file.type=File -#appender.file.name=file -#appender.file.fileName=target/cometd_benchmark_client.log -#appender.file.append=false -#appender.file.layout.type=PatternLayout -#appender.file.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console -#rootLogger.appenderRef.file.ref=file - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-common/src/main/java/org/cometd/benchmark/Config.java b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-common/src/main/java/org/cometd/benchmark/Config.java index 6783e36aa5..ef030f1d4f 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-common/src/main/java/org/cometd/benchmark/Config.java +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-common/src/main/java/org/cometd/benchmark/Config.java @@ -19,7 +19,7 @@ public class Config { public static final String CONTEXT_PATH = "/cometd"; - public static final String SERVLET_PATH = "/cometd"; + public static final String COMETD_PATH = "/cometd"; public static final String ID_FIELD = "msg_id"; public static final String CHANNEL_PREFIX = "/bench/"; diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/pom.xml b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/pom.xml index 33aa74e6c9..22720afa4f 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/pom.xml +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/pom.xml @@ -84,6 +84,16 @@ cometd-java-server-common ${project.version} + + org.cometd.java + cometd-java-server-http-jakarta + ${project.version} + + + org.cometd.java + cometd-java-server-http-jetty + ${project.version} + org.cometd.java cometd-java-server-websocket-jakarta @@ -145,13 +155,8 @@ ${jackson-version} - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl + org.eclipse.jetty + jetty-slf4j-impl runtime diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/java/org/cometd/benchmark/server/CometDLoadServer.java b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/java/org/cometd/benchmark/server/CometDLoadServer.java index f73e5fdf5a..7fc518ed96 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/java/org/cometd/benchmark/server/CometDLoadServer.java +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/java/org/cometd/benchmark/server/CometDLoadServer.java @@ -17,7 +17,6 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; -import java.io.IOException; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.nio.file.Files; @@ -31,7 +30,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import jakarta.servlet.ServletContext; import org.HdrHistogram.Histogram; import org.HdrHistogram.Recorder; @@ -43,17 +41,17 @@ import org.cometd.server.AbstractServerTransport; import org.cometd.server.AbstractService; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; import org.cometd.server.JacksonJSONContextServer; import org.cometd.server.ext.AcknowledgedMessagesExtension; -import org.cometd.server.http.AsyncJSONTransport; -import org.cometd.server.http.JSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.TransportContext; +import org.cometd.server.http.jakarta.CometDServlet; +import org.cometd.server.http.jetty.CometDHandler; import org.cometd.server.websocket.common.AbstractWebSocketEndPoint; import org.cometd.server.websocket.common.AbstractWebSocketTransport; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.cometd.server.websocket.jetty.JettyWebSocketTransport; import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; -import org.eclipse.jetty.ee10.servlet.DefaultServlet; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; @@ -71,6 +69,7 @@ import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.toolchain.perf.HistogramSnapshot; import org.eclipse.jetty.toolchain.perf.MeasureConverter; @@ -78,8 +77,11 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.AutoLock; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler; public class CometDLoadServer { + private static final String MICROS = "\u00B5s"; + private final MonitoringQueuedThreadPool jettyThreadPool = new MonitoringQueuedThreadPool(0); private final MonitoringQueuedThreadPool cometdThreadPool = new MonitoringQueuedThreadPool(0); private final BayeuxServerImpl bayeuxServer = new BayeuxServerImpl(); @@ -90,7 +92,7 @@ public class CometDLoadServer { private boolean tls = false; private int selectors = Runtime.getRuntime().availableProcessors(); private int maxThreads = 256; - private String transports = "jakartaws,asynchttp"; + private String transport = "jakarta"; private boolean perMessageDeflate = false; private boolean statistics = true; private boolean latencies = true; @@ -117,7 +119,7 @@ private static void parseArguments(String[] args, CometDLoadServer server) { } else if (arg.startsWith("--maxThreads=")) { server.maxThreads = Integer.parseInt(arg.substring("--maxThreads=".length())); } else if (arg.startsWith("--transports=")) { - server.transports = arg.substring("--transports=".length()); + server.transport = arg.substring("--transports=".length()); } else if (arg.equals("--permessage-deflate")) { server.perMessageDeflate = true; } else if (arg.equals("--statistics")) { @@ -137,7 +139,7 @@ public void run() throws Exception { if (interactive) { System.err.printf("listen port [%d]: ", port); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(port); } port = Integer.parseInt(value); @@ -147,7 +149,7 @@ public void run() throws Exception { if (interactive) { System.err.printf("use tls [%b]: ", tls); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(tls); } tls = Boolean.parseBoolean(value); @@ -157,7 +159,7 @@ public void run() throws Exception { if (interactive) { System.err.printf("selectors [%d]: ", selectors); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(selectors); } selectors = Integer.parseInt(value); @@ -168,7 +170,7 @@ public void run() throws Exception { maxThreads = Integer.parseInt(System.getProperty("cometd.threads", String.valueOf(maxThreads))); System.err.printf("max threads [%d]: ", maxThreads); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(maxThreads); } maxThreads = Integer.parseInt(value); @@ -178,68 +180,61 @@ public void run() throws Exception { // The BayeuxServer executor uses PEC mode only. cometdThreadPool.setReservedThreads(0); - String availableTransports = "jakartaws,jettyws,http,asynchttp"; - String transports = this.transports; + boolean perMessageDeflate = this.perMessageDeflate; if (interactive) { - System.err.printf("transports (%s) [%s]: ", availableTransports, transports); + System.err.printf("enable permessage-deflate extension [%b]: ", perMessageDeflate); String value = console.readLine().trim(); - if (value.length() == 0) { - value = transports; - } - transports = value; - } - for (String token : transports.split(",")) { - String transport = token.trim(); - switch (transport) { - case "jakartaws" -> { - boolean perMessageDeflate = readPerMessageDeflate(transport, console); - WebSocketTransport serverTransport = new WebSocketTransport(bayeuxServer) { - @Override - protected void writeComplete(AbstractWebSocketEndPoint.Context context, List messages) { - messageLatencyExtension.complete(messages); - } - }; - serverTransport.setOption(AbstractWebSocketTransport.ENABLE_EXTENSION_PREFIX_OPTION + "permessage-deflate", perMessageDeflate); - bayeuxServer.addTransport(serverTransport); - } - case "jettyws" -> { - boolean perMessageDeflate = readPerMessageDeflate(transport, console); - JettyWebSocketTransport serverTransport = new JettyWebSocketTransport(bayeuxServer) { - @Override - protected void writeComplete(AbstractWebSocketEndPoint.Context context, List messages) { - messageLatencyExtension.complete(messages); - } - }; - serverTransport.setOption(AbstractWebSocketTransport.ENABLE_EXTENSION_PREFIX_OPTION + "permessage-deflate", perMessageDeflate); - bayeuxServer.addTransport(serverTransport); - } - case "http" -> { - bayeuxServer.addTransport(new JSONTransport(bayeuxServer) { - @Override - protected void writeComplete(Context context, List messages) { - messageLatencyExtension.complete(messages); - } - }); - } - case "asynchttp" -> { - bayeuxServer.addTransport(new AsyncJSONTransport(bayeuxServer) { - @Override - protected void writeComplete(Context context, List messages) { - messageLatencyExtension.complete(messages); - } - }); - } - default -> { - throw new IllegalArgumentException("Invalid transport: " + token); - } + if (value.isEmpty()) { + value = String.valueOf(perMessageDeflate); } + perMessageDeflate = Boolean.parseBoolean(value); } + String availableTransports = "jakarta | jetty"; + String transport = this.transport; + if (interactive) { + System.err.printf("transports (%s) [%s]: ", availableTransports, transport); + String value = console.readLine().trim(); + if (value.isEmpty()) { + value = transport; + } + transport = value; + } + AbstractWebSocketTransport wsTransport = switch (transport) { + case "jakarta" -> { + yield new WebSocketTransport(bayeuxServer) { + @Override + protected void writeComplete(AbstractWebSocketEndPoint.Context context, List messages) { + messageLatencyExtension.complete(messages); + } + }; + } + case "jetty" -> { + yield new JettyWebSocketTransport(bayeuxServer) { + @Override + protected void writeComplete(AbstractWebSocketEndPoint.Context context, List messages) { + messageLatencyExtension.complete(messages); + } + }; + } + default -> { + throw new IllegalArgumentException("Invalid transport: " + transport); + } + }; + wsTransport.setOption(AbstractWebSocketTransport.ENABLE_EXTENSION_PREFIX_OPTION + "permessage-deflate", perMessageDeflate); + bayeuxServer.addTransport(wsTransport); + bayeuxServer.addTransport(new JSONHttpTransport(bayeuxServer) { + @Override + protected void writeComplete(TransportContext context, List messages) { + messageLatencyExtension.complete(messages); + } + }); + boolean statistics = this.statistics; if (interactive) { System.err.printf("record statistics [%b]: ", statistics); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(statistics); } statistics = Boolean.parseBoolean(value); @@ -249,7 +244,7 @@ protected void writeComplete(Context context, List messages) { if (interactive) { System.err.printf("record latencies [%b]: ", latencies); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(latencies); } latencies = Boolean.parseBoolean(value); @@ -259,13 +254,13 @@ protected void writeComplete(Context context, List messages) { if (interactive) { System.err.printf("detect long requests [%b]: ", longRequests); String value = console.readLine().trim(); - if (value.length() == 0) { + if (value.isEmpty()) { value = String.valueOf(longRequests); } longRequests = Boolean.parseBoolean(value); } - // Setup JMX + // Setup JMX. MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); server.addBean(mbeanContainer); @@ -293,9 +288,9 @@ protected void writeComplete(Context context, List messages) { } ServerConnector connector = new ServerConnector(server, null, null, null, 1, selectors, factories); // Make sure the OS is configured properly for load testing; - // see http://cometd.org/documentation/howtos/loadtesting + // see http://cometd.org/documentation/howtos/loadtesting. connector.setAcceptQueueSize(2048); - // Make sure the server timeout on a TCP connection is large + // Make sure the server timeout on a TCP connection is large. connector.setIdleTimeout(Config.META_CONNECT_TIMEOUT + 10 * Config.MAX_NETWORK_DELAY); connector.setPort(port); server.addConnector(connector); @@ -320,35 +315,49 @@ protected void writeComplete(Context context, List messages) { handler = statisticsHandler; } - // Add more handlers if needed + // Add more handlers if needed. - ServletContextHandler context = new ServletContextHandler(Config.CONTEXT_PATH, ServletContextHandler.SESSIONS); - handler.setHandler(context); - context.getServletContext().setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); - context.setInitParameter(ServletContextHandler.MANAGED_ATTRIBUTES, BayeuxServer.ATTRIBUTE); + String cometdURLMapping = Config.COMETD_PATH + "/*"; + switch (transport) { + case "jakarta" -> { + ServletContextHandler context = new ServletContextHandler(Config.CONTEXT_PATH); + handler.setHandler(context); + context.getServletContext().setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); + context.setInitParameter(ServletContextHandler.MANAGED_ATTRIBUTES, BayeuxServer.ATTRIBUTE); - JakartaWebSocketServletContainerInitializer.configure(context, null); + JakartaWebSocketServletContainerInitializer.configure(context, null); - // Setup default servlet to serve static files - context.addServlet(DefaultServlet.class, "/"); + // Set up the CometDServlet. + CometDServlet cometServlet = new CometDServlet(); + ServletHolder cometdServletHolder = new ServletHolder(cometServlet); + context.addServlet(cometdServletHolder, cometdURLMapping); + } + case "jetty" -> { + ContextHandler context = new ContextHandler(Config.CONTEXT_PATH); + handler.setHandler(context); + context.getContext().setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); + context.setAttribute(ContextHandler.MANAGED_ATTRIBUTES, BayeuxServer.ATTRIBUTE); + + WebSocketUpgradeHandler wsHandler = WebSocketUpgradeHandler.from(server, context); + context.setHandler(wsHandler); - // Setup comet servlet - String cometdURLMapping = Config.SERVLET_PATH + "/*"; - CometDServlet cometServlet = new CometDServlet(); - ServletHolder cometdServletHolder = new ServletHolder(cometServlet); - context.addServlet(cometdServletHolder, cometdURLMapping); + wsHandler.setHandler(new CometDHandler()); + } + default -> { + throw new IllegalArgumentException("Invalid transport: " + transport); + } + } // Make sure the expiration timeout is large to avoid clients to timeout // This value must be several times larger than the client value // (e.g. 60 s on server vs 5 s on client) so that it's guaranteed that // it will be the client to dispose idle connections. bayeuxServer.setOption(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(10 * Config.MAX_NETWORK_DELAY)); - // Explicitly set the timeout value + // Explicitly set the timeout value. bayeuxServer.setOption(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(Config.META_CONNECT_TIMEOUT)); - // Use the faster JSON parser/generator + // Use the faster JSON parser/generator. bayeuxServer.setOption(AbstractServerTransport.JSON_CONTEXT_OPTION, JacksonJSONContextServer.class.getName()); - bayeuxServer.setOption("ws.cometdURLMapping", cometdURLMapping); - bayeuxServer.setOption(ServletContext.class.getName(), context.getServletContext()); + bayeuxServer.setOption(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, cometdURLMapping); bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); bayeuxServer.addExtension(messageLatencyExtension); @@ -360,19 +369,6 @@ protected void writeComplete(Context context, List messages) { new StatisticsService(this); } - private boolean readPerMessageDeflate(String transport, BufferedReader console) throws IOException { - boolean perMessageDeflate = this.perMessageDeflate; - if (interactive) { - System.err.printf("enable %s permessage-deflate extension [%b]: ", transport, perMessageDeflate); - String value = console.readLine().trim(); - if (value.length() == 0) { - value = String.valueOf(perMessageDeflate); - } - perMessageDeflate = Boolean.parseBoolean(value); - } - return perMessageDeflate; - } - public static class StatisticsService extends AbstractService { private final AutoLock lock = new AutoLock(); private final PlatformMonitor monitor = new PlatformMonitor(); @@ -507,7 +503,7 @@ private void onLongRequestDetected(long requestId, Request request, Thread threa formatStackFrames(stackFrames, builder); System.err.println("Request #" + requestId + " is too slow (> " + maxRequestTime + " ms)\n" + builder); long end = System.nanoTime(); - System.err.println("Request #" + requestId + " printed in " + TimeUnit.NANOSECONDS.toMicros(end - begin) + " \u00B5s"); + System.err.println("Request #" + requestId + " printed in " + TimeUnit.NANOSECONDS.toMicros(end - begin) + " " + MICROS); } catch (Exception x) { x.printStackTrace(); } @@ -581,7 +577,7 @@ private void print() { return h1; }); if (histogram.getTotalCount() > 0) { - System.err.println(new HistogramSnapshot(histogram, 20, "Requests - Latency", "\u00B5s", this)); + System.err.println(new HistogramSnapshot(histogram, 20, "Requests - Latency", MICROS, this)); } } @@ -629,7 +625,7 @@ private void print() { Histogram histogram = latencies.getIntervalHistogram(); if (histogram.getTotalCount() > 0) { System.err.println("========================================"); - System.err.println(new HistogramSnapshot(histogram, 20, "Messages - Processing", "\u00B5s", this)); + System.err.println(new HistogramSnapshot(histogram, 20, "Messages - Processing", MICROS, this)); } } } diff --git a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/resources/log4j2.properties b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/resources/log4j2.properties index 626ecd5bf0..6a0fcfb868 100644 --- a/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/resources/log4j2.properties +++ b/cometd-java/cometd-java-benchmark/cometd-java-benchmark-server/src/main/resources/log4j2.properties @@ -1,24 +1,3 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -#appender.file.type=File -#appender.file.name=file -#appender.file.fileName=target/cometd_benchmark_server.log -#appender.file.append=false -#appender.file.layout.type=PatternLayout -#appender.file.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console -#rootLogger.appenderRef.file.ref=file - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/BayeuxClient.java b/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/BayeuxClient.java index 95ad1eded6..499fea5473 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/BayeuxClient.java +++ b/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/BayeuxClient.java @@ -387,7 +387,9 @@ public boolean waitFor(long waitMs, State state, State... states) { waitForStates.addAll(List.of(states)); try (AutoLock ignored = lock.lock()) { - while (waitMs > 0) { + final long startNs = System.nanoTime(); + long elapsedMs = 0L; + while (true) { // This check is needed to avoid that we return from waitFor() too early, // when the state has been set, but its effects (like notifying listeners) // are not completed yet (issue #212). @@ -409,21 +411,23 @@ public boolean waitFor(long waitMs, State state, State... states) { } } + long delay = waitMs - elapsedMs; if (logger.isDebugEnabled()) { - logger.debug("Waiting {}ms for {}", waitMs, waitForStates); + logger.debug("Waiting {}ms for {}", delay, waitForStates); } - long start = System.nanoTime(); - if (sessionState.await(waitMs)) { + if (sessionState.await(delay)) { break; } - long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); + elapsedMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); if (logger.isDebugEnabled()) { - logger.debug("Waited {}/{}ms for {}, state is {}", elapsed, waitMs, waitForStates, sessionState.getState()); + logger.debug("Waited {}/{}ms for {}, state is {}", elapsedMs, waitMs, waitForStates, sessionState.getState()); } - waitMs -= elapsed; + if (waitMs - elapsedMs < 0) { + break; + } } return false; } @@ -1166,7 +1170,6 @@ public void reset() { } } - /** *

A strategy that increases the wait time linearly up to a maximum.

*/ diff --git a/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/transport/HttpClientTransport.java b/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/transport/HttpClientTransport.java index 3db1523df0..8e33b94f62 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/transport/HttpClientTransport.java +++ b/cometd-java/cometd-java-client/cometd-java-client-common/src/main/java/org/cometd/client/transport/HttpClientTransport.java @@ -15,24 +15,21 @@ */ package org.cometd.client.transport; -import java.io.IOException; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.CookieStore; import java.net.URI; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpCookieStore; +import org.eclipse.jetty.http.SetCookieParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class HttpClientTransport extends ClientTransport { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientTransport.class); + private final SetCookieParser cookieParser = SetCookieParser.newInstance(); private volatile HttpCookieStore cookieStore; @Deprecated @@ -57,66 +54,18 @@ protected List getCookies(URI uri) { } protected void storeCookies(URI uri, Map> headers) { - // TODO: change this old API that uses java.net to use Jetty 12 cookie APIs. - try { - Store store = new Store(); - CookieManager cookieManager = new CookieManager(store, CookiePolicy.ACCEPT_ALL); - cookieManager.put(uri, headers); - List cookies = store.cookies; - if (cookies != null) { - cookies.forEach(cookie -> cookieStore.add(uri, cookie)); + headers.forEach((key, value1) -> { + if ("set-cookie".equalsIgnoreCase(key)) { + value1.forEach(value -> { + HttpCookie cookie = cookieParser.parse(value); + if (cookie != null) { + cookieStore.add(uri, cookie); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Stored cookie {}", cookie); + } + } + }); } - } catch (IOException x) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Could not parse cookies", x); - } - } - } - - private static class Store implements CookieStore - { - private List cookies; - - @Override - public void add(URI uri, java.net.HttpCookie cookie) - { - String domain = cookie.getDomain(); - if ("localhost.local".equals(domain)) - cookie.setDomain("localhost"); - if (cookies == null) { - cookies = new ArrayList<>(); - } - cookies.add(HttpCookie.from(cookie)); - } - - @Override - public List get(URI uri) - { - throw new UnsupportedOperationException(); - } - - @Override - public List getCookies() - { - throw new UnsupportedOperationException(); - } - - @Override - public List getURIs() - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(URI uri, java.net.HttpCookie cookie) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll() - { - throw new UnsupportedOperationException(); - } + }); } } diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-okhttp/src/main/java/module-info.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-okhttp/src/main/java/module-info.java index 46429c07cf..749f3ba84e 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-okhttp/src/main/java/module-info.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-okhttp/src/main/java/module-info.java @@ -16,8 +16,8 @@ module org.cometd.client.http.okhttp { exports org.cometd.client.http.okhttp; - requires okhttp3; requires kotlin.stdlib; + requires transitive okhttp3; requires transitive org.cometd.client.http.common; requires org.slf4j; } diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/pom.xml b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/pom.xml index 730919f3ab..813182f82f 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/pom.xml +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/pom.xml @@ -15,18 +15,6 @@ - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - jakarta.servlet jakarta.servlet-api @@ -50,6 +38,12 @@ ${project.version} test + + org.cometd.java + cometd-java-server-http-jakarta + ${project.version} + test + org.eclipse.jetty jetty-io diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/BayeuxClientCallbacksTest.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/BayeuxClientCallbacksTest.java index 17aed936d2..4d28496c49 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/BayeuxClientCallbacksTest.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/BayeuxClientCallbacksTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.client.ClientSession; @@ -70,7 +71,6 @@ public boolean canHandshake(BayeuxServer server, ServerSession session, ServerMe } }); - BayeuxClient client = newBayeuxClient(); CountDownLatch successLatch = new CountDownLatch(1); diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/ClientServerTest.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/ClientServerTest.java index b5c69137e1..eeb239f1c2 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/ClientServerTest.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/ClientServerTest.java @@ -21,7 +21,7 @@ import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -37,7 +37,7 @@ public abstract class ClientServerTest { @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); protected final Logger logger = LoggerFactory.getLogger(getClass()); protected ServerConnector connector; @@ -63,7 +63,6 @@ protected void startServer(Map initParams, ConnectionFactory... context = new ServletContextHandler("/"); server.setHandler(context); - // CometD servlet ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); cometdServletHolder.setInitParameter("timeout", "10000"); cometdServletHolder.setInitOrder(1); diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JSONContextTest.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JSONContextTest.java index 26e1a0e1de..7c0d4a1364 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JSONContextTest.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JSONContextTest.java @@ -41,7 +41,7 @@ import org.cometd.server.JacksonJSONContextServer; import org.cometd.server.JettyJSONContextServer; import org.cometd.server.ServerMessageImpl; -import org.cometd.server.http.AsyncJSONTransport; +import org.cometd.server.http.JSONHttpTransport; import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.StringRequestContent; import org.eclipse.jetty.http.HttpMethod; @@ -99,7 +99,7 @@ public void testAsyncParser(Class jsonContextServerClass, Cla @Test public void testHandshakeMessageNoArray() throws Exception { Map serverOptions = new HashMap<>(); - serverOptions.put(BayeuxServerImpl.TRANSPORTS_OPTION, AsyncJSONTransport.class.getName()); + serverOptions.put(BayeuxServerImpl.TRANSPORTS_OPTION, JSONHttpTransport.class.getName()); // Only Jetty supports the lenient parsing tested here. serverOptions.put(AbstractServerTransport.JSON_CONTEXT_OPTION, JettyJSONContextServer.class.getName()); start(serverOptions); diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JacksonCustomSerializationTest.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JacksonCustomSerializationTest.java index 7313e2bdb7..7bc0f330fb 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JacksonCustomSerializationTest.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JacksonCustomSerializationTest.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.cometd.bayeux.Message; diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JettyHttpClientTransportTest.java b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JettyHttpClientTransportTest.java index e6c7f4e174..889180303e 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JettyHttpClientTransportTest.java +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/java/org/cometd/client/http/JettyHttpClientTransportTest.java @@ -47,7 +47,7 @@ public class JettyHttpClientTransportTest { @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); private HttpClient httpClient; diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-java/cometd-java-client/cometd-java-client-http/cometd-java-client-http-tests/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jakarta/pom.xml b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jakarta/pom.xml index b5a287dc8b..e6a53677b6 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jakarta/pom.xml +++ b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jakarta/pom.xml @@ -8,7 +8,7 @@ 4.0.0 cometd-java-client-websocket-jakarta - CometD :: Java :: Client :: WebSocket :: Jakarta + CometD :: Java :: Client :: WebSocket :: Jakarta EE10 diff --git a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jetty/src/main/java/org/cometd/client/websocket/jetty/JettyWebSocketTransport.java b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jetty/src/main/java/org/cometd/client/websocket/jetty/JettyWebSocketTransport.java index 1cb0e00f60..c0a3d5993d 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jetty/src/main/java/org/cometd/client/websocket/jetty/JettyWebSocketTransport.java +++ b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-jetty/src/main/java/org/cometd/client/websocket/jetty/JettyWebSocketTransport.java @@ -94,9 +94,7 @@ protected Delegate connect(String uri, TransportListener listener, List LOGGER.debug("Opening websocket session to {}", uri); } ClientUpgradeRequest request = new ClientUpgradeRequest(); - // TODO: remove this mangling when HttpCookieStore supports the "ws" scheme. - String mangledURI = uri.replaceFirst("^ws", "http"); - List cookies = getHttpCookieStore().match(URI.create(mangledURI)); + List cookies = getHttpCookieStore().match(URI.create(uri)); request.setCookies(cookies.stream().map(HttpCookie::asJavaNetHttpCookie).toList()); String protocol = getProtocol(); if (protocol != null) { diff --git a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-okhttp/src/main/java/module-info.java b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-okhttp/src/main/java/module-info.java index c2a68b7367..f7f258e002 100644 --- a/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-okhttp/src/main/java/module-info.java +++ b/cometd-java/cometd-java-client/cometd-java-client-websocket/cometd-java-client-websocket-okhttp/src/main/java/module-info.java @@ -16,8 +16,8 @@ module org.cometd.client.websocket.okhttp { exports org.cometd.client.websocket.okhttp; - requires okhttp3; requires kotlin.stdlib; + requires transitive okhttp3; requires transitive org.cometd.client.websocket.common; requires org.slf4j; } diff --git a/cometd-java/cometd-java-common/pom.xml b/cometd-java/cometd-java-common/pom.xml index 2667b61abc..c0544af946 100644 --- a/cometd-java/cometd-java-common/pom.xml +++ b/cometd-java/cometd-java-common/pom.xml @@ -54,18 +54,5 @@ ${jackson-version} true - - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - diff --git a/cometd-java/cometd-java-common/src/main/java/org/cometd/common/AsyncFoldLeft.java b/cometd-java/cometd-java-common/src/main/java/org/cometd/common/AsyncFoldLeft.java index 9f05ec35bb..4d35997bae 100644 --- a/cometd-java/cometd-java-common/src/main/java/org/cometd/common/AsyncFoldLeft.java +++ b/cometd-java/cometd-java-common/src/main/java/org/cometd/common/AsyncFoldLeft.java @@ -123,6 +123,9 @@ public static void reverseRun(List list, R zero, Operation opera run(new ReverseIterable<>(list), zero, operation, promise); } + private AsyncFoldLeft() { + } + /** *

The operation to invoke for each element.

* @@ -301,7 +304,6 @@ public void fail(Throwable x) { } } - private static class IndexedLoop extends AbstractLoop { private final IntFunction element; private final int size; diff --git a/cometd-java/cometd-java-common/src/main/java/org/cometd/common/JSONContext.java b/cometd-java/cometd-java-common/src/main/java/org/cometd/common/JSONContext.java index 665e06a04f..41548898ea 100644 --- a/cometd-java/cometd-java-common/src/main/java/org/cometd/common/JSONContext.java +++ b/cometd-java/cometd-java-common/src/main/java/org/cometd/common/JSONContext.java @@ -19,6 +19,7 @@ import java.nio.ByteBuffer; import java.text.ParseException; import java.util.List; + import org.cometd.bayeux.Message; /** diff --git a/cometd-java/cometd-java-common/src/test/java/org/cometd/common/Z85Test.java b/cometd-java/cometd-java-common/src/test/java/org/cometd/common/Z85Test.java index 8f37cf0e5c..071e4a7425 100644 --- a/cometd-java/cometd-java-common/src/test/java/org/cometd/common/Z85Test.java +++ b/cometd-java/cometd-java-common/src/test/java/org/cometd/common/Z85Test.java @@ -15,7 +15,6 @@ */ package org.cometd.common; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/cometd-java/cometd-java-common/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-common/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-common/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-common/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-common/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-java/cometd-java-common/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-examples/cometd-java-examples-embedded/src/main/java/org/cometd/examples/CometDDemo.java b/cometd-java/cometd-java-examples/cometd-java-examples-embedded/src/main/java/org/cometd/examples/CometDDemo.java index 88da89a3a4..6033af1be9 100644 --- a/cometd-java/cometd-java-examples/cometd-java-examples-embedded/src/main/java/org/cometd/examples/CometDDemo.java +++ b/cometd-java/cometd-java-examples/cometd-java-examples-embedded/src/main/java/org/cometd/examples/CometDDemo.java @@ -79,7 +79,6 @@ public static void main(String[] args) throws Exception { ServletHolder dftServlet = context.addServlet(DefaultServlet.class, "/"); dftServlet.setInitOrder(1); - // CometD servlet AnnotationCometDServlet cometdServlet = new AnnotationCometDServlet(); ServletHolder cometd = new ServletHolder(cometdServlet); context.addServlet(cometd, "/cometd/*"); @@ -95,7 +94,7 @@ public static void main(String[] args) throws Exception { server.start(); - BayeuxServer bayeux = cometdServlet.getBayeux(); + BayeuxServer bayeux = cometdServlet.getBayeuxServer(); bayeux.setSecurityPolicy(new DefaultSecurityPolicy()); // Demo lazy messages diff --git a/cometd-java/cometd-java-examples/pom.xml b/cometd-java/cometd-java-examples/pom.xml index 4ae46581a3..f9b2233ced 100644 --- a/cometd-java/cometd-java-examples/pom.xml +++ b/cometd-java/cometd-java-examples/pom.xml @@ -15,6 +15,7 @@ cometd-java-examples-embedded + diff --git a/cometd-java/cometd-java-oort/cometd-java-oort-common/pom.xml b/cometd-java/cometd-java-oort/cometd-java-oort-common/pom.xml new file mode 100644 index 0000000000..8083f88d3d --- /dev/null +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/pom.xml @@ -0,0 +1,41 @@ + + + + org.cometd.java + cometd-java-oort + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-oort-common + jar + CometD :: Java :: Oort :: Common + + + + org.cometd.java + cometd-java-server-common + ${project.version} + + + org.cometd.java + cometd-java-client-http-jetty + ${project.version} + + + org.cometd.java + cometd-java-client-websocket-jakarta + ${project.version} + + + org.eclipse.jetty + jetty-jmx + ${jetty-version} + true + + + org.slf4j + slf4j-api + + + diff --git a/cometd-java/cometd-java-oort/src/main/java/module-info.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/module-info.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/module-info.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/module-info.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Oort.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Oort.java similarity index 98% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Oort.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Oort.java index 7c2874a69c..bbd73381eb 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Oort.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Oort.java @@ -68,8 +68,6 @@ /** *

Oort is the cluster manager that links one CometD server to a set of other CometD servers.

- *

The Oort instance is created and configured by either {@link OortMulticastConfigServlet} or - * {@link OortStaticConfigServlet}.

*

This class maintains a collection of {@link OortComet} instances to each * CometD server, created by calls to {@link #observeComet(String)}.

*

The key configuration parameter is the Oort URL, which is @@ -78,9 +76,6 @@ *

Oort instances can be configured with a shared {@link #setSecret(String) secret}, which allows * the Oort instance to distinguish handshakes coming from remote clients from handshakes coming from * other Oort comets: the firsts may be subject to a stricter authentication policy than the seconds.

- * - * @see OortMulticastConfigServlet - * @see OortStaticConfigServlet */ @ManagedObject("CometD cloud node") public class Oort extends ContainerLifeCycle { @@ -311,7 +306,7 @@ public OortComet observeComet(String cometURL) { return _membership.observeComet(cometURL); } - protected OortComet newOortComet(String cometURL) { + public OortComet newOortComet(String cometURL) { Map options = new HashMap<>(2); options.put(ClientTransport.SCHEDULER_OPTION, _scheduler); @@ -522,7 +517,7 @@ public boolean isOortHandshake(Message handshake) { return b64LocalSecret.equals(b64RemoteSecret); } - protected Map newOortHandshakeFields(String cometURL, String oortAliasURL) { + public Map newOortHandshakeFields(String cometURL, String oortAliasURL) { Map fields = new HashMap<>(1); Map ext = new HashMap<>(1); fields.put(Message.EXT_FIELD, ext); diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortComet.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortComet.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortComet.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortComet.java index a3c5ad0aa2..a093946f6e 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortComet.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortComet.java @@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ScheduledExecutorService; + import org.cometd.bayeux.ChannelId; import org.cometd.bayeux.client.ClientSession; import org.cometd.bayeux.client.ClientSessionChannel; diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortContainer.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortContainer.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortContainer.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortContainer.java index 49b21c1702..1e6155b9e8 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortContainer.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortContainer.java @@ -21,6 +21,7 @@ import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortList.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortList.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortList.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortList.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortLong.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortLong.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortLong.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortLong.java index fdd0a88ebb..dcf6011c15 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortLong.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortLong.java @@ -16,6 +16,7 @@ package org.cometd.oort; import java.util.concurrent.atomic.AtomicLong; + import org.cometd.bayeux.server.LocalSession; import org.eclipse.jetty.util.component.AbstractLifeCycle; diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortLongMap.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortLongMap.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortLongMap.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortLongMap.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMap.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMap.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMap.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMap.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMembership.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMembership.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMembership.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMembership.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMulticastConfigurer.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMulticastConfigurer.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMulticastConfigurer.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortMulticastConfigurer.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObject.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObject.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObject.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObject.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObjectFactories.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObjectFactories.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObjectFactories.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObjectFactories.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObjectMergers.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObjectMergers.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortObjectMergers.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortObjectMergers.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortPrimaryLong.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortPrimaryLong.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortPrimaryLong.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortPrimaryLong.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortPrimaryService.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortPrimaryService.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortPrimaryService.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortPrimaryService.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortService.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortService.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortService.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortService.java index 3c2263ad35..78d10d9e6b 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortService.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortService.java @@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.LocalSession; diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortStringMap.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortStringMap.java similarity index 100% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortStringMap.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/OortStringMap.java diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Seti.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Seti.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Seti.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Seti.java index fd31f3df8f..b5b682324a 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/Seti.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/Seti.java @@ -73,8 +73,6 @@ * {@link #sendMessage(String, String, Object)} methods may be * used to send messages to user(s) anywhere in the Oort cluster * and Seti organizes the search in order to locate the user(s).

- * - * @see SetiServlet */ @ManagedObject("CometD cloud peer discovery component") public class Seti extends AbstractLifeCycle implements Dumpable { diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/jmx/OortMBean.java b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/jmx/OortMBean.java similarity index 99% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/jmx/OortMBean.java rename to cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/jmx/OortMBean.java index eafb409dfb..5782cb5542 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/jmx/OortMBean.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-common/src/main/java/org/cometd/oort/jmx/OortMBean.java @@ -17,6 +17,7 @@ import java.util.Set; import java.util.TreeSet; + import org.cometd.oort.Oort; import org.eclipse.jetty.jmx.ObjectMBean; import org.eclipse.jetty.util.annotation.ManagedAttribute; diff --git a/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/pom.xml b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/pom.xml new file mode 100644 index 0000000000..22edde4261 --- /dev/null +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/pom.xml @@ -0,0 +1,30 @@ + + + + org.cometd.java + cometd-java-oort + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-oort-jakarta + jar + CometD :: Java :: Oort :: Jakarta EE10 + + + + jakarta.servlet + jakarta.servlet-api + + + org.cometd.java + cometd-java-oort-common + ${project.version} + + + org.slf4j + slf4j-api + + + diff --git a/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/module-info.java b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/module-info.java new file mode 100644 index 0000000000..8f9cbee5f4 --- /dev/null +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/module-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +module org.cometd.oort.jakarta { + exports org.cometd.oort.jakarta; + + requires transitive jakarta.servlet; + requires transitive org.cometd.oort; + requires org.slf4j; +} diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortConfigServlet.java b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortConfigServlet.java similarity index 98% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortConfigServlet.java rename to cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortConfigServlet.java index 2e9819e669..a6a5fc761b 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortConfigServlet.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortConfigServlet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.oort; +package org.cometd.oort.jakarta; import java.util.ArrayList; import java.util.List; @@ -23,10 +23,13 @@ import jakarta.servlet.ServletException; import jakarta.servlet.UnavailableException; import jakarta.servlet.http.HttpServlet; + import org.cometd.bayeux.server.BayeuxServer; import org.cometd.client.BayeuxClient; import org.cometd.client.transport.ClientTransport; import org.cometd.common.JSONContext; +import org.cometd.oort.Oort; +import org.cometd.oort.OortComet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -221,7 +224,7 @@ private void joinCloud() { String[] patterns = channels.split(","); for (String channel : patterns) { channel = channel.trim(); - if (channel.length() > 0) { + if (!channel.isEmpty()) { oort.observeChannel(channel); } } diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMulticastConfigServlet.java b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortMulticastConfigServlet.java similarity index 98% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMulticastConfigServlet.java rename to cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortMulticastConfigServlet.java index 5dcade5b4b..207763c7c1 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortMulticastConfigServlet.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortMulticastConfigServlet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.oort; +package org.cometd.oort.jakarta; import java.net.InetAddress; import java.net.MulticastSocket; @@ -21,7 +21,10 @@ import java.util.ArrayList; import java.util.List; import jakarta.servlet.ServletConfig; + import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.oort.Oort; +import org.cometd.oort.OortMulticastConfigurer; /** *

This servlet initializes and configures an instance of the {@link Oort} diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortStaticConfigServlet.java b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortStaticConfigServlet.java similarity index 91% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortStaticConfigServlet.java rename to cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortStaticConfigServlet.java index 76288b083e..f187899e9c 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/OortStaticConfigServlet.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/OortStaticConfigServlet.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.oort; +package org.cometd.oort.jakarta; import jakarta.servlet.ServletConfig; import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.oort.Oort; +import org.cometd.oort.OortComet; /** *

This servlet initializes and configures an instance of the {@link Oort} @@ -40,11 +42,11 @@ public class OortStaticConfigServlet extends OortConfigServlet { @Override protected void configureCloud(ServletConfig config, Oort oort) { String cloud = config.getInitParameter(OORT_CLOUD_PARAM); - if (cloud != null && cloud.length() > 0) { + if (cloud != null && !cloud.isEmpty()) { String[] urls = cloud.split(","); for (String comet : urls) { comet = comet.trim(); - if (comet.length() > 0) { + if (!comet.isEmpty()) { OortComet oortComet = oort.observeComet(comet); if (oortComet == null) { throw new IllegalArgumentException("Invalid value for " + OORT_CLOUD_PARAM); diff --git a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/SetiServlet.java b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/SetiServlet.java similarity index 96% rename from cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/SetiServlet.java rename to cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/SetiServlet.java index f7b8ee7aad..f69538b704 100644 --- a/cometd-java/cometd-java-oort/src/main/java/org/cometd/oort/SetiServlet.java +++ b/cometd-java/cometd-java-oort/cometd-java-oort-jakarta/src/main/java/org/cometd/oort/jakarta/SetiServlet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.oort; +package org.cometd.oort.jakarta; import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; @@ -21,6 +21,9 @@ import jakarta.servlet.UnavailableException; import jakarta.servlet.http.HttpServlet; +import org.cometd.oort.Oort; +import org.cometd.oort.Seti; + /** *

This servlet initializes and configures and instance of the {@link Seti} * user mapper.

diff --git a/cometd-java/cometd-java-oort/pom.xml b/cometd-java/cometd-java-oort/pom.xml index 7fe407edec..6add488903 100644 --- a/cometd-java/cometd-java-oort/pom.xml +++ b/cometd-java/cometd-java-oort/pom.xml @@ -1,5 +1,5 @@ - + org.cometd.java cometd-java @@ -8,42 +8,11 @@ 4.0.0 cometd-java-oort - jar + pom CometD :: Java :: Oort - - - jakarta.servlet - jakarta.servlet-api - - - jakarta.websocket - jakarta.websocket-api - - - org.cometd.java - cometd-java-server-common - ${project.version} - - - org.cometd.java - cometd-java-client-http-jetty - ${project.version} - - - org.cometd.java - cometd-java-client-websocket-jakarta - ${project.version} - - - org.eclipse.jetty - jetty-jmx - ${jetty-version} - true - - - org.slf4j - slf4j-api - - + + cometd-java-oort-common + cometd-java-oort-jakarta + diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-common/pom.xml index 4ee4c7abde..ce856ee83e 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/pom.xml +++ b/cometd-java/cometd-java-server/cometd-java-server-common/pom.xml @@ -28,10 +28,6 @@ - - jakarta.servlet - jakarta.servlet-api - org.cometd.java cometd-java-api-server @@ -55,18 +51,6 @@ true - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - org.eclipse.jetty jetty-client @@ -79,16 +63,5 @@ ${jetty-version} test - - org.eclipse.jetty.ee10 - jetty-ee10-servlet - ${jetty-version} - test - - - org.awaitility - awaitility - test - diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/module-info.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/module-info.java index edc22e2c17..eb28945414 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/module-info.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/module-info.java @@ -18,10 +18,9 @@ exports org.cometd.server.authorizer; exports org.cometd.server.ext; exports org.cometd.server.filter; - exports org.cometd.server.http; exports org.cometd.server.jmx; + exports org.cometd.server.http; - requires transitive jakarta.servlet; requires transitive org.cometd.api.server; requires transitive org.cometd.common; requires org.slf4j; diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractServerTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractServerTransport.java index 7ec9e056f1..316735f2f2 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractServerTransport.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractServerTransport.java @@ -15,10 +15,10 @@ */ package org.cometd.server; -import java.io.BufferedReader; import java.io.IOException; import java.text.ParseException; import java.util.concurrent.atomic.AtomicLong; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerTransport; @@ -57,7 +57,7 @@ public abstract class AbstractServerTransport extends AbstractTransport implemen private JSONContextServer _jsonContext; private boolean _handshakeReconnect; private boolean _allowHandshakeDelivery; - private long _maxMessageSize; + private int _maxMessageSize; /** *

The constructor is passed the {@link BayeuxServerImpl} instance for @@ -138,7 +138,7 @@ public void setAllowMessageDeliveryDuringHandshake(boolean allow) { _allowHandshakeDelivery = allow; } - public long getMaxMessageSize() { + public int getMaxMessageSize() { return _maxMessageSize; } @@ -168,44 +168,14 @@ protected JSONContextServer getJSONContextServer() { return _jsonContext; } - protected ServerMessage.Mutable[] parseMessages(BufferedReader reader, boolean jsonDebug) throws ParseException, IOException { - if (jsonDebug || getMaxMessageSize() > 0) { - return parseMessages(read(reader)); - } else { - return _jsonContext.parse(reader); - } - } - public ServerMessage.Mutable[] parseMessages(String json) throws ParseException { return _jsonContext.parse(json); } - private String read(BufferedReader reader) throws IOException { - long maxMessageSize = getMaxMessageSize(); - StringBuilder builder = new StringBuilder(); - long total = 0; - char[] buffer = new char[1024]; - while (true) { - int read = reader.read(buffer); - if (read < 0) { - break; - } else { - if (maxMessageSize > 0) { - total += read; - if (total > maxMessageSize) { - throw new IOException("Max message size " + maxMessageSize + " exceeded"); - } - } - builder.append(buffer, 0, read); - } - } - return builder.toString(); - } - /** * @return the BayeuxServer object */ - public BayeuxServerImpl getBayeux() { + public BayeuxServerImpl getBayeuxServer() { return _bayeux; } @@ -244,7 +214,7 @@ protected void sweep() { } public void processReply(ServerSessionImpl session, ServerMessage.Mutable reply, Promise promise) { - getBayeux().extendReply(session, session, reply, promise); + getBayeuxServer().extendReply(session, session, reply, promise); } protected String toJSON(ServerMessage msg) { diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractService.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractService.java index 8334217d94..e9b7ee045c 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractService.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractService.java @@ -191,7 +191,7 @@ public void setSeeOwnPublishes(boolean seeOwnPublishes) { * are received on the channel * @see #removeService(String, String) */ - protected void addService(String channelName, String methodName) { + public void addService(String channelName, String methodName) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Mapping {}#{} to {}", _name, methodName, channelName); } @@ -240,7 +240,7 @@ protected void addService(String channelName, String methodName) { * @see #addService(String, String) * @see #removeService(String) */ - protected void removeService(String channelName, String methodName) { + public void removeService(String channelName, String methodName) { ServerChannel channel = _bayeux.getChannel(channelName); if (channel != null) { Invoker invoker = invokers.remove(methodName); @@ -255,7 +255,7 @@ protected void removeService(String channelName, String methodName) { * @see #addService(String, String) * @see #removeService(String, String) */ - protected void removeService(String channelName) { + public void removeService(String channelName) { ServerChannel channel = _bayeux.getChannel(channelName); if (channel != null) { for (Invoker invoker : invokers.values()) { diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/BayeuxServerImpl.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/BayeuxServerImpl.java index e82d30c39f..25432a8333 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/BayeuxServerImpl.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/BayeuxServerImpl.java @@ -39,7 +39,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.stream.Collectors; -import jakarta.servlet.http.HttpServletRequest; import org.cometd.bayeux.Bayeux; import org.cometd.bayeux.Channel; @@ -61,10 +60,6 @@ import org.cometd.bayeux.server.ServerSession; import org.cometd.bayeux.server.ServerTransport; import org.cometd.common.AsyncFoldLeft; -import org.cometd.server.http.AbstractHttpTransport; -import org.cometd.server.http.AsyncJSONTransport; -import org.cometd.server.http.JSONPTransport; -import org.cometd.server.http.JSONTransport; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; @@ -175,13 +170,17 @@ protected void doStop() throws Exception { _transports.clear(); _allowedTransports.clear(); _options.clear(); - removeBean(_scheduler.getReference()); - if (_scheduler.isMarked()) { - _scheduler = null; + if (_scheduler != null) { + removeBean(_scheduler.getReference()); + if (_scheduler.isMarked()) { + _scheduler = null; + } } - removeBean(_executor.getReference()); - if (_executor.isMarked()) { - _executor = null; + if (_executor != null) { + removeBean(_executor.getReference()); + if (_executor.isMarked()) { + _executor = null; + } } } @@ -218,13 +217,23 @@ protected void initializeServerTransports() { if (_transports.isEmpty()) { String option = (String)getOption(TRANSPORTS_OPTION); if (option == null) { - // Order is important, see #findHttpTransport() - ServerTransport transport = newWebSocketTransport(); + // Order is important: first websocket, then http. + ServerTransport transport; + transport = newWebSocketTransport(); + if (transport != null) { + addTransport(transport); + } + transport = newJSONTransport(); if (transport != null) { addTransport(transport); } - addTransport(newJSONTransport()); - addTransport(new JSONPTransport(this)); + transport = newJSONPTransport(); + if (transport != null) { + addTransport(transport); + } + if (_transports.isEmpty()) { + throw new IllegalArgumentException("No transport found"); + } } else { for (String className : option.split(",")) { ServerTransport transport = newServerTransport(className.trim()); @@ -232,10 +241,8 @@ protected void initializeServerTransports() { addTransport(transport); } } - if (_transports.isEmpty()) { - throw new IllegalArgumentException("Option '" + TRANSPORTS_OPTION + - "' does not contain a valid list of server transport class names"); + throw new IllegalArgumentException("Option '%s' does not contain a valid list of server transport class names".formatted(TRANSPORTS_OPTION)); } } } @@ -252,8 +259,7 @@ protected void initializeServerTransports() { } if (_allowedTransports.isEmpty()) { - throw new IllegalArgumentException("Option '" + ALLOWED_TRANSPORTS_OPTION + - "' does not contain at least one configured server transport name"); + throw new IllegalArgumentException("Option '%s' does not contain at least one configured server transport name".formatted(ALLOWED_TRANSPORTS_OPTION)); } } } @@ -279,7 +285,7 @@ private ServerTransport newWebSocketTransport() { ServerTransport transport = newServerTransport(transportClass); if (transport == null) { _logger.info("Jakarta WebSocket classes available, but " + transportClass + - " unavailable: Jakarta WebSocket transport disabled"); + " unavailable: Jakarta WebSocket transport disabled"); } return transport; } catch (Exception x) { @@ -289,11 +295,17 @@ private ServerTransport newWebSocketTransport() { private ServerTransport newJSONTransport() { try { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - loader.loadClass("jakarta.servlet.ReadListener"); - return new AsyncJSONTransport(this); + return newServerTransport("org.cometd.server.http.JSONHttpTransport"); } catch (Exception x) { - return new JSONTransport(this); + return null; + } + } + + private ServerTransport newJSONPTransport() { + try { + return newServerTransport("org.cometd.server.http.JSONPHttpTransport"); + } catch (Exception x) { + return null; } } @@ -527,7 +539,7 @@ public ServerSession getSession(String clientId) { return clientId == null ? null : _sessions.get(clientId); } - protected void addServerSession(ServerSessionImpl session, ServerMessage message) { + public void addServerSession(ServerSessionImpl session, ServerMessage message) { if (_logger.isDebugEnabled()) { _logger.debug("Adding {}", session); } @@ -711,7 +723,7 @@ private void handle1(ServerSessionImpl session, ServerMessage.Mutable message, P ServerMessage.Mutable reply = message.getAssociated(); if (session == null || session.isDisconnected() || - (!session.getId().equals(message.getClientId()) && !Channel.META_HANDSHAKE.equals(message.getChannel()))) { + (!session.getId().equals(message.getClientId()) && !Channel.META_HANDSHAKE.equals(message.getChannel()))) { unknownSession(reply); promise.succeed(reply); } else { @@ -1173,18 +1185,6 @@ public List getTransports() { return new ArrayList<>(_transports.values()); } - protected AbstractHttpTransport findHttpTransport(HttpServletRequest request) { - for (String transportName : _allowedTransports) { - ServerTransport serverTransport = getTransport(transportName); - if (serverTransport instanceof AbstractHttpTransport transport) { - if (transport.accept(request)) { - return transport; - } - } - } - return null; - } - @ManagedAttribute(value = "The transports allowed by this CometD server", readonly = true) @Override public List getAllowedTransports() { @@ -1270,7 +1270,7 @@ public void sweep() { } } - CompletableFuture asyncSweep() { + public CompletableFuture asyncSweep() { return _sweeper.asyncSweep(); } @@ -1292,13 +1292,11 @@ public void setDetailedDump(boolean detailedDump) { } @ManagedAttribute("The period, in milliseconds, of the sweeping activity performed by the server") - public long getSweepPeriod() - { + public long getSweepPeriod() { return _sweepPeriod; } - public void setSweepPeriod(long sweepPeriod) - { + public void setSweepPeriod(long sweepPeriod) { if (sweepPeriod < 0) { sweepPeriod = DEFAULT_SWEEP_PERIOD; } @@ -1306,13 +1304,11 @@ public void setSweepPeriod(long sweepPeriod) } @ManagedAttribute("The maximum number of threads that can be used by the sweeping activity performed by the server") - public int getSweepThreads() - { + public int getSweepThreads() { return _sweepThreads; } - public void setSweepThreads(int sweepThreads) - { + public void setSweepThreads(int sweepThreads) { if (sweepThreads < 1) { sweepThreads = DEFAULT_SWEEP_THREADS; } @@ -1593,53 +1589,56 @@ private CompletableFuture asyncSweep() { } return CompletableFuture.runAsync(BayeuxServerImpl.this::sweepTransports, getExecutor()) - .thenCompose(unused -> { - long now = System.nanoTime(); - sweeperInfo.transportSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); - if (_logger.isDebugEnabled()) { - _logger.debug("Swept transports, took {}ms", sweeperInfo.transportSweepDuration); - } - return runAsync(_channels.values(), serverChannel -> { - if (serverChannel.sweep()) - serverChannelSweepCounter.incrementAndGet(); - }); - }) - .thenCompose(unused -> { - long now = System.nanoTime(); - sweeperInfo.serverChannelSweepCount = serverChannelSweepCounter.get(); - sweeperInfo.serverChannelSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); - if (_logger.isDebugEnabled()) { - _logger.debug("Swept server channels, {} in {}ms", sweeperInfo.serverChannelSweepCount, sweeperInfo.serverChannelSweepDuration); - } - return runAsync(_sessions.values(), serverSession -> { - if (serverSession.sweep(now)) - serverSessionSweepCounter.incrementAndGet(); + .thenCompose(unused -> { + long now = System.nanoTime(); + sweeperInfo.transportSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); + if (_logger.isDebugEnabled()) { + _logger.debug("Swept transports, took {}ms", sweeperInfo.transportSweepDuration); + } + return runAsync(_channels.values(), serverChannel -> { + if (serverChannel.sweep()) { + serverChannelSweepCounter.incrementAndGet(); + } + }); + }) + .thenCompose(unused -> { + long now = System.nanoTime(); + sweeperInfo.serverChannelSweepCount = serverChannelSweepCounter.get(); + sweeperInfo.serverChannelSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); + if (_logger.isDebugEnabled()) { + _logger.debug("Swept server channels, {} in {}ms", sweeperInfo.serverChannelSweepCount, sweeperInfo.serverChannelSweepDuration); + } + return runAsync(_sessions.values(), serverSession -> { + if (serverSession.sweep(now)) { + serverSessionSweepCounter.incrementAndGet(); + } + }); + }) + .thenRun(() -> { + long now = System.nanoTime(); + sweeperInfo.serverSessionSweepCount = serverSessionSweepCounter.get(); + sweeperInfo.serverSessionSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); + sweeperInfo.sweepDurationNanos = now - beginNanoTime; + if (sweeperInfo.sweepDurationNanos >= _lastSweepInfo.sweepDurationNanos) { + _longestSweepInfo = sweeperInfo; + } + _lastSweepInfo = sweeperInfo; + if (_logger.isDebugEnabled()) { + _logger.debug("Swept server sessions, {} in {}ms", sweeperInfo.serverSessionSweepCount, sweeperInfo.serverSessionSweepDuration); + _logger.debug("End of async sweep in {}ns at {}", sweeperInfo.sweepDurationNanos, Instant.now()); + } }); - }) - .thenRun(() -> { - long now = System.nanoTime(); - sweeperInfo.serverSessionSweepCount = serverSessionSweepCounter.get(); - sweeperInfo.serverSessionSweepDuration = TimeUnit.NANOSECONDS.toMillis(now - previousNanoTime.getAndSet(now)); - sweeperInfo.sweepDurationNanos = now - beginNanoTime; - if (sweeperInfo.sweepDurationNanos >= _lastSweepInfo.sweepDurationNanos) { - _longestSweepInfo = sweeperInfo; - } - _lastSweepInfo = sweeperInfo; - if (_logger.isDebugEnabled()) { - _logger.debug("Swept server sessions, {} in {}ms", sweeperInfo.serverSessionSweepCount, sweeperInfo.serverSessionSweepDuration); - _logger.debug("End of async sweep in {}ns at {}", sweeperInfo.sweepDurationNanos, Instant.now()); - } - }); } /** *

Asynchronously run an action on every element of a collection.

*

This is equivalent to {@code CompletableFuture.runAsync(() -> elements.forEach(action), getExecutor())} but parallelized * up to {@link #getSweepThreads()} threads.

+ * * @param elements the collection of elements to act upon - * @param action the action to run on each entry of the collection + * @param action the action to run on each entry of the collection + * @param the type of the collection's elements * @return a CompletableFuture that completes when all the actions returned - * @param the type of the collection's elements */ private CompletableFuture runAsync(Collection elements, Consumer action) { int threadCount = getSweepThreads(); diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDRequest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDRequest.java new file mode 100644 index 0000000000..a1ff9b04f4 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDRequest.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +/** + *

An abstraction over HTTP requests.

+ *

This abstraction allows CometD to be independent + * from Servlet, or server-specific HTTP APIs.

+ */ +public interface CometDRequest { + /** + * @return the HTTP method + */ + String getMethod(); + + /** + * @return the HTTP protocol version + */ + String getProtocol(); + + /** + * @param name the query parameter name + * @return the values of the given query parameter + */ + String[] getParameterValues(String name); + + /** + * @return the charset of the request body + */ + String getCharacterEncoding(); + + /** + * @return the request cookies + */ + List getCookies(); + + /** + * @return the input to read the request body from + */ + Input getInput(); + + /** + * @param name the attribute name + * @return the value of the attribute with the given name, + * or {@code null} if not such attribute exists + */ + Object getAttribute(String name); + + /** + * @param name the attribute name + * @param value the attribute value + */ + void setAttribute(String name, Object value); + + /** + * @param name the cookie name + * @param value the cookie value + */ + record CometDCookie(String name, String value) { + } + + /** + *

The source of the request body.

+ */ + interface Input { + /** + *

Demands to invoke the given callback when request content bytes are available.

+ * + * @param demandCallback the callback to invoke when request content bytes are available + */ + void demand(Runnable demandCallback); + + /** + *

Reads request content bytes into a {@link Chunk}.

+ *

The returned {@link Chunk} can be:

+ *
    + *
  • {@code null}, if no request content bytes are available
  • + *
  • a possibly empty {@link Chunk} of request content bytes
  • + *
+ * + * @return a {@link Chunk} of request content bytes, + * or {@code null} if no request content bytes are available + * @throws IOException if the read fails + */ + Chunk read() throws IOException; + + /** + *

Request content bytes with the indication of whether they are the last.

+ */ + interface Chunk { + /** + *

A convenient {@link Chunk} constant indicating end-of-file.

+ */ + Chunk EOF = new Chunk() { + private static final ByteBuffer EMPTY = ByteBuffer.allocate(0); + + @Override + public ByteBuffer byteBuffer() { + return EMPTY; + } + + @Override + public boolean isLast() { + return true; + } + + @Override + public void release() { + } + + @Override + public String toString() { + return "%s@%x[EOF]".formatted(Chunk.class.getSimpleName(), hashCode()); + } + }; + + /** + * @return the {@link ByteBuffer} containing the request content bytes + */ + ByteBuffer byteBuffer(); + + /** + * @return whether this {@link Chunk} is the last + */ + boolean isLast(); + + /** + *

Releases this {@link Chunk} so its {@link #byteBuffer()} + * can be recycled.

+ */ + void release(); + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDResponse.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDResponse.java new file mode 100644 index 0000000000..aa9883bfb6 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDResponse.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server; + +import org.cometd.bayeux.Promise; + +/** + *

An abstraction over HTTP responses.

+ *

This abstraction allows CometD to be independent + * from Servlet, or server-specific HTTP APIs.

+ */ +public interface CometDResponse { + /** + *

Adds an HTTP header to this response.

+ * + * @param name the HTTP header name + * @param value the HTTP header value + */ + void addHeader(String name, String value); + + /** + * @param contentType the content type of the response body + */ + void setContentType(String contentType); + + /** + * @return the sink to write the response body to + */ + Output getOutput(); + + /** + *

The sink of the response body.

+ */ + interface Output { + /** + *

Writes the given response bytes, notifying the + * given promise when the write operation is complete.

+ * + * @param last whether the response bytes to write are the last + * @param bytes the response bytes to write + * @param promise the promise to notify when the write operation is complete + */ + void write(boolean last, byte[] bytes, Promise promise); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/HttpException.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/HttpException.java new file mode 100644 index 0000000000..b985f698e0 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/HttpException.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server; + +public class HttpException extends RuntimeException { + private final int code; + + public HttpException(int code, Throwable cause) { + super(cause); + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ServerSessionImpl.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ServerSessionImpl.java index ecd9162cf3..934e8c0be6 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ServerSessionImpl.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ServerSessionImpl.java @@ -368,7 +368,7 @@ private void notifyQueued(QueueListener listener, ServerSession session, ServerM } } - protected boolean handshake(ServerMessage.Mutable message) { + public boolean handshake(ServerMessage.Mutable message) { AbstractServerTransport transport = message == null ? null : (AbstractServerTransport)message.getServerTransport(); if (transport != null) { _maxQueue = transport.getOption(AbstractServerTransport.MAX_QUEUE_OPTION, -1); @@ -391,7 +391,7 @@ protected boolean handshake(ServerMessage.Mutable message) { } } - protected boolean connected() { + public boolean connected() { lock.lock(); try { if (_state == State.HANDSHAKEN || _state == State.CONNECTED) { @@ -719,7 +719,7 @@ public void scheduleExpiration(long defaultInterval, long defaultMaxInterval, lo } } - long getMetaConnectCycle() { + public long getMetaConnectCycle() { lock.lock(); try { return _scheduler.getMetaConnectCycle(); @@ -738,7 +738,7 @@ public void setMaxInterval(long maxInterval) { _maxInterval = maxInterval; } - long getIntervalTimestamp() { + public long getIntervalTimestamp() { return _expireTime; } diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ext/AcknowledgedMessagesSessionExtension.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ext/AcknowledgedMessagesSessionExtension.java index e684cfbff7..8b5150b1ed 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ext/AcknowledgedMessagesSessionExtension.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/ext/AcknowledgedMessagesSessionExtension.java @@ -237,7 +237,7 @@ private void notifyBatchReceive(ServerSession session, long batch) { } // Used only in tests. - BatchArrayQueue getBatchArrayQueue() { + public BatchArrayQueue getBatchArrayQueue() { return _queue; } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpScheduler.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpScheduler.java new file mode 100644 index 0000000000..fec787cc94 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpScheduler.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http; + +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.ServerMessage; +import org.cometd.server.CometDRequest; +import org.eclipse.jetty.util.thread.Scheduler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractHttpScheduler implements Runnable, AbstractHttpTransport.HttpScheduler { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractHttpScheduler.class); + + private final AtomicReference task = new AtomicReference<>(); + private final AbstractHttpTransport transport; + private final TransportContext context; + private final Promise promise; + private final ServerMessage.Mutable message; + + protected AbstractHttpScheduler(AbstractHttpTransport transport, TransportContext context, Promise promise, ServerMessage.Mutable message, long timeout) { + this.transport = transport; + this.context = context; + this.promise = promise; + this.message = message; + this.task.set(transport.getBayeuxServer().schedule(this, timeout)); + context.metaConnectCycle(transport.newMetaConnectCycle()); + } + + public TransportContext getContext() { + return context; + } + + public Promise getPromise() { + return promise; + } + + @Override + public ServerMessage.Mutable getMessage() { + return message; + } + + @Override + public long getMetaConnectCycle() { + return context.metaConnectCycle(); + } + + @Override + public void schedule() { + if (cancelTimeout()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Resuming suspended {} for {}", message, context.session()); + } + resume(false); + } + } + + @Override + public void cancel() { + if (cancelTimeout()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Cancelling suspended {} for {}", message, context.session()); + } + error(new TimeoutException()); + } + } + + @Override + public void destroy() { + cancel(); + } + + private boolean cancelTimeout() { + // Cannot rely on the return value of task.cancel() + // since it may be invoked when the task is in run() + // where cancellation is not possible (it's too late). + Scheduler.Task task = this.task.getAndSet(null); + if (task == null) { + return false; + } + task.cancel(); + return true; + } + + @Override + public void run() { + if (cancelTimeout()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Timing out suspended {} for {}", message, context.session()); + } + resume(true); + } + } + + private void resume(boolean timeout) { + transport.decBrowserId(context.session(), transport.isHTTP2(context.request())); + dispatch(timeout); + } + + protected abstract void dispatch(boolean timeout); + + protected void error(Throwable failure) { + CometDRequest request = context.request(); + transport.decBrowserId(context.session(), transport.isHTTP2(request)); + getPromise().fail(failure); + } + + @Override + public String toString() { + return String.format("%s@%x[cycle=%d]", getClass().getSimpleName(), hashCode(), getMetaConnectCycle()); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpTransport.java index b76cf8752a..8dbd844781 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpTransport.java +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractHttpTransport.java @@ -16,14 +16,9 @@ package org.cometd.server.http; import java.io.IOException; -import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; -import java.security.Principal; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -31,30 +26,24 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import jakarta.servlet.AsyncContext; -import jakarta.servlet.AsyncEvent; -import jakarta.servlet.AsyncListener; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxContext; +import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; +import org.cometd.bayeux.server.ServerTransport; import org.cometd.common.AsyncFoldLeft; import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.CometDRequest; +import org.cometd.server.CometDResponse; +import org.cometd.server.HttpException; import org.cometd.server.ServerMessageImpl; import org.cometd.server.ServerSessionImpl; -import org.eclipse.jetty.util.thread.Scheduler.Task; +import org.eclipse.jetty.util.IteratingCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +52,18 @@ * HTTP as transport or to initiate a transport connection.

*/ public abstract class AbstractHttpTransport extends AbstractServerTransport { + public static AbstractHttpTransport find(BayeuxServer bayeuxServer, CometDRequest request) { + for (String transportName : bayeuxServer.getAllowedTransports()) { + ServerTransport serverTransport = bayeuxServer.getTransport(transportName); + if (serverTransport instanceof AbstractHttpTransport transport) { + if (transport.accept(request)) { + return transport; + } + } + } + return null; + } + public final static String PREFIX = "long-polling"; public static final String JSON_DEBUG_OPTION = "jsonDebug"; public static final String MESSAGE_PARAM = "message"; @@ -78,6 +79,9 @@ public abstract class AbstractHttpTransport extends AbstractServerTransport { public final static String TRUST_CLIENT_SESSION_OPTION = "trustClientSession"; public final static String DUPLICATE_META_CONNECT_HTTP_RESPONSE_CODE_OPTION = "duplicateMetaConnectHttpResponseCode"; private static final Logger LOGGER = LoggerFactory.getLogger(AbstractHttpTransport.class); + private static final byte[] OPEN_BRACKET = new byte[]{'['}; + private static final byte[] COMMA = new byte[]{','}; + private static final byte[] CLOSE_BRACKET = new byte[]{']'}; private final ConcurrentMap> _sessions = new ConcurrentHashMap<>(); private final ConcurrentMap _browserMap = new ConcurrentHashMap<>(); @@ -113,10 +117,12 @@ public void init() { _http2MaxSessionsPerBrowser = getOption(HTTP2_MAX_SESSIONS_PER_BROWSER_OPTION, -1); _multiSessionInterval = getOption(MULTI_SESSION_INTERVAL_OPTION, 2000); _trustClientSession = getOption(TRUST_CLIENT_SESSION_OPTION, false); - _duplicateMetaConnectHttpResponseCode = getOption(DUPLICATE_META_CONNECT_HTTP_RESPONSE_CODE_OPTION, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + _duplicateMetaConnectHttpResponseCode = getOption(DUPLICATE_META_CONNECT_HTTP_RESPONSE_CODE_OPTION, 500); if (_duplicateMetaConnectHttpResponseCode < 400) { - throw new IllegalArgumentException("Option '" + DUPLICATE_META_CONNECT_HTTP_RESPONSE_CODE_OPTION + - "' must be greater or equal to 400, not " + _duplicateMetaConnectHttpResponseCode); + throw new IllegalArgumentException("Option '%s' must be greater or equal to 400, not %s".formatted( + DUPLICATE_META_CONNECT_HTTP_RESPONSE_CODE_OPTION, + _duplicateMetaConnectHttpResponseCode) + ); } } @@ -128,19 +134,61 @@ protected int getDuplicateMetaConnectHttpResponseCode() { return _duplicateMetaConnectHttpResponseCode; } - public abstract boolean accept(HttpServletRequest request); + public abstract boolean accept(CometDRequest request); + + public void handle(BayeuxContext bayeuxContext, CometDRequest request, CometDResponse response, Promise promise) { + promise = new Promise.Wrapper<>(promise) { + @Override + public void fail(Throwable failure) { + if (failure instanceof HttpException) { + super.fail(failure); + } else { + int code = failure instanceof TimeoutException ? getDuplicateMetaConnectHttpResponseCode() : 500; + super.fail(new HttpException(code, failure)); + } + } + }; + + TransportContext context = new TransportContext(bayeuxContext, request, response, promise); + handle(context); + } - public abstract void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException; + protected abstract void handle(TransportContext context); - protected abstract HttpScheduler suspend(Context context, Promise promise, ServerMessage.Mutable message, long timeout); + protected HttpScheduler suspend(TransportContext context, Promise promise, ServerMessage.Mutable message, long timeout) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Suspended {}", message); + } + context.scheduler(newHttpScheduler(context, promise, message, timeout)); + context.session().notifySuspended(message, timeout); + return context.scheduler(); + } - protected abstract void write(Context context, List messages, Promise promise); + protected HttpScheduler newHttpScheduler(TransportContext context, Promise promise, ServerMessage.Mutable reply, long timeout) { + return new HttpSchedulerImpl(this, context, promise, reply, timeout); + } - protected void processMessages(Context context, List messages, Promise promise) { + protected void write(TransportContext context, List messages) { + try { + // TODO: do not allocate a Writer every time, it can be reused. + Writer writer = new Writer(context, messages); + writer.iterate(); + } catch (Throwable x) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Exception while writing messages", x); + } + if (context.scheduleExpiration()) { + scheduleExpiration(context.session(), context.metaConnectCycle()); + } + context.promise().fail(x); + } + } + + protected void processMessages(TransportContext context, List messages) { if (messages.isEmpty()) { - promise.fail(new IOException("protocol violation")); + context.promise().fail(new IOException("protocol violation")); } else { - Collection sessions = findCurrentSessions(context.request); + Collection sessions = findCurrentSessions(context.request()); ServerMessage.Mutable message = messages.get(0); ServerSessionImpl session = findSession(sessions, message); if (LOGGER.isDebugEnabled()) { @@ -151,14 +199,13 @@ protected void processMessages(Context context, List mess session.startBatch(); } - context.messages = messages; - context.session = session; - context.bayeuxContext = new HttpContext(context.request); + context.messages(messages); + context.session(session); AsyncFoldLeft.run(messages, null, (result, item, loop) -> processMessage(context, (ServerMessageImpl)item, Promise.from(loop::proceed, loop::fail)), Promise.complete((r, x) -> { if (x == null) { - flush(context, promise); + flush(context); } else { - promise.fail(x); + context.promise().fail(x); } if (batch) { session.endBatch(); @@ -167,27 +214,27 @@ protected void processMessages(Context context, List mess } } - private void processMessage(Context context, ServerMessageImpl message, Promise promise) { + private void processMessage(TransportContext context, ServerMessageImpl message, Promise promise) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Processing {}", message); } message.setServerTransport(this); - message.setBayeuxContext(context.bayeuxContext); - ServerSessionImpl session = context.session; + message.setBayeuxContext(context.bayeuxContext()); + ServerSessionImpl session = context.session(); if (session != null) { session.setServerTransport(this); } String channel = message.getChannel(); if (Channel.META_HANDSHAKE.equals(channel)) { - if (context.messages.size() > 1) { + if (context.messages().size() > 1) { promise.fail(new IOException("bayeux protocol violation")); } else { processMetaHandshake(context, message, promise); } } else if (Channel.META_CONNECT.equals(channel)) { - boolean canSuspend = context.messages.size() == 1; + boolean canSuspend = context.messages().size() == 1; processMetaConnect(context, message, canSuspend, Promise.from(y -> resume(context, message, promise), promise::fail)); } else { processMessage1(context, message, promise); @@ -196,7 +243,7 @@ private void processMessage(Context context, ServerMessageImpl message, Promise< protected ServerSessionImpl findSession(Collection sessions, ServerMessage.Mutable message) { if (Channel.META_HANDSHAKE.equals(message.getChannel())) { - ServerSessionImpl session = getBayeux().newServerSession(); + ServerSessionImpl session = getBayeuxServer().newServerSession(); session.setAllowMessageDeliveryDuringHandshake(isAllowMessageDeliveryDuringHandshake()); return session; } @@ -214,27 +261,27 @@ protected ServerSessionImpl findSession(Collection sessions, } if (_trustClientSession) { - return (ServerSessionImpl)getBayeux().getSession(clientId); + return (ServerSessionImpl)getBayeuxServer().getSession(clientId); } return null; } - protected Collection findCurrentSessions(HttpServletRequest request) { - Cookie[] cookies = request.getCookies(); + protected Collection findCurrentSessions(CometDRequest request) { + List cookies = request.getCookies(); if (cookies != null) { - for (Cookie cookie : cookies) { - if (_browserCookieName.equals(cookie.getName())) { - return _sessions.get(cookie.getValue()); + for (CometDRequest.CometDCookie cookie : cookies) { + if (_browserCookieName.equals(cookie.name())) { + return _sessions.get(cookie.value()); } } } return null; } - private void processMetaHandshake(Context context, ServerMessage.Mutable message, Promise promise) { + private void processMetaHandshake(TransportContext context, ServerMessage.Mutable message, Promise promise) { handleMessage(context, message, Promise.from(reply -> { - ServerSessionImpl session = context.session; + ServerSessionImpl session = context.session(); if (reply.isSuccessful()) { String id = findBrowserId(context); if (id == null) { @@ -255,17 +302,17 @@ private void processMetaHandshake(Context context, ServerMessage.Mutable message } processReply(session, reply, Promise.from(r -> { if (r != null) { - context.replies.add(r); + context.replies().add(r); } - context.sendQueue = r != null && r.isSuccessful() && allowMessageDeliveryDuringHandshake(session); - context.scheduleExpiration = true; + context.sendQueue(r != null && r.isSuccessful() && allowMessageDeliveryDuringHandshake(session)); + context.scheduleExpiration(true); promise.succeed(null); - }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle, promise, x))); + }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle(), promise, x))); }, promise::fail)); } - private void processMetaConnect(Context context, ServerMessage.Mutable message, boolean canSuspend, Promise promise) { - ServerSessionImpl session = context.session; + private void processMetaConnect(TransportContext context, ServerMessage.Mutable message, boolean canSuspend, Promise promise) { + ServerSessionImpl session = context.session(); if (session != null) { // Cancel the previous scheduler to cancel any prior waiting /meta/connect. session.setScheduler(null); @@ -277,7 +324,7 @@ private void processMetaConnect(Context context, ServerMessage.Mutable message, if (session != null) { boolean maySuspend = !session.shouldSchedule(); if (canSuspend && maySuspend && reply.isSuccessful()) { - HttpServletRequest request = context.request; + CometDRequest request = context.request(); // Detect if we have multiple sessions from the same browser. boolean allowSuspendConnect = incBrowserId(session, isHTTP2(request)); if (allowSuspendConnect) { @@ -319,19 +366,19 @@ private void processMetaConnect(Context context, ServerMessage.Mutable message, if (proceed) { promise.succeed(null); } - }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle, promise, x))); + }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle(), promise, x))); } - private void processMessage1(Context context, ServerMessageImpl message, Promise promise) { + private void processMessage1(TransportContext context, ServerMessageImpl message, Promise promise) { handleMessage(context, message, Promise.from(y -> { - ServerSessionImpl session = context.session; + ServerSessionImpl session = context.session(); processReply(session, message.getAssociated(), Promise.from(reply -> { if (reply != null) { - context.replies.add(reply); + context.replies().add(reply); } boolean metaConnectDelivery = isMetaConnectDeliveryOnly() || session != null && session.isMetaConnectDeliveryOnly(); if (!metaConnectDelivery) { - context.sendQueue = true; + context.sendQueue(true); } // Leave scheduleExpiration unchanged. promise.succeed(null); @@ -339,29 +386,29 @@ private void processMessage1(Context context, ServerMessageImpl message, Promise }, promise::fail)); } - protected boolean isHTTP2(HttpServletRequest request) { + protected boolean isHTTP2(CometDRequest request) { return "HTTP/2.0".equals(request.getProtocol()); } - protected void flush(Context context, Promise promise) { + protected void flush(TransportContext context) { List messages = List.of(); - ServerSessionImpl session = context.session; - if (context.sendQueue && session != null) { - messages = session.takeQueue(context.replies); + ServerSessionImpl session = context.session(); + if (context.sendQueue() && session != null) { + messages = session.takeQueue(context.replies()); } if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Flushing {}, replies={}, messages={}", session, context.replies, messages); + LOGGER.debug("Flushing {}, replies={}, messages={}", session, context.replies(), messages); } - write(context, messages, promise); + write(context, messages); } - protected void resume(Context context, ServerMessage.Mutable message, Promise promise) { + protected void resume(TransportContext context, ServerMessage.Mutable message, Promise promise) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Resumed {}", message); } ServerMessage.Mutable reply = message.getAssociated(); - ServerSessionImpl session = context.session; + ServerSessionImpl session = context.session(); if (session != null) { Map advice = session.takeAdvice(this); if (advice != null) { @@ -374,12 +421,12 @@ protected void resume(Context context, ServerMessage.Mutable message, Promise { if (r != null) { - context.replies.add(r); + context.replies().add(r); } - context.sendQueue = true; - context.scheduleExpiration = true; + context.sendQueue(true); + context.scheduleExpiration(true); promise.succeed(null); - }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle, promise, x))); + }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle(), promise, x))); } private void scheduleExpirationAndFail(ServerSessionImpl session, long metaConnectCycle, Promise promise, Throwable x) { @@ -389,25 +436,14 @@ private void scheduleExpirationAndFail(ServerSessionImpl session, long metaConne promise.fail(x); } - protected void sendError(HttpServletRequest request, HttpServletResponse response, int code, Throwable failure) { - try { - request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, failure); - response.setStatus(code); - } catch (Throwable x) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("", x); - } - } - } - - protected String findBrowserId(Context context) { - return context.bayeuxContext.getCookie(_browserCookieName); + protected String findBrowserId(TransportContext context) { + return context.bayeuxContext().getCookie(_browserCookieName); } - protected String setBrowserId(Context context) { + protected String setBrowserId(TransportContext context) { StringBuilder builder = new StringBuilder(); while (builder.length() < 16) { - builder.append(Long.toString(getBayeux().randomLong(), 36)); + builder.append(Long.toString(getBayeuxServer().randomLong(), 36)); } builder.setLength(16); String browserId = builder.toString(); @@ -424,13 +460,13 @@ protected String setBrowserId(Context context) { if (_browserCookieHttpOnly) { builder.append("; HttpOnly"); } - if (context.request.isSecure() && _browserCookieSecure) { + if (context.bayeuxContext().isSecure() && _browserCookieSecure) { builder.append("; Secure"); } if (_browserCookieSameSite != null) { builder.append("; SameSite=").append(_browserCookieSameSite); } - context.response.addHeader("Set-Cookie", builder.toString()); + context.response().addHeader("Set-Cookie", builder.toString()); return browserId; } @@ -444,7 +480,7 @@ protected String setBrowserId(Context context) { * If false is returned, the count is not incremented. * @see #decBrowserId(ServerSessionImpl, boolean) */ - protected boolean incBrowserId(ServerSessionImpl session, boolean http2) { + public boolean incBrowserId(ServerSessionImpl session, boolean http2) { int maxSessionsPerBrowser = http2 ? _http2MaxSessionsPerBrowser : _maxSessionsPerBrowser; if (maxSessionsPerBrowser < 0) { return true; @@ -476,7 +512,7 @@ protected boolean incBrowserId(ServerSessionImpl session, boolean http2) { return result; } - protected void decBrowserId(ServerSessionImpl session, boolean http2) { + public void decBrowserId(ServerSessionImpl session, boolean http2) { int maxSessionsPerBrowser = http2 ? _http2MaxSessionsPerBrowser : _maxSessionsPerBrowser; String browserId = session.getBrowserId(); if (maxSessionsPerBrowser <= 0 || browserId == null) { @@ -498,23 +534,30 @@ protected void decBrowserId(ServerSessionImpl session, boolean http2) { } } - protected void handleJSONParseException(HttpServletRequest request, HttpServletResponse response, String json, Throwable failure) throws IOException { - LOGGER.warn("Could not parse JSON: " + json, failure); - sendError(request, response, HttpServletResponse.SC_BAD_REQUEST, failure); + protected void handleMessage(TransportContext context, ServerMessage.Mutable message, Promise promise) { + getBayeuxServer().handle(context.session(), message, promise); } - protected void handleMessage(Context context, ServerMessage.Mutable message, Promise promise) { - getBayeux().handle(context.session, message, promise); + protected void writePrepare(TransportContext context, Promise promise) { + context.response().setContentType("application/json"); + promise.succeed(null); } - protected AsyncContext getAsyncContext(HttpServletRequest request) { - try { - return request.getAsyncContext(); - } catch (Throwable x) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Could not retrieve AsyncContext for " + request, x); - } - return null; + protected void writeBegin(CometDResponse.Output output, Promise promise) { + output.write(false, OPEN_BRACKET, promise); + } + + protected void writeMessage(CometDResponse.Output output, ServerMessage message, Promise promise) { + output.write(false, toJSONBytes(message), promise); + } + + protected void writeEnd(CometDResponse.Output output, Promise promise) { + output.write(true, CLOSE_BRACKET, promise); + } + + protected void writeComplete(TransportContext context, List messages) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Messages/replies {}/{} written for {}", messages.size(), context.replies().size(), context.session()); } } @@ -551,7 +594,7 @@ protected void sweep() { } protected byte[] toJSONBytes(ServerMessage msg) { - ServerMessageImpl message = (ServerMessageImpl)(msg instanceof ServerMessageImpl ? msg : getBayeux().newMessage(msg)); + ServerMessageImpl message = (ServerMessageImpl)(msg instanceof ServerMessageImpl ? msg : getBayeuxServer().newMessage(msg)); byte[] bytes = message.getJSONBytes(); if (bytes == null) { bytes = toJSON(message).getBytes(StandardCharsets.UTF_8); @@ -559,301 +602,185 @@ protected byte[] toJSONBytes(ServerMessage msg) { return bytes; } - private static class HttpContext implements BayeuxContext { - final HttpServletRequest _request; - - private HttpContext(HttpServletRequest request) { - _request = request; - } - - @Override - public Principal getUserPrincipal() { - return _request.getUserPrincipal(); - } - - @Override - public boolean isUserInRole(String role) { - return _request.isUserInRole(role); - } - - @Override - public InetSocketAddress getRemoteAddress() { - return new InetSocketAddress(_request.getRemoteHost(), _request.getRemotePort()); - } + /** + *

A {@link Scheduler} for HTTP-based transports.

+ */ + public interface HttpScheduler extends Scheduler { + ServerMessage.Mutable getMessage(); + } - @Override - public InetSocketAddress getLocalAddress() { - return new InetSocketAddress(_request.getLocalName(), _request.getLocalPort()); + // TODO: coalesce with AbstractHttpScheduler + private static class HttpSchedulerImpl extends AbstractHttpScheduler { + private HttpSchedulerImpl(AbstractHttpTransport transport, TransportContext context, Promise promise, ServerMessage.Mutable message, long timeout) { + super(transport, context, promise, message, timeout); } @Override - public String getHeader(String name) { - return _request.getHeader(name); + protected void dispatch(boolean timeout) { + // Directly succeeding the callback to write messages and replies. + // Since the write is async, we will never block and thus never delay other sessions. + getContext().session().notifyResumed(getMessage(), timeout); + getPromise().succeed(null); } + } - @Override - public List getHeaderValues(String name) { - return Collections.list(_request.getHeaders(name)); - } + protected class Writer extends IteratingCallback implements Promise { + private final TransportContext context; + private final List messages; + private State state = State.PREPARE; + private int replyIndex; + private int messageIndex; + private boolean needsComma; - @Override - public String getParameter(String name) { - return _request.getParameter(name); + protected Writer(TransportContext context, List messages) { + this.context = context; + this.messages = messages; } @Override - public List getParameterValues(String name) { - return List.of(_request.getParameterValues(name)); - } + protected Action process() throws Throwable { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Processing write {} for messages/replies {}/{} for {}", state, messages.size(), context.replies().size(), context.session()); + } - @Override - public String getCookie(String name) { - Cookie[] cookies = _request.getCookies(); - if (cookies != null) { - for (Cookie c : cookies) { - if (name.equals(c.getName())) { - return c.getValue(); + CometDResponse.Output output = context.response().getOutput(); + return switch (state) { + case PREPARE -> { + state = State.BEGIN; + writePrepare(context, this); + yield Action.SCHEDULED; + } + case BEGIN -> { + state = Writer.State.HANDSHAKE; + writeBegin(output, this); + yield Action.SCHEDULED; + } + case HANDSHAKE -> { + state = Writer.State.MESSAGES; + writeHandshakeReply(output, this); + yield Action.SCHEDULED; + } + case MESSAGES -> { + if (writeMessages(output, this)) { + state = Writer.State.REPLIES; } + yield Action.SCHEDULED; } - } - return null; - } - - @Override - public String getHttpSessionId() { - HttpSession session = _request.getSession(false); - if (session != null) { - return session.getId(); - } - return null; + case REPLIES -> { + if (writeReplies(output, this)) { + state = Writer.State.END; + } + yield Action.SCHEDULED; + } + case END -> { + state = Writer.State.COMPLETE; + writeEnd(output, this); + yield Action.SCHEDULED; + } + case COMPLETE -> { + yield Action.SUCCEEDED; + } + }; } @Override - public Object getHttpSessionAttribute(String name) { - HttpSession session = _request.getSession(false); - if (session != null) { - return session.getAttribute(name); - } - return null; + public void succeed(Void result) { + succeeded(); } @Override - public void setHttpSessionAttribute(String name, Object value) { - HttpSession session = _request.getSession(false); - if (session != null) { - session.setAttribute(name, value); - } else { - throw new IllegalStateException("!session"); - } + public void fail(Throwable failure) { + failed(failure); } @Override - public void invalidateHttpSession() { - HttpSession session = _request.getSession(false); - if (session != null) { - session.invalidate(); - } + protected void onCompleteSuccess() { + context.promise().succeed(null); + writeComplete(context, messages); } @Override - public Object getRequestAttribute(String name) { - return _request.getAttribute(name); - } - - private ServletContext getServletContext() { - HttpSession s = _request.getSession(false); - if (s != null) { - return s.getServletContext(); - } else { - s = _request.getSession(true); - ServletContext servletContext = s.getServletContext(); - s.invalidate(); - return servletContext; + protected void onCompleteFailure(Throwable failure) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Failure writing messages", failure); } + // Start the interval timeout also in case of + // errors to ensure the session can be swept. + startExpiration(); + context.promise().fail(failure); } - @Override - public Object getContextAttribute(String name) { - return getServletContext().getAttribute(name); - } - - @Override - public String getContextInitParameter(String name) { - return getServletContext().getInitParameter(name); - } - - @Override - public String getContextPath() { - return _request.getContextPath(); - } - - @Override - public String getURL() { - StringBuffer url = _request.getRequestURL(); - String query = _request.getQueryString(); - if (query != null) { - url.append("?").append(query); + private void startExpiration() { + if (context.scheduleExpiration()) { + scheduleExpiration(context.session(), context.metaConnectCycle()); } - return url.toString(); } - @Override - public List getLocales() { - return Collections.list(_request.getLocales()); - } - - @Override - public String getProtocol() { - return _request.getProtocol(); - } - - @Override - public boolean isSecure() { - return _request.isSecure(); - } - } - - /** - *

A {@link Scheduler} for HTTP-based transports.

- */ - public interface HttpScheduler extends Scheduler { - public ServerMessage.Mutable getMessage(); - } - - protected abstract class LongPollScheduler implements Runnable, HttpScheduler, AsyncListener { - private final AtomicReference task = new AtomicReference<>(); - private final Context context; - private final Promise promise; - private final ServerMessage.Mutable message; - - protected LongPollScheduler(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - this.context = context; - this.promise = promise; - this.message = message; - this.task.set(getBayeux().schedule(this, timeout)); - context.metaConnectCycle = newMetaConnectCycle(); - AsyncContext asyncContext = getAsyncContext(context.request); - if (asyncContext != null) { - asyncContext.addListener(this); + private void writeHandshakeReply(CometDResponse.Output output, Promise promise) { + List replies = context.replies(); + if (replies.isEmpty()) { + promise.succeed(null); + return; } - } - - public Context getContext() { - return context; - } - - public Promise getPromise() { - return promise; - } - - @Override - public ServerMessage.Mutable getMessage() { - return message; - } - - @Override - public long getMetaConnectCycle() { - return context.metaConnectCycle; - } - - @Override - public void schedule() { - if (cancelTimeout()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Resuming suspended {} for {}", message, context.session); + ServerMessage.Mutable reply = replies.get(0); + if (Channel.META_HANDSHAKE.equals(reply.getChannel())) { + if (allowMessageDeliveryDuringHandshake(context.session()) && !messages.isEmpty()) { + reply.put("x-messages", messages.size()); } - resume(false); + getBayeuxServer().freeze(reply); + output.write(false, toJSONBytes(reply), promise); + needsComma = true; + ++replyIndex; + } else { + promise.succeed(null); } } - @Override - public void cancel() { - if (cancelTimeout()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Cancelling suspended {} for {}", message, context.session); + private boolean writeMessages(CometDResponse.Output output, Promise promise) { + int size = messages.size(); + if (messageIndex == size) { + // Start the interval timeout after writing the + // messages since they may take time to be written. + startExpiration(); + promise.succeed(null); + return true; + } else { + if (needsComma) { + needsComma = false; + output.write(false, COMMA, promise); + } else { + ServerMessage message = messages.get(messageIndex); + needsComma = true; + ++messageIndex; + writeMessage(output, message, promise); } - error(new TimeoutException()); - } - } - - @Override - public void destroy() { - cancel(); - } - - private boolean cancelTimeout() { - // Cannot rely on the return value of task.cancel() - // since it may be invoked when the task is in run() - // where cancellation is not possible (it's too late). - Task task = this.task.getAndSet(null); - if (task == null) { return false; } - task.cancel(); - return true; } - @Override - public void run() { - if (cancelTimeout()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Timing out suspended {} for {}", message, context.session); + private boolean writeReplies(CometDResponse.Output output, Promise promise) { + List replies = context.replies(); + int size = replies.size(); + if (replyIndex == size) { + promise.succeed(null); + return true; + } else { + ServerMessage.Mutable reply = replies.get(replyIndex); + if (needsComma) { + needsComma = false; + output.write(false, COMMA, promise); + } else { + getBayeuxServer().freeze(reply); + needsComma = replyIndex < size; + ++replyIndex; + output.write(false, toJSONBytes(reply), promise); } - resume(true); + return false; } } - private void resume(boolean timeout) { - decBrowserId(context.session, isHTTP2(context.request)); - dispatch(timeout); - } - - @Override - public void onStartAsync(AsyncEvent event) { - } - - @Override - public void onTimeout(AsyncEvent event) { - } - - @Override - public void onComplete(AsyncEvent asyncEvent) throws IOException { - } - - @Override - public void onError(AsyncEvent event) { - error(event.getThrowable()); - } - - protected abstract void dispatch(boolean timeout); - - private void error(Throwable failure) { - HttpServletRequest request = context.request; - decBrowserId(context.session, isHTTP2(request)); - promise.fail(failure); - } - - @Override - public String toString() { - return String.format("%s@%x[cycle=%d]", getClass().getSimpleName(), hashCode(), getMetaConnectCycle()); - } - } - - public static class Context { - protected final List replies = new ArrayList<>(); - public final HttpServletRequest request; - public final HttpServletResponse response; - protected List messages; - protected ServerSessionImpl session; - protected BayeuxContext bayeuxContext; - protected boolean sendQueue; - protected boolean scheduleExpiration; - protected HttpScheduler scheduler; - protected long metaConnectCycle; - - protected Context(HttpServletRequest request, HttpServletResponse response) { - this.request = request; - this.response = response; + private enum State { + PREPARE, BEGIN, HANDSHAKE, MESSAGES, REPLIES, END, COMPLETE } } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractStreamHttpTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractStreamHttpTransport.java deleted file mode 100644 index a5ee5bdab3..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AbstractStreamHttpTransport.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.http; - -import java.io.IOException; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; -import jakarta.servlet.AsyncContext; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.cometd.bayeux.Channel; -import org.cometd.bayeux.Promise; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.ServerSessionImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - *

The base class for HTTP transports that use blocking stream I/O.

- */ -public abstract class AbstractStreamHttpTransport extends AbstractHttpTransport { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractStreamHttpTransport.class); - private static final String CONTEXT_ATTRIBUTE = "org.cometd.transport.context"; - private static final String HEARTBEAT_TIMEOUT_ATTRIBUTE = "org.cometd.transport.heartbeat.timeout"; - - protected AbstractStreamHttpTransport(BayeuxServerImpl bayeux, String name) { - super(bayeux, name); - } - - @Override - public void handle(HttpServletRequest request, HttpServletResponse response) { - // API calls could be async, so we must be async in the request processing too. - AsyncContext asyncContext = request.startAsync(); - // Explicitly disable the timeout, to prevent - // that the timeout fires in case of slow reads. - asyncContext.setTimeout(0); - - Promise promise = new Promise<>() { - @Override - public void succeed(Void result) { - asyncContext.complete(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Handling successful"); - } - } - - @Override - public void fail(Throwable failure) { - int code = failure instanceof TimeoutException ? - getDuplicateMetaConnectHttpResponseCode() : - HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - sendError(request, response, code, failure); - asyncContext.complete(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Handling failed", failure); - } - } - }; - - Context context = (Context)request.getAttribute(CONTEXT_ATTRIBUTE); - if (context == null) { - process(new Context(request, response), promise); - } else { - ServerMessage.Mutable message = context.scheduler.getMessage(); - context.session.notifyResumed(message, (Boolean)request.getAttribute(HEARTBEAT_TIMEOUT_ATTRIBUTE)); - resume(context, message, Promise.from(y -> flush(context, promise), promise::fail)); - } - } - - protected void process(Context context, Promise promise) { - HttpServletRequest request = context.request; - try { - try { - ServerMessage.Mutable[] messages = parseMessages(request); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Parsed {} messages", messages == null ? -1 : messages.length); - } - if (messages != null) { - processMessages(context, List.of(messages), promise); - } else { - promise.succeed(null); - } - } catch (ParseException x) { - handleJSONParseException(request, context.response, x.getMessage(), x.getCause()); - promise.succeed(null); - } - } catch (Throwable x) { - promise.fail(x); - } - } - - @Override - protected HttpScheduler suspend(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Suspended {}", message); - } - HttpServletRequest request = context.request; - context.scheduler = newHttpScheduler(context, promise, message, timeout); - request.setAttribute(CONTEXT_ATTRIBUTE, context); - context.session.notifySuspended(message, timeout); - return context.scheduler; - } - - protected HttpScheduler newHttpScheduler(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - return new DispatchingLongPollScheduler(context, promise, message, timeout); - } - - protected abstract ServerMessage.Mutable[] parseMessages(HttpServletRequest request) throws IOException, ParseException; - - protected ServerMessage.Mutable[] parseMessages(String[] requestParameters) throws IOException, ParseException { - if (requestParameters == null || requestParameters.length == 0) { - throw new IOException("Missing '" + MESSAGE_PARAM + "' request parameter"); - } - - if (requestParameters.length == 1) { - return parseMessages(requestParameters[0]); - } - - List messages = new ArrayList<>(); - for (String batch : requestParameters) { - if (batch == null) { - continue; - } - ServerMessage.Mutable[] parsed = parseMessages(batch); - if (parsed != null) { - messages.addAll(List.of(parsed)); - } - } - return messages.toArray(new ServerMessage.Mutable[0]); - } - - @Override - protected void write(Context context, List messages, Promise promise) { - HttpServletRequest request = context.request; - HttpServletResponse response = context.response; - try { - ServerSessionImpl session = context.session; - List replies = context.replies; - int replyIndex = 0; - boolean needsComma = false; - ServletOutputStream output; - try { - output = beginWrite(request, response); - - // First message is always the handshake reply, if any. - if (replies.size() > 0) { - ServerMessage.Mutable reply = replies.get(0); - if (Channel.META_HANDSHAKE.equals(reply.getChannel())) { - if (allowMessageDeliveryDuringHandshake(session) && !messages.isEmpty()) { - reply.put("x-messages", messages.size()); - } - getBayeux().freeze(reply); - writeMessage(context, output, reply); - needsComma = true; - ++replyIndex; - } - } - - // Write the messages. - for (ServerMessage message : messages) { - if (needsComma) { - output.write(','); - } - needsComma = true; - writeMessage(context, output, message); - } - } finally { - // Start the interval timeout after writing the messages - // since they may take time to be written, even in case - // of exceptions to make sure the session can be swept. - if (context.scheduleExpiration) { - scheduleExpiration(session, context.metaConnectCycle); - } - } - - // Write the replies, if any. - while (replyIndex < replies.size()) { - ServerMessage.Mutable reply = replies.get(replyIndex); - if (needsComma) { - output.write(','); - } - needsComma = true; - getBayeux().freeze(reply); - writeMessage(context, output, reply); - ++replyIndex; - } - - endWrite(response, output); - promise.succeed(null); - writeComplete(context, messages); - } catch (Throwable x) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Failure writing messages", x); - } - promise.fail(x); - } - } - - protected void writeMessage(Context context, ServletOutputStream output, ServerMessage message) throws IOException { - writeMessage(context.response, output, context.session, message); - } - - protected void writeMessage(HttpServletResponse response, ServletOutputStream output, ServerSessionImpl session, ServerMessage message) throws IOException { - output.write(toJSONBytes(message)); - } - - protected abstract ServletOutputStream beginWrite(HttpServletRequest request, HttpServletResponse response) throws IOException; - - protected abstract void endWrite(HttpServletResponse response, ServletOutputStream output) throws IOException; - - protected void writeComplete(Context context, List messages) { - } - - protected class DispatchingLongPollScheduler extends LongPollScheduler { - public DispatchingLongPollScheduler(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - super(context, promise, message, timeout); - } - - @Override - protected void dispatch(boolean timeout) { - // We dispatch() when either we are suspended or timed out, instead of doing a write() + complete(). - // If we have to write a message to 10 clients, and the first client write() blocks, then we would - // be delaying the other 9 clients. - // By always calling dispatch() we allow each write to be on its own thread, and it may block without - // affecting other writes. - // Only with Servlet 3.1 and standard asynchronous I/O we would be able to do write() + complete() - // without blocking, and it will be much more efficient because there is no thread dispatching and - // there will be more mechanical sympathy. - HttpServletRequest request = getContext().request; - request.setAttribute(HEARTBEAT_TIMEOUT_ATTRIBUTE, timeout); - AsyncContext asyncContext = getAsyncContext(request); - if (asyncContext != null) { - asyncContext.dispatch(); - } - } - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AsyncJSONTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AsyncJSONTransport.java deleted file mode 100644 index e1c569da85..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/AsyncJSONTransport.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.http; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.text.ParseException; -import java.util.List; -import java.util.concurrent.TimeoutException; -import jakarta.servlet.AsyncContext; -import jakarta.servlet.ReadListener; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.ServletInputStream; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.WriteListener; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import org.cometd.bayeux.Channel; -import org.cometd.bayeux.Promise; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.common.BufferingJSONAsyncParser; -import org.cometd.common.JSONContext; -import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.JSONContextServer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AsyncJSONTransport extends AbstractHttpTransport { - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncJSONTransport.class); - private static final String PREFIX = "long-polling.json"; - private static final String NAME = "long-polling"; - private static final int BUFFER_CAPACITY = 512; - private static final ThreadLocal buffers = ThreadLocal.withInitial(() -> new byte[BUFFER_CAPACITY]); - - public AsyncJSONTransport(BayeuxServerImpl bayeux) { - super(bayeux, NAME); - setOptionPrefix(PREFIX); - } - - @Override - public boolean accept(HttpServletRequest request) { - return "POST".equalsIgnoreCase(request.getMethod()); - } - - @Override - public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException { - String encoding = request.getCharacterEncoding(); - if (encoding == null) { - encoding = "UTF-8"; - } - request.setCharacterEncoding(encoding); - AsyncContext asyncContext = request.startAsync(); - // Explicitly disable the timeout, to prevent - // that the timeout fires in case of slow reads. - asyncContext.setTimeout(0); - - Promise promise = new Promise<>() { - @Override - public void succeed(Void result) { - asyncContext.complete(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Handling successful"); - } - } - - @Override - public void fail(Throwable failure) { - request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, failure); - int code = failure instanceof TimeoutException ? - getDuplicateMetaConnectHttpResponseCode() : - HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - sendError(request, response, code, failure); - asyncContext.complete(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Handling failed", failure); - } - } - }; - - Context context = new Context(request, response); - - Charset charset = Charset.forName(encoding); - ReadListener reader = "UTF-8".equals(charset.name()) ? - new UTF8Reader(context, promise) : - new CharsetReader(context, promise, charset); - ServletInputStream input = request.getInputStream(); - input.setReadListener(reader); - } - - protected void process(String json, Context context, Promise promise) { - try { - try { - ServerMessage.Mutable[] messages = parseMessages(json); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Parsed {} messages", messages == null ? -1 : messages.length); - } - process(messages == null ? null : List.of(messages), context, promise); - } catch (ParseException x) { - handleJSONParseException(context.request, context.response, json, x); - promise.succeed(null); - } - } catch (Throwable x) { - promise.fail(x); - } - } - - private void process(List messages, Context context, Promise promise) { - try { - if (messages != null) { - processMessages(context, messages, promise); - } else { - promise.succeed(null); - } - } catch (Throwable x) { - promise.fail(x); - } - } - - @Override - protected HttpScheduler suspend(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Suspended {}", message); - } - context.scheduler = newHttpScheduler(context, promise, message, timeout); - context.session.notifySuspended(message, timeout); - return context.scheduler; - } - - protected HttpScheduler newHttpScheduler(Context context, Promise promise, ServerMessage.Mutable reply, long timeout) { - return new AsyncLongPollScheduler(context, promise, reply, timeout); - } - - @Override - protected void write(Context context, List messages, Promise promise) { - HttpServletResponse response = context.response; - try { - // Always write asynchronously - response.setContentType("application/json;charset=UTF-8"); - ServletOutputStream output = response.getOutputStream(); - output.setWriteListener(new Writer(context, messages, promise)); - } catch (Throwable x) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Exception while writing messages", x); - } - if (context.scheduleExpiration) { - scheduleExpiration(context.session, context.metaConnectCycle); - } - promise.fail(x); - } - } - - protected void writeComplete(Context context, List messages) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Messages/replies {}/{} written for {}", messages.size(), context.replies.size(), context.session); - } - } - - protected abstract class AbstractReader implements ReadListener { - private final Context context; - private final Promise promise; - private int total; - - protected AbstractReader(Context context, Promise promise) { - this.context = context; - this.promise = promise; - } - - @Override - public void onDataAvailable() throws IOException { - ServletInputStream input = context.request.getInputStream(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Asynchronous read start from {}", input); - } - long maxMessageSize = getMaxMessageSize(); - byte[] buffer = buffers.get(); - while (input.isReady()) { - int read = input.read(buffer); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Asynchronous read {} bytes from {}", read, input); - } - if (read < 0) { - break; - } else { - if (maxMessageSize > 0) { - total += read; - if (total > maxMessageSize) { - throw new IOException("Max message size " + maxMessageSize + " exceeded"); - } - } - append(buffer, 0, read); - } - } - if (!input.isFinished()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Asynchronous read pending from {}", input); - } - } - } - - protected abstract void append(byte[] buffer, int offset, int length); - - protected void finish(List messages) throws IOException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Asynchronous read end from {}: {}", context.request.getInputStream(), messages); - } - process(messages, context, promise); - } - - protected void finish(String json) throws IOException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Asynchronous read end from {}: {}", context.request.getInputStream(), json); - } - process(json, context, promise); - } - - @Override - public void onError(Throwable failure) { - promise.fail(failure); - } - } - - protected class UTF8Reader extends AbstractReader { - private final JSONContext.AsyncParser parser; - - protected UTF8Reader(Context context, Promise promise) { - super(context, promise); - JSONContextServer jsonContext = getJSONContextServer(); - JSONContext.AsyncParser asyncParser = jsonContext.newAsyncParser(); - if (asyncParser == null) { - asyncParser = new BufferingJSONAsyncParser(jsonContext); - } - this.parser = asyncParser; - } - - @Override - protected void append(byte[] bytes, int offset, int length) { - parser.parse(bytes, offset, length); - } - - @Override - public void onAllDataRead() throws IOException { - List messages = parser.complete(); - finish(messages); - } - } - - protected class CharsetReader extends AbstractReader { - private byte[] content = new byte[BUFFER_CAPACITY]; - private final Charset charset; - private int count; - - public CharsetReader(Context context, Promise promise, Charset charset) { - super(context, promise); - this.charset = charset; - } - - @Override - protected void append(byte[] buffer, int offset, int length) { - int size = content.length; - int newSize = size; - while (newSize - count < length) { - newSize <<= 1; - } - - if (newSize < 0) { - throw new IllegalArgumentException("Message too large"); - } - - if (newSize != size) { - byte[] newContent = new byte[newSize]; - System.arraycopy(content, 0, newContent, 0, count); - content = newContent; - } - - System.arraycopy(buffer, offset, content, count, length); - count += length; - } - - @Override - public void onAllDataRead() throws IOException { - finish(new String(content, 0, count, charset)); - } - } - - protected class Writer implements WriteListener { - private final Context context; - private final List messages; - private final Promise promise; - private int messageIndex; - private int replyIndex; - private boolean needsComma; - private State state = State.BEGIN; - - protected Writer(Context context, List messages, Promise promise) { - this.context = context; - this.messages = messages; - this.promise = promise; - } - - @Override - public void onWritePossible() throws IOException { - ServletOutputStream output = context.response.getOutputStream(); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Messages/replies {}/{} to write for {}", messages.size(), context.replies.size(), context.session); - } - - while (true) { - State current = state; - switch (current) { - case BEGIN -> { - state = State.HANDSHAKE; - if (!writeBegin(output)) { - return; - } - } - case HANDSHAKE -> { - state = State.MESSAGES; - if (!writeHandshakeReply(output)) { - return; - } - } - case MESSAGES -> { - if (!writeMessages(output)) { - return; - } - state = State.REPLIES; - } - case REPLIES -> { - if (!writeReplies(output)) { - return; - } - state = State.END; - } - case END -> { - state = State.COMPLETE; - if (!writeEnd(output)) { - return; - } - } - case COMPLETE -> { - promise.succeed(null); - writeComplete(context, messages); - return; - } - default -> { - throw new IllegalStateException("Could not write in state " + current); - } - } - } - } - - private boolean writeBegin(ServletOutputStream output) throws IOException { - output.write('['); - return output.isReady(); - } - - private boolean writeHandshakeReply(ServletOutputStream output) throws IOException { - List replies = context.replies; - if (replies.size() > 0) { - ServerMessage.Mutable reply = replies.get(0); - if (Channel.META_HANDSHAKE.equals(reply.getChannel())) { - if (allowMessageDeliveryDuringHandshake(context.session) && !messages.isEmpty()) { - reply.put("x-messages", messages.size()); - } - getBayeux().freeze(reply); - output.write(toJSONBytes(reply)); - needsComma = true; - ++replyIndex; - } - } - return output.isReady(); - } - - private boolean writeMessages(ServletOutputStream output) throws IOException { - try { - int size = messages.size(); - while (output.isReady()) { - if (messageIndex == size) { - // Start the interval timeout after writing the - // messages since they may take time to be written. - startExpiration(); - return true; - } else { - if (needsComma) { - output.write(','); - needsComma = false; - } else { - ServerMessage message = messages.get(messageIndex); - output.write(toJSONBytes(message)); - needsComma = messageIndex < size; - ++messageIndex; - } - } - } - return false; - } catch (Throwable x) { - // Start the interval timeout also in case of - // exceptions to ensure the session can be swept. - startExpiration(); - throw x; - } - } - - private void startExpiration() { - if (context.scheduleExpiration) { - scheduleExpiration(context.session, context.metaConnectCycle); - } - } - - private boolean writeReplies(ServletOutputStream output) throws IOException { - List replies = context.replies; - int size = replies.size(); - while (output.isReady()) { - if (replyIndex == size) { - return true; - } else { - ServerMessage.Mutable reply = replies.get(replyIndex); - if (needsComma) { - output.write(','); - needsComma = false; - } else { - getBayeux().freeze(reply); - output.write(toJSONBytes(reply)); - needsComma = replyIndex < size; - ++replyIndex; - } - } - } - return false; - } - - private boolean writeEnd(ServletOutputStream output) throws IOException { - output.write(']'); - return output.isReady(); - } - - @Override - public void onError(Throwable failure) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Failure writing messages", failure); - } - // Start the interval timeout also in case of - // errors to ensure the session can be swept. - startExpiration(); - promise.fail(failure); - } - } - - private enum State { - BEGIN, HANDSHAKE, MESSAGES, REPLIES, END, COMPLETE - } - - private class AsyncLongPollScheduler extends LongPollScheduler { - private AsyncLongPollScheduler(Context context, Promise promise, ServerMessage.Mutable reply, long timeout) { - super(context, promise, reply, timeout); - } - - @Override - protected void dispatch(boolean timeout) { - // Directly succeeding the callback to write messages and replies. - // Since the write is async, we will never block and thus never delay other sessions. - getContext().session.notifyResumed(getMessage(), timeout); - getPromise().succeed(null); - } - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONHttpTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONHttpTransport.java new file mode 100644 index 0000000000..c1b43dfddc --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONHttpTransport.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.ParseException; +import java.util.List; + +import org.cometd.bayeux.server.ServerMessage; +import org.cometd.common.BufferingJSONAsyncParser; +import org.cometd.common.JSONContext; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.CometDRequest; +import org.cometd.server.HttpException; +import org.cometd.server.JSONContextServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JSONHttpTransport extends AbstractHttpTransport { + public static final String NAME = "long-polling"; + + private static final Logger LOGGER = LoggerFactory.getLogger(JSONHttpTransport.class); + private static final String PREFIX = "long-polling.json"; + + public JSONHttpTransport(BayeuxServerImpl bayeux) { + super(bayeux, NAME); + setOptionPrefix(PREFIX); + } + + @Override + public boolean accept(CometDRequest request) { + return "POST".equalsIgnoreCase(request.getMethod()); + } + + @Override + protected void handle(TransportContext context) { + CometDRequest request = context.request(); + String encoding = request.getCharacterEncoding(); + if (encoding == null) { + encoding = "UTF-8"; + } + + AbstractReader reader; + if ("UTF-8".equalsIgnoreCase(encoding)) { + reader = new UTF8Reader(context); + } else { + Charset charset = Charset.forName(encoding); + reader = new CharsetReader(context, charset); + } + CometDRequest.Input input = request.getInput(); + input.demand(reader::read); + } + + private void process(TransportContext context, String json) { + try { + ServerMessage.Mutable[] messages = parseMessages(json); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Parsed {} messages", messages == null ? -1 : messages.length); + } + process(context, messages == null ? List.of() : List.of(messages)); + } catch (ParseException x) { + LOGGER.warn("Could not parse JSON: " + x.getMessage(), x.getMessage()); + context.promise().fail(new HttpException(400, x.getCause())); + } catch (Throwable x) { + context.promise().fail(x); + } + } + + private void process(TransportContext context, List messages) { + try { + processMessages(context, messages == null ? List.of() : messages); + } catch (Throwable x) { + context.promise().fail(x); + } + } + + private abstract class AbstractReader { + private final TransportContext context; + private int total; + + private AbstractReader(TransportContext context) { + this.context = context; + } + + private TransportContext context() { + return context; + } + + private void read() { + try { + onDataAvailable(); + } catch (Throwable x) { + context().promise().fail(x); + } + } + + private void onDataAvailable() throws IOException { + CometDRequest.Input input = context.request().getInput(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Asynchronous read start from {}", input); + } + long maxMessageSize = getMaxMessageSize(); + while (true) { + CometDRequest.Input.Chunk chunk = input.read(); + if (chunk == null) { + input.demand(this::read); + return; + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Asynchronous read {} from {}", chunk, input); + } + int read = chunk.byteBuffer().remaining(); + if (read > 0) { + if (maxMessageSize > 0) { + total += read; + if (total > maxMessageSize) { + throw new IOException("Max message size " + maxMessageSize + " exceeded"); + } + } + processChunk(chunk); + } + chunk.release(); + if (chunk.isLast()) { + processEOF(); + break; + } + } + } + + private void processChunk(CometDRequest.Input.Chunk chunk) { + try { + onChunk(chunk); + } catch (Throwable x) { + throw new HttpException(400, x); + } + } + + private void processEOF() { + try { + onEOF(); + } catch (Throwable x) { + throw new HttpException(400, x); + } + } + + protected abstract void onChunk(CometDRequest.Input.Chunk chunk); + + protected abstract void onEOF(); + + protected void finish(List messages) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Asynchronous read end from {}: {}", context.request().getInput(), messages); + } + process(context, messages); + } + + protected void finish(String json) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Asynchronous read end from {}: {}", context.request().getInput(), json); + } + process(context, json); + } + } + + private class UTF8Reader extends AbstractReader { + private final JSONContext.AsyncParser parser; + + private UTF8Reader(TransportContext context) { + super(context); + JSONContextServer jsonContext = getJSONContextServer(); + JSONContext.AsyncParser asyncParser = jsonContext.newAsyncParser(); + if (asyncParser == null) { + asyncParser = new BufferingJSONAsyncParser(jsonContext); + } + this.parser = asyncParser; + } + + @Override + protected void onChunk(CometDRequest.Input.Chunk chunk) { + parser.parse(chunk.byteBuffer()); + } + + @Override + protected void onEOF() { + List messages = parser.complete(); + finish(messages); + } + } + + private class CharsetReader extends AbstractReader { + private final Charset charset; + private ByteBuffer aggregator = ByteBuffer.allocateDirect(256); + + private CharsetReader(TransportContext context, Charset charset) { + super(context); + this.charset = charset; + } + + @Override + protected void onChunk(CometDRequest.Input.Chunk chunk) { + ByteBuffer byteBuffer = chunk.byteBuffer(); + int remaining = byteBuffer.remaining(); + if (aggregator.remaining() < remaining) { + ByteBuffer newAggregator = ByteBuffer.allocateDirect(aggregator.position() + 2 * remaining); + newAggregator.put(aggregator.flip()); + aggregator = newAggregator; + } + aggregator.put(byteBuffer); + } + + @Override + protected void onEOF() { + String json = charset.decode(aggregator.flip()).toString(); + finish(json); + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPHttpTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPHttpTransport.java new file mode 100644 index 0000000000..1384153467 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPHttpTransport.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.ServerMessage; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.CometDRequest; +import org.cometd.server.CometDResponse; +import org.cometd.server.HttpException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JSONPHttpTransport extends AbstractHttpTransport { + public final static String NAME = "callback-polling"; + public final static String CALLBACK_PARAMETER_OPTION = "callbackParameter"; + public final static String CALLBACK_PARAMETER_MAX_LENGTH_OPTION = "callbackParameterMaxLength"; + + private static final Logger LOGGER = LoggerFactory.getLogger(JSONHttpTransport.class); + private final static String PREFIX = "long-polling.jsonp"; + private final static Pattern CALLBACK_PATTERN = Pattern.compile("^[a-zA-Z0-9._\\-]+$"); + private final static byte[] MESSAGE_BEGIN = new byte[]{'(', '['}; + private final static byte[] MESSAGE_END = new byte[]{']', ')'}; + + private String callbackParam = "jsonp"; + private int callbackMaxLength = 64; + + public JSONPHttpTransport(BayeuxServerImpl bayeux) { + super(bayeux, NAME); + setOptionPrefix(PREFIX); + } + + @Override + public void init() { + super.init(); + callbackParam = getOption(CALLBACK_PARAMETER_OPTION, callbackParam); + callbackMaxLength = getOption(CALLBACK_PARAMETER_MAX_LENGTH_OPTION, callbackMaxLength); + // This transport must deliver only via /meta/connect + setMetaConnectDeliveryOnly(true); + } + + public String getCallbackParameter() { + return callbackParam; + } + + public int getCallbackMaxLength() { + return callbackMaxLength; + } + + @Override + public boolean accept(CometDRequest request) { + String[] callbackValue = request.getParameterValues(getCallbackParameter()); + return "GET".equals(request.getMethod()) && isCallbackValueValid(callbackValue); + } + + private boolean isCallbackValueValid(String[] callbackValues) { + if (callbackValues == null || callbackValues.length != 1) { + return false; + } + String callbackValue = callbackValues[0]; + return callbackValue.length() <= getCallbackMaxLength() && CALLBACK_PATTERN.matcher(callbackValue).matches(); + } + + @Override + protected void handle(TransportContext context) { + try { + String[] requestParameters = context.request().getParameterValues(MESSAGE_PARAM); + + if (requestParameters == null || requestParameters.length == 0) { + throw new IOException("Missing '" + MESSAGE_PARAM + "' request parameter"); + } + + List messages; + if (requestParameters.length == 1) { + ServerMessage.Mutable[] parsed = parseMessages(requestParameters[0]); + messages = parsed == null ? List.of() : List.of(parsed); + } else { + messages = new ArrayList<>(); + for (String batch : requestParameters) { + if (batch == null) { + continue; + } + ServerMessage.Mutable[] parsed = parseMessages(batch); + if (parsed != null) { + messages.addAll(List.of(parsed)); + } + } + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Parsed {} messages", messages.size()); + } + + processMessages(context, messages); + } catch (ParseException x) { + LOGGER.warn("Could not parse JSON: " + x.getMessage(), x.getMessage()); + context.promise().fail(new HttpException(400, x.getCause())); + } catch (Throwable x) { + context.promise().fail(x); + } + } + + @Override + protected void writePrepare(TransportContext context, Promise promise) { + CometDResponse response = context.response(); + response.setContentType("text/javascript;charset=UTF-8"); + String callback = context.request().getParameterValues(getCallbackParameter())[0]; + response.getOutput().write(false, callback.getBytes(StandardCharsets.UTF_8), promise); + } + + @Override + protected void writeBegin(CometDResponse.Output output, Promise promise) { + output.write(false, MESSAGE_BEGIN, promise); + } + + @Override + protected void writeEnd(CometDResponse.Output output, Promise promise) { + output.write(true, MESSAGE_END, promise); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPTransport.java deleted file mode 100644 index a04215a55b..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONPTransport.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.http; - -import java.io.IOException; -import java.text.ParseException; -import java.util.regex.Pattern; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.server.BayeuxServerImpl; - -public class JSONPTransport extends AbstractStreamHttpTransport { - public final static String PREFIX = "long-polling.jsonp"; - public final static String NAME = "callback-polling"; - public final static String CALLBACK_PARAMETER_OPTION = "callbackParameter"; - public final static String CALLBACK_PARAMETER_MAX_LENGTH_OPTION = "callbackParameterMaxLength"; - - private final static Pattern CALLBACK_PATTERN = Pattern.compile("^[a-zA-Z0-9._\\-]+$"); - private final static byte[] MESSAGE_BEGIN = new byte[]{'(', '['}; - private final static byte[] MESSAGE_END = new byte[]{']', ')'}; - - private String _callbackParam = "jsonp"; - private int _callbackMaxLength = 64; - - public JSONPTransport(BayeuxServerImpl bayeux) { - super(bayeux, NAME); - setOptionPrefix(PREFIX); - } - - @Override - public void init() { - super.init(); - _callbackParam = getOption(CALLBACK_PARAMETER_OPTION, _callbackParam); - _callbackMaxLength = getOption(CALLBACK_PARAMETER_MAX_LENGTH_OPTION, _callbackMaxLength); - // This transport must deliver only via /meta/connect - setMetaConnectDeliveryOnly(true); - } - - @Override - public boolean accept(HttpServletRequest request) { - String callbackValue = request.getParameter(getCallbackParameter()); - return "GET".equals(request.getMethod()) && isCallbackValueValid(callbackValue); - } - - @Override - protected ServerMessage.Mutable[] parseMessages(HttpServletRequest request) throws IOException, ParseException { - return parseMessages(request.getParameterValues(MESSAGE_PARAM)); - } - - public String getCallbackParameter() { - return _callbackParam; - } - - @Override - protected ServletOutputStream beginWrite(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("text/javascript;charset=UTF-8"); - String callback = request.getParameter(_callbackParam); - ServletOutputStream output = response.getOutputStream(); - output.write(callback.getBytes(response.getCharacterEncoding())); - output.write(MESSAGE_BEGIN); - return output; - } - - @Override - protected void endWrite(HttpServletResponse response, ServletOutputStream output) throws IOException { - output.write(MESSAGE_END); - output.close(); - } - - private boolean isCallbackValueValid(String callbackValue) { - return callbackValue != null && - callbackValue.length() <= _callbackMaxLength && - CALLBACK_PATTERN.matcher(callbackValue).matches(); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONTransport.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONTransport.java deleted file mode 100644 index 4787ab7b92..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/JSONTransport.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.http; - -import java.io.IOException; -import java.text.ParseException; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.server.BayeuxServerImpl; - -public class JSONTransport extends AbstractStreamHttpTransport { - public final static String PREFIX = "long-polling.json"; - public final static String NAME = "long-polling"; - - private boolean _jsonDebug = false; - - public JSONTransport(BayeuxServerImpl bayeux) { - super(bayeux, NAME); - setOptionPrefix(PREFIX); - } - - @Override - public void init() { - super.init(); - _jsonDebug = getOption(JSON_DEBUG_OPTION, _jsonDebug); - } - - @Override - public boolean accept(HttpServletRequest request) { - return "POST".equals(request.getMethod()); - } - - @Override - protected ServerMessage.Mutable[] parseMessages(HttpServletRequest request) throws IOException, ParseException { - String charset = request.getCharacterEncoding(); - if (charset == null) { - request.setCharacterEncoding("UTF-8"); - } - String contentType = request.getContentType(); - if (contentType == null || contentType.startsWith("application/json")) { - return parseMessages(request.getReader(), _jsonDebug); - } else if (contentType.startsWith("application/x-www-form-urlencoded")) { - return parseMessages(request.getParameterValues(MESSAGE_PARAM)); - } else { - throw new IOException("Invalid Content-Type " + contentType); - } - } - - @Override - protected ServletOutputStream beginWrite(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("application/json;charset=UTF-8"); - ServletOutputStream output = response.getOutputStream(); - output.write('['); - return output; - } - - @Override - protected void endWrite(HttpServletResponse response, ServletOutputStream output) throws IOException { - output.write(']'); - output.close(); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/TransportContext.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/TransportContext.java new file mode 100644 index 0000000000..bee82b3bf6 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/http/TransportContext.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http; + +import java.util.ArrayList; +import java.util.List; + +import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxContext; +import org.cometd.bayeux.server.ServerMessage; +import org.cometd.server.CometDRequest; +import org.cometd.server.CometDResponse; +import org.cometd.server.ServerSessionImpl; + +public class TransportContext +{ + private final BayeuxContext bayeuxContext; + private final CometDRequest cometDRequest; + private final CometDResponse cometDResponse; + private final Promise promise; + private final List replies = new ArrayList<>(); + + private List messages; + private long metaConnectCycle; + private boolean scheduleExpiration; + private AbstractHttpTransport.HttpScheduler scheduler; + private boolean sendQueue; + private ServerSessionImpl session; + + public TransportContext(BayeuxContext bayeuxContext, CometDRequest cometDRequest, CometDResponse cometDResponse, Promise promise) + { + this.bayeuxContext = bayeuxContext; + this.cometDRequest = cometDRequest; + this.cometDResponse = cometDResponse; + this.promise = promise; + } + + public BayeuxContext bayeuxContext() + { + return bayeuxContext; + } + + public CometDRequest request() + { + return cometDRequest; + } + + public CometDResponse response() + { + return cometDResponse; + } + + public Promise promise() { + return promise; + } + + public List messages() + { + return messages; + } + + public void messages(List messages) + { + this.messages = messages; + } + + public long metaConnectCycle() + { + return metaConnectCycle; + } + + public void metaConnectCycle(long l) + { + this.metaConnectCycle = l; + } + + public List replies() + { + return replies; + } + + public void scheduleExpiration(boolean b) + { + this.scheduleExpiration = b; + } + + public boolean scheduleExpiration() + { + return scheduleExpiration; + } + + public AbstractHttpTransport.HttpScheduler scheduler() + { + return scheduler; + } + + public void scheduler(AbstractHttpTransport.HttpScheduler httpScheduler) + { + this.scheduler = httpScheduler; + } + + public void sendQueue(boolean b) + { + this.sendQueue = b; + } + + public boolean sendQueue() + { + return sendQueue; + } + + public ServerSessionImpl session() + { + return session; + } + + public void session(ServerSessionImpl session) + { + this.session = session; + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxServerTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxServerTest.java deleted file mode 100644 index 2938bad5f2..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxServerTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.cometd.server.http.AsyncJSONTransport; -import org.cometd.server.http.JSONTransport; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.RegisterExtension; - -public abstract class AbstractBayeuxServerTest { - public static List transports() { - return List.of(JSONTransport.class.getName(), AsyncJSONTransport.class.getName()); - } - - @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> - System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); - protected Server server; - protected ServerConnector connector; - protected int port; - protected ServletContextHandler context; - protected CometDServlet cometdServlet; - protected String cometdURL; - protected BayeuxServerImpl bayeux; - protected long timeout = 2000; - - public void startServer(String serverTransport, Map options) throws Exception { - server = new Server(); - connector = new ServerConnector(server); - server.addConnector(connector); - - ContextHandlerCollection handlers = new ContextHandlerCollection(); - server.setHandler(handlers); - - String contextPath = "/cometd"; - context = new ServletContextHandler(contextPath, ServletContextHandler.SESSIONS); - handlers.addHandler(context); - - // Setup comet servlet - cometdServlet = new CometDServlet(); - ServletHolder cometdServletHolder = new ServletHolder(cometdServlet); - if (options == null) { - options = new HashMap<>(); - } - options.put("timeout", String.valueOf(timeout)); - options.put("transports", serverTransport); - for (Map.Entry entry : options.entrySet()) { - cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); - } - String cometdServletPath = "/cometd"; - context.addServlet(cometdServletHolder, cometdServletPath + "/*"); - - server.start(); - port = connector.getLocalPort(); - - String contextURL = "http://localhost:" + port + contextPath; - cometdURL = contextURL + cometdServletPath; - - bayeux = cometdServlet.getBayeux(); - } - - @AfterEach - public void stopServer() throws Exception { - if (server != null) { - server.stop(); - } - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxContextTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxContextTest.java deleted file mode 100644 index 681924fd2a..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxContextTest.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server; - -import java.io.IOException; -import java.util.EnumSet; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import jakarta.servlet.DispatcherType; -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; - -import org.cometd.bayeux.server.BayeuxServer; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.bayeux.server.ServerSession; -import org.eclipse.jetty.client.ContentResponse; -import org.eclipse.jetty.client.Request; -import org.eclipse.jetty.ee10.servlet.FilterHolder; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -public class BayeuxContextTest extends AbstractBayeuxClientServerTest { - @ParameterizedTest - @MethodSource("transports") - public void testAddresses(String serverTransport) throws Exception { - startServer(serverTransport, null); - - CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertNotNull(message.getBayeuxContext().getLocalAddress()); - Assertions.assertNotNull(message.getBayeuxContext().getRemoteAddress()); - latch.countDown(); - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @ParameterizedTest - @MethodSource("transports") - public void testRequestHeader(String serverTransport) throws Exception { - startServer(serverTransport, null); - - String name = "test"; - String value1 = "foo"; - String value2 = "bar"; - CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertEquals(value1, message.getBayeuxContext().getHeader(name)); - Assertions.assertEquals(List.of(value1, value2), message.getBayeuxContext().getHeaderValues(name)); - latch.countDown(); - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - handshake.headers(headers -> headers.put(name, value1)); - handshake.headers(headers -> headers.add(name, value2)); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @ParameterizedTest - @MethodSource("transports") - public void testRequestAttribute(String serverTransport) throws Exception { - startServer(serverTransport, null); - - String name = "test"; - String value = "foo"; - - context.stop(); - context.addFilter(new FilterHolder(new Filter() { - @Override - public void init(FilterConfig filterConfig) { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - servletRequest.setAttribute(name, value); - filterChain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - } - }), "/*", EnumSet.of(DispatcherType.REQUEST)); - context.start(); - bayeux = cometdServlet.getBayeux(); - - CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertEquals(value, message.getBayeuxContext().getRequestAttribute(name)); - latch.countDown(); - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @ParameterizedTest - @MethodSource("transports") - public void testSessionAttribute(String serverTransport) throws Exception { - startServer(serverTransport, null); - - String name = "test"; - String value = "foo"; - - context.stop(); - context.addFilter(new FilterHolder(new Filter() { - @Override - public void init(FilterConfig filterConfig) { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest)servletRequest; - request.getSession(true).setAttribute(name, value); - filterChain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - } - }), "/*", EnumSet.of(DispatcherType.REQUEST)); - context.start(); - bayeux = cometdServlet.getBayeux(); - - CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertNotNull(message.getBayeuxContext().getHttpSessionId()); - Assertions.assertEquals(value, message.getBayeuxContext().getHttpSessionAttribute(name)); - latch.countDown(); - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - - @ParameterizedTest - @MethodSource("transports") - public void testContextAttribute(String serverTransport) throws Exception { - startServer(serverTransport, null); - - CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertSame(bayeux, message.getBayeuxContext().getContextAttribute(BayeuxServer.ATTRIBUTE)); - latch.countDown(); - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxServerJMXTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxServerJMXTest.java deleted file mode 100644 index 4113fe9bc9..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BayeuxServerJMXTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.openmbean.CompositeData; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import jakarta.servlet.http.HttpServlet; - -import org.cometd.bayeux.server.BayeuxServer; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.jmx.ConnectorServer; -import org.eclipse.jetty.jmx.MBeanContainer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.util.component.LifeCycle; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.awaitility.Awaitility.await; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; - -public class BayeuxServerJMXTest { - private Server server; - private JMXServiceURL jmxURL; - private BayeuxServerImpl bayeux; - - @BeforeEach - public void setUp() throws Exception { - server = new Server(); - ServerConnector connector = new ServerConnector(server); - server.addConnector(connector); - - int freePort = freePort(); - jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + freePort + "/jmxrmi"); - String remoteRootObjectName = "org.eclipse.jetty:name=rmiconnectorserver"; - ConnectorServer connectorServer = new ConnectorServer(jmxURL, remoteRootObjectName); - server.addBean(connectorServer); - - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - MBeanContainer mbeanContainer = new MBeanContainer(mbeanServer); - server.addBean(mbeanContainer); - - ServletContextHandler context = new ServletContextHandler("/"); - server.setHandler(context); - - // CometD servlet - String cometdServletPath = "/cometd"; - String cometdURLMapping = cometdServletPath + "/*"; - ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - cometdServletHolder.setInitOrder(1); - context.addServlet(cometdServletHolder, cometdURLMapping); - - ServletHolder jmxServletHolder = new ServletHolder(CometDJMXExporter.class); - jmxServletHolder.setInitOrder(2); - context.addServlet(jmxServletHolder, "/jmx"); - - server.start(); - bayeux = (BayeuxServerImpl)CometDJMXExporter.BAYEUX.get(); - } - - @AfterEach - public void tearDown() { - LifeCycle.stop(server); - } - - @Test - public void testLastSweepInfoOverRemoteJMX() throws Exception { - try (JMXConnector client = JMXConnectorFactory.connect(jmxURL, null)) { - for (int i = 0; i < 100; i++) { - newServerSession(bayeux).scheduleExpiration(0, 0, 0); - } - - MBeanServerConnection msc = client.getMBeanServerConnection(); - Set mbeanNames = msc.queryNames(ObjectName.getInstance(BayeuxServerImpl.class.getPackage().getName() + ":*,type=bayeuxserverimpl"), null); - ObjectName bayeuxObjectName = mbeanNames.iterator().next(); - AtomicReference lastSweepInfoRef = new AtomicReference<>(); - await().pollDelay(1, TimeUnit.MILLISECONDS).atMost(5, TimeUnit.SECONDS).until(() -> { - CompositeData lastSweepInfo = (CompositeData)msc.getAttribute(bayeuxObjectName, "lastSweepInfo"); - long lastSweepTransportDuration = (long)lastSweepInfo.get("serverSessionSweepCount"); - if (lastSweepTransportDuration != 0) { - lastSweepInfoRef.set(lastSweepInfo); - return true; - } - return false; - }); - CompositeData lastSweepInfo = lastSweepInfoRef.get(); - assertThat(lastSweepInfo.containsKey("startInstant"), is(true)); - assertThat(lastSweepInfo.containsKey("transportSweepDuration"), is(true)); - assertThat(lastSweepInfo.containsKey("serverChannelSweepCount"), is(true)); - assertThat(lastSweepInfo.containsKey("serverChannelSweepDuration"), is(true)); - assertThat(((Number)lastSweepInfo.get("serverSessionSweepCount")).longValue(), greaterThan(0L)); - assertThat(lastSweepInfo.containsKey("serverSessionSweepDuration"), is(true)); - assertThat(lastSweepInfo.containsKey("sweepDuration"), is(true)); - } - } - - private ServerSessionImpl newServerSession(BayeuxServerImpl bayeux) { - ServerSessionImpl session = bayeux.newServerSession(); - bayeux.addServerSession(session, bayeux.newMessage()); - session.handshake(null); - session.connected(); - return session; - } - - private static int freePort() throws IOException { - try (ServerSocket server = new ServerSocket()) { - server.setReuseAddress(true); - server.bind(new InetSocketAddress("localhost", 0)); - return server.getLocalPort(); - } - } - - public static class CometDJMXExporter extends HttpServlet { - private static final AtomicReference BAYEUX = new AtomicReference<>(); - private final List mbeans = new ArrayList<>(); - private volatile MBeanContainer mbeanContainer; - - @Override - public void init() { - mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); - BayeuxServer bayeuxServer = (BayeuxServer)getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); - BAYEUX.set(bayeuxServer); - mbeanContainer.beanAdded(null, bayeuxServer); - mbeans.add(bayeuxServer); - // Add other components - } - - @Override - public void destroy() { - for (int i = mbeans.size() - 1; i >= 0; --i) { - mbeanContainer.beanRemoved(null, mbeans.get(i)); - } - } - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/IdleLongPollTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/IdleLongPollTest.java deleted file mode 100644 index f7b2f83502..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/IdleLongPollTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import jakarta.servlet.AsyncEvent; - -import org.cometd.bayeux.Message; -import org.cometd.bayeux.Promise; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.bayeux.server.ServerSession; -import org.cometd.common.JSONContext; -import org.cometd.common.JettyJSONContextClient; -import org.cometd.server.http.JSONTransport; -import org.eclipse.jetty.client.ContentResponse; -import org.eclipse.jetty.client.Request; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -public class IdleLongPollTest extends AbstractBayeuxClientServerTest { - @ParameterizedTest - @MethodSource("transports") - public void testIdleLongPollDoesNotCauseMultipleClientsAdvice(String serverTransport) throws Exception { - startServer(serverTransport, null); - - long timeout = 2000; - long sleep = 500; - JSONTransport transport = new JSONTransport(bayeux) { - @Override - protected HttpScheduler newHttpScheduler(Context context, Promise promise, ServerMessage.Mutable message, long timeout) { - return new DispatchingLongPollScheduler(context, promise, message, timeout) { - private final AtomicInteger decrements = new AtomicInteger(); - - @Override - public void onComplete(AsyncEvent asyncEvent) throws IOException { - if (decrements.incrementAndGet() == 1) { - // Simulate that onComplete() is delayed without blocking - // this thread, to cause a race condition - new Thread(() -> { - try { - Thread.sleep(sleep); - superOnComplete(asyncEvent); - } catch (Exception x) { - x.printStackTrace(); - } - }).start(); - } else { - superOnComplete(asyncEvent); - } - } - - private void superOnComplete(AsyncEvent asyncEvent) throws IOException { - super.onComplete(asyncEvent); - } - }; - } - }; - transport.setOption(AbstractServerTransport.TIMEOUT_OPTION, timeout); - transport.init(); - bayeux.setTransports(transport); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - String clientId = extractClientId(response); - - Request connect1 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect1.send(); - Assertions.assertEquals(200, response.getStatus()); - - ServerSession serverSession = bayeux.getSession(clientId); - Assertions.assertNotNull(serverSession); - - Request connect2 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect2.send(); - Assertions.assertEquals(200, response.getStatus()); - - Request connect3 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect3.send(); - Assertions.assertEquals(200, response.getStatus()); - - JSONContext.Client jsonContext = new JettyJSONContextClient(); - Message.Mutable[] messages = jsonContext.parse(response.getContentAsString()); - Assertions.assertEquals(1, messages.length); - Message.Mutable message = messages[0]; - Map advice = message.getAdvice(); - Assertions.assertNull(advice); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/SlowConnectionTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/SlowConnectionTest.java deleted file mode 100644 index 3f66e00cb5..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/SlowConnectionTest.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.net.Socket; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletResponse; - -import org.cometd.bayeux.Channel; -import org.cometd.bayeux.Message; -import org.cometd.bayeux.Promise; -import org.cometd.bayeux.server.BayeuxServer; -import org.cometd.bayeux.server.ServerMessage; -import org.cometd.bayeux.server.ServerSession; -import org.cometd.common.JettyJSONContextClient; -import org.cometd.server.http.JSONTransport; -import org.eclipse.jetty.client.ContentResponse; -import org.eclipse.jetty.client.Request; -import org.eclipse.jetty.io.EofException; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -public class SlowConnectionTest extends AbstractBayeuxClientServerTest { - @ParameterizedTest - @MethodSource("transports") - public void testSessionSweptDoesNotSendReconnectNoneAdvice(String serverTransport) throws Exception { - long maxInterval = 1000; - Map options = new HashMap<>(); - options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - startServer(serverTransport, options); - - CountDownLatch sweeperLatch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionRemoved(ServerSession session, ServerMessage message, boolean timeout) { - if (timeout) { - sweeperLatch.countDown(); - } - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - String clientId = extractClientId(response); - - Request connect1 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect1.send(); - Assertions.assertEquals(200, response.getStatus()); - - // Do not send the second connect, so the sweeper can do its job - Assertions.assertTrue(sweeperLatch.await(2 * maxInterval, TimeUnit.MILLISECONDS)); - - // Send the second connect, we should not get the reconnect:"none" advice - Request connect2 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect2.send(); - Assertions.assertEquals(200, response.getStatus()); - - Message.Mutable reply = new JettyJSONContextClient().parse(response.getContentAsString())[0]; - Assertions.assertEquals(Channel.META_CONNECT, reply.getChannel()); - Map advice = reply.getAdvice(false); - if (advice != null) { - Assertions.assertNotEquals(advice.get(Message.RECONNECT_FIELD), Message.RECONNECT_NONE_VALUE); - } - } - - @ParameterizedTest - @MethodSource("transports") - public void testSessionSweptWhileWritingQueueDoesNotSendReconnectNoneAdvice(String serverTransport) throws Exception { - long maxInterval = 1000; - Map options = new HashMap<>(); - options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - startServer(serverTransport, options); - - String channelName = "/test"; - JSONTransport transport = new JSONTransport(bayeux) { - @Override - protected void writeMessage(HttpServletResponse response, ServletOutputStream output, ServerSessionImpl session, ServerMessage message) throws IOException { - try { - if (channelName.equals(message.getChannel())) { - session.scheduleExpiration(0, maxInterval, session.getMetaConnectCycle()); - TimeUnit.MILLISECONDS.sleep(2 * maxInterval); - } - super.writeMessage(response, output, session, message); - } catch (InterruptedException x) { - throw new InterruptedIOException(); - } - } - }; - transport.init(); - bayeux.setTransports(transport); - - CountDownLatch sweeperLatch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { - @Override - public void sessionAdded(ServerSession session, ServerMessage message) { - session.deliver(null, channelName, "test", Promise.noop()); - } - - @Override - public void sessionRemoved(ServerSession session, ServerMessage message, boolean timeout) { - if (timeout) { - sweeperLatch.countDown(); - } - } - }); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - String clientId = extractClientId(response); - - Request connect1 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect1.send(); - Assertions.assertEquals(200, response.getStatus()); - - Assertions.assertTrue(sweeperLatch.await(maxInterval, TimeUnit.MILLISECONDS)); - - Message.Mutable[] replies = new JettyJSONContextClient().parse(response.getContentAsString()); - Message.Mutable reply = replies[replies.length - 1]; - Assertions.assertEquals(Channel.META_CONNECT, reply.getChannel()); - Map advice = reply.getAdvice(false); - if (advice != null) { - Assertions.assertNotEquals(advice.get(Message.RECONNECT_FIELD), Message.RECONNECT_NONE_VALUE); - } - } - - @ParameterizedTest - @MethodSource("transports") - public void testSlowConnection(String serverTransport) throws Exception { - startServer(serverTransport, null); - - CountDownLatch sendLatch = new CountDownLatch(1); - CountDownLatch closeLatch = new CountDownLatch(1); - JSONTransport transport = new JSONTransport(bayeux) { - @Override - protected void writeMessage(HttpServletResponse response, ServletOutputStream output, ServerSessionImpl session, ServerMessage message) throws IOException { - if (!message.isMeta() && !message.isPublishReply()) { - sendLatch.countDown(); - await(closeLatch); - // Simulate that an exception is being thrown while writing - throw new EofException("test_exception"); - } - super.writeMessage(response, output, session, message); - } - }; - transport.init(); - bayeux.setTransports(transport); - long maxInterval = 5000L; - transport.setMaxInterval(maxInterval); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - String clientId = extractClientId(response); - String cookieName = "BAYEUX_BROWSER"; - String browserId = extractCookie(cookieName); - - String channelName = "/foo"; - Request subscribe = newBayeuxRequest("[{" + - "\"clientId\": \"" + clientId + "\"," + - "\"channel\": \"/meta/subscribe\"," + - "\"subscription\": \"" + channelName + "\"" + - "}]"); - response = subscribe.send(); - Assertions.assertEquals(200, response.getStatus()); - - Request connect1 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect1.send(); - Assertions.assertEquals(200, response.getStatus()); - - // Send a server-side message so it gets written to the client - bayeux.getChannel(channelName).publish(null, "x", Promise.noop()); - - Socket socket = new Socket("localhost", port); - OutputStream output = socket.getOutputStream(); - byte[] content = ("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]").getBytes(StandardCharsets.UTF_8); - String request = "" + - "POST " + new URI(cometdURL).getPath() + "/connect HTTP/1.1\r\n" + - "Host: localhost:" + port + "\r\n" + - "Content-Type: application/json;charset=UTF-8\r\n" + - "Content-Length: " + content.length + "\r\n" + - "Cookie: " + cookieName + "=" + browserId + "\r\n" + - "\r\n"; - output.write(request.getBytes(StandardCharsets.UTF_8)); - output.write(content); - output.flush(); - - CountDownLatch removeLatch = new CountDownLatch(1); - ServerSession session = bayeux.getSession(clientId); - session.addListener((ServerSession.RemovedListener)(s, m, t) -> removeLatch.countDown()); - - // Wait for messages to be written, but close the connection instead - Assertions.assertTrue(sendLatch.await(5, TimeUnit.SECONDS)); - socket.close(); - closeLatch.countDown(); - - // The session must be swept even if the server could not write a response - // to the connect because of the exception. - Assertions.assertTrue(removeLatch.await(2 * maxInterval, TimeUnit.MILLISECONDS)); - } - - @ParameterizedTest - @MethodSource("transports") - public void testLargeMessageOnSlowConnection(String serverTransport) throws Exception { - Map options = new HashMap<>(); - long maxInterval = 5000; - options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - startServer(serverTransport, options); - connector.setIdleTimeout(1000); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(200, response.getStatus()); - - String clientId = extractClientId(response); - String cookieName = "BAYEUX_BROWSER"; - String browserId = extractCookie(cookieName); - - String channelName = "/foo"; - Request subscribe = newBayeuxRequest("[{" + - "\"clientId\": \"" + clientId + "\"," + - "\"channel\": \"/meta/subscribe\"," + - "\"subscription\": \"" + channelName + "\"" + - "}]"); - response = subscribe.send(); - Assertions.assertEquals(200, response.getStatus()); - - Request connect1 = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); - response = connect1.send(); - Assertions.assertEquals(200, response.getStatus()); - - // Send a server-side message so it gets written to the client - char[] chars = new char[64 * 1024 * 1024]; - Arrays.fill(chars, 'z'); - String data = new String(chars); - bayeux.getChannel(channelName).publish(null, data, Promise.noop()); - - try (Socket socket = new Socket("localhost", port)) { - OutputStream output = socket.getOutputStream(); - byte[] content = ("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]").getBytes(StandardCharsets.UTF_8); - String request = "" + - "POST " + new URI(cometdURL).getPath() + "/connect HTTP/1.1\r\n" + - "Host: localhost:" + port + "\r\n" + - "Content-Type: application/json;charset=UTF-8\r\n" + - "Content-Length: " + content.length + "\r\n" + - "Cookie: " + cookieName + "=" + browserId + "\r\n" + - "\r\n"; - output.write(request.getBytes(StandardCharsets.UTF_8)); - output.write(content); - output.flush(); - - CountDownLatch removeLatch = new CountDownLatch(1); - ServerSession session = bayeux.getSession(clientId); - session.addListener((ServerSession.RemovedListener)(s, m, t) -> removeLatch.countDown()); - - // Do not read, the server should idle timeout and close the connection. - - // The session must be swept even if the server could not write a response - // to the connect because of the exception. - Assertions.assertTrue(removeLatch.await(2 * maxInterval, TimeUnit.MILLISECONDS)); - } - } - - private void await(CountDownLatch latch) { - try { - latch.await(); - } catch (InterruptedException x) { - Thread.currentThread().interrupt(); - } - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/http/JSONPTransportCallbackParamValidationTest.java b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/http/JSONPTransportCallbackParamValidationTest.java deleted file mode 100644 index b13e071e37..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/http/JSONPTransportCallbackParamValidationTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.http; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.cometd.server.AbstractBayeuxClientServerTest; -import org.eclipse.jetty.client.ContentResponse; -import org.eclipse.jetty.client.Request; -import org.eclipse.jetty.http.HttpMethod; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class JSONPTransportCallbackParamValidationTest extends AbstractBayeuxClientServerTest { - // We want to test only the JSONPTransport. - private final String serverTransport = JSONPTransport.class.getName(); - private final Map initParams = new HashMap<>(); - private final String jsonpPath = "/?jsonp="; - - public JSONPTransportCallbackParamValidationTest() { - initParams.put("long-polling.jsonp.callbackParameterMaxLength", "10"); - } - - @Test - public void testValidCallbackParamLength() throws Exception { - startServer(serverTransport, initParams); - cometdURL = cometdURL + jsonpPath + "short"; - testSubscribe(200); - } - - @Test - public void testInvalidCallbackParamLength() throws Exception { - startServer(serverTransport, initParams); - cometdURL = cometdURL + jsonpPath + "waytoolongforthistest"; - testSubscribe(400); - } - - @Test - public void testValidCallbackParamCharacters() throws Exception { - startServer(serverTransport, initParams); - cometdURL = cometdURL + jsonpPath + "s-h_o.R1"; - testSubscribe(200); - } - - @Test - public void testInvalidCallbackParamCharacters() throws Exception { - startServer(serverTransport, initParams); - cometdURL = cometdURL + jsonpPath + "sh%20rt"; - testSubscribe(400); - cometdURL = cometdURL + jsonpPath + "sh%0d%0art"; - testSubscribe(400); - cometdURL = cometdURL + jsonpPath + "NOTICE:"; - testSubscribe(400); - } - - @Override - protected Request newBayeuxRequest(String requestBody) throws UnsupportedEncodingException { - String messagePath = "&message="; - Request request = httpClient.newRequest(cometdURL + messagePath + URLEncoder.encode(requestBody, StandardCharsets.UTF_8)); - request.timeout(5, TimeUnit.SECONDS); - request.method(HttpMethod.GET); - return request; - } - - private void testSubscribe(int errorCode) throws UnsupportedEncodingException, InterruptedException, TimeoutException, ExecutionException { - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"callback-polling\"]" + - "}]"); - ContentResponse response = handshake.send(); - Assertions.assertEquals(errorCode, response.getStatus()); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/pom.xml new file mode 100644 index 0000000000..896593d4ce --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/pom.xml @@ -0,0 +1,85 @@ + + + + org.cometd.java + cometd-java-server-http + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-server-http-jakarta + CometD :: Java :: Server :: HTTP :: Jakarta EE10 + + + + + maven-surefire-plugin + + + @{argLine} + + --add-modules org.eclipse.jetty.jmx + + --add-modules org.eclipse.jetty.util.ajax + + --add-exports org.cometd.server.servlet/org.cometd.server.servlet.ext=org.cometd.server + --add-exports org.cometd.server.servlet/org.cometd.server.servlet.ext=ALL-UNNAMED + + + + + + + + + jakarta.servlet + jakarta.servlet-api + + + org.cometd.java + cometd-java-api-server + ${project.version} + + + org.cometd.java + cometd-java-common + ${project.version} + + + org.cometd.java + cometd-java-server-common + ${project.version} + + + org.eclipse.jetty + jetty-jmx + ${jetty-version} + true + + + org.eclipse.jetty + jetty-util-ajax + ${jetty-version} + true + + + + org.eclipse.jetty + jetty-client + ${jetty-version} + test + + + org.eclipse.jetty + jetty-server + ${jetty-version} + test + + + org.eclipse.jetty.ee10 + jetty-ee10-servlet + ${jetty-version} + test + + + diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/module-info.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/module-info.java new file mode 100644 index 0000000000..bce7c17f3f --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +module org.cometd.server.http.jakarta { + exports org.cometd.server.http.jakarta; + + requires transitive jakarta.servlet; + requires transitive org.cometd.api.server; + requires org.cometd.server; + requires org.slf4j; + + // Only required when using JMX. + requires static org.eclipse.jetty.jmx; + // Only required when using Jetty's JSON. + requires static org.eclipse.jetty.util.ajax; +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDServlet.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/CometDServlet.java similarity index 53% rename from cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDServlet.java rename to cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/CometDServlet.java index 76b68bc4f6..82c4af5c2e 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/CometDServlet.java +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/CometDServlet.java @@ -13,23 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.server; +package org.cometd.server.http.jakarta; import java.io.IOException; import java.util.Collections; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.RequestDispatcher; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + +import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxContext; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerSession; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.CometDRequest; +import org.cometd.server.CometDResponse; +import org.cometd.server.HttpException; +import org.cometd.server.ServerSessionImpl; import org.cometd.server.http.AbstractHttpTransport; +import org.eclipse.jetty.util.component.LifeCycle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - *

The CometD Servlet maps HTTP requests to the {@link org.cometd.server.http.AbstractHttpTransport} + *

The CometD Servlet maps HTTP requests to the {@link AbstractHttpTransport} * of a {@link BayeuxServer} instance.

*

The {@link BayeuxServer} instance is searched in the servlet context under the {@link BayeuxServer#ATTRIBUTE} * attribute; if it is found then it is used without further configuration, otherwise a new {@link BayeuxServer} @@ -38,41 +49,42 @@ public class CometDServlet extends HttpServlet { private static final Logger LOGGER = LoggerFactory.getLogger(CometDServlet.class); - private BayeuxServerImpl _bayeux; + private BayeuxServer bayeuxServer; @Override public void init() throws ServletException { try { + bayeuxServer = (BayeuxServer)getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); + boolean export = false; - _bayeux = (BayeuxServerImpl)getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); - if (_bayeux == null) { + if (bayeuxServer == null) { export = true; - _bayeux = newBayeuxServer(); + bayeuxServer = newBayeuxServer(); - // Transfer all servlet init parameters to the BayeuxServer implementation + // Transfer all servlet init parameters to the BayeuxServer implementation. for (String initParamName : Collections.list(getInitParameterNames())) { - _bayeux.setOption(initParamName, getInitParameter(initParamName)); + bayeuxServer.setOption(initParamName, getInitParameter(initParamName)); } - - // Add the ServletContext to the options - _bayeux.setOption(ServletContext.class.getName(), getServletContext()); } - _bayeux.start(); + // Add the ServletContext to the options. + bayeuxServer.setOption(ServletContext.class.getName(), getServletContext()); + + LifeCycle.start(bayeuxServer); if (export) { - getServletContext().setAttribute(BayeuxServer.ATTRIBUTE, _bayeux); + getServletContext().setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); } } catch (Exception x) { throw new ServletException(x); } } - public BayeuxServerImpl getBayeux() { - return _bayeux; + public BayeuxServer getBayeuxServer() { + return bayeuxServer; } - protected BayeuxServerImpl newBayeuxServer() { + protected BayeuxServer newBayeuxServer() { return new BayeuxServerImpl(); } @@ -83,11 +95,41 @@ protected void service(HttpServletRequest request, HttpServletResponse response) return; } - AbstractHttpTransport transport = _bayeux.findHttpTransport(request); + // API calls could be async, so we must be async in the request processing too. + AsyncContext asyncContext = request.startAsync(); + // Explicitly disable the timeout, to prevent + // that the timeout fires in case of slow reads. + asyncContext.setTimeout(0); + + CometDRequest cometDRequest = new JakartaCometDRequest(request); + CometDResponse cometDResponse = new JakartaCometDResponse(response); + BayeuxContext bayeuxContext = new JakartaBayeuxContext(request); + + Promise promise = new Promise<>() { + @Override + public void succeed(Void result) { + asyncContext.complete(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Handling successful"); + } + } + + @Override + public void fail(Throwable failure) { + int code = failure instanceof HttpException http ? http.getCode() : HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + sendError(request, response, code, failure); + asyncContext.complete(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Handling failed", failure); + } + } + }; + + AbstractHttpTransport transport = AbstractHttpTransport.find(bayeuxServer, cometDRequest); if (transport == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown Bayeux Transport"); } else { - transport.handle(request, response); + transport.handle(bayeuxContext, cometDRequest, cometDResponse, promise); } } @@ -102,20 +144,31 @@ protected void serviceOptions(HttpServletRequest request, HttpServletResponse re // Just return 200 OK, there is nothing more to add to such requests. } + protected void sendError(HttpServletRequest request, HttpServletResponse response, int code, Throwable failure) { + try { + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, failure); + response.setStatus(code); + } catch (Throwable x) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("", x); + } + } + } + @Override public void destroy() { - for (ServerSession session : _bayeux.getSessions()) { + for (ServerSession session : bayeuxServer.getSessions()) { ((ServerSessionImpl)session).destroyScheduler(); } try { - _bayeux.stop(); + LifeCycle.start(bayeuxServer); } catch (Exception x) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("", x); } } finally { - _bayeux = null; + bayeuxServer = null; getServletContext().removeAttribute(BayeuxServer.ATTRIBUTE); } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaBayeuxContext.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaBayeuxContext.java new file mode 100644 index 0000000000..802da73db0 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaBayeuxContext.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jakarta; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; + +import org.cometd.bayeux.server.BayeuxContext; + +class JakartaBayeuxContext implements BayeuxContext { + private final HttpServletRequest request; + + JakartaBayeuxContext(HttpServletRequest request) { + this.request = request; + } + + @Override + public Principal getUserPrincipal() { + return request.getUserPrincipal(); + } + + @Override + public boolean isUserInRole(String role) { + return request.isUserInRole(role); + } + + @Override + public SocketAddress getRemoteAddress() { + return new InetSocketAddress(request.getRemoteHost(), request.getRemotePort()); + } + + @Override + public SocketAddress getLocalAddress() { + return new InetSocketAddress(request.getLocalName(), request.getLocalPort()); + } + + @Override + public String getHeader(String name) { + return request.getHeader(name); + } + + @Override + public List getHeaderValues(String name) { + return Collections.list(request.getHeaders(name)); + } + + @Override + public String getParameter(String name) { + return request.getParameter(name); + } + + @Override + public List getParameterValues(String name) { + return List.of(request.getParameterValues(name)); + } + + @Override + public String getCookie(String name) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie c : cookies) { + if (name.equals(c.getName())) { + return c.getValue(); + } + } + } + return null; + } + + @Override + public Object getContextAttribute(String name) { + return getServletContext().getAttribute(name); + } + + @Override + public Object getRequestAttribute(String name) { + return request.getAttribute(name); + } + + @Override + public Object getSessionAttribute(String name) { + HttpSession session = request.getSession(false); + return session != null ? session.getAttribute(name) : null; + } + + private ServletContext getServletContext() { + return request.getServletContext(); + } + + @Override + public String getContextPath() { + return request.getContextPath(); + } + + @Override + public String getURL() { + StringBuffer url = request.getRequestURL(); + String query = request.getQueryString(); + if (query != null) { + url.append("?").append(query); + } + return url.toString(); + } + + @Override + public List getLocales() { + return Collections.list(request.getLocales()); + } + + @Override + public String getProtocol() { + return request.getProtocol(); + } + + @Override + public boolean isSecure() { + return request.isSecure(); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDRequest.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDRequest.java new file mode 100644 index 0000000000..67ff27e9bf --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDRequest.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jakarta; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; + +import org.cometd.server.CometDRequest; +import org.eclipse.jetty.util.IO; + +class JakartaCometDRequest implements CometDRequest { + private final HttpServletRequest request; + private JakartaCometDInput input; + + JakartaCometDRequest(HttpServletRequest request) { + this.request = request; + } + + @Override + public String getCharacterEncoding() { + return request.getCharacterEncoding(); + } + + @Override + public List getCookies() { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + return null; + } + List result = new ArrayList<>(); + for (Cookie cookie : cookies) { + result.add(new CometDCookie(cookie.getName(), cookie.getValue())); + } + return result; + } + + @Override + public String[] getParameterValues(String name) { + return request.getParameterValues(name); + } + + @Override + public String getMethod() { + return request.getMethod(); + } + + @Override + public Input getInput() { + if (input == null) { + try { + input = new JakartaCometDInput(request); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return input; + } + + @Override + public String getProtocol() { + return request.getProtocol(); + } + + @Override + public Object getAttribute(String name) { + return request.getAttribute(name); + } + + @Override + public void setAttribute(String name, Object value) { + request.setAttribute(name, value); + } + + private static class JakartaCometDInput implements Input, ReadListener { + private static final Runnable READ_READY = () -> {}; + + private final ServletInputStream inputStream; + private final AtomicReference state = new AtomicReference<>(); + private volatile Throwable failure; + + private JakartaCometDInput(HttpServletRequest request) throws IOException { + this.inputStream = request.getInputStream(); + if ("POST".equals(request.getMethod())) { + this.inputStream.setReadListener(this); + } + } + + @Override + public void demand(Runnable demandCallback) { + // This method races with onDataAvailable() and onAllDataRead(). + Runnable readReady = state.getAndUpdate(existing -> existing == null ? demandCallback : null); + if (readReady != null) { + // Lost the race with onDataAvailable(), but there + // is data available, so run the demandCallback. + demandCallback.run(); + } + } + + @Override + public Input.Chunk read() throws IOException { + if (failure != null) { + throw IO.rethrow(failure); + } else if (inputStream.isFinished()) { + return Input.Chunk.EOF; + } else if (inputStream.isReady()) { + // TODO: the chunks can be pooled. + Input.Chunk chunk = new Chunk(); + ByteBuffer byteBuffer = chunk.byteBuffer(); + int read = inputStream.read(byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.remaining()); + if (read < 0) { + chunk.release(); + return Input.Chunk.EOF; + } else if (read == 0) { + chunk.release(); + return null; + } else { + byteBuffer.limit(read); + return chunk; + } + } else { + return null; + } + } + + @Override + public void onDataAvailable() { + // This method races with demand(Runnable). + Runnable readCallback = state.getAndUpdate(existing -> existing == null ? READ_READY : null); + if (readCallback != null) { + readCallback.run(); + } + } + + @Override + public void onAllDataRead() { + onDataAvailable(); + } + + @Override + public void onError(Throwable failure) { + this.failure = failure; + onDataAvailable(); + } + + private static class Chunk implements Input.Chunk { + private final ByteBuffer byteBuffer = ByteBuffer.allocate(512); + + @Override + public ByteBuffer byteBuffer() { + return byteBuffer; + } + + @Override + public boolean isLast() { + return false; + } + + @Override + public void release() { + } + + @Override + public String toString() { + return "%s@%x[last=%b,%s]".formatted(getClass().getSimpleName(), hashCode(), isLast(), byteBuffer()); + } + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDResponse.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDResponse.java new file mode 100644 index 0000000000..6c036c9e90 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jakarta/src/main/java/org/cometd/server/http/jakarta/JakartaCometDResponse.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jakarta; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; + +import org.cometd.bayeux.Promise; +import org.cometd.server.CometDResponse; + +class JakartaCometDResponse implements CometDResponse { + private final HttpServletResponse response; + private JakartaCometDOutput output; + + JakartaCometDResponse(HttpServletResponse response) { + this.response = response; + } + + @Override + public void addHeader(String name, String value) { + response.addHeader(name, value); + } + + @Override + public Output getOutput() { + if (output == null) { + try { + output = new JakartaCometDOutput(response); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return output; + } + + @Override + public void setContentType(String contentType) { + response.setContentType(contentType); + } + + private static class JakartaCometDOutput implements Output, WriteListener { + public static final Promise WRITE_READY = new Promise<>() {}; + + private final AtomicReference> state = new AtomicReference<>(); + private final ServletOutputStream outputStream; + + private JakartaCometDOutput(HttpServletResponse response) throws IOException { + this.outputStream = response.getOutputStream(); + this.outputStream.setWriteListener(this); + } + + @Override + public void onWritePossible() { + // This method races with write(). + Promise pendingPromise = state.getAndUpdate(existing -> existing == null ? WRITE_READY : null); + if (pendingPromise != null) { + pendingPromise.succeed(null); + } + } + + @Override + public void onError(Throwable failure) { + // This method races with write(). + Promise pendingPromise = state.getAndUpdate(existing -> existing == null ? WRITE_READY : null); + if (pendingPromise != null) { + pendingPromise.fail(failure); + } + } + + @Override + public void write(boolean last, byte[] bytes, Promise promise) { + try { + outputStream.write(bytes); + if (outputStream.isReady()) { + promise.succeed(null); + } else { + // In a race with onWritePossible(). + Promise writeReady = state.getAndUpdate(existing -> existing == null ? promise : null); + if (writeReady != null) { + // Lost the race with onWritePossible(), but it + // is possible to write, so succeed the promise. + promise.succeed(null); + } + } + } catch (Throwable x) { + promise.fail(x); + } + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/pom.xml new file mode 100644 index 0000000000..8e4fcd1696 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/pom.xml @@ -0,0 +1,67 @@ + + + + org.cometd.java + cometd-java-server-http + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-server-http-jetty + CometD :: Java :: Server :: HTTP :: Jetty + + + + + maven-surefire-plugin + + + @{argLine} + + --add-modules org.eclipse.jetty.jmx + + --add-modules org.eclipse.jetty.util.ajax + + --add-exports org.cometd.server.servlet/org.cometd.server.http.ext=org.cometd.server + --add-exports org.cometd.server.servlet/org.cometd.server.http.ext=ALL-UNNAMED + + + + + + + + + org.eclipse.jetty + jetty-server + ${jetty-version} + + + org.cometd.java + cometd-java-api-server + ${project.version} + + + org.cometd.java + cometd-java-common + ${project.version} + + + org.cometd.java + cometd-java-server-common + ${project.version} + + + org.eclipse.jetty + jetty-jmx + ${jetty-version} + true + + + org.eclipse.jetty + jetty-util-ajax + ${jetty-version} + true + + + diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/module-info.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/module-info.java new file mode 100644 index 0000000000..2687c5ead8 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +module org.cometd.server.http.jetty { + exports org.cometd.server.http.jetty; + + requires transitive org.eclipse.jetty.server; + requires transitive org.cometd.api.server; + requires org.cometd.server; + requires org.slf4j; + + // Only required when using JMX. + requires static org.eclipse.jetty.jmx; + // Only required when using Jetty's JSON. + requires static org.eclipse.jetty.util.ajax; +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/CometDHandler.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/CometDHandler.java new file mode 100644 index 0000000000..446a1ba902 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/CometDHandler.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jetty; + +import java.util.Map; +import java.util.Objects; + +import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.bayeux.server.ServerSession; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.HttpException; +import org.cometd.server.ServerSessionImpl; +import org.cometd.server.http.AbstractHttpTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Context; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.Callback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *

{@code CometDHandler} maps HTTP requests to the HTTP server transports + * of a {@link BayeuxServer} instance.

+ *

The {@link BayeuxServer} instance is created and configured using the + * given {@link #setOptions(Map) options}.

+ */ + +// TODO: can this handler be the direct child of Server? +// In this way we will save the ContextHandler wrapping & machinery. + +public class CometDHandler extends Handler.Abstract { + private static final Logger LOGGER = LoggerFactory.getLogger(CometDHandler.class); + + private Map options = Map.of(); + private BayeuxServer bayeuxServer; + + public CometDHandler() { + this(InvocationType.BLOCKING); + } + + public CometDHandler(InvocationType invocationType) { + super(invocationType); + } + + public Map getOptions() { + return options; + } + + public void setOptions(Map options) { + this.options = Objects.requireNonNull(options); + } + + @Override + protected void doStart() throws Exception { + Context context = ContextHandler.getCurrentContext(getServer()); + bayeuxServer = (BayeuxServer)context.getAttribute(BayeuxServer.ATTRIBUTE); + + boolean export = false; + if (bayeuxServer == null) { + export = true; + bayeuxServer = newBayeuxServer(); + + String transports = JSONHttpTransport.class.getName() + ",org.cometd.server.websocket.jetty.JettyWebSocketTransport"; + bayeuxServer.setOption(BayeuxServerImpl.TRANSPORTS_OPTION, transports); + for (Map.Entry entry : getOptions().entrySet()) { + this.bayeuxServer.setOption(entry.getKey(), entry.getValue()); + } + } + + bayeuxServer.setOption(Context.class.getName(), context); + + addBean(bayeuxServer); + + if (export) { + context.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); + } + + super.doStart(); + } + + @Override + protected void doStop() throws Exception { + for (ServerSession session : bayeuxServer.getSessions()) { + ((ServerSessionImpl)session).destroyScheduler(); + } + super.doStop(); + removeBean(bayeuxServer); + } + + public BayeuxServer getBayeuxServer() { + return bayeuxServer; + } + + protected BayeuxServer newBayeuxServer() { + return new BayeuxServerImpl(); + } + + @Override + public boolean handle(Request request, Response response, Callback callback) { + if ("OPTIONS".equals(request.getMethod())) { + serviceOptions(request, response, callback); + return true; + } + + JettyCometDRequest cometDRequest = new JettyCometDRequest(request); + JettyCometDResponse cometDResponse = new JettyCometDResponse(response); + JettyBayeuxContext bayeuxContext = new JettyBayeuxContext(cometDRequest, request); + + Promise promise = new Promise<>() { + @Override + public void succeed(Void result) { + callback.succeeded(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Handling successful"); + } + } + + @Override + public void fail(Throwable failure) { + int code = failure instanceof HttpException http ? http.getCode() : HttpStatus.INTERNAL_SERVER_ERROR_500; + sendError(request, response, callback, code, failure); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Handling failed", failure); + } + } + }; + + AbstractHttpTransport transport = AbstractHttpTransport.find(bayeuxServer, cometDRequest); + if (transport == null) { + Response.writeError(request, response, callback, HttpStatus.BAD_REQUEST_400, "Unknown Bayeux Transport"); + } else { + transport.handle(bayeuxContext, cometDRequest, cometDResponse, promise); + } + return true; + } + + protected void serviceOptions(Request request, Response response, Callback callback) { + // OPTIONS requests are made by browsers that are CORS compliant + // (see http://www.w3.org/TR/cors/) during a "preflight request". + // Preflight requests happen for each different new URL, then + // results are cached by the browser. + // For the Bayeux protocol, preflight requests happen for URLs + // such as "/cometd/handshake", "/cometd/connect", etc., since + // the Bayeux clients append the Bayeux message type to the base + // Bayeux server URL. + // Just return 200 OK, there is nothing more to add to such requests. + callback.succeeded(); + } + + protected void sendError(Request request, Response response, Callback callback, int code, Throwable failure) { + Response.writeError(request, response, callback, code); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyBayeuxContext.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyBayeuxContext.java new file mode 100644 index 0000000000..0f8bf3c66f --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyBayeuxContext.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jetty; + +import java.net.SocketAddress; +import java.security.Principal; +import java.util.List; +import java.util.Locale; + +import org.cometd.bayeux.server.BayeuxContext; +import org.cometd.server.CometDRequest; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Session; + +class JettyBayeuxContext implements BayeuxContext { + private final JettyCometDRequest cometDRequest; + private final Request request; + + JettyBayeuxContext(JettyCometDRequest cometDRequest, Request request) { + this.cometDRequest = cometDRequest; + this.request = request; + } + + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public boolean isUserInRole(String role) { + return false; + } + + @Override + public SocketAddress getRemoteAddress() { + return request.getConnectionMetaData().getRemoteSocketAddress(); + } + + @Override + public SocketAddress getLocalAddress() { + return request.getConnectionMetaData().getLocalSocketAddress(); + } + + @Override + public String getHeader(String name) { + return request.getHeaders().get(name); + } + + @Override + public List getHeaderValues(String name) { + return request.getHeaders().getValuesList(name); + } + + @Override + public String getParameter(String name) { + return Request.extractQueryParameters(request).getValue(name); + } + + @Override + public List getParameterValues(String name) { + return Request.extractQueryParameters(request).getValues(name); + } + + @Override + public String getCookie(String name) { + return cometDRequest.getCookies().stream() + .filter(cometDCookie -> cometDCookie.name().equals(name)) + .map(CometDRequest.CometDCookie::value) + .findFirst() + .orElse(null); + } + + @Override + public Object getContextAttribute(String name) { + return request.getContext().getAttribute(name); + } + + @Override + public Object getRequestAttribute(String name) { + return request.getAttribute(name); + } + + @Override + public Object getSessionAttribute(String name) { + Session session = request.getSession(false); + return session == null ? null : session.getAttribute(name); + } + + @Override + public String getContextPath() { + return request.getContext().getContextPath(); + } + + @Override + public String getURL() { + return request.getHttpURI().asString(); + } + + @Override + public List getLocales() { + return Request.getLocales(request); + } + + @Override + public String getProtocol() { + return request.getConnectionMetaData().getProtocol(); + } + + @Override + public boolean isSecure() { + return request.getConnectionMetaData().isSecure(); + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDRequest.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDRequest.java new file mode 100644 index 0000000000..6f8fc655e7 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDRequest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jetty; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +import org.cometd.server.CometDRequest; +import org.eclipse.jetty.http.CookieCache; +import org.eclipse.jetty.http.HttpCookie; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.IO; + +class JettyCometDRequest implements CometDRequest { + private final Request request; + private final CookieCache cookieCache = new CookieCache(); + private Input cometDInput; + + public JettyCometDRequest(Request request) { + this.request = request; + } + + @Override + public String getCharacterEncoding() { + String[] split = request.getHeaders().get(HttpHeader.CONTENT_TYPE).split(";"); + if (split.length == 2) + return split[1].split("=")[1]; + return "iso-8859-1"; + } + + @Override + public List getCookies() { + List cookies = cookieCache.getCookies(request.getHeaders()); + return cookies.stream() + .map(httpCookie -> new CometDCookie(httpCookie.getName(), httpCookie.getValue())) + .toList(); + } + + @Override + public String[] getParameterValues(String name) { + throw new UnsupportedOperationException("REMOVE API?"); + } + + @Override + public String getMethod() { + return request.getMethod(); + } + + @Override + public String getProtocol() { + return request.getConnectionMetaData().getProtocol(); + } + + @Override + public Input getInput() { + if (cometDInput == null) { + cometDInput = new JettyCometDInput(this); + } + return cometDInput; + } + + @Override + public Object getAttribute(String name) { + return request.getAttribute(name); + } + + @Override + public void setAttribute(String name, Object value) { + request.setAttribute(name, value); + } + + private static class JettyCometDInput implements Input { + private final JettyCometDRequest request; + + private JettyCometDInput(JettyCometDRequest request) { + this.request = request; + } + + @Override + public void demand(Runnable r) { + request.request.demand(r); + } + + @Override + public Input.Chunk read() throws IOException { + Content.Chunk chunk = request.request.read(); + if (chunk == null) { + return null; + } + if (Content.Chunk.isFailure(chunk)) { + throw IO.rethrow(chunk.getFailure()); + } + return new Chunk(chunk); + } + + private static class Chunk implements Input.Chunk { + private final Content.Chunk chunk; + + private Chunk(Content.Chunk chunk) { + this.chunk = chunk; + } + + @Override + public ByteBuffer byteBuffer() { + return chunk.getByteBuffer(); + } + + @Override + public boolean isLast() { + return chunk.isLast(); + } + + @Override + public void release() { + chunk.release(); + } + + @Override + public String toString() { + return "%s@%x[%s]".formatted(getClass().getSimpleName(), hashCode(), chunk); + } + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDResponse.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDResponse.java new file mode 100644 index 0000000000..39429bab0c --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-jetty/src/main/java/org/cometd/server/http/jetty/JettyCometDResponse.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http.jetty; + +import java.nio.ByteBuffer; + +import org.cometd.bayeux.Promise; +import org.cometd.server.CometDResponse; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; + +class JettyCometDResponse implements CometDResponse { + private final Response response; + private Output cometDOutput; + + JettyCometDResponse(Response response) { + this.response = response; + } + + @Override + public void addHeader(String name, String value) { + response.getHeaders().add(name, value); + } + + @Override + public Output getOutput() { + if (cometDOutput == null) { + cometDOutput = new JettyCometDOutput(Response.asBufferedSink(response.getRequest(), response)); + } + return cometDOutput; + } + + @Override + public void setContentType(String contentType) { + response.getHeaders().put(HttpHeader.CONTENT_TYPE, contentType); + } + + private static class JettyCometDOutput implements Output { + private final Content.Sink sink; + + private JettyCometDOutput(Content.Sink sink) { + this.sink = sink; + } + + @Override + public void write(boolean last, byte[] bytes, Promise promise) { + sink.write(last, ByteBuffer.wrap(bytes), new Callback() { + @Override + public void succeeded() { + promise.succeed(null); + } + + @Override + public void failed(Throwable x) { + promise.fail(x); + } + }); + } + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/pom.xml new file mode 100644 index 0000000000..2557632fb3 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/pom.xml @@ -0,0 +1,47 @@ + + + + org.cometd.java + cometd-java-server-http + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-server-http-tests + CometD :: Java :: Server :: HTTP :: Tests + + + + org.cometd.java + cometd-java-server-http-jakarta + ${project.version} + test + + + org.cometd.java + cometd-java-server-http-jetty + ${project.version} + test + + + org.eclipse.jetty + jetty-client + ${jetty-version} + test + + + org.eclipse.jetty.ee10 + jetty-ee10-servlet + ${jetty-version} + test + + + org.eclipse.jetty + jetty-util-ajax + ${jetty-version} + test + + + diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxClientServerTest.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxClientServerTest.java similarity index 98% rename from cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxClientServerTest.java rename to cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxClientServerTest.java index d169c94f71..86b2956c93 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/AbstractBayeuxClientServerTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxClientServerTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.server; +package org.cometd.server.http; import java.io.UnsupportedEncodingException; import java.net.URI; diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxServerTest.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxServerTest.java new file mode 100644 index 0000000000..f4e48bb15a --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/AbstractBayeuxServerTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008-2022 the original author or authors. + * + * Licensed 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. + */ +package org.cometd.server.http; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.http.jakarta.CometDServlet; +import org.cometd.server.http.jetty.CometDHandler; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.RegisterExtension; + +public abstract class AbstractBayeuxServerTest { + public static Transport[] transports() { + return Transport.values(); + } + + @RegisterExtension + public final BeforeTestExecutionCallback printMethodName = context -> + System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); + protected Server server; + protected ServerConnector connector; + protected int port; + protected ContextHandler context; + protected String cometdURL; + protected BayeuxServerImpl bayeux; + protected long timeout = 2000; + + public void startServer(Transport transport, Map options) throws Exception { + server = new Server(); + connector = new ServerConnector(server); + server.addConnector(connector); + + String contextPath = "/"; + String cometdPath = "/cometd"; + Supplier getBayeuxServer = switch (transport) { + case JAKARTA -> { + ServletContextHandler servletContext = new ServletContextHandler(contextPath); + context = servletContext; + server.setHandler(context); + CometDServlet cometdServlet = new CometDServlet(); + ServletHolder cometdServletHolder = new ServletHolder(cometdServlet); + if (options == null) { + options = new HashMap<>(); + } + options.put("timeout", String.valueOf(timeout)); + options.put("transports", JSONHttpTransport.class.getName()); + for (Map.Entry entry : options.entrySet()) { + cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + } + servletContext.addServlet(cometdServletHolder, cometdPath + "/*"); + yield cometdServlet::getBayeuxServer; + } + case JETTY -> { + context = new ContextHandler(contextPath); + server.setHandler(context); + CometDHandler cometdHandler = new CometDHandler(); + context.setHandler(cometdHandler); + if (options == null) { + options = new HashMap<>(); + } + options.put("timeout", String.valueOf(timeout)); + options.put("transports", JSONHttpTransport.class.getName()); + cometdHandler.setOptions(options); + yield cometdHandler::getBayeuxServer; + } + }; + + server.start(); + port = connector.getLocalPort(); + + cometdURL = "http://localhost:" + port + cometdPath; + + bayeux = (BayeuxServerImpl)getBayeuxServer.get(); + } + + @AfterEach + public void stopServer() throws Exception { + if (server != null) { + server.stop(); + } + } + + public enum Transport { + JAKARTA, JETTY + } +} diff --git a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BadJSONTest.java b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/BadJSONTest.java similarity index 51% rename from cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BadJSONTest.java rename to cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/BadJSONTest.java index d12677f01e..06bfb4be3a 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-common/src/test/java/org/cometd/server/BadJSONTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/java/org/cometd/server/http/BadJSONTest.java @@ -13,92 +13,80 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.cometd.server; - -import java.io.IOException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +package org.cometd.server.http; import org.cometd.bayeux.Message; import org.cometd.common.JSONContext; import org.cometd.common.JettyJSONContextClient; -import org.cometd.server.http.JSONTransport; import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.Request; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; public class BadJSONTest extends AbstractBayeuxClientServerTest { - @Test - public void testBadJSON() throws Exception { - startServer(JSONTransport.class.getName(), null); - - JSONTransport transport = new JSONTransport(bayeux) { - @Override - protected void handleJSONParseException(HttpServletRequest request, HttpServletResponse response, String json, Throwable exception) throws IOException { - // Suppress logging during tests - if (!response.isCommitted()) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - } - } - }; - transport.init(); - bayeux.setTransports(transport); - - Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); + @ParameterizedTest + @MethodSource("transports") + public void testBadJSON(Transport transport) throws Exception { + startServer(transport, null); + + Request handshake = newBayeuxRequest(""" + [{ + "channel": "/meta/handshake", + "version": "1.0", + "minimumVersion": "1.0", + "supportedConnectionTypes": ["long-polling"] + }] + """); ContentResponse response = handshake.send(); Assertions.assertEquals(200, response.getStatus()); String clientId = extractClientId(response); - Request connect = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); + Request connect = newBayeuxRequest(""" + [{ + "channel": "/meta/connect", + "clientId": "%s", + "connectionType": "long-polling" + }] + """.formatted(clientId)); response = connect.send(); Assertions.assertEquals(200, response.getStatus()); - // Forge a bad JSON message - Request badConnect = newBayeuxRequest("[{" + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\""); - //"}]"); Bad JSON, missing this line + // Forge a bad JSON message, missing the closing brackets. + Request badConnect = newBayeuxRequest(""" + [{ + "channel": "/meta/connect", + "clientId": "%s", + "connectionType": "long-polling" + """.formatted(clientId)); response = badConnect.send(); Assertions.assertEquals(400, response.getStatus()); } @ParameterizedTest @MethodSource("transports") - public void testValidation(String serverTransport) throws Exception { - startServer(serverTransport, null); + public void testValidation(Transport transport) throws Exception { + startServer(transport, null); Request handshake = newBayeuxRequest("[{" + - "\"channel\": \"/meta/handshake\"," + - "\"version\": \"1.0\"," + - "\"minimumVersion\": \"1.0\"," + - "\"supportedConnectionTypes\": [\"long-polling\"]" + - "}]"); + "\"channel\": \"/meta/handshake\"," + + "\"version\": \"1.0\"," + + "\"minimumVersion\": \"1.0\"," + + "\"supportedConnectionTypes\": [\"long-polling\"]" + + "}]"); ContentResponse response = handshake.send(); Assertions.assertEquals(200, response.getStatus()); String clientId = extractClientId(response); Request connect = newBayeuxRequest("[{" + - "\"id\": \"\"," + - "\"channel\": \"/meta/connect\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"connectionType\": \"long-polling\"" + - "}]"); + "\"id\": \"\"," + + "\"channel\": \"/meta/connect\"," + + "\"clientId\": \"" + clientId + "\"," + + "\"connectionType\": \"long-polling\"" + + "}]"); response = connect.send(); Assertions.assertEquals(200, response.getStatus()); JSONContext.Client jsonContext = new JettyJSONContextClient(); @@ -107,10 +95,10 @@ public void testValidation(String serverTransport) throws Exception { Assertions.assertFalse(reply.isSuccessful()); Request subscribe = newBayeuxRequest("[{" + - "\"channel\": \"/meta/subscribe\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"subscription\": \"/bar"; Request publish = newBayeuxRequest("[{" + - "\"channel\": \"" + unfiltered + "\"," + - "\"clientId\": \"" + clientId + "\"," + - "\"data\": {" + - " \"message\": \"" + script + "\"" + - "}" + - "}]"); + "\"channel\": \"" + unfiltered + "\"," + + "\"clientId\": \"" + clientId + "\"," + + "\"data\": {" + + " \"message\": \"" + script + "\"" + + "}" + + "}]"); response = publish.send(); Assertions.assertEquals(200, response.getStatus()); diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/cometd-java-server-http-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-server/cometd-java-server-http/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-http/pom.xml new file mode 100644 index 0000000000..b83becc5c2 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-http/pom.xml @@ -0,0 +1,19 @@ + + + + org.cometd.java + cometd-java-server + 8.0.0-SNAPSHOT + + + 4.0.0 + cometd-java-server-http + pom + CometD :: Java :: Server :: HTTP + + + cometd-java-server-http-jakarta + cometd-java-server-http-jetty + cometd-java-server-http-tests + + diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/pom.xml index 102902fbc8..9b8fdc2ac0 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/pom.xml +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/pom.xml @@ -11,10 +11,6 @@ CometD :: Java :: Server :: WebSocket :: Common - - jakarta.servlet - jakarta.servlet-api - org.cometd.java cometd-java-api-server @@ -39,18 +35,5 @@ org.slf4j slf4j-api - - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractBayeuxContext.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractBayeuxContext.java index 1d101998fb..105b316c08 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractBayeuxContext.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractBayeuxContext.java @@ -16,15 +16,14 @@ package org.cometd.server.websocket.common; import java.net.HttpCookie; -import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.security.Principal; import java.text.ParseException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TreeMap; -import jakarta.servlet.ServletContext; -import jakarta.servlet.http.HttpSession; + import org.cometd.bayeux.server.BayeuxContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,26 +31,24 @@ public abstract class AbstractBayeuxContext implements BayeuxContext { private static final Logger logger = LoggerFactory.getLogger(BayeuxContext.class); - private final ServletContext context; private final String url; + private final String contextPath; private final Map> headers; private final Map> parameters; private final Principal principal; - private final HttpSession session; - private final InetSocketAddress localAddress; - private final InetSocketAddress remoteAddress; + private final SocketAddress localAddress; + private final SocketAddress remoteAddress; private final List locales; private final String protocol; private final boolean secure; - public AbstractBayeuxContext(ServletContext context, String uri, String query, Map> headers, Map> parameters, Principal principal, HttpSession session, InetSocketAddress local, InetSocketAddress remote, List locales, String protocol, boolean secure) { - this.context = context; + public AbstractBayeuxContext(String uri, String contextPath, String query, Map> headers, Map> parameters, Principal principal, SocketAddress local, SocketAddress remote, List locales, String protocol, boolean secure) { this.url = uri + (query == null ? "" : "?" + query); + this.contextPath = contextPath; this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); this.headers.putAll(headers); this.parameters = parameters; this.principal = principal; - this.session = session; this.localAddress = local; this.remoteAddress = remote; this.locales = locales; @@ -97,36 +94,12 @@ public boolean isUserInRole(String role) { } @Override - public String getHttpSessionId() { - return session == null ? null : session.getId(); - } - - @Override - public Object getHttpSessionAttribute(String name) { - return session == null ? null : session.getAttribute(name); - } - - @Override - public void setHttpSessionAttribute(String name, Object value) { - if (session != null) { - session.setAttribute(name, value); - } - } - - @Override - public void invalidateHttpSession() { - if (session != null) { - session.invalidate(); - } - } - - @Override - public InetSocketAddress getRemoteAddress() { + public SocketAddress getRemoteAddress() { return remoteAddress; } @Override - public InetSocketAddress getLocalAddress() { + public SocketAddress getLocalAddress() { return localAddress; } @@ -156,23 +129,23 @@ public String getCookie(String name) { } @Override - public Object getRequestAttribute(String name) { + public Object getContextAttribute(String name) { return null; } @Override - public Object getContextAttribute(String name) { - return context.getAttribute(name); + public Object getRequestAttribute(String name) { + return null; } @Override - public String getContextInitParameter(String name) { - return context.getInitParameter(name); + public Object getSessionAttribute(String name) { + return null; } @Override public String getContextPath() { - return context.getContextPath(); + return contextPath; } @Override diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractWebSocketEndPoint.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractWebSocketEndPoint.java index cfbdd64e87..23b1efba36 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractWebSocketEndPoint.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-common/src/main/java/org/cometd/server/websocket/common/AbstractWebSocketEndPoint.java @@ -16,7 +16,7 @@ package org.cometd.server.websocket.common; import java.io.IOException; -import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.text.ParseException; import java.util.ArrayDeque; @@ -38,7 +38,6 @@ import org.cometd.server.AbstractServerTransport; import org.cometd.server.ServerMessageImpl; import org.cometd.server.ServerSessionImpl; -import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.thread.AutoLock; import org.eclipse.jetty.util.thread.Scheduler; @@ -58,7 +57,7 @@ protected AbstractWebSocketEndPoint(AbstractWebSocketTransport transport, Bayeux this._bayeuxContext = context; } - protected abstract void send(ServerSession session, String data, Callback callback); + protected abstract void send(ServerSession session, String data, Promise promise); public abstract void close(int code, String reason); @@ -109,7 +108,7 @@ public void onError(Throwable failure) { _logger.debug("WebSocket timeout on {}", this, failure); } } else { - InetSocketAddress address = _bayeuxContext == null ? null : _bayeuxContext.getRemoteAddress(); + SocketAddress address = _bayeuxContext == null ? null : _bayeuxContext.getRemoteAddress(); if (_logger.isDebugEnabled()) { _logger.debug("WebSocket failure, address {} on {}", address, this, failure); } @@ -125,15 +124,15 @@ private void processMessages(ServerMessage.Mutable[] messages, Promise pro ServerMessage.Mutable m = messages[0]; if (Channel.META_HANDSHAKE.equals(m.getChannel())) { _session = null; - session = _transport.getBayeux().newServerSession(); + session = _transport.getBayeuxServer().newServerSession(); session.setAllowMessageDeliveryDuringHandshake(_transport.isAllowMessageDeliveryDuringHandshake()); } else { session = _session; if (session == null) { if (!_transport.isRequireHandshakePerConnection()) { - session = _session = (ServerSessionImpl)_transport.getBayeux().getSession(m.getClientId()); + session = _session = (ServerSessionImpl)_transport.getBayeuxServer().getSession(m.getClientId()); } - } else if (_transport.getBayeux().getSession(session.getId()) == null) { + } else if (_transport.getBayeuxServer().getSession(session.getId()) == null) { session = _session = null; } } @@ -199,7 +198,7 @@ private void processMessage(ServerMessage.Mutable[] messages, Context context, S private void processMetaHandshake(Context context, ServerMessage.Mutable message, Promise promise) { ServerSessionImpl session = context.session; - _transport.getBayeux().handle(session, message, Promise.from(reply -> { + _transport.getBayeuxServer().handle(session, message, Promise.from(reply -> { _transport.processReply(session, reply, Promise.from(r -> { if (r != null) { context.replies.add(r); @@ -218,7 +217,7 @@ private void processMetaConnect(Context context, ServerMessage.Mutable message, ServerSessionImpl session = context.session; // Remember the connected status before handling the message. boolean wasConnected = session != null && session.isConnected(); - _transport.getBayeux().handle(session, message, Promise.from(reply -> { + _transport.getBayeuxServer().handle(session, message, Promise.from(reply -> { boolean proceed = true; if (session != null) { boolean maySuspend = !session.shouldSchedule(); @@ -241,7 +240,7 @@ private void processMetaConnect(Context context, ServerMessage.Mutable message, private void processMessage(Context context, ServerMessageImpl message, Promise promise) { ServerSessionImpl session = context.session; - _transport.getBayeux().handle(session, message, Promise.from(y -> + _transport.getBayeuxServer().handle(session, message, Promise.from(y -> _transport.processReply(session, message.getAssociated(), Promise.from(reply -> { if (reply != null) { context.replies.add(reply); @@ -333,7 +332,7 @@ private class WebSocketScheduler implements AbstractServerTransport.Scheduler, R public WebSocketScheduler(Context context, ServerMessage.Mutable message, long timeout) { this.context = context; this.message = message; - this.taskRef = new AtomicMarkableReference<>(timeout > 0 ? _transport.getBayeux().schedule(this, timeout) : null, true); + this.taskRef = new AtomicMarkableReference<>(timeout > 0 ? _transport.getBayeuxServer().schedule(this, timeout) : null, true); context.metaConnectCycle = _transport.newMetaConnectCycle(); } @@ -387,7 +386,7 @@ private void flush(Context context) { } private void executeFlush(Context context, Promise promise) { - _transport.getBayeux().execute(() -> AbstractWebSocketEndPoint.this.flush(context, promise)); + _transport.getBayeuxServer().execute(() -> AbstractWebSocketEndPoint.this.flush(context, promise)); } @Override @@ -454,7 +453,7 @@ public String toString() { } } - private class Flusher extends IteratingCallback { + private class Flusher extends IteratingCallback implements Promise { private final AutoLock _lock = new AutoLock(); private final Queue _entries = new ArrayDeque<>(); private State _state = State.IDLE; @@ -506,7 +505,7 @@ protected Action process() { if (_transport.allowMessageDeliveryDuringHandshake(_session) && !queue.isEmpty()) { reply.put("x-messages", queue.size()); } - _transport.getBayeux().freeze(reply); + _transport.getBayeuxServer().freeze(reply); _buffer.setLength(0); _buffer.append("["); _buffer.append(toJSON(reply)); @@ -560,7 +559,7 @@ protected Action process() { boolean comma = false; while (_replyIndex < size) { ServerMessage.Mutable reply = replies.get(_replyIndex); - _transport.getBayeux().freeze(reply); + _transport.getBayeuxServer().freeze(reply); if (comma) { _buffer.append(","); } @@ -591,6 +590,16 @@ protected Action process() { } } + @Override + public void succeed(Void result) { + succeeded(); + } + + @Override + public void fail(Throwable failure) { + failed(failure); + } + @Override protected void onCompleteFailure(Throwable x) { List entries; diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/pom.xml index 6fac72f87f..707641bc0b 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/pom.xml +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/pom.xml @@ -8,7 +8,7 @@ 4.0.0 cometd-java-server-websocket-jakarta - CometD :: Java :: Server :: WebSocket :: EE10 + CometD :: Java :: Server :: WebSocket :: Jakarta EE10 diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/module-info.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/module-info.java index fb2ce40345..cb703d6a5d 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/module-info.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/module-info.java @@ -19,4 +19,5 @@ requires transitive jakarta.websocket; requires transitive org.cometd.server.websocket.common; requires org.slf4j; + requires jakarta.servlet; } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketEndPoint.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketEndPoint.java index 449a33d2f8..8938f67d45 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketEndPoint.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketEndPoint.java @@ -29,7 +29,6 @@ import org.cometd.bayeux.server.ServerSession; import org.cometd.server.websocket.common.AbstractWebSocketEndPoint; import org.cometd.server.websocket.common.AbstractWebSocketTransport; -import org.eclipse.jetty.util.Callback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +93,7 @@ public Delegate(AbstractWebSocketTransport transport, BayeuxContext bayeuxContex } @Override - protected void send(ServerSession session, String data, Callback callback) { + protected void send(ServerSession session, String data, Promise promise) { if (_logger.isDebugEnabled()) { _logger.debug("Sending {} on {}", data, this); } @@ -102,9 +101,9 @@ protected void send(ServerSession session, String data, Callback callback) { _wsSession.getAsyncRemote().sendText(data, result -> { Throwable failure = result.getException(); if (failure == null) { - callback.succeeded(); + promise.succeed(null); } else { - callback.failed(failure); + promise.fail(failure); } }); } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketTransport.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketTransport.java index 8544ae5846..350b5e7063 100755 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketTransport.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jakarta/src/main/java/org/cometd/server/websocket/jakarta/WebSocketTransport.java @@ -15,13 +15,16 @@ */ package org.cometd.server.websocket.jakarta; -import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Function; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpSession; import jakarta.websocket.DeploymentException; @@ -51,7 +54,7 @@ public WebSocketTransport(BayeuxServerImpl bayeux) { public void init() { super.init(); - ServletContext context = (ServletContext)getOption(ServletContext.class.getName()); + ServletContext context = (ServletContext)getBayeuxServer().getOption(ServletContext.class.getName()); if (context == null) { throw new IllegalArgumentException("Missing ServletContext"); } @@ -105,15 +108,57 @@ protected Object newWebSocketEndPoint(BayeuxContext bayeuxContext) { return new EndPoint(bayeuxContext); } - private static class WebSocketContext extends AbstractBayeuxContext { - private WebSocketContext(ServletContext context, HandshakeRequest request, Map userProperties) { - super(context, request.getRequestURI().toString(), request.getQueryString(), request.getHeaders(), - request.getParameterMap(), request.getUserPrincipal(), (HttpSession)request.getHttpSession(), + private static class JakartaWebSocketContext extends AbstractBayeuxContext { + private final Map contextAttributes; + private final Map requestAttributes; + private final Map sessionAttributes; + + private JakartaWebSocketContext(ServletContext context, HandshakeRequest request, Map userProperties) { + super(request.getRequestURI().toString(), context.getContextPath(), request.getQueryString(), request.getHeaders(), + request.getParameterMap(), request.getUserPrincipal(), // Hopefully these will become a standard, for now they are Jetty specific. - (InetSocketAddress)userProperties.get("jakarta.websocket.endpoint.localAddress"), - (InetSocketAddress)userProperties.get("jakarta.websocket.endpoint.remoteAddress"), + (SocketAddress)userProperties.get("jakarta.websocket.endpoint.localAddress"), + (SocketAddress)userProperties.get("jakarta.websocket.endpoint.remoteAddress"), WebSocketTransport.retrieveLocales(userProperties), "HTTP/1.1", WebSocketTransport.isSecure(request)); + contextAttributes = Map.copyOf(attributesToMap(context)); + requestAttributes = Map.of(); + sessionAttributes = Map.copyOf(attributesToMap((HttpSession)request.getHttpSession())); + } + + private static Map attributesToMap(ServletContext context) { + return attributesToMap(context.getAttributeNames(), context::getAttribute); + } + + private static Map attributesToMap(HttpSession session) { + if (session == null) { + return Map.of(); + } + return attributesToMap(session.getAttributeNames(), session::getAttribute); + } + + private static Map attributesToMap(Enumeration names, Function getter) { + Map result = new HashMap<>(); + while (names.hasMoreElements()) { + String name = names.nextElement(); + result.put(name, getter.apply(name)); + } + return result; + } + + @Override + public Object getContextAttribute(String name) { + return contextAttributes.get(name); + } + + @Override + public Object getRequestAttribute(String name) { + return requestAttributes.get(name); + } + + @Override + public Object getSessionAttribute(String name) { + return sessionAttributes.get(name); } } @@ -141,7 +186,7 @@ private Configurator(ServletContext servletContext) { @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { BayeuxContextHolder context = provideContext(); - context.bayeuxContext = new WebSocketContext(servletContext, request, sec.getUserProperties()); + context.bayeuxContext = new JakartaWebSocketContext(servletContext, request, sec.getUserProperties()); WebSocketTransport.this.modifyHandshake(request, response); } @@ -183,7 +228,7 @@ public List getNegotiatedExtensions(List installed, List T getEndpointInstance(Class endpointClass) throws InstantiationException { BayeuxContextHolder holder = provideContext(); - if (!getBayeux().getAllowedTransports().contains(getName())) { + if (!getBayeuxServer().getAllowedTransports().contains(getName())) { throw new InstantiationException("Transport not allowed"); } if (!holder.protocolMatches) { @@ -223,7 +268,7 @@ private BayeuxContextHolder provideContext() { private static class BayeuxContextHolder { private static final ThreadLocal holder = new ThreadLocal<>(); - private WebSocketContext bayeuxContext; + private JakartaWebSocketContext bayeuxContext; private boolean protocolMatches; public void clear() { diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/pom.xml index 431b476ea6..8701da656f 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/pom.xml +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/pom.xml @@ -21,10 +21,9 @@ ${project.version} - org.eclipse.jetty.ee10.websocket - jetty-ee10-websocket-jetty-server + org.eclipse.jetty.websocket + jetty-websocket-jetty-server ${jetty-version} - provided org.slf4j diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/module-info.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/module-info.java index 91017da461..81bf6aeb55 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/module-info.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/module-info.java @@ -17,6 +17,6 @@ exports org.cometd.server.websocket.jetty; requires transitive org.cometd.server.websocket.common; - requires transitive org.eclipse.jetty.ee10.websocket.jetty.server; + requires transitive org.eclipse.jetty.websocket.server; requires org.slf4j; } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketEndPoint.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketEndPoint.java index ba2ef33eaa..e4997dcb0a 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketEndPoint.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketEndPoint.java @@ -19,7 +19,6 @@ import org.cometd.bayeux.server.BayeuxContext; import org.cometd.bayeux.server.ServerSession; import org.cometd.server.websocket.common.AbstractWebSocketEndPoint; -import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.websocket.api.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,21 +58,20 @@ public void onWebSocketError(Throwable failure) { } @Override - protected void send(ServerSession session, String data, Callback callback) { + protected void send(ServerSession session, String data, Promise promise) { if (_logger.isDebugEnabled()) { _logger.debug("Sending {} on {}", data, this); } - // Async version. _wsSession.sendText(data, new org.eclipse.jetty.websocket.api.Callback() { @Override public void succeed() { - callback.succeeded(); + promise.succeed(null); } @Override public void fail(Throwable x) { - callback.failed(x); + promise.fail(x); } }); } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketTransport.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketTransport.java index c9f2a411aa..814671f95f 100755 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketTransport.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-jetty/src/main/java/org/cometd/server/websocket/jetty/JettyWebSocketTransport.java @@ -15,24 +15,26 @@ */ package org.cometd.server.websocket.jetty; -import java.net.InetSocketAddress; import java.time.Duration; import java.util.ArrayList; -import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import jakarta.servlet.ServletContext; -import jakarta.servlet.http.HttpSession; import org.cometd.bayeux.server.BayeuxContext; import org.cometd.bayeux.server.ServerMessage; import org.cometd.server.BayeuxServerImpl; import org.cometd.server.websocket.common.AbstractBayeuxContext; import org.cometd.server.websocket.common.AbstractWebSocketTransport; -import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeRequest; -import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeResponse; -import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.server.Context; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Session; +import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.websocket.api.ExtensionConfig; +import org.eclipse.jetty.websocket.server.ServerUpgradeRequest; +import org.eclipse.jetty.websocket.server.ServerUpgradeResponse; +import org.eclipse.jetty.websocket.server.ServerWebSocketContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,9 +49,9 @@ public JettyWebSocketTransport(BayeuxServerImpl bayeux) { public void init() { super.init(); - ServletContext context = (ServletContext)getOption(ServletContext.class.getName()); + Context context = (Context)getBayeuxServer().getOption(Context.class.getName()); if (context == null) { - throw new IllegalArgumentException("Missing ServletContext"); + throw new IllegalArgumentException("Missing Context"); } String cometdURLMapping = (String)getOption(COMETD_URL_MAPPING_OPTION); @@ -57,7 +59,7 @@ public void init() { throw new IllegalArgumentException("Missing '" + COMETD_URL_MAPPING_OPTION + "' parameter"); } - JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(context); + ServerWebSocketContainer container = ServerWebSocketContainer.get(context); if (container == null) { throw new IllegalArgumentException("Missing JettyWebSocketServerContainer"); } @@ -74,10 +76,10 @@ public void init() { container.setIdleTimeout(Duration.ofMillis(idleTimeout)); for (String mapping : normalizeURLMapping(cometdURLMapping)) { - container.addMapping(mapping, (request, response) -> { - String origin = request.getHeader("Origin"); + container.addMapping(mapping, (request, response, callback) -> { + String origin = request.getHeaders().get("Origin"); if (origin == null) { - origin = request.getHeader("Sec-WebSocket-Origin"); + origin = request.getHeaders().get("Sec-WebSocket-Origin"); } if (checkOrigin(request, origin)) { List negotiated = new ArrayList<>(); @@ -92,9 +94,9 @@ public void init() { modifyUpgrade(request, response); - List allowedTransports = getBayeux().getAllowedTransports(); + List allowedTransports = getBayeuxServer().getAllowedTransports(); if (allowedTransports.contains(getName())) { - WebSocketContext handshake = new WebSocketContext(context, request); + JettyWebSocketContext handshake = new JettyWebSocketContext(request); Object instance = newWebSocketEndPoint(handshake); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Created {}", instance); @@ -119,35 +121,74 @@ protected Object newWebSocketEndPoint(BayeuxContext bayeuxContext) { return new EndPoint(bayeuxContext); } - protected void modifyUpgrade(JettyServerUpgradeRequest request, JettyServerUpgradeResponse response) { + protected void modifyUpgrade(ServerUpgradeRequest request, ServerUpgradeResponse response) { } - protected boolean checkOrigin(JettyServerUpgradeRequest request, String origin) { + protected boolean checkOrigin(ServerUpgradeRequest request, String origin) { return true; } - private static class WebSocketContext extends AbstractBayeuxContext { - private final Map attributes; + private static class JettyWebSocketContext extends AbstractBayeuxContext { + private final Map contextAttributes; + private final Map requestAttributes; + private final Map sessionAttributes; + + private JettyWebSocketContext(ServerUpgradeRequest request) { + super(request.getHttpURI().toString(), request.getContext().getContextPath(), null, headersToMap(request), + queryToMap(request), /*TODO*/null, + request.getConnectionMetaData().getLocalSocketAddress(), request.getConnectionMetaData().getRemoteSocketAddress(), + Request.getLocales(request), "HTTP/1.1", request.isSecure()); + this.contextAttributes = Map.copyOf(request.getContext().asAttributeMap()); + this.requestAttributes = Map.copyOf(request.asAttributeMap()); + Session session = request.getSession(false); + this.sessionAttributes = session == null ? Map.of() : Map.copyOf(session.asAttributeMap()); + } + + private static Map> headersToMap(ServerUpgradeRequest request) { + HttpFields headers = request.getHeaders(); + Map> result = new LinkedHashMap<>(); + headers.forEach(field -> { + String name = field.getName(); + result.compute(name, (k, v) -> { + if (v == null) { + v = new ArrayList<>(1); + } + v.addAll(field.getValueList()); + return v; + }); + }); + return result; + } + + private static Map> queryToMap(ServerUpgradeRequest request) { + Fields fields = Request.extractQueryParameters(request); + Map> result = new LinkedHashMap<>(); + fields.forEach(field -> { + String name = field.getName(); + result.compute(name, (k, v) -> { + if (v == null) { + v = new ArrayList<>(1); + } + v.addAll(field.getValues()); + return v; + }); + }); + return result; + } - private WebSocketContext(ServletContext context, JettyServerUpgradeRequest request) { - super(context, request.getRequestURI().toString(), request.getQueryString(), request.getHeaders(), - request.getParameterMap(), request.getUserPrincipal(), getHttpSession(request), - (InetSocketAddress)request.getLocalSocketAddress(), (InetSocketAddress)request.getRemoteSocketAddress(), - Collections.list(request.getLocales()), "HTTP/1.1", request.isSecure()); - this.attributes = request.getServletAttributes(); + @Override + public Object getContextAttribute(String name) { + return contextAttributes.get(name); } @Override public Object getRequestAttribute(String name) { - return attributes.get(name); + return requestAttributes.get(name); } - private static HttpSession getHttpSession(JettyServerUpgradeRequest request) { - try { - return (HttpSession)request.getSession(); - } catch (Throwable x) { - return null; - } + @Override + public Object getSessionAttribute(String name) { + return sessionAttributes.get(name); } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/pom.xml b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/pom.xml index 702b641b36..a1fa513f77 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/pom.xml +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/pom.xml @@ -15,18 +15,6 @@ - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - jakarta.servlet jakarta.servlet-api @@ -63,7 +51,13 @@ org.cometd.java - cometd-java-server-common + cometd-java-server-http-jakarta + ${project.version} + test + + + org.cometd.java + cometd-java-server-http-jetty ${project.version} test @@ -110,8 +104,8 @@ test - org.eclipse.jetty.ee10.websocket - jetty-ee10-websocket-jetty-server + org.eclipse.jetty.websocket + jetty-websocket-jetty-server ${jetty-version} test diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BatchedRepliesWebSocketTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BatchedRepliesWebSocketTest.java index e12a55bf06..de505b2fcc 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BatchedRepliesWebSocketTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BatchedRepliesWebSocketTest.java @@ -32,8 +32,8 @@ public class BatchedRepliesWebSocketTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testBatchedReplies(String wsType) throws Exception { + @MethodSource("transports") + public void testBatchedReplies(Transport wsType) throws Exception { prepareAndStart(wsType, null); AtomicReference> batch = new AtomicReference<>(); @@ -42,7 +42,6 @@ public void testBatchedReplies(String wsType) throws Exception { case WEBSOCKET_JAKARTA -> new WSTransport(batch, repliesLatch); case WEBSOCKET_JETTY -> new JettyWSTransport(batch, repliesLatch); case WEBSOCKET_OKHTTP -> new OkWSTransport(batch, repliesLatch); - default -> throw new IllegalArgumentException(); }; BayeuxClient client = new BayeuxClient(cometdURL, transport); diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientTest.java index a759d61ce9..0ba6ac185b 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientTest.java @@ -15,22 +15,11 @@ */ package org.cometd.server.websocket; -import java.io.IOException; -import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import jakarta.servlet.DispatcherType; -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpServletResponseWrapper; import org.cometd.bayeux.Channel; import org.cometd.bayeux.MarkedReference; @@ -47,8 +36,8 @@ import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.client.transport.ClientTransport; import org.cometd.common.HashMapMessage; +import org.cometd.server.BayeuxServerImpl; import org.cometd.server.DefaultSecurityPolicy; -import org.eclipse.jetty.ee10.servlet.FilterHolder; import org.eclipse.jetty.util.BlockingArrayQueue; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; @@ -57,16 +46,16 @@ public class BayeuxClientTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testHandshakeDenied(String wsType) throws Exception { + @MethodSource("transports") + public void testHandshakeDenied(Transport wsType) throws Exception { prepareAndStart(wsType, null); BayeuxClient client = newBayeuxClient(wsType); long backOffIncrement = 500; client.setBackOffStrategy(new BayeuxClient.BackOffStrategy.Linear(backOffIncrement, -1)); - SecurityPolicy oldPolicy = bayeux.getSecurityPolicy(); - bayeux.setSecurityPolicy(new DefaultSecurityPolicy() { + SecurityPolicy oldPolicy = bayeuxServer.getSecurityPolicy(); + bayeuxServer.setSecurityPolicy(new DefaultSecurityPolicy() { @Override public boolean canHandshake(BayeuxServer server, ServerSession session, ServerMessage message) { return false; @@ -88,20 +77,20 @@ public boolean canHandshake(BayeuxServer server, ServerSession session, ServerMe Assertions.assertTrue(client.waitFor(5000, State.DISCONNECTED)); } finally { - bayeux.setSecurityPolicy(oldPolicy); + bayeuxServer.setSecurityPolicy(oldPolicy); disconnectBayeuxClient(client); } } @ParameterizedTest - @MethodSource("wsTypes") - public void testPublish(String wsType) throws Exception { + @MethodSource("transports") + public void testPublish(Transport wsType) throws Exception { prepareAndStart(wsType, null); BlockingArrayQueue results = new BlockingArrayQueue<>(); String channelName = "/chat/msg"; - MarkedReference channel = bayeux.createChannelIfAbsent(channelName); + MarkedReference channel = bayeuxServer.createChannelIfAbsent(channelName); channel.getReference().addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, Mutable message) { @@ -128,14 +117,14 @@ public boolean onMessage(ServerSession from, ServerChannel channel, Mutable mess } @ParameterizedTest - @MethodSource("wsTypes") - public void testWaitFor(String wsType) throws Exception { + @MethodSource("transports") + public void testWaitFor(Transport wsType) throws Exception { prepareAndStart(wsType, null); BlockingArrayQueue results = new BlockingArrayQueue<>(); String channelName = "/chat/msg"; - MarkedReference channel = bayeux.createChannelIfAbsent(channelName); + MarkedReference channel = bayeuxServer.createChannelIfAbsent(channelName); channel.getReference().addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, Mutable message) { @@ -169,8 +158,8 @@ public boolean onMessage(ServerSession from, ServerChannel channel, Mutable mess } @ParameterizedTest - @MethodSource("wsTypes") - public void testAuthentication(String wsType) throws Exception { + @MethodSource("transports") + public void testAuthentication(Transport wsType) throws Exception { prepareAndStart(wsType, null); AtomicReference sessionId = new AtomicReference<>(); @@ -208,8 +197,8 @@ public void removed(ServerSession session, ServerMessage message, boolean timeou } A authenticator = new A(); - SecurityPolicy oldPolicy = bayeux.getSecurityPolicy(); - bayeux.setSecurityPolicy(authenticator); + SecurityPolicy oldPolicy = bayeuxServer.getSecurityPolicy(); + bayeuxServer.setSecurityPolicy(authenticator); try { BayeuxClient client = newBayeuxClient(wsType); @@ -227,13 +216,13 @@ public void removed(ServerSession session, ServerMessage message, boolean timeou Assertions.assertNull(sessionId.get()); } finally { - bayeux.setSecurityPolicy(oldPolicy); + bayeuxServer.setSecurityPolicy(oldPolicy); } } @ParameterizedTest - @MethodSource("wsTypes") - public void testClient(String wsType) throws Exception { + @MethodSource("transports") + public void testClient(Transport wsType) throws Exception { prepareAndStart(wsType, null); BayeuxClient client = newBayeuxClient(wsType); @@ -292,12 +281,12 @@ public void testClient(String wsType) throws Exception { @Disabled("TODO: verify why it does not work; I suspect the setAllowedTransport() does not play since the WSUpgradeFilter kicks in first") @ParameterizedTest - @MethodSource("wsTypes") - public void testHandshakeOverWebSocketReportsHTTPFailure(String wsType) throws Exception { + @MethodSource("transports") + public void testHandshakeOverWebSocketReportsHTTPFailure(Transport wsType) throws Exception { prepareAndStart(wsType, null); // No transports on server, to make the client fail - bayeux.setAllowedTransports(); + ((BayeuxServerImpl)bayeuxServer).setAllowedTransports(); BayeuxClient client = newBayeuxClient(wsType); CountDownLatch latch = new CountDownLatch(1); @@ -328,36 +317,37 @@ public void testHandshakeOverWebSocketReportsHTTPFailure(String wsType) throws E // response so they cannot be removed/intercepted before they are sent to the client. @Disabled @ParameterizedTest - @MethodSource("wsTypes") - public void testWebSocketResponseHeadersRemoved(String wsType) throws Exception { + @MethodSource("transports") + public void testWebSocketResponseHeadersRemoved(Transport wsType) throws Exception { prepareAndStart(wsType, null); - context.addFilter(new FilterHolder(new Filter() { - @Override - public void init(FilterConfig filterConfig) { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - try { - // Wrap the response to remove the header - chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse)response) { - @Override - public void addHeader(String name, String value) { - if (!"Sec-WebSocket-Accept".equals(name)) { - super.addHeader(name, value); - } - } - }); - } finally { - ((HttpServletResponse)response).setHeader("Sec-WebSocket-Accept", null); - } - } - - @Override - public void destroy() { - } - }), cometdServletPath, EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC)); + // TODO +// context.addFilter(new FilterHolder(new Filter() { +// @Override +// public void init(FilterConfig filterConfig) { +// } +// +// @Override +// public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { +// try { +// // Wrap the response to remove the header +// chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse)response) { +// @Override +// public void addHeader(String name, String value) { +// if (!"Sec-WebSocket-Accept".equals(name)) { +// super.addHeader(name, value); +// } +// } +// }); +// } finally { +// ((HttpServletResponse)response).setHeader("Sec-WebSocket-Accept", null); +// } +// } +// +// @Override +// public void destroy() { +// } +// }), cometdServletPath, EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC)); ClientTransport webSocketTransport = newWebSocketTransport(wsType, null); ClientTransport longPollingTransport = newLongPollingTransport(null); @@ -378,8 +368,8 @@ public void destroy() { } @ParameterizedTest - @MethodSource("wsTypes") - public void testCustomTransportURL(String wsType) throws Exception { + @MethodSource("transports") + public void testCustomTransportURL(Transport wsType) throws Exception { prepareAndStart(wsType, null); ClientTransport transport = newWebSocketTransport(wsType, cometdURL, null); diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientWebSocketTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientWebSocketTest.java index 51a2dd9e06..b995ddc8a7 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientWebSocketTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxClientWebSocketTest.java @@ -48,13 +48,14 @@ import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; import org.cometd.server.ext.AcknowledgedMessagesExtension; -import org.cometd.server.http.JSONTransport; +import org.cometd.server.http.JSONHttpTransport; import org.cometd.server.websocket.jakarta.WebSocketTransport; +import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.util.BlockingArrayQueue; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -62,8 +63,8 @@ public class BayeuxClientWebSocketTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testClientRetriesWebSocketTransportIfCannotConnect(String wsType) throws Exception { + @MethodSource("transports") + public void testClientRetriesWebSocketTransportIfCannotConnect(Transport wsType) throws Exception { prepareAndStart(wsType, null); CountDownLatch connectLatch = new CountDownLatch(2); @@ -102,8 +103,8 @@ protected void sendConnect() { } @ParameterizedTest - @MethodSource("wsTypes") - public void testAbortThenRestart(String wsType) throws Exception { + @MethodSource("transports") + public void testAbortThenRestart(Transport wsType) throws Exception { prepareAndStart(wsType, null); BayeuxClient client = newBayeuxClient(wsType); @@ -133,8 +134,8 @@ public void testAbortThenRestart(String wsType) throws Exception { } @ParameterizedTest - @MethodSource("wsTypes") - public void testRestart(String wsType) throws Exception { + @MethodSource("transports") + public void testRestart(Transport wsType) throws Exception { prepareAndStart(wsType, null); ClientTransport webSocketTransport = newWebSocketTransport(wsType, null); @@ -177,9 +178,10 @@ public void testRestart(String wsType) throws Exception { disconnectBayeuxClient(client); } + @Disabled("WEBSOCKET_JETTY transport does not clear previous mappings upon restart") @ParameterizedTest - @MethodSource("wsTypes") - public void testRestartAfterConnectWithFatalException(String wsType) throws Exception { + @MethodSource("transports") + public void testRestartAfterConnectWithFatalException(Transport wsType) throws Exception { prepareAndStart(wsType, null); // ConnectException is a recoverable exception that does not disable the transport. @@ -231,7 +233,6 @@ public void onFailure(Throwable failure, List messages) { }, messages); } }; - default -> throw new IllegalArgumentException(); }; BayeuxClient client = new BayeuxClient(cometdURL, webSocketTransport); @@ -273,13 +274,13 @@ public void onFailure(Throwable failure, List messages) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testHandshakeExpiration(String wsType) throws Exception { + @MethodSource("transports") + public void testHandshakeExpiration(Transport wsType) throws Exception { prepareAndStart(wsType, null); long maxNetworkDelay = 2000; - bayeux.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { try { @@ -317,8 +318,8 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectNotRespondedOnServerSidePublish(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectNotRespondedOnServerSidePublish(Transport wsType) throws Exception { prepareAndStart(wsType, null); BayeuxClient client = newBayeuxClient(wsType); @@ -338,10 +339,10 @@ public void testMetaConnectNotRespondedOnServerSidePublish(String wsType) throws Thread.sleep(1000); // Test publish triggered by an external event - LocalSession emitter = bayeux.newLocalSession("test_emitter"); + LocalSession emitter = bayeuxServer.newLocalSession("test_emitter"); emitter.handshake(); String data = "test_data"; - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); Assertions.assertTrue(publishLatch.get().await(5, TimeUnit.SECONDS)); // Make sure long poll is not responded @@ -352,11 +353,11 @@ public void testMetaConnectNotRespondedOnServerSidePublish(String wsType) throws publishLatch.set(new CountDownLatch(1)); connectLatch.set(new CountDownLatch(1)); String serviceChannelName = "/service/test"; - ServerChannel serviceChannel = bayeux.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); + ServerChannel serviceChannel = bayeuxServer.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); serviceChannel.addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); return true; } }); @@ -370,8 +371,8 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectDeliveryOnlyTransport(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectDeliveryOnlyTransport(Transport wsType) throws Exception { Map options = new HashMap<>(); options.put(AbstractServerTransport.META_CONNECT_DELIVERY_OPTION, "true"); prepareAndStart(wsType, options); @@ -393,10 +394,10 @@ public void testMetaConnectDeliveryOnlyTransport(String wsType) throws Exception Thread.sleep(1000); // Test publish triggered by an external event - LocalSession emitter = bayeux.newLocalSession("test_emitter"); + LocalSession emitter = bayeuxServer.newLocalSession("test_emitter"); emitter.handshake(); String data = "test_data"; - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); Assertions.assertTrue(publishLatch.get().await(5, TimeUnit.SECONDS)); // Make sure long poll is responded @@ -408,11 +409,11 @@ public void testMetaConnectDeliveryOnlyTransport(String wsType) throws Exception publishLatch.set(new CountDownLatch(1)); connectLatch.set(new CountDownLatch(1)); String serviceChannelName = "/service/test"; - ServerChannel serviceChannel = bayeux.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); + ServerChannel serviceChannel = bayeuxServer.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); serviceChannel.addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); return true; } }); @@ -426,11 +427,11 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectDeliveryOnlySession(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectDeliveryOnlySession(Transport wsType) throws Exception { prepareAndStart(wsType, null); - bayeux.addExtension(new BayeuxServer.Extension() { + bayeuxServer.addExtension(new BayeuxServer.Extension() { @Override public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { if (Channel.META_HANDSHAKE.equals(message.getChannel())) { @@ -459,10 +460,10 @@ public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { Thread.sleep(1000); // Test publish triggered by an external event - LocalSession emitter = bayeux.newLocalSession("test_emitter"); + LocalSession emitter = bayeuxServer.newLocalSession("test_emitter"); emitter.handshake(); String data = "test_data"; - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); Assertions.assertTrue(publishLatch.get().await(5, TimeUnit.SECONDS)); // Make sure long poll is responded @@ -473,11 +474,11 @@ public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { publishLatch.set(new CountDownLatch(1)); connectLatch.set(new CountDownLatch(1)); String serviceChannelName = "/service/test"; - ServerChannel serviceChannel = bayeux.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); + ServerChannel serviceChannel = bayeuxServer.createChannelIfAbsent(serviceChannelName, new Persistent()).getReference(); serviceChannel.addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { - bayeux.getChannel(channelName).publish(emitter, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(emitter, data, Promise.noop()); return true; } }); @@ -491,8 +492,8 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectExpires(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectExpires(Transport wsType) throws Exception { long timeout = 2000; Map options = new HashMap<>(); options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); @@ -515,13 +516,13 @@ public void testMetaConnectExpires(String wsType) throws Exception { } @ParameterizedTest - @MethodSource("wsTypes") - public void testWebSocketWithAckExtension(String wsType) throws Exception { + @MethodSource("transports") + public void testWebSocketWithAckExtension(Transport wsType) throws Exception { prepareAndStart(wsType, null); BayeuxClient client = newBayeuxClient(wsType); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); client.addExtension(new AckExtension()); String channelName = "/chat/demo"; @@ -542,7 +543,7 @@ public void testWebSocketWithAckExtension(String wsType) throws Exception { Assertions.assertTrue(subscribed.await(5, TimeUnit.SECONDS)); Assertions.assertEquals(0, messages.size()); - ServerChannel chatChannel = bayeux.getChannel(channelName); + ServerChannel chatChannel = bayeuxServer.getChannel(channelName); Assertions.assertNotNull(chatChannel); int count = 5; @@ -598,22 +599,22 @@ public void testWebSocketWithAckExtension(String wsType) throws Exception { } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectDelayedOnServerRespondedBeforeRetry(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectDelayedOnServerRespondedBeforeRetry(Transport wsType) throws Exception { long maxNetworkDelay = 2000; long backoffIncrement = 2000; testMetaConnectDelayedOnServer(wsType, maxNetworkDelay, backoffIncrement, maxNetworkDelay + backoffIncrement / 2); } @ParameterizedTest - @MethodSource("wsTypes") - public void testMetaConnectDelayedOnServerRespondedAfterRetry(String wsType) throws Exception { + @MethodSource("transports") + public void testMetaConnectDelayedOnServerRespondedAfterRetry(Transport wsType) throws Exception { long maxNetworkDelay = 2000; long backoffIncrement = 1000; testMetaConnectDelayedOnServer(wsType, maxNetworkDelay, backoffIncrement, maxNetworkDelay + backoffIncrement * 2); } - private void testMetaConnectDelayedOnServer(String wsType, long maxNetworkDelay, long backoffIncrement, long delay) throws Exception { + private void testMetaConnectDelayedOnServer(Transport wsType, long maxNetworkDelay, long backoffIncrement, long delay) throws Exception { stopAndDispose(); Map initParams = new HashMap<>(); @@ -621,9 +622,9 @@ private void testMetaConnectDelayedOnServer(String wsType, long maxNetworkDelay, initParams.put("timeout", String.valueOf(timeout)); switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> - initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); case WEBSOCKET_JETTY -> - initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); default -> throw new IllegalArgumentException(); } prepareAndStart(wsType, initParams); @@ -634,7 +635,7 @@ private void testMetaConnectDelayedOnServer(String wsType, long maxNetworkDelay, BayeuxClient client = new BayeuxClient(cometdURL, webSocketTransport); client.setOption(BayeuxClient.BACKOFF_INCREMENT_OPTION, backoffIncrement); - bayeux.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { private final AtomicInteger connects = new AtomicInteger(); @Override @@ -683,8 +684,8 @@ public void onMessage(ClientSessionChannel channel, Message message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testClientSendsAndReceivesBigMessage(String wsType) throws Exception { + @MethodSource("transports") + public void testClientSendsAndReceivesBigMessage(Transport wsType) throws Exception { int maxMessageSize = 128 * 1024; Map serverOptions = new HashMap<>(); serverOptions.put("ws.maxMessageSize", String.valueOf(maxMessageSize)); @@ -712,14 +713,14 @@ public void testClientSendsAndReceivesBigMessage(String wsType) throws Exception } @ParameterizedTest - @MethodSource("wsTypes") - public void testClientDisconnectingClosesTheConnection(String wsType) throws Exception { + @MethodSource("transports") + public void testClientDisconnectingClosesTheConnection(Transport wsType) throws Exception { Map initParams = new HashMap<>(); switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> - initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); case WEBSOCKET_JETTY -> - initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); default -> throw new IllegalArgumentException(); } prepareAndStart(wsType, initParams); @@ -733,11 +734,11 @@ public void testClientDisconnectingClosesTheConnection(String wsType) throws Exc switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> { - CloseLatchWebSocketTransport jakartaTransport = (CloseLatchWebSocketTransport)bayeux.getTransport("websocket"); + CloseLatchWebSocketTransport jakartaTransport = (CloseLatchWebSocketTransport)bayeuxServer.getTransport("websocket"); Assertions.assertTrue(jakartaTransport.latch.await(5, TimeUnit.SECONDS)); } case WEBSOCKET_JETTY -> { - CloseLatchJettyWebSocketTransport jettyTransport = (CloseLatchJettyWebSocketTransport)bayeux.getTransport("websocket"); + CloseLatchJettyWebSocketTransport jettyTransport = (CloseLatchJettyWebSocketTransport)bayeuxServer.getTransport("websocket"); Assertions.assertTrue(jettyTransport.latch.await(5, TimeUnit.SECONDS)); } default -> throw new IllegalArgumentException(); @@ -745,14 +746,14 @@ public void testClientDisconnectingClosesTheConnection(String wsType) throws Exc } @ParameterizedTest - @MethodSource("wsTypes") - public void testClientDisconnectingSynchronouslyClosesTheConnection(String wsType) throws Exception { + @MethodSource("transports") + public void testClientDisconnectingSynchronouslyClosesTheConnection(Transport wsType) throws Exception { Map initParams = new HashMap<>(); switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> - initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); case WEBSOCKET_JETTY -> - initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONTransport.class.getName()); + initParams.put("transports", CloseLatchJettyWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName()); default -> throw new IllegalArgumentException(); } prepareAndStart(wsType, initParams); @@ -766,11 +767,11 @@ public void testClientDisconnectingSynchronouslyClosesTheConnection(String wsTyp switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> { - CloseLatchWebSocketTransport jakartaTransport = (CloseLatchWebSocketTransport)bayeux.getTransport("websocket"); + CloseLatchWebSocketTransport jakartaTransport = (CloseLatchWebSocketTransport)bayeuxServer.getTransport("websocket"); Assertions.assertTrue(jakartaTransport.latch.await(5, TimeUnit.SECONDS)); } case WEBSOCKET_JETTY -> { - CloseLatchJettyWebSocketTransport jettyTransport = (CloseLatchJettyWebSocketTransport)bayeux.getTransport("websocket"); + CloseLatchJettyWebSocketTransport jettyTransport = (CloseLatchJettyWebSocketTransport)bayeuxServer.getTransport("websocket"); Assertions.assertTrue(jettyTransport.latch.await(5, TimeUnit.SECONDS)); } default -> throw new IllegalArgumentException(); @@ -804,8 +805,8 @@ protected void onClose(int code, String reason) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testWhenClientAbortsServerSessionIsSwept(String wsType) throws Exception { + @MethodSource("transports") + public void testWhenClientAbortsServerSessionIsSwept(Transport wsType) throws Exception { Map options = new HashMap<>(); long timeout = 2000; long maxInterval = 1000; @@ -821,7 +822,7 @@ public void testWhenClientAbortsServerSessionIsSwept(String wsType) throws Excep Thread.sleep(1000); CountDownLatch latch = new CountDownLatch(1); - ServerSession session = bayeux.getSession(client.getId()); + ServerSession session = bayeuxServer.getSession(client.getId()); session.addListener((ServerSession.RemovedListener)(s, m, t) -> latch.countDown()); client.abort(); @@ -830,14 +831,14 @@ public void testWhenClientAbortsServerSessionIsSwept(String wsType) throws Excep } @ParameterizedTest - @MethodSource("wsTypes") - public void testDisconnectWithPendingMetaConnectWithoutResponseIsFailedOnClient(String wsType) throws Exception { + @MethodSource("transports") + public void testDisconnectWithPendingMetaConnectWithoutResponseIsFailedOnClient(Transport wsType) throws Exception { long timeout = 2000L; Map serverOptions = new HashMap<>(); serverOptions.put("timeout", String.valueOf(timeout)); prepareAndStart(wsType, serverOptions); - bayeux.addExtension(new BayeuxServer.Extension() { + bayeuxServer.addExtension(new BayeuxServer.Extension() { @Override public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { if (Channel.META_CONNECT.equals(message.getChannel())) { @@ -880,8 +881,8 @@ public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testDeliverDuringHandshakeProcessing(String wsType) throws Exception { + @MethodSource("transports") + public void testDeliverDuringHandshakeProcessing(Transport wsType) throws Exception { prepareAndStart(wsType, null); String channelName = "/service/test"; @@ -895,7 +896,7 @@ public void testDeliverDuringHandshakeProcessing(String wsType) throws Exception }); // SessionListener is the first listener notified after the ServerSession is created. - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { session.deliver(null, channelName, "data", Promise.noop()); @@ -911,11 +912,11 @@ public void sessionAdded(ServerSession session, ServerMessage message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testDeliverDuringHandshakeProcessingWithAckExtension(String wsType) throws Exception { + @MethodSource("transports") + public void testDeliverDuringHandshakeProcessingWithAckExtension(Transport wsType) throws Exception { prepareAndStart(wsType, null); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); String channelName = "/service/test"; BayeuxClient client = newBayeuxClient(wsType); @@ -929,7 +930,7 @@ public void testDeliverDuringHandshakeProcessingWithAckExtension(String wsType) }); // SessionListener is the first listener notified after the ServerSession is created. - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { session.deliver(null, channelName, "data", Promise.noop()); @@ -945,14 +946,14 @@ public void sessionAdded(ServerSession session, ServerMessage message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testExtensionIsInvokedAfterNetworkFailure(String wsType) throws Exception { + @MethodSource("transports") + public void testExtensionIsInvokedAfterNetworkFailure(Transport wsType) throws Exception { // No way to stop OkHttpClient. - Assumptions.assumeFalse(wsType.equals(WEBSOCKET_OKHTTP)); + Assumptions.assumeFalse(wsType == Transport.WEBSOCKET_OKHTTP); prepareAndStart(wsType, null); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); BayeuxClient client = newBayeuxClient(wsType); String channelName = "/test"; @@ -972,7 +973,7 @@ public boolean rcv(ClientSession session, Message.Mutable message) { Assertions.assertTrue(client.waitFor(5000, BayeuxClient.State.CONNECTED)); // This message will be delivered via /meta/connect. - bayeux.createChannelIfAbsent(channelName).getReference().publish(null, "data1", Promise.noop()); + bayeuxServer.createChannelIfAbsent(channelName).getReference().publish(null, "data1", Promise.noop()); Assertions.assertTrue(rcv.get().await(5, TimeUnit.SECONDS)); // Wait for the /meta/connect to be established again. Thread.sleep(1000); @@ -982,7 +983,7 @@ public boolean rcv(ClientSession session, Message.Mutable message) { Assertions.assertTrue(client.waitFor(5000, BayeuxClient.State.UNCONNECTED)); // Send a message while disconnected. - bayeux.createChannelIfAbsent(channelName).getReference().publish(null, "data2", Promise.noop()); + bayeuxServer.createChannelIfAbsent(channelName).getReference().publish(null, "data2", Promise.noop()); rcv.set(new CountDownLatch(1)); httpClient.start(); diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxContextTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxContextTest.java index c5aaf23f94..bab8f153cf 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxContextTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/BayeuxContextTest.java @@ -43,22 +43,29 @@ import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.cometd.server.websocket.jetty.JettyWebSocketTransport; import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeRequest; -import org.eclipse.jetty.ee10.websocket.server.JettyServerUpgradeResponse; import org.eclipse.jetty.http.HttpCookie; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.Session; +import org.eclipse.jetty.session.SessionHandler; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.websocket.server.ServerUpgradeRequest; +import org.eclipse.jetty.websocket.server.ServerUpgradeResponse; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; public class BayeuxContextTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testRequestHeaderIsCaseInsensitive(String wsType) throws Exception { + @MethodSource("transports") + public void testRequestHeaderIsCaseInsensitive(Transport wsType) throws Exception { prepareAndStart(wsType, null); CountDownLatch latch = new CountDownLatch(1); - bayeux.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { BayeuxContext context = message.getBayeuxContext(); @@ -78,14 +85,14 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testCookiesSentToServer(String wsType) throws Exception { + @MethodSource("transports") + public void testCookiesSentToServer(Transport wsType) throws Exception { prepareAndStart(wsType, null); String cookieName = "name"; String cookieValue = "value"; CountDownLatch latch = new CountDownLatch(1); - bayeux.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { BayeuxContext context = message.getBayeuxContext(); @@ -105,12 +112,11 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testCookiesSentToClient(String wsType) throws Exception { + @MethodSource("transports") + public void testCookiesSentToClient(Transport wsType) throws Exception { String wsTransportClass = switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> CookieWebSocketTransport.class.getName(); case WEBSOCKET_JETTY -> CookieJettyWebSocketTransport.class.getName(); - default -> throw new IllegalArgumentException(); }; prepareServer(wsType, 0, "/cometd", null, wsTransportClass); startServer(); @@ -129,8 +135,8 @@ public void testCookiesSentToClient(String wsType) throws Exception { } @ParameterizedTest - @MethodSource("wsTypes") - public void testMultipleCookiesSentToServer(String wsType) throws Exception { + @MethodSource("transports") + public void testMultipleCookiesSentToServer(Transport wsType) throws Exception { prepareAndStart(wsType, null); List cookieNames = List.of("a", "BAYEUX_BROWSER", "b"); @@ -141,7 +147,7 @@ public void testMultipleCookiesSentToServer(String wsType) throws Exception { } CountDownLatch latch = new CountDownLatch(1); - bayeux.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_HANDSHAKE).addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { BayeuxContext context = message.getBayeuxContext(); @@ -156,14 +162,14 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag try (Socket socket = new Socket("localhost", connector.getLocalPort())) { OutputStream output = socket.getOutputStream(); String upgrade = "" + - "GET " + cometdServletPath + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Connection: Upgrade\r\n" + - "Upgrade: websocket\r\n" + - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + - "Sec-WebSocket-Version: 13\r\n" + - "Cookie: " + cookies + "\r\n" + - "\r\n"; + "GET " + cometdPath + " HTTP/1.1\r\n" + + "Host: localhost:" + connector.getLocalPort() + "\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: websocket\r\n" + + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + + "Sec-WebSocket-Version: 13\r\n" + + "Cookie: " + cookies + "\r\n" + + "\r\n"; output.write(upgrade.getBytes(StandardCharsets.UTF_8)); output.flush(); @@ -171,12 +177,12 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag Thread.sleep(1000); String handshake = "" + - "{" + - "\"id\":\"1\"," + - "\"channel\":\"/meta/handshake\"," + - "\"version\":\"1.0\"," + - "\"supportedConnectionTypes\":[\"websocket\"]" + - "}"; + "{" + + "\"id\":\"1\"," + + "\"channel\":\"/meta/handshake\"," + + "\"version\":\"1.0\"," + + "\"supportedConnectionTypes\":[\"websocket\"]" + + "}"; byte[] handshakeBytes = handshake.getBytes(StandardCharsets.UTF_8); Assertions.assertTrue(handshakeBytes.length <= 125); // Max payload length @@ -191,22 +197,44 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } @ParameterizedTest - @MethodSource("wsTypes") - public void testSessionAttribute(String wsType) throws Exception { + @MethodSource("transports") + public void testSessionAttribute(Transport wsType) throws Exception { String wsTransportClass = switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> SessionWebSocketTransport.class.getName(); case WEBSOCKET_JETTY -> SessionJettyWebSocketTransport.class.getName(); - default -> throw new IllegalArgumentException(); }; prepareServer(wsType, 0, "/cometd", null, wsTransportClass); - context.addServlet(new ServletHolder(new HttpServlet() { - @Override - protected void service(HttpServletRequest request, HttpServletResponse resp) { - HttpSession session = request.getSession(true); - session.setAttribute(SessionConstants.ATTRIBUTE_NAME, SessionConstants.ATTRIBUTE_VALUE); + switch (wsType) { + case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> { + context.insertHandler(new org.eclipse.jetty.ee10.servlet.SessionHandler()); + ((ServletContextHandler)context).addServlet(new ServletHolder(new HttpServlet() { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(true); + session.setAttribute(SessionConstants.ATTRIBUTE_NAME, SessionConstants.ATTRIBUTE_VALUE); + } + }), "/session"); } - }), "/session"); + case WEBSOCKET_JETTY -> { + SessionHandler sessionHandler = new SessionHandler(); + context.insertHandler(sessionHandler); + sessionHandler.insertHandler(new Handler.Wrapper() { + @Override + public boolean handle(Request request, Response response, Callback callback) throws Exception { + if ("/session".equals(Request.getPathInContext(request))) { + Session session = request.getSession(true); + session.setAttribute(SessionConstants.ATTRIBUTE_NAME, SessionConstants.ATTRIBUTE_VALUE); + callback.succeeded(); + return true; + } + return super.handle(request, response, callback); + } + }); + } + default -> throw new IllegalArgumentException(); + } + startServer(); prepareClient(wsType); startClient(); @@ -230,11 +258,10 @@ protected void service(HttpServletRequest request, HttpServletResponse resp) { Assertions.assertNotNull(sessionCookie); CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertNotNull(message.getBayeuxContext().getHttpSessionId()); - Assertions.assertEquals(SessionConstants.ATTRIBUTE_VALUE, message.getBayeuxContext().getHttpSessionAttribute(SessionConstants.ATTRIBUTE_NAME)); + Assertions.assertEquals(SessionConstants.ATTRIBUTE_VALUE, message.getBayeuxContext().getSessionAttribute(SessionConstants.ATTRIBUTE_NAME)); latch.countDown(); } }); @@ -250,15 +277,15 @@ public void sessionAdded(ServerSession session, ServerMessage message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testContextAttribute(String wsType) throws Exception { + @MethodSource("transports") + public void testContextAttribute(Transport wsType) throws Exception { prepareAndStart(wsType, null); CountDownLatch latch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { - Assertions.assertSame(bayeux, message.getBayeuxContext().getContextAttribute(BayeuxServer.ATTRIBUTE)); + Assertions.assertSame(bayeuxServer, message.getBayeuxContext().getContextAttribute(BayeuxServer.ATTRIBUTE)); latch.countDown(); } }); @@ -273,12 +300,11 @@ public void sessionAdded(ServerSession session, ServerMessage message) { } @ParameterizedTest - @MethodSource("wsTypes") - public void testConcurrentClientsHaveDifferentBayeuxContexts(String wsType) throws Exception { + @MethodSource("transports") + public void testConcurrentClientsHaveDifferentBayeuxContexts(Transport wsType) throws Exception { String wsTransportClass = switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> ConcurrentBayeuxContextWebSocketTransport.class.getName(); case WEBSOCKET_JETTY -> ConcurrentBayeuxContextJettyWebSocketTransport.class.getName(); - default -> throw new IllegalArgumentException(); }; prepareServer(wsType, 0, "/cometd", null, wsTransportClass); startServer(); @@ -293,11 +319,11 @@ public void testConcurrentClientsHaveDifferentBayeuxContexts(String wsType) thro // Wait for the first client to arrive at the concurrency point. switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> { - CountDownLatch enterLatch = ((ConcurrentBayeuxContextWebSocketTransport)bayeux.getTransport("websocket")).enterLatch; + CountDownLatch enterLatch = ((ConcurrentBayeuxContextWebSocketTransport)bayeuxServer.getTransport("websocket")).enterLatch; Assertions.assertTrue(enterLatch.await(5, TimeUnit.SECONDS)); } case WEBSOCKET_JETTY -> { - CountDownLatch enterLatch = ((ConcurrentBayeuxContextJettyWebSocketTransport)bayeux.getTransport("websocket")).enterLatch; + CountDownLatch enterLatch = ((ConcurrentBayeuxContextJettyWebSocketTransport)bayeuxServer.getTransport("websocket")).enterLatch; Assertions.assertTrue(enterLatch.await(5, TimeUnit.SECONDS)); } default -> throw new IllegalArgumentException(); @@ -311,9 +337,9 @@ public void testConcurrentClientsHaveDifferentBayeuxContexts(String wsType) thro // Release the first client. switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> - ((ConcurrentBayeuxContextWebSocketTransport)bayeux.getTransport("websocket")).proceedLatch.countDown(); + ((ConcurrentBayeuxContextWebSocketTransport)bayeuxServer.getTransport("websocket")).proceedLatch.countDown(); case WEBSOCKET_JETTY -> - ((ConcurrentBayeuxContextJettyWebSocketTransport)bayeux.getTransport("websocket")).proceedLatch.countDown(); + ((ConcurrentBayeuxContextJettyWebSocketTransport)bayeuxServer.getTransport("websocket")).proceedLatch.countDown(); default -> throw new IllegalArgumentException(); } Assertions.assertTrue(client1.waitFor(1000, BayeuxClient.State.CONNECTED)); @@ -321,7 +347,7 @@ public void testConcurrentClientsHaveDifferentBayeuxContexts(String wsType) thro String channelName = "/service/test"; Map contexts = new ConcurrentHashMap<>(); CountDownLatch contextLatch = new CountDownLatch(2); - bayeux.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { + bayeuxServer.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { contexts.put(from.getId(), message.getBayeuxContext()); @@ -363,8 +389,8 @@ public CookieJettyWebSocketTransport(BayeuxServerImpl bayeux) { } @Override - protected void modifyUpgrade(JettyServerUpgradeRequest request, JettyServerUpgradeResponse response) { - response.setHeader("Set-Cookie", COOKIE_NAME + "=" + COOKIE_VALUE); + protected void modifyUpgrade(ServerUpgradeRequest request, ServerUpgradeResponse response) { + response.getHeaders().put("Set-Cookie", COOKIE_NAME + "=" + COOKIE_VALUE); } } @@ -392,8 +418,8 @@ public SessionJettyWebSocketTransport(BayeuxServerImpl bayeux) { } @Override - protected void modifyUpgrade(JettyServerUpgradeRequest request, JettyServerUpgradeResponse response) { - HttpSession session = (HttpSession)request.getSession(); + protected void modifyUpgrade(ServerUpgradeRequest request, ServerUpgradeResponse response) { + Session session = request.getSession(false); Assertions.assertNotNull(session); Assertions.assertEquals(ATTRIBUTE_VALUE, session.getAttribute(ATTRIBUTE_NAME)); } @@ -425,7 +451,7 @@ public ConcurrentBayeuxContextJettyWebSocketTransport(BayeuxServerImpl bayeux) { } @Override - protected void modifyUpgrade(JettyServerUpgradeRequest request, JettyServerUpgradeResponse response) { + protected void modifyUpgrade(ServerUpgradeRequest request, ServerUpgradeResponse response) { onUpgrade(handshakes, enterLatch, proceedLatch); super.modifyUpgrade(request, response); } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ClientServerWebSocketTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ClientServerWebSocketTest.java index c332f37ef9..271892def3 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ClientServerWebSocketTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ClientServerWebSocketTest.java @@ -15,7 +15,7 @@ */ package org.cometd.server.websocket; -import java.util.List; +import java.util.HashMap; import java.util.Map; import jakarta.websocket.ContainerProvider; import jakarta.websocket.WebSocketContainer; @@ -26,21 +26,25 @@ import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.client.transport.ClientTransport; import org.cometd.client.websocket.okhttp.OkHttpWebSocketTransport; +import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; -import org.cometd.server.http.JSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; +import org.cometd.server.http.jetty.CometDHandler; +import org.cometd.server.websocket.common.AbstractWebSocketTransport; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.cometd.server.websocket.jetty.JettyWebSocketTransport; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; -import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.RegisterExtension; @@ -48,58 +52,53 @@ import org.slf4j.LoggerFactory; public abstract class ClientServerWebSocketTest { - protected static final String WEBSOCKET_JAKARTA = "JAKARTA"; - protected static final String WEBSOCKET_JETTY = "JETTY"; - protected static final String WEBSOCKET_OKHTTP = "OKHTTP"; - - public static List wsTypes() { - return List.of(WEBSOCKET_JAKARTA, WEBSOCKET_JETTY, WEBSOCKET_OKHTTP); + public static Transport[] transports() { + return Transport.values(); } @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); protected final Logger logger = LoggerFactory.getLogger(getClass()); protected ServerConnector connector; protected Server server; - protected ServletContextHandler context; - protected String cometdServletPath; + protected ContextHandler context; + protected String cometdPath; protected HttpClient httpClient; protected WebSocketContainer wsClientContainer; protected WebSocketClient wsClient; protected OkHttpClient okHttpClient; protected String cometdURL; - protected BayeuxServerImpl bayeux; + protected BayeuxServer bayeuxServer; - protected void prepareAndStart(String wsType, Map initParams) throws Exception { - prepareAndStart(wsType, "/cometd", initParams); + protected void prepareAndStart(Transport wsType, Map options) throws Exception { + prepareAndStart(wsType, "/cometd", options); } - protected void prepareAndStart(String wsType, String servletPath, Map initParams) throws Exception { - prepareServer(wsType, 0, servletPath, initParams); + protected void prepareAndStart(Transport wsType, String cometdPath, Map options) throws Exception { + prepareServer(wsType, 0, cometdPath, options); prepareClient(wsType); startServer(); startClient(); } - protected void prepareServer(String wsType, int port) { + protected void prepareServer(Transport wsType, int port) { prepareServer(wsType, port, "/cometd", null); } - protected void prepareServer(String wsType, Map initParams) { - prepareServer(wsType, 0, "/cometd", initParams); + protected void prepareServer(Transport wsType, Map options) { + prepareServer(wsType, 0, "/cometd", options); } - protected void prepareServer(String wsType, int port, String servletPath, Map initParams) { + protected void prepareServer(Transport wsType, int port, String cometdPath, Map options) { String wsTransportClass = switch (wsType) { case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> WebSocketTransport.class.getName(); case WEBSOCKET_JETTY -> JettyWebSocketTransport.class.getName(); - default -> throw new IllegalArgumentException(); }; - prepareServer(wsType, port, servletPath, initParams, wsTransportClass); + prepareServer(wsType, port, cometdPath, options, wsTransportClass); } - protected void prepareServer(String wsType, int port, String servletPath, Map initParams, String wsTransportClass) { + protected void prepareServer(Transport wsType, int port, String cometdPath, Map options, String wsTransportClass) { QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server"); server = new Server(serverThreads); @@ -108,40 +107,52 @@ protected void prepareServer(String wsType, int port, String servletPath, Map - JakartaWebSocketServletContainerInitializer.configure(context, null); - case WEBSOCKET_JETTY -> JettyWebSocketServletContainerInitializer.configure(context, null); - default -> throw new IllegalArgumentException("Unsupported transport " + wsType); + if (cometdPath.endsWith("/*")) { + cometdPath = cometdPath.substring(0, cometdPath.length() - 2); } + this.cometdPath = cometdPath; + String cometdURLMapping = cometdPath + "/*"; - // CometD servlet - cometdServletPath = servletPath; - if (cometdServletPath.endsWith("/*")) { - cometdServletPath = cometdServletPath.substring(0, cometdServletPath.length() - 2); - } - String cometdURLMapping = cometdServletPath; - if (!cometdURLMapping.endsWith("/*")) { - cometdURLMapping = cometdURLMapping + "/*"; - } - ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - String transports = wsTransportClass + "," + JSONTransport.class.getName(); - cometdServletHolder.setInitParameter("transports", transports); - cometdServletHolder.setInitParameter("timeout", "10000"); - cometdServletHolder.setInitParameter("ws.cometdURLMapping", cometdURLMapping); - cometdServletHolder.setInitOrder(1); - if (initParams != null) { - for (Map.Entry entry : initParams.entrySet()) { - cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + switch (wsType) { + case WEBSOCKET_JAKARTA, WEBSOCKET_OKHTTP -> { + ServletContextHandler servletContext = new ServletContextHandler("/"); + server.setHandler(servletContext); + context = servletContext; + JakartaWebSocketServletContainerInitializer.configure(servletContext, null); + CometDServlet cometdServlet = new CometDServlet(); + ServletHolder cometdServletHolder = new ServletHolder(cometdServlet); + String transports = wsTransportClass + "," + JSONHttpTransport.class.getName(); + cometdServletHolder.setInitParameter(BayeuxServerImpl.TRANSPORTS_OPTION, transports); + cometdServletHolder.setInitParameter(AbstractServerTransport.TIMEOUT_OPTION, "10000"); + cometdServletHolder.setInitParameter(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, cometdURLMapping); + if (options != null) { + for (Map.Entry entry : options.entrySet()) { + cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + } + } + cometdServletHolder.setInitOrder(1); + servletContext.addServlet(cometdServletHolder, cometdURLMapping); + } + case WEBSOCKET_JETTY -> { + context = new ContextHandler("/"); + server.setHandler(context); + WebSocketUpgradeHandler wsHandler = WebSocketUpgradeHandler.from(server, context); + context.setHandler(wsHandler); + CometDHandler cometdHandler = new CometDHandler(); + if (options == null) { + options = new HashMap<>(); + } + String transports = wsTransportClass + "," + JSONHttpTransport.class.getName(); + options.putIfAbsent(BayeuxServerImpl.TRANSPORTS_OPTION, transports); + options.putIfAbsent(AbstractServerTransport.TIMEOUT_OPTION, "10000"); + options.putIfAbsent(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, cometdURLMapping); + cometdHandler.setOptions(options); + wsHandler.setHandler(cometdHandler); } } - context.addServlet(cometdServletHolder, cometdURLMapping); } - protected void prepareClient(String wsType) { + protected void prepareClient(Transport wsType) { QueuedThreadPool clientThreads = new QueuedThreadPool(); clientThreads.setName("client"); httpClient = new HttpClient(new HttpClientTransportOverHTTP(1)); @@ -163,32 +174,35 @@ protected void prepareClient(String wsType) { protected void startServer() throws Exception { server.start(); int port = connector.getLocalPort(); - cometdURL = "http://localhost:" + port + cometdServletPath; - bayeux = (BayeuxServerImpl)context.getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); + cometdURL = "http://localhost:" + port + cometdPath; + bayeuxServer = (BayeuxServer)context.getContext().getAttribute(BayeuxServer.ATTRIBUTE); } protected void startClient() throws Exception { httpClient.start(); } - protected BayeuxClient newBayeuxClient(String wsType) { - return new BayeuxClient(cometdURL, newWebSocketTransport(wsType, null)); + protected BayeuxClient newBayeuxClient(Transport wsType) { + return newBayeuxClient(wsType, cometdURL); + } + + protected BayeuxClient newBayeuxClient(Transport wsType, String url) { + return new BayeuxClient(url, newWebSocketTransport(wsType, null)); } protected ClientTransport newLongPollingTransport(Map options) { return new JettyHttpClientTransport(options, httpClient); } - protected ClientTransport newWebSocketTransport(String wsType, Map options) { + protected ClientTransport newWebSocketTransport(Transport wsType, Map options) { return newWebSocketTransport(wsType, null, options); } - protected ClientTransport newWebSocketTransport(String wsType, String url, Map options) { + protected ClientTransport newWebSocketTransport(Transport wsType, String url, Map options) { return switch (wsType) { case WEBSOCKET_JAKARTA -> newWebSocketTransport(url, options, wsClientContainer); case WEBSOCKET_JETTY -> newJettyWebSocketTransport(url, options, wsClient); case WEBSOCKET_OKHTTP -> newOkHttpWebSocketTransport(url, options, okHttpClient); - default -> throw new IllegalArgumentException(); }; } @@ -225,4 +239,8 @@ protected void stopClient() throws Exception { httpClient.stop(); } } + + public enum Transport { + WEBSOCKET_JAKARTA, WEBSOCKET_JETTY, WEBSOCKET_OKHTTP + } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ConcurrentAbortPublishTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ConcurrentAbortPublishTest.java index 701746dad6..09275029c1 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ConcurrentAbortPublishTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/ConcurrentAbortPublishTest.java @@ -54,8 +54,8 @@ protected ClientTransport newOkHttpWebSocketTransport(String url, Map serverOptions = new HashMap<>(); diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/MultipleURLMappingsTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/MultipleURLMappingsTest.java deleted file mode 100644 index d3f32d7e58..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/MultipleURLMappingsTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2008-2022 the original author or authors. - * - * Licensed 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. - */ -package org.cometd.server.websocket; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import jakarta.websocket.ContainerProvider; -import jakarta.websocket.WebSocketContainer; - -import org.cometd.client.BayeuxClient; -import org.cometd.client.transport.ClientTransport; -import org.cometd.server.CometDServlet; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; -import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -public class MultipleURLMappingsTest { - private static final String JAKARTA_WS_TRANSPORT = "org.cometd.server.websocket.jakarta.WebSocketTransport"; - private static final String JETTY_WS_TRANSPORT = "org.cometd.server.websocket.jetty.JettyWebSocketTransport"; - - public static List wsTransports() { - return List.of(JAKARTA_WS_TRANSPORT, JETTY_WS_TRANSPORT); - } - - private Server server; - private ServerConnector connector; - private WebSocketContainer wsClientContainer; - private WebSocketClient wsClient; - private String servletPath1 = "/cometd1"; - private String servletPath2 = "/cometd2"; - - private void start(String wsTransportClass) throws Exception { - server = new Server(); - - connector = new ServerConnector(server); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler("/", true, false); - server.setHandler(context); - - switch (wsTransportClass) { - case JAKARTA_WS_TRANSPORT -> JakartaWebSocketServletContainerInitializer.configure(context, null); - case JETTY_WS_TRANSPORT -> JettyWebSocketServletContainerInitializer.configure(context, null); - default -> throw new IllegalArgumentException("Unsupported transport " + wsTransportClass); - } - - ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - cometdServletHolder.setInitParameter("transports", wsTransportClass); - cometdServletHolder.setInitParameter("timeout", "10000"); - cometdServletHolder.setInitParameter("ws.cometdURLMapping", servletPath1 + "," + servletPath2); - cometdServletHolder.setInitOrder(1); - context.addServlet(cometdServletHolder, servletPath1 + "/*"); - context.addServlet(cometdServletHolder, servletPath2 + "/*"); - - switch (wsTransportClass) { - case JAKARTA_WS_TRANSPORT -> { - wsClientContainer = ContainerProvider.getWebSocketContainer(); - server.addBean(wsClientContainer); - } - case JETTY_WS_TRANSPORT -> { - wsClient = new WebSocketClient(); - server.addBean(wsClient); - } - default -> throw new AssertionError(); - } - - server.start(); - } - - private BayeuxClient newBayeuxClient(String wsTransportClass, String servletPath) { - return new BayeuxClient("http://localhost:" + connector.getLocalPort() + servletPath, newWebSocketTransport(wsTransportClass)); - } - - private ClientTransport newWebSocketTransport(String wsTransportClass) { - return switch (wsTransportClass) { - case JAKARTA_WS_TRANSPORT -> - new org.cometd.client.websocket.jakarta.WebSocketTransport(null, null, wsClientContainer); - case JETTY_WS_TRANSPORT -> - new org.cometd.client.websocket.jetty.JettyWebSocketTransport(null, null, wsClient); - default -> throw new AssertionError(); - }; - } - - @AfterEach - public void dispose() throws Exception { - server.stop(); - } - - @ParameterizedTest - @MethodSource("wsTransports") - public void testMultipleURLMappings(String wsTransportClass) throws Exception { - start(wsTransportClass); - - BayeuxClient client1 = newBayeuxClient(wsTransportClass, servletPath1); - client1.handshake(); - Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); - - BayeuxClient client2 = newBayeuxClient(wsTransportClass, servletPath2); - client2.handshake(); - Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); - - String channelName = "/foobarbaz"; - CountDownLatch messageLatch = new CountDownLatch(4); - CountDownLatch subscribeLatch = new CountDownLatch(2); - client1.getChannel(channelName).subscribe((channel, message) -> messageLatch.countDown(), message -> subscribeLatch.countDown()); - client2.getChannel(channelName).subscribe((channel, message) -> messageLatch.countDown(), message -> subscribeLatch.countDown()); - Assertions.assertTrue(subscribeLatch.await(5, TimeUnit.SECONDS)); - - client1.getChannel(channelName).publish("1"); - client2.getChannel(channelName).publish("2"); - - Assertions.assertTrue(messageLatch.await(5, TimeUnit.SECONDS)); - - client1.disconnect(1000); - client2.disconnect(1000); - } -} diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/SlowConnectionTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/SlowConnectionTest.java index a6467bb0fd..3fbe867ba2 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/SlowConnectionTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/SlowConnectionTest.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.Promise; @@ -37,23 +38,25 @@ import org.cometd.server.websocket.common.AbstractWebSocketTransport; import org.eclipse.jetty.util.Utf8StringBuilder; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; public class SlowConnectionTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testLargeMessageOnSlowConnection(String wsType) throws Exception { + @MethodSource("transports") + @Tag("flaky") + public void testLargeMessageOnSlowConnection(Transport wsType) throws Exception { testLargeMessageOnSlowConnection(wsType, false); } @ParameterizedTest - @MethodSource("wsTypes") - public void testLargeMessageOnSlowConnectionWithAckExtension(String wsType) throws Exception { + @MethodSource("transports") + public void testLargeMessageOnSlowConnectionWithAckExtension(Transport wsType) throws Exception { testLargeMessageOnSlowConnection(wsType, true); } - private void testLargeMessageOnSlowConnection(String wsType, boolean ackExtension) throws Exception { + private void testLargeMessageOnSlowConnection(Transport wsType, boolean ackExtension) throws Exception { Map serverOptions = new HashMap<>(); long timeout = 2000; serverOptions.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); @@ -64,21 +67,20 @@ private void testLargeMessageOnSlowConnection(String wsType, boolean ackExtensio prepareServer(wsType, serverOptions); startServer(); - bayeux.setDetailedDump(true); if (ackExtension) { - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); } try (Socket socket = new Socket("localhost", connector.getLocalPort())) { OutputStream output = socket.getOutputStream(); String upgrade = "" + - "GET " + cometdServletPath + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Connection: Upgrade\r\n" + - "Upgrade: websocket\r\n" + - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + - "Sec-WebSocket-Version: 13\r\n" + - "\r\n"; + "GET " + cometdPath + " HTTP/1.1\r\n" + + "Host: localhost:" + connector.getLocalPort() + "\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: websocket\r\n" + + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + + "Sec-WebSocket-Version: 13\r\n" + + "\r\n"; output.write(upgrade.getBytes(StandardCharsets.UTF_8)); output.flush(); @@ -150,7 +152,7 @@ private void testLargeMessageOnSlowConnection(String wsType, boolean ackExtensio } CountDownLatch removeLatch = new CountDownLatch(1); - ServerSessionImpl session = (ServerSessionImpl)bayeux.getSession(clientId); + ServerSessionImpl session = (ServerSessionImpl)bayeuxServer.getSession(clientId); session.addListener((ServerSession.RemovedListener)(s, m, t) -> removeLatch.countDown()); String connect2 = "[{" + @@ -166,7 +168,7 @@ private void testLargeMessageOnSlowConnection(String wsType, boolean ackExtensio char[] chars = new char[64 * 1024 * 1024]; Arrays.fill(chars, 'x'); String data = new String(chars); - bayeux.getChannel(channelName).publish(null, data, Promise.noop()); + bayeuxServer.getChannel(channelName).publish(null, data, Promise.noop()); // After timeout ms, the /meta/connect reply should be added to the // queue to be written, but the connection is still TCP congested. @@ -175,6 +177,9 @@ private void testLargeMessageOnSlowConnection(String wsType, boolean ackExtensio // After maxInterval, the session should be swept. Assertions.assertTrue(removeLatch.await(timeout + idleTimeout + 2 * maxInterval, TimeUnit.MILLISECONDS)); + + // TODO this helps with the flakyness + Thread.sleep(100); } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/URLMappingTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/URLMappingTest.java index 99891537e9..1c45a4ba1d 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/URLMappingTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/URLMappingTest.java @@ -15,38 +15,44 @@ */ package org.cometd.server.websocket; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + import org.cometd.client.BayeuxClient; import org.cometd.client.transport.ClientTransport; +import org.cometd.server.websocket.common.AbstractWebSocketTransport; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; public class URLMappingTest extends ClientServerWebSocketTest { @ParameterizedTest - @MethodSource("wsTypes") - public void testURLMappingNoGlobbing(String wsType) throws Exception { + @MethodSource("transports") + public void testURLMappingNoGlobbing(Transport wsType) throws Exception { testURLMapping(wsType, "/cometd"); } @ParameterizedTest - @MethodSource("wsTypes") - public void testRootURLMappingNoGlobbing(String wsType) throws Exception { + @MethodSource("transports") + public void testRootURLMappingNoGlobbing(Transport wsType) throws Exception { testURLMapping(wsType, "/"); } @ParameterizedTest - @MethodSource("wsTypes") - public void testURLMappingWithGlobbing(String wsType) throws Exception { + @MethodSource("transports") + public void testURLMappingWithGlobbing(Transport wsType) throws Exception { testURLMapping(wsType, "/cometd/*"); } @ParameterizedTest - @MethodSource("wsTypes") - public void testRootURLMappingWithGlobbing(String wsType) throws Exception { + @MethodSource("transports") + public void testRootURLMappingWithGlobbing(Transport wsType) throws Exception { testURLMapping(wsType, "/*"); } - private void testURLMapping(String wsType, String urlMapping) throws Exception { + private void testURLMapping(Transport wsType, String urlMapping) throws Exception { prepareAndStart(wsType, urlMapping, null); BayeuxClient client = newBayeuxClient(wsType); @@ -61,4 +67,35 @@ private void testURLMapping(String wsType, String urlMapping) throws Exception { disconnectBayeuxClient(client); } + + @ParameterizedTest + @MethodSource("transports") + public void testMultipleURLMappings(Transport wsType) throws Exception { + Map options = new HashMap<>(); + options.put(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, "/cometd/ws1,/cometd/ws2"); + prepareAndStart(wsType, "/cometd", options); + + BayeuxClient client1 = newBayeuxClient(wsType, "ws://localhost:%d/cometd/ws1".formatted(connector.getLocalPort())); + client1.handshake(); + Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); + + BayeuxClient client2 = newBayeuxClient(wsType, "ws://localhost:%d/cometd/ws2".formatted(connector.getLocalPort())); + client2.handshake(); + Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); + + String channelName = "/foobarbaz"; + CountDownLatch messageLatch = new CountDownLatch(4); + CountDownLatch subscribeLatch = new CountDownLatch(2); + client1.getChannel(channelName).subscribe((channel, message) -> messageLatch.countDown(), message -> subscribeLatch.countDown()); + client2.getChannel(channelName).subscribe((channel, message) -> messageLatch.countDown(), message -> subscribeLatch.countDown()); + Assertions.assertTrue(subscribeLatch.await(5, TimeUnit.SECONDS)); + + client1.getChannel(channelName).publish("1"); + client2.getChannel(channelName).publish("2"); + + Assertions.assertTrue(messageLatch.await(5, TimeUnit.SECONDS)); + + client1.disconnect(1000); + client2.disconnect(1000); + } } diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/WebSocketTransportTest.java b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/WebSocketTransportTest.java index aa7fda6d73..2b811bfd2d 100644 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/WebSocketTransportTest.java +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/java/org/cometd/server/websocket/WebSocketTransportTest.java @@ -35,7 +35,7 @@ import org.cometd.common.JettyJSONContextClient; import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-java/cometd-java-server/cometd-java-server-websocket/cometd-java-server-websocket-tests/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-server/pom.xml b/cometd-java/cometd-java-server/pom.xml index 062d027f87..3dee470ba1 100644 --- a/cometd-java/cometd-java-server/pom.xml +++ b/cometd-java/cometd-java-server/pom.xml @@ -13,6 +13,7 @@ cometd-java-server-common + cometd-java-server-http cometd-java-server-websocket diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/pom.xml b/cometd-java/cometd-java-tests/cometd-java-tests-common/pom.xml index cfab926aab..2c08bf1dcd 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/pom.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/pom.xml @@ -11,18 +11,6 @@ CometD :: Java :: Tests :: Common - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - org.eclipse.jetty jetty-jmx @@ -60,8 +48,8 @@ test - org.eclipse.jetty.ee10.websocket - jetty-ee10-websocket-jetty-server + org.eclipse.jetty.websocket + jetty-websocket-jetty-server ${jetty-version} test @@ -79,7 +67,13 @@ org.cometd.java - cometd-java-server-common + cometd-java-server-http-jakarta + ${project.version} + test + + + org.cometd.java + cometd-java-server-http-jetty ${project.version} test diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AbstractClientServerTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AbstractClientServerTest.java index 7199ac546e..402a21e5e5 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AbstractClientServerTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AbstractClientServerTest.java @@ -38,18 +38,19 @@ import org.cometd.client.websocket.jetty.JettyWebSocketTransport; import org.cometd.client.websocket.okhttp.OkHttpWebSocketTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; -import org.cometd.server.http.AsyncJSONTransport; -import org.cometd.server.http.JSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; +import org.cometd.server.http.jetty.CometDHandler; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; -import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.RegisterExtension; @@ -62,15 +63,15 @@ public static Collection transports() { } @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); protected final Logger logger = LoggerFactory.getLogger(getClass()); protected Server server; protected ServerConnector connector; - protected ServletContextHandler context; - protected String cometdServletPath = "/cometd"; + protected ContextHandler context; + protected String cometdPath = "/cometd"; protected String cometdURL; - protected BayeuxServer bayeux; + protected BayeuxServer bayeuxServer; private ScheduledExecutorService scheduler; private HttpClient httpClient; private WebSocketContainer wsContainer; @@ -81,80 +82,88 @@ public void start(Transport transport) throws Exception { start(transport, serverOptions(transport)); } - public void start(Transport transport, Map initParams) throws Exception { - startServer(transport, initParams); + public void start(Transport transport, Map options) throws Exception { + startServer(transport, options); startClient(transport); } - private void startServer(Transport transport, Map initParams) throws Exception { + private void startServer(Transport transport, Map options) throws Exception { server = new Server(); - connector = new ServerConnector(server, 1, 1); - connector.setIdleTimeout(30000); server.addConnector(connector); - context = new ServletContextHandler("/"); - server.setHandler(context); - switch (transport) { - case JAKARTA_WEBSOCKET, OKHTTP_WEBSOCKET -> - JakartaWebSocketServletContainerInitializer.configure(context, null); - case JETTY_WEBSOCKET -> JettyWebSocketServletContainerInitializer.configure(context, null); - default -> { + case JAKARTA_HTTP, OKHTTP_HTTP, JAKARTA_WEBSOCKET, OKHTTP_WEBSOCKET -> { + ServletContextHandler servletContext = new ServletContextHandler("/"); + context = servletContext; + server.setHandler(context); + ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); + cometdServletHolder.setInitParameter("timeout", "10000"); + cometdServletHolder.setInitOrder(1); + if (options != null) { + for (Map.Entry entry : options.entrySet()) { + cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + } + } + servletContext.addServlet(cometdServletHolder, cometdPath + "/*"); + if (transport == Transport.JAKARTA_WEBSOCKET || transport == Transport.OKHTTP_WEBSOCKET) { + JakartaWebSocketServletContainerInitializer.configure(servletContext, null); + } } - } - - // CometD servlet - ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - cometdServletHolder.setInitParameter("timeout", "10000"); - cometdServletHolder.setInitOrder(1); - if (initParams != null) { - for (Map.Entry entry : initParams.entrySet()) { - cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + case JETTY_HTTP, JETTY_WEBSOCKET -> { + context = new ContextHandler("/"); + server.setHandler(context); + CometDHandler cometdHandler = new CometDHandler(); + cometdHandler.setOptions(options == null ? Map.of() : options); + context.setHandler(cometdHandler); + if (transport == Transport.JETTY_WEBSOCKET) { + WebSocketUpgradeHandler wsHandler = WebSocketUpgradeHandler.from(server, context); + context.insertHandler(wsHandler); + } } + default -> throw new IllegalStateException(); } - context.addServlet(cometdServletHolder, cometdServletPath + "/*"); - server.start(); int port = connector.getLocalPort(); - cometdURL = "http://localhost:" + port + cometdServletPath; - - bayeux = (BayeuxServer)context.getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); + cometdURL = "http://localhost:" + port + cometdPath; + bayeuxServer = (BayeuxServer)context.getContext().getAttribute(BayeuxServer.ATTRIBUTE); } protected void startClient(Transport transport) throws Exception { scheduler = Executors.newSingleThreadScheduledExecutor(); switch (transport) { - case JETTY_HTTP, ASYNC_HTTP -> { + case JETTY_HTTP, JAKARTA_HTTP -> { httpClient = new HttpClient(); httpClient.start(); } - case JAKARTA_WEBSOCKET -> wsContainer = ContainerProvider.getWebSocketContainer(); + case JAKARTA_WEBSOCKET -> { + wsContainer = ContainerProvider.getWebSocketContainer(); + } case JETTY_WEBSOCKET -> { httpClient = new HttpClient(); httpClient.start(); wsClient = new WebSocketClient(httpClient); wsClient.start(); } - case OKHTTP_HTTP, OKHTTP_WEBSOCKET -> + case OKHTTP_HTTP, OKHTTP_WEBSOCKET -> { // There's no lifecycle of OkHttp client. - okHttpClient = new OkHttpClient(); - default -> throw new IllegalArgumentException(); + okHttpClient = new OkHttpClient(); + } + default -> throw new IllegalStateException(); } } protected Map serverOptions(Transport transport) { Map options = new HashMap<>(); options.put(BayeuxServerImpl.TRANSPORTS_OPTION, serverTransport(transport)); - options.put("ws.cometdURLMapping", cometdServletPath + "/*"); + options.put("ws.cometdURLMapping", cometdPath + "/*"); return options; } protected String serverTransport(Transport transport) { return switch (transport) { - case JETTY_HTTP -> JSONTransport.class.getName(); - case ASYNC_HTTP, OKHTTP_HTTP -> AsyncJSONTransport.class.getName(); + case JAKARTA_HTTP, JETTY_HTTP, OKHTTP_HTTP -> JSONHttpTransport.class.getName(); case JAKARTA_WEBSOCKET, OKHTTP_WEBSOCKET -> org.cometd.server.websocket.jakarta.WebSocketTransport.class.getName(); case JETTY_WEBSOCKET -> org.cometd.server.websocket.jetty.JettyWebSocketTransport.class.getName(); @@ -167,7 +176,7 @@ protected BayeuxClient newBayeuxClient(Transport transport) { protected ClientTransport newClientTransport(Transport transport, Map options) { return switch (transport) { - case JETTY_HTTP, ASYNC_HTTP -> new JettyHttpClientTransport(options, httpClient); + case JETTY_HTTP, JAKARTA_HTTP -> new JettyHttpClientTransport(options, httpClient); case OKHTTP_HTTP -> new OkHttpClientTransport(options, okHttpClient); case JAKARTA_WEBSOCKET -> new WebSocketTransport(options, scheduler, wsContainer); case JETTY_WEBSOCKET -> new JettyWebSocketTransport(options, scheduler, wsClient); @@ -221,6 +230,6 @@ protected boolean ipv6Available() { } public enum Transport { - JETTY_HTTP, ASYNC_HTTP, OKHTTP_HTTP, JAKARTA_WEBSOCKET, JETTY_WEBSOCKET, OKHTTP_WEBSOCKET + JAKARTA_HTTP, JETTY_HTTP, OKHTTP_HTTP, JAKARTA_WEBSOCKET, JETTY_WEBSOCKET, OKHTTP_WEBSOCKET } } diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AckExtensionTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AckExtensionTest.java index e2c34b1b9d..3d00161dfe 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AckExtensionTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/AckExtensionTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSessionChannel; import org.cometd.bayeux.server.ServerMessage; @@ -55,7 +56,7 @@ public void onBatchReceive(ServerSession session, long batch) { } } }); - bayeux.addExtension(extension); + bayeuxServer.addExtension(extension); String channelName = "/ack_listener"; @@ -72,7 +73,7 @@ public void onBatchReceive(ServerSession session, long batch) { Assertions.assertTrue(readyLatch.await(5, TimeUnit.SECONDS)); String sessionId = client.getId(); - ServerSession serverSession = bayeux.getSession(sessionId); + ServerSession serverSession = bayeuxServer.getSession(sessionId); Assertions.assertNotNull(serverSession); // Send a message directly to the client. diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/BayeuxClientTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/BayeuxClientTest.java index d9991a6f92..bb660b5d1c 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/BayeuxClientTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/BayeuxClientTest.java @@ -15,6 +15,7 @@ */ package org.cometd.tests; +import java.util.EnumSet; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -33,12 +34,18 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import static org.cometd.tests.AbstractClientServerTest.Transport.JAKARTA_HTTP; +import static org.cometd.tests.AbstractClientServerTest.Transport.JETTY_HTTP; +import static org.cometd.tests.AbstractClientServerTest.Transport.OKHTTP_HTTP; + public class BayeuxClientTest extends AbstractClientServerTest { @Disabled("Restore when Jetty issue #10219 is released") @ParameterizedTest @MethodSource("transports") public void testIPv6Address(Transport transport) throws Exception { Assumptions.assumeTrue(ipv6Available()); + Assumptions.assumeFalse(EnumSet.of(JETTY_HTTP, JAKARTA_HTTP, OKHTTP_HTTP).contains(transport), + "Cookies+IPv6 support currently is broken, see bug #9665"); start(transport); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/DuplicateMetaConnectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/DuplicateMetaConnectTest.java index 1ac689cb31..d7e15152cc 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/DuplicateMetaConnectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/DuplicateMetaConnectTest.java @@ -21,6 +21,7 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.client.ClientSessionChannel; @@ -89,7 +90,7 @@ public void testDuplicateMetaConnectWithExistingMetaConnectFailedOnClient(Transp clientOptions.put(BayeuxClient.BACKOFF_INCREMENT_OPTION, backoff); BayeuxClient client = new BayeuxClient(cometdURL, newClientTransport(transport, clientOptions)); - bayeux.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { private final AtomicInteger metaConnects = new AtomicInteger(); @Override diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeReconnectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeReconnectTest.java index 3facf7e610..39ad73ac0d 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeReconnectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeReconnectTest.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.client.ClientSessionChannel; import org.cometd.bayeux.server.BayeuxServer; @@ -65,7 +66,7 @@ public void testReconnectUsingHandshake(Transport transport) throws Exception { // Wait for the session to be swept (timeout + maxInterval). CountDownLatch sessionRemoved = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionRemoved(ServerSession session, ServerMessage message, boolean timeout) { sessionRemoved.countDown(); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeWithExpiredSessionTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeWithExpiredSessionTest.java index 71adf1283b..d9c39f7b15 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeWithExpiredSessionTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/HandshakeWithExpiredSessionTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.client.ClientSessionChannel; @@ -54,7 +55,7 @@ public void testHandshakeWithExpiredSession(Transport transport) throws Exceptio metaHandshake.addListener(new ClientSessionChannel.MessageListener() { @Override public void onMessage(ClientSessionChannel channel, Message message) { - sessionRef1.set(bayeux.getSession(message.getClientId())); + sessionRef1.set(bayeuxServer.getSession(message.getClientId())); handshakeLatch1.countDown(); metaHandshake.removeListener(this); } @@ -81,7 +82,7 @@ public void onMessage(ClientSessionChannel channel, Message message) { CountDownLatch handshakeLatch2 = new CountDownLatch(1); AtomicReference sessionRef2 = new AtomicReference<>(); metaHandshake.addListener((ClientSessionChannel.MessageListener)(channel, message) -> { - sessionRef2.set(bayeux.getSession(message.getClientId())); + sessionRef2.set(bayeuxServer.getSession(message.getClientId())); handshakeLatch2.countDown(); }); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MaxMessageSizeTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MaxMessageSizeTest.java index e0a25d93d1..b69d8c1829 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MaxMessageSizeTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MaxMessageSizeTest.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSessionChannel; import org.cometd.bayeux.server.ServerChannel; @@ -86,7 +87,7 @@ public void testClientMaxMessageSize(Transport transport) throws Exception { BayeuxClient client = new BayeuxClient(cometdURL, newClientTransport(transport, clientOptions)); client.handshake(message -> { ClientSessionChannel channel = client.getChannel(channelName); - channel.subscribe((c, m) -> messageLatch.countDown(), m -> bayeux.getChannel(channelName).publish(null, data, Promise.noop())); + channel.subscribe((c, m) -> messageLatch.countDown(), m -> bayeuxServer.getChannel(channelName).publish(null, data, Promise.noop())); }); Assertions.assertFalse(messageLatch.await(1, TimeUnit.SECONDS)); @@ -111,7 +112,7 @@ public void testClientMaxSendBayeuxMessageSize(Transport transport) throws Excep String channelName = "/max_msg"; CountDownLatch serverLatch = new CountDownLatch(1); - bayeux.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { + bayeuxServer.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession sender, ServerChannel channel, ServerMessage.Mutable message) { serverLatch.countDown(); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MessageDeliveryDuringHandshakeTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MessageDeliveryDuringHandshakeTest.java index 6fe5706bae..c659d743d3 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MessageDeliveryDuringHandshakeTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MessageDeliveryDuringHandshakeTest.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSessionChannel; @@ -58,7 +59,7 @@ public void testMessagesSentInHandshakeResponseWithAckExtension(Transport transp Map options = serverOptions(transport); options.put(AbstractServerTransport.ALLOW_MESSAGE_DELIVERY_DURING_HANDSHAKE, String.valueOf(true)); start(transport, options); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); BayeuxClient client = newBayeuxClient(transport); client.addExtension(new AckExtension()); testMessagesInHandshakeResponse(client, true); @@ -66,7 +67,7 @@ public void testMessagesSentInHandshakeResponseWithAckExtension(Transport transp private void testMessagesInHandshakeResponse(BayeuxClient client, boolean allowHandshakeMessages) throws Exception { String channelName = "/test"; - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { // Send messages during the handshake processing. @@ -87,7 +88,7 @@ public void sessionAdded(ServerSession session, ServerMessage message) { CountDownLatch queueLatch = new CountDownLatch(1); client.getChannel(Channel.META_HANDSHAKE).addListener((ClientSessionChannel.MessageListener)(channel, message) -> { - ServerSessionImpl serverSession = (ServerSessionImpl)bayeux.getSession(client.getId()); + ServerSessionImpl serverSession = (ServerSessionImpl)bayeuxServer.getSession(client.getId()); if (serverSession.getQueue().isEmpty() == allowHandshakeMessages) { queueLatch.countDown(); } @@ -111,8 +112,8 @@ public void testMessagesSentInHandshakeResponseWithAckExtensionWithDeQueueListen Map options = serverOptions(transport); options.put(AbstractServerTransport.ALLOW_MESSAGE_DELIVERY_DURING_HANDSHAKE, String.valueOf(true)); start(transport, options); - bayeux.addExtension(new AcknowledgedMessagesExtension()); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { session.addListener((ServerSession.DeQueueListener)(s, queue) -> { @@ -126,7 +127,7 @@ public void sessionAdded(ServerSession session, ServerMessage message) { client.addExtension(new AckExtension()); String channelName = "/test"; - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { // Send messages during the handshake processing. diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectDeliverOnlyTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectDeliverOnlyTest.java index 06521eda09..b4b82b8934 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectDeliverOnlyTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectDeliverOnlyTest.java @@ -18,6 +18,7 @@ import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; @@ -35,7 +36,7 @@ public void testMetaConnectDeliveryOnly(Transport transport) throws Exception { BayeuxClient client = newBayeuxClient(transport); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { session.setMetaConnectDeliveryOnly(true); @@ -49,7 +50,7 @@ public void sessionAdded(ServerSession session, ServerMessage message) { client.getChannel(channelName).subscribe((c, m) -> { latch.countDown(); if (latch.getCount() == 1) { - bayeux.getChannel(channelName).publish(null, "data2", Promise.noop()); + bayeuxServer.getChannel(channelName).publish(null, "data2", Promise.noop()); Assertions.assertFalse(await(latch, Duration.ofSeconds(1))); } }); @@ -63,7 +64,7 @@ public void sessionAdded(ServerSession session, ServerMessage message) { // In the message listener, we perform a second server-side // publish and the second message should not arrive to the // client yet because we deliver messages only via /meta/connect. - bayeux.getChannel(channelName).publish(null, "data1", Promise.noop()); + bayeuxServer.getChannel(channelName).publish(null, "data1", Promise.noop()); Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureTest.java index de7e567b22..0995c03244 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureTest.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; @@ -51,7 +52,7 @@ public void testMetaConnectSuspendedThenConnectionClosed(Transport transport) th // Verify that the /meta/connect reply is written. CountDownLatch metaConnectReplyLatch = new CountDownLatch(1); - bayeux.addExtension(new BayeuxServer.Extension() { + bayeuxServer.addExtension(new BayeuxServer.Extension() { @Override public boolean sendMeta(ServerSession session, ServerMessage.Mutable message) { if (Channel.META_CONNECT.equals(message.getChannel())) { @@ -63,7 +64,7 @@ public boolean sendMeta(ServerSession session, ServerMessage.Mutable message) { // Verify that the session is swept. CountDownLatch sessionRemovedLatch = new CountDownLatch(1); - ServerSession session = bayeux.getSession(client.getId()); + ServerSession session = bayeuxServer.getSession(client.getId()); session.addListener((ServerSession.RemovedListener)(s, m, t) -> sessionRemovedLatch.countDown()); // Stop the connector so the /meta/connect response cannot be sent, diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureWithAckExtensionTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureWithAckExtensionTest.java index b57ae9dd6c..e1f5551ea2 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureWithAckExtensionTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectFailureWithAckExtensionTest.java @@ -18,6 +18,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSession; @@ -34,17 +35,19 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class MetaConnectFailureWithAckExtensionTest extends AbstractClientServerTest { @ParameterizedTest @MethodSource("transports") public void testMetaConnectFailureWithAckExtension(Transport transport) throws Exception { start(transport); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); String channelName = "/test"; CountDownLatch serverSubscribeLatch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SubscriptionListener() { + bayeuxServer.addListener(new BayeuxServer.SubscriptionListener() { @Override public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message) { if (channelName.equals(channel.getId())) { @@ -55,7 +58,7 @@ public void subscribed(ServerSession session, ServerChannel channel, ServerMessa long delay = 1000; long maxNetworkDelay = 3 * delay; - bayeux.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { + bayeuxServer.getChannel(Channel.META_CONNECT).addListener(new ServerChannel.MessageListener() { private final AtomicInteger connects = new AtomicInteger(); @Override @@ -67,16 +70,15 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag // Be sure we are subscribed. try { - serverSubscribeLatch.await(5, TimeUnit.SECONDS); - } catch (InterruptedException x) { - // Ignored + assertTrue(serverSubscribeLatch.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException ignored) { } int connect = connects.incrementAndGet(); if (connect == 1) { // Publish a message on the first connect, which will fail. // The ack extension will deliver it via /meta/connect. - bayeux.createChannelIfAbsent(channelName).getReference().publish(null, "data", Promise.noop()); + bayeuxServer.createChannelIfAbsent(channelName).getReference().publish(null, "data", Promise.noop()); sleep(maxNetworkDelay + delay); } else if (connect == 2) { // When the second connect arrives, maxNetworkDelay has elapsed. @@ -115,8 +117,8 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag } }); - Assertions.assertTrue(clientSubscribeLatch.await(5, TimeUnit.SECONDS)); - Assertions.assertTrue(messageLatch1.await(2 * maxNetworkDelay, TimeUnit.MILLISECONDS)); + assertTrue(clientSubscribeLatch.await(5, TimeUnit.SECONDS)); + assertTrue(messageLatch1.await(2 * maxNetworkDelay, TimeUnit.MILLISECONDS)); Assertions.assertFalse(messageLatch2.await(2 * delay, TimeUnit.MILLISECONDS)); disconnectBayeuxClient(client); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectOvertakenWithAckExtensionTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectOvertakenWithAckExtensionTest.java index b506881dbb..10c776eed1 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectOvertakenWithAckExtensionTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/MetaConnectOvertakenWithAckExtensionTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; + import org.cometd.bayeux.Channel; import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSession; @@ -47,7 +48,7 @@ public void testMetaConnectFailureWithAckExtension(Transport transport) throws E start(transport, serverOptions); AtomicReference messageRef = new AtomicReference<>(); AtomicReference> promiseRef = new AtomicReference<>(); - bayeux.addExtension(new BayeuxServer.Extension() { + bayeuxServer.addExtension(new BayeuxServer.Extension() { @Override public boolean rcvMeta(ServerSession session, ServerMessage.Mutable message) { if (Channel.META_HANDSHAKE.equals(message.getChannel())) { @@ -71,7 +72,7 @@ public void outgoing(ServerSession sender, ServerSession session, ServerMessage. return true; } }); - bayeux.addExtension(new AcknowledgedMessagesExtension()); + bayeuxServer.addExtension(new AcknowledgedMessagesExtension()); String channelName = "/overtaken"; @@ -111,7 +112,7 @@ public void outgoing(ServerSession sender, ServerSession session, ServerMessage. // Send a message to deliver it with the ack extension. // The 2nd /meta/connect reply will be delayed by the extension on server. - ServerChannel serverChannel = bayeux.getChannel(channelName); + ServerChannel serverChannel = bayeuxServer.getChannel(channelName); serverChannel.publish(null, "data1", Promise.noop()); // Setup to hold the 3rd /meta/connect on the client, so the 4th is delayed. diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/NetworkDelayListenerTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/NetworkDelayListenerTest.java index 36ca58468c..8f81642ded 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/NetworkDelayListenerTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/NetworkDelayListenerTest.java @@ -66,9 +66,9 @@ public class NetworkDelayListenerTest extends AbstractClientServerTest { public void testNetworkDelayListener(Transport transport) throws Exception { try (ServerSocketChannel serverSocket = ServerSocketChannel.open()) { serverSocket.bind(new InetSocketAddress("localhost", 0)); - cometdServletPath = "/cometd"; + cometdPath = "/cometd"; int port = serverSocket.socket().getLocalPort(); - cometdURL = "http://localhost:" + port + cometdServletPath; + cometdURL = "http://localhost:" + port + cometdPath; LOGGER.debug("Listening on localhost:{}", port); startClient(transport); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/OrphanedSessionTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/OrphanedSessionTest.java index 8d243b5c23..73d18ba872 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/OrphanedSessionTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/OrphanedSessionTest.java @@ -19,6 +19,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; @@ -40,7 +41,7 @@ public void testForOrphanedSessionDeliverDoesNotEnqueue(Transport transport) thr AtomicReference serverSessionRef = new AtomicReference<>(); CountDownLatch removedLatch = new CountDownLatch(1); - bayeux.addListener(new BayeuxServer.SessionListener() { + bayeuxServer.addListener(new BayeuxServer.SessionListener() { @Override public void sessionAdded(ServerSession session, ServerMessage message) { serverSessionRef.set(session); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ProxyTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ProxyTest.java index 4fb429c1c4..b518437be4 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ProxyTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ProxyTest.java @@ -34,9 +34,9 @@ import org.cometd.client.transport.ClientTransport; import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; import org.cometd.server.ServerMessageImpl; -import org.cometd.server.http.AsyncJSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -97,9 +97,8 @@ protected void startProxy(Map initParams) throws Exception { private ServletContextHandler prepareContext(Server server, Map initParams) { ServletContextHandler context = new ServletContextHandler("/"); server.setHandler(context); - // CometD servlet ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - cometdServletHolder.setInitParameter(BayeuxServerImpl.TRANSPORTS_OPTION, AsyncJSONTransport.class.getName()); + cometdServletHolder.setInitParameter(BayeuxServerImpl.TRANSPORTS_OPTION, JSONHttpTransport.class.getName()); cometdServletHolder.setInitParameter(AbstractServerTransport.TIMEOUT_OPTION, "10000"); cometdServletHolder.setInitOrder(1); if (initParams != null) { diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ServerSendMessageTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ServerSendMessageTest.java index 9b99d56225..366552b595 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ServerSendMessageTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/ServerSendMessageTest.java @@ -17,6 +17,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.Promise; import org.cometd.bayeux.client.ClientSessionChannel; import org.cometd.bayeux.server.ServerChannel; @@ -35,7 +36,7 @@ public void testServerCanSendMessageBeforeFirstMetaConnect(Transport transport) String channelName = "/service/test"; String response = "response"; - bayeux.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { + bayeuxServer.createChannelIfAbsent(channelName).getReference().addListener(new ServerChannel.MessageListener() { @Override public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessage.Mutable message) { from.deliver(null, channelName, response, Promise.noop()); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/SweepTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/SweepTest.java index a7898c591a..109e585871 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/SweepTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/SweepTest.java @@ -45,7 +45,7 @@ public void testMaxProcessingPostponesSweeping(Transport transport) throws Excep CountDownLatch suspendLatch = new CountDownLatch(1); CountDownLatch removeLatch = new CountDownLatch(1); client.handshake(r -> { - ServerSession session = bayeux.getSession(r.getClientId()); + ServerSession session = bayeuxServer.getSession(r.getClientId()); session.addListener(new ServerSession.HeartBeatListener() { @Override public void onSuspended(ServerSession session, ServerMessage message, long timeout) { diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/TransportFailureTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/TransportFailureTest.java index fa1bb48d92..65fabd090c 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/TransportFailureTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/TransportFailureTest.java @@ -32,7 +32,7 @@ import org.cometd.client.transport.ClientTransport; import org.cometd.client.websocket.jakarta.WebSocketTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -64,7 +64,6 @@ private void startServer() throws Exception { cometdServletPath = "/cometd"; - // CometD servlet ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); cometdServletHolder.setInitParameter("timeout", "10000"); cometdServletHolder.setInitParameter("ws.cometdURLMapping", cometdServletPath); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppService.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppService.java index 4c78d5f0d5..e74dfee1ec 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppService.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppService.java @@ -176,7 +176,7 @@ public void toJSON(Object obj, JSON.Output out) { } @Override - public Object fromJSON(Map map) { + public Object fromJSON(Map map) { Custom custom = new Custom(); custom.data = (String)map.get("data"); return custom; diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppTest.java index d307f1ce0a..28397052dd 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/java/org/cometd/tests/WebAppTest.java @@ -42,7 +42,8 @@ import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.client.websocket.jakarta.WebSocketTransport; -import org.cometd.client.websocket.jetty.JettyWebSocketTransport; +import org.cometd.server.CometDRequest; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.component.LifeCycle; @@ -56,11 +57,10 @@ import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.RegisterExtension; - public class WebAppTest { private String testName; @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> { + public final BeforeTestExecutionCallback printMethodName = context -> { testName = context.getRequiredTestMethod().getName(); System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), testName, context.getDisplayName()); }; @@ -90,9 +90,7 @@ private void start(Path webXML) throws Exception { copyWebAppDependency(jakarta.inject.Inject.class, webINF); copyWebAppDependency(jakarta.annotation.PostConstruct.class, webINF); copyWebAppDependency(org.slf4j.Logger.class, webINF); - copyWebAppDependency(org.apache.logging.slf4j.Log4jLogger.class, webINF); - copyWebAppDependency(org.apache.logging.log4j.Level.class, webINF); - copyWebAppDependency(org.apache.logging.log4j.core.LoggerContext.class, webINF); + copyWebAppDependency(org.eclipse.jetty.logging.JettyLogger.class, webINF); copyWebAppDependency(org.cometd.annotation.Service.class, webINF); copyWebAppDependency(org.cometd.annotation.server.RemoteCall.class, webINF); copyWebAppDependency(org.cometd.bayeux.Message.class, webINF); @@ -102,7 +100,6 @@ private void start(Path webXML) throws Exception { copyWebAppDependency(org.cometd.server.BayeuxServerImpl.class, webINF); copyWebAppDependency(org.cometd.server.websocket.common.AbstractWebSocketTransport.class, webINF); copyWebAppDependency(org.cometd.server.websocket.jakarta.WebSocketTransport.class, webINF); - copyWebAppDependency(org.cometd.server.websocket.jetty.JettyWebSocketTransport.class, webINF); copyWebAppDependency(org.cometd.client.BayeuxClient.class, webINF); copyWebAppDependency(org.cometd.client.http.common.AbstractHttpClientTransport.class, webINF); copyWebAppDependency(org.cometd.client.http.jetty.JettyHttpClientTransport.class, webINF); @@ -117,10 +114,17 @@ private void start(Path webXML) throws Exception { copyWebAppDependency(org.eclipse.jetty.ee10.servlets.CrossOriginFilter.class, webINF); copyWebAppDependency(org.eclipse.jetty.util.Callback.class, webINF); copyWebAppDependency(org.eclipse.jetty.util.ajax.JSON.class, webINF); + copyWebAppDependency(org.eclipse.jetty.websocket.api.Configurable.class, webINF); copyWebAppDependency(org.eclipse.jetty.websocket.common.WebSocketSession.class, webINF); copyWebAppDependency(org.eclipse.jetty.websocket.client.WebSocketClient.class, webINF); copyWebAppDependency(org.eclipse.jetty.websocket.core.client.WebSocketCoreClient.class, webINF); copyWebAppDependency(org.eclipse.jetty.websocket.core.Configuration.class, webINF); + copyWebAppDependency(CometDServlet.class, webINF); + copyWebAppDependency(CometDRequest.class, webINF); + copyWebAppDependency(org.cometd.bayeux.server.BayeuxContext.class, webINF); + copyWebAppDependency(org.cometd.bayeux.Promise.class, webINF); + copyWebAppDependency(org.cometd.common.JSONContext.class, webINF); + copyWebAppDependency(org.cometd.bayeux.client.ClientSession.class, webINF); // Web application classes. Path testClasses = baseDir.resolve("target/test-classes/"); @@ -150,9 +154,7 @@ private void start(Path webXML) throws Exception { addServerDependency(jakarta.annotation.Resources.class, serverClassPath); addServerDependency(jakarta.annotation.security.RunAs.class, serverClassPath); addServerDependency(org.slf4j.Logger.class, serverClassPath); - addServerDependency(org.apache.logging.slf4j.SLF4JServiceProvider.class, serverClassPath); - addServerDependency(org.apache.logging.log4j.Logger.class, serverClassPath); - addServerDependency(org.apache.logging.log4j.core.Appender.class, serverClassPath); + addServerDependency(org.eclipse.jetty.logging.JettyLogger.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.annotations.AnnotationConfiguration.class, serverClassPath); addServerDependency(org.eclipse.jetty.client.HttpClient.class, serverClassPath); addServerDependency(org.eclipse.jetty.http.HttpStatus.class, serverClassPath); @@ -164,6 +166,9 @@ private void start(Path webXML) throws Exception { addServerDependency(org.eclipse.jetty.server.Server.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.servlet.ServletContextHandler.class, serverClassPath); addServerDependency(org.eclipse.jetty.util.Callback.class, serverClassPath); + addServerDependency(org.eclipse.jetty.server.Deployable.class, serverClassPath); + addServerDependency(org.eclipse.jetty.session.SessionManager.class, serverClassPath); + addServerDependency(org.eclipse.jetty.util.ajax.JSON.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.webapp.WebAppContext.class, serverClassPath); addServerDependency(org.eclipse.jetty.websocket.api.Session.class, serverClassPath); addServerDependency(org.eclipse.jetty.websocket.common.WebSocketSession.class, serverClassPath); @@ -173,7 +178,6 @@ private void start(Path webXML) throws Exception { addServerDependency(org.eclipse.jetty.ee10.websocket.jakarta.client.JakartaWebSocketClientContainerProvider.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketContainer.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketConfiguration.class, serverClassPath); - addServerDependency(org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketConfiguration.class, serverClassPath); addServerDependency(org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter.class, serverClassPath); addServerDependency(org.eclipse.jetty.xml.XmlConfiguration.class, serverClassPath); addServerDependency(org.objectweb.asm.ClassVisitor.class, serverClassPath); @@ -212,15 +216,6 @@ public void dispose() { IO.close(server); } - @Test - public void testWebAppWithNativeJettyWebSocketTransport() throws Exception { - start(baseDir.resolve("src/test/resources/jetty-ws-web.xml")); - - BayeuxClient client = new BayeuxClient(cometdURI, new JettyWebSocketTransport(null, null, wsClient)); - subscribePublishReceive(client); - client.disconnect(); - } - @Test public void testWebAppWithWebSocketTransport() throws Exception { start(baseDir.resolve("src/test/resources/jakarta-ws-web.xml")); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/http-web.xml b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/http-web.xml index 926b02676e..1edf417652 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/http-web.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/http-web.xml @@ -17,10 +17,10 @@ cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet transports - org.cometd.server.http.AsyncJSONTransport + org.cometd.server.http.JSONHttpTransport 1 true diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jakarta-ws-web.xml b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jakarta-ws-web.xml index 66a27ae789..f9dbe8b1e1 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jakarta-ws-web.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jakarta-ws-web.xml @@ -28,7 +28,7 @@ cometd - org.cometd.server.CometDServlet + org.cometd.server.http.jakarta.CometDServlet ws.cometdURLMapping /cometd/* diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-ws-web.xml b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-ws-web.xml deleted file mode 100644 index 1c2cec6224..0000000000 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/jetty-ws-web.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - cross-origin - org.eclipse.jetty.ee10.servlets.CrossOriginFilter - true - - - cross-origin - /cometd/* - - - - org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter - org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter - true - - - - org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter - /cometd/* - - - - cometd - org.cometd.server.CometDServlet - - transports - - org.cometd.server.websocket.jetty.JettyWebSocketTransport,org.cometd.server.http.AsyncJSONTransport - - - - ws.cometdURLMapping - /cometd/* - - 1 - true - - - - cometd - /cometd/* - - - diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/log4j2-test.properties deleted file mode 100644 index 276f0d2e8b..0000000000 --- a/cometd-java/cometd-java-tests/cometd-java-tests-common/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/pom.xml b/cometd-java/cometd-java-tests/cometd-java-tests-oort/pom.xml index 6c1ca6f8de..d43e58b38f 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/pom.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/pom.xml @@ -12,26 +12,32 @@ - org.junit.jupiter - junit-jupiter + org.cometd.java + cometd-java-oort-common + ${project.version} + test - org.apache.logging.log4j - log4j-core + org.cometd.java + cometd-java-oort-jakarta + ${project.version} + test - org.apache.logging.log4j - log4j-slf4j2-impl + org.cometd.java + cometd-java-annotation-server + ${project.version} + test org.cometd.java - cometd-java-oort + cometd-java-server-http-jakarta ${project.version} test org.cometd.java - cometd-java-annotation-server + cometd-java-server-http-jetty ${project.version} test @@ -90,8 +96,8 @@ test - org.eclipse.jetty.ee10.websocket - jetty-ee10-websocket-jetty-server + org.eclipse.jetty.websocket + jetty-websocket-jetty-server ${jetty-version} test diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortObjectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortObjectTest.java index c66c7536c8..c53334306b 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortObjectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortObjectTest.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerChannel; import org.cometd.bayeux.server.ServerMessage; @@ -30,19 +31,19 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -public abstract class AbstractOortObjectTest extends OortTest { +public abstract class AbstractOortObjectTest extends AbstractOortTest { private final List> oortObjects = new ArrayList<>(); protected Oort oort1; protected Oort oort2; - protected void prepare(String serverTransport) throws Exception { - prepare(serverTransport, new HashMap<>()); + protected void prepare(Transport transport) throws Exception { + prepare(transport, new HashMap<>()); } - protected void prepare(String serverTransport, Map options) throws Exception { - Server server1 = startServer(serverTransport, 0, options); + protected void prepare(Transport transport, Map options) throws Exception { + Server server1 = startServer(transport, 0, options); oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); + Server server2 = startServer(transport, 0, options); oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(2); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortTest.java similarity index 72% rename from cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortTest.java rename to cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortTest.java index a4ce7ebdae..23be8ffcf4 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/AbstractOortTest.java @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import org.cometd.bayeux.Message; import org.cometd.bayeux.client.ClientSessionChannel; @@ -35,42 +36,48 @@ import org.cometd.bayeux.server.ServerSession; import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; -import org.cometd.server.CometDServlet; -import org.cometd.server.http.JSONTransport; +import org.cometd.oort.jakarta.OortConfigServlet; +import org.cometd.server.AbstractServerTransport; +import org.cometd.server.BayeuxServerImpl; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; +import org.cometd.server.http.jetty.CometDHandler; +import org.cometd.server.websocket.common.AbstractWebSocketTransport; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.cometd.server.websocket.jetty.JettyWebSocketTransport; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; -import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; import org.junit.jupiter.api.extension.RegisterExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class OortTest { - public static List transports() { - return List.of(WebSocketTransport.class.getName(), JettyWebSocketTransport.class.getName()); +public abstract class AbstractOortTest { + public static Transport[] transports() { + return Transport.values(); } @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); protected final Logger logger = LoggerFactory.getLogger(getClass()); protected final List servers = new ArrayList<>(); protected final List oorts = new ArrayList<>(); private final List clients = new ArrayList<>(); - protected Server startServer(String serverTransport, int port) throws Exception { - return startServer(serverTransport, port, new HashMap<>()); + protected Server startServer(Transport transport, int port) throws Exception { + return startServer(transport, port, new HashMap<>()); } - protected Server startServer(String serverTransport, int port, Map options) throws Exception { + protected Server startServer(Transport transport, int port, Map options) throws Exception { QueuedThreadPool serverThreads = new QueuedThreadPool(); serverThreads.setName("server_" + servers.size()); Server server = new Server(serverThreads); @@ -78,35 +85,46 @@ protected Server startServer(String serverTransport, int port, Map entry : options.entrySet()) { - cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); - } - cometdServletHolder.setInitOrder(1); - context.addServlet(cometdServletHolder, cometdURLMapping); + String cometdPath = "/cometd"; + String cometdURLMapping = cometdPath + "/*"; + Supplier getBayeuxServer = switch (transport) { + case JAKARTA_WEBSOCKET -> { + ServletContextHandler context = new ServletContextHandler("/"); + server.setHandler(context); + JakartaWebSocketServletContainerInitializer.configure(context, null); + CometDServlet cometdServlet = new CometDServlet(); + ServletHolder cometdServletHolder = new ServletHolder(cometdServlet); + String transports = WebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName(); + cometdServletHolder.setInitParameter(BayeuxServerImpl.TRANSPORTS_OPTION, transports); + cometdServletHolder.setInitParameter(AbstractServerTransport.TIMEOUT_OPTION, "10000"); + cometdServletHolder.setInitParameter(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, cometdURLMapping); + for (Map.Entry entry : options.entrySet()) { + cometdServletHolder.setInitParameter(entry.getKey(), entry.getValue()); + } + cometdServletHolder.setInitOrder(1); + context.addServlet(cometdServletHolder, cometdURLMapping); + yield cometdServlet::getBayeuxServer; + } + case JETTY_WEBSOCKET -> { + ContextHandler context = new ContextHandler("/"); + server.setHandler(context); + WebSocketUpgradeHandler wsHandler = WebSocketUpgradeHandler.from(server, context); + context.setHandler(wsHandler); + CometDHandler cometdHandler = new CometDHandler(); + wsHandler.setHandler(cometdHandler); + String transports = JettyWebSocketTransport.class.getName() + "," + JSONHttpTransport.class.getName(); + options.put(BayeuxServerImpl.TRANSPORTS_OPTION, transports); + options.putIfAbsent(AbstractServerTransport.TIMEOUT_OPTION, "10000"); + options.put(AbstractWebSocketTransport.COMETD_URL_MAPPING_OPTION, cometdURLMapping); + cometdHandler.setOptions(options); + yield cometdHandler::getBayeuxServer; + } + }; server.start(); - String url = "http://localhost:" + connector.getLocalPort() + cometdServletPath; + String url = "http://localhost:" + connector.getLocalPort() + cometdPath; server.setAttribute(OortConfigServlet.OORT_URL_PARAM, url); - BayeuxServer bayeux = (BayeuxServer)context.getServletContext().getAttribute(BayeuxServer.ATTRIBUTE); + BayeuxServer bayeux = getBayeuxServer.get(); server.setAttribute(BayeuxServer.ATTRIBUTE, bayeux); servers.add(server); @@ -303,4 +321,8 @@ private boolean snd(ServerMessage.Mutable message) { return true; } } + + public enum Transport { + JAKARTA_WEBSOCKET, JETTY_WEBSOCKET + } } diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JMXTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JMXTest.java index 81acef29ce..cb7ea12f9c 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JMXTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JMXTest.java @@ -24,8 +24,11 @@ import jakarta.servlet.http.HttpServlet; import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.oort.jakarta.OortConfigServlet; +import org.cometd.oort.jakarta.OortStaticConfigServlet; +import org.cometd.oort.jakarta.SetiServlet; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; @@ -54,9 +57,8 @@ public void testJMX() throws Exception { String value = BayeuxServerImpl.ATTRIBUTE + "," + Oort.OORT_ATTRIBUTE + "," + Seti.SETI_ATTRIBUTE; context.setInitParameter(ServletContextHandler.MANAGED_ATTRIBUTES, value); - // CometD servlet - String cometdServletPath = "/cometd"; - String cometdURLMapping = cometdServletPath + "/*"; + String cometdPath = "/cometd"; + String cometdURLMapping = cometdPath + "/*"; ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); cometdServletHolder.setInitParameter("timeout", "10000"); cometdServletHolder.setInitParameter("ws.cometdURLMapping", cometdURLMapping); @@ -64,7 +66,7 @@ public void testJMX() throws Exception { context.addServlet(cometdServletHolder, cometdURLMapping); ServletHolder oortServletHolder = new ServletHolder(OortStaticConfigServlet.class); - oortServletHolder.setInitParameter(OortConfigServlet.OORT_URL_PARAM, "http://localhost" + cometdServletPath); + oortServletHolder.setInitParameter(OortConfigServlet.OORT_URL_PARAM, "http://localhost" + cometdPath); oortServletHolder.setInitOrder(2); context.addServlet(oortServletHolder, "/oort"); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JacksonOortObjectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JacksonOortObjectTest.java index 0f8d138c7c..f226f66a18 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JacksonOortObjectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/JacksonOortObjectTest.java @@ -25,12 +25,12 @@ public class JacksonOortObjectTest extends OortObjectTest { @Override - protected Server startServer(String serverTransport, int port, Map options) throws Exception { + protected Server startServer(Transport transport, int port, Map options) throws Exception { if (options == null) { options = new HashMap<>(); } options.put(AbstractServerTransport.JSON_CONTEXT_OPTION, JacksonJSONContextServer.class.getName()); - return super.startServer(serverTransport, port, options); + return super.startServer(transport, port, options); } @Override diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortAuthenticationTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortAuthenticationTest.java index 3671726bdf..6892b88c25 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortAuthenticationTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortAuthenticationTest.java @@ -32,15 +32,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class OortAuthenticationTest extends OortTest { +public class OortAuthenticationTest extends AbstractOortTest { @ParameterizedTest @MethodSource("transports") - public void testAuthenticationWithSecurityPolicy(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testAuthenticationWithSecurityPolicy(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); oort1.setSecret("test_secret"); oort1.getBayeuxServer().setSecurityPolicy(new TestSecurityPolicy(oort1)); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); oort2.setSecret(oort1.getSecret()); oort2.getBayeuxServer().setSecurityPolicy(new TestSecurityPolicy(oort2)); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortDemo.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortDemo.java index 4f050983cf..cf6a784863 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortDemo.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortDemo.java @@ -19,7 +19,9 @@ import java.net.URI; import java.util.List; -import org.cometd.server.CometDServlet; +import org.cometd.oort.jakarta.OortMulticastConfigServlet; +import org.cometd.oort.jakarta.SetiServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.jmx.MBeanContainer; @@ -72,7 +74,6 @@ public OortDemo(int port) throws Exception { URI.create(base + "/../../cometd-demo/target/cometd-demo-2.4.0-SNAPSHOT/") ))); - // CometD servlet ServletHolder cometd_holder = new ServletHolder(CometDServlet.class); cometd_holder.setInitParameter("timeout", "200000"); cometd_holder.setInitParameter("interval", "100"); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortListTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortListTest.java index 2f4d99c628..be057f0b8e 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortListTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortListTest.java @@ -30,8 +30,8 @@ public class OortListTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testElementAdded(String serverTransport) throws Exception { - prepare(serverTransport); + public void testElementAdded(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentList(); @@ -58,8 +58,8 @@ public void onAdded(OortObject.Info> info, List elements) { @ParameterizedTest @MethodSource("transports") - public void testElementRemoved(String serverTransport) throws Exception { - prepare(serverTransport); + public void testElementRemoved(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentList(); @@ -100,8 +100,8 @@ public void onRemoved(OortObject.Info> info, List elements) { @ParameterizedTest @MethodSource("transports") - public void testDeltaListener(String serverTransport) throws Exception { - prepare(serverTransport); + public void testDeltaListener(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentList(); @@ -171,8 +171,8 @@ public void onRemoved(OortObject.Info> info, List elements) @ParameterizedTest @MethodSource("transports") - public void testContains(String serverTransport) throws Exception { - prepare(serverTransport); + public void testContains(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentList(); @@ -225,8 +225,8 @@ public void onAdded(OortObject.Info> info, List elements) { @ParameterizedTest @MethodSource("transports") - public void testConcurrent(String serverTransport) throws Exception { - prepare(serverTransport); + public void testConcurrent(Transport transport) throws Exception { + prepare(transport); String name = "concurrent"; OortObject.Factory> factory = OortObjectFactories.forConcurrentList(); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortLongMapTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortLongMapTest.java index c8e03b079c..caa60b8cd2 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortLongMapTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortLongMapTest.java @@ -28,8 +28,8 @@ public class OortLongMapTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testShare(String serverTransport) throws Exception { - prepare(serverTransport); + public void testShare(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -86,8 +86,8 @@ public void onUpdated(OortObject.Info> oldInfo, Oort @ParameterizedTest @MethodSource("transports") - public void testHowToDealWitMutableValues(String serverTransport) throws Exception { - prepare(serverTransport); + public void testHowToDealWitMutableValues(Transport transport) throws Exception { + prepare(transport); // We are using a Map as mutable value because it serializes easily in JSON. // Any other mutable data structure would require a serializer/deserializer. diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortMulticastConfigurerTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortMulticastConfigurerTest.java index 0782e86b41..2154a01f68 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortMulticastConfigurerTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortMulticastConfigurerTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class OortMulticastConfigurerTest extends OortTest { +public class OortMulticastConfigurerTest extends AbstractOortTest { private final List configurers = new ArrayList<>(); @BeforeEach @@ -81,13 +81,13 @@ private void stopConfigurer(OortMulticastConfigurer configurer) throws Exception @ParameterizedTest @MethodSource("transports") - public void testTwoComets(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testTwoComets(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); int groupPort = ((NetworkConnector)server1.getConnectors()[0]).getLocalPort(); Oort oort1 = startOort(server1); startConfigurer(oort1, groupPort); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); startConfigurer(oort2, groupPort); @@ -100,13 +100,13 @@ public void testTwoComets(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testThreeComets(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testThreeComets(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); int groupPort = ((NetworkConnector)server1.getConnectors()[0]).getLocalPort(); Oort oort1 = startOort(server1); startConfigurer(oort1, groupPort); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); OortMulticastConfigurer configurer2 = startConfigurer(oort2, groupPort); @@ -117,7 +117,7 @@ public void testThreeComets(String serverTransport) throws Exception { Assertions.assertEquals(1, oort2.getKnownComets().size()); // Create another comet - Server server3 = startServer(serverTransport, 0); + Server server3 = startServer(transport, 0); Oort oort3 = startOort(server3); startConfigurer(oort3, groupPort); @@ -143,10 +143,10 @@ public void testThreeComets(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testTwoCometsOneWithWrongURL(String serverTransport) throws Exception { + public void testTwoCometsOneWithWrongURL(Transport transport) throws Exception { long connectTimeout = 2000; - Server serverA = startServer(serverTransport, 0); + Server serverA = startServer(transport, 0); int groupPort = ((NetworkConnector)serverA.getConnectors()[0]).getLocalPort(); Oort oortA = startOort(serverA); OortMulticastConfigurer configurerA = new OortMulticastConfigurer(oortA); @@ -155,7 +155,7 @@ public void testTwoCometsOneWithWrongURL(String serverTransport) throws Exceptio configurers.add(configurerA); configurerA.start(); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); String wrongURL = "http://localhost:4/cometd"; BayeuxServer bayeuxServerB = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); Oort oortB = new Oort(bayeuxServerB, wrongURL); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectStartupTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectStartupTest.java index ec2c7dc7f2..7c1e1fa57c 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectStartupTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectStartupTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class OortObjectStartupTest extends OortTest { +public class OortObjectStartupTest extends AbstractOortTest { private final List> oortObjects = new ArrayList<>(); @AfterEach @@ -44,7 +44,7 @@ public void dispose() throws Exception { @ParameterizedTest @MethodSource("transports") - public void testOortObjectStartup(String serverTransport) throws Exception { + public void testOortObjectStartup(Transport transport) throws Exception { int nodes = 4; int edges = nodes * (nodes - 1); CountDownLatch joinLatch = new CountDownLatch(edges); @@ -57,7 +57,7 @@ public void cometJoined(Event event) { Map options = new HashMap<>(); options.put("ws.maxMessageSize", String.valueOf(1024 * 1024)); for (int i = 0; i < nodes; i++) { - Oort oort = startOort(startServer(serverTransport, 0, options)); + Oort oort = startOort(startServer(transport, 0, options)); oort.addCometListener(joinListener); } Oort oort1 = oorts.get(0); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectTest.java index d4943d3f36..d1531b6135 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObjectTest.java @@ -40,8 +40,8 @@ public class OortObjectTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testShareObject(String serverTransport) throws Exception { - prepare(serverTransport); + public void testShareObject(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forMap(); @@ -98,8 +98,8 @@ public void onUpdated(OortObject.Info> oldInfo, OortObject.I @ParameterizedTest @MethodSource("transports") - public void testShareObjectWithAllChannelsSubscription(String serverTransport) throws Exception { - prepare(serverTransport); + public void testShareObjectWithAllChannelsSubscription(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forMap(); @@ -142,8 +142,8 @@ public void onUpdated(OortObject.Info> oldInfo, OortObject.I @ParameterizedTest @MethodSource("transports") - public void testLocalObjectIsPushedWhenNodeJoins(String serverTransport) throws Exception { - prepare(serverTransport); + public void testLocalObjectIsPushedWhenNodeJoins(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forMap(); @@ -167,7 +167,7 @@ public void testLocalObjectIsPushedWhenNodeJoins(String serverTransport) throws Thread.sleep(1000); // Connect node3 - Server server3 = startServer(serverTransport, 0); + Server server3 = startServer(transport, 0); Oort oort3 = startOort(server3); OortComet oortComet31 = oort3.observeComet(oort1.getURL()); Assertions.assertTrue(oortComet31.waitFor(5000, BayeuxClient.State.CONNECTED)); @@ -217,8 +217,8 @@ public void onUpdated(OortObject.Info> oldInfo, OortObject.I @ParameterizedTest @MethodSource("transports") - public void testLocalObjectIsRemovedWhenNodeLeaves(String serverTransport) throws Exception { - prepare(serverTransport); + public void testLocalObjectIsRemovedWhenNodeLeaves(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forMap(); @@ -252,8 +252,8 @@ public void testLocalObjectIsRemovedWhenNodeLeaves(String serverTransport) throw @ParameterizedTest @MethodSource("transports") - public void testIterationOverInfos(String serverTransport) throws Exception { - prepare(serverTransport); + public void testIterationOverInfos(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forMap(); @@ -293,8 +293,8 @@ public void testIterationOverInfos(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testNonCompositeObject(String serverTransport) throws Exception { - prepare(serverTransport); + public void testNonCompositeObject(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory factory = OortObjectFactories.forLong(0); @@ -334,8 +334,8 @@ public void onUpdated(OortObject.Info oldInfo, OortObject.Info newIn @ParameterizedTest @MethodSource("transports") - public void testStaleUpdateIsDiscarded(String serverTransport) throws Exception { - prepare(serverTransport); + public void testStaleUpdateIsDiscarded(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory factory = OortObjectFactories.forLong(0); @@ -399,8 +399,8 @@ public boolean rcv(ServerSession from, ServerMessage.Mutable message) { @ParameterizedTest @MethodSource("transports") - public void testConcurrent(String serverTransport) throws Exception { - prepare(serverTransport); + public void testConcurrent(Transport transport) throws Exception { + prepare(transport); String name = "concurrent"; OortObject.Factory factory = OortObjectFactories.forString(""); @@ -470,8 +470,8 @@ public void onUpdated(OortObject.Info oldInfo, OortObject.Info n @ParameterizedTest @MethodSource("transports") - public void testApplicationLocking(String serverTransport) throws Exception { - prepare(serverTransport); + public void testApplicationLocking(Transport transport) throws Exception { + prepare(transport); String name = "locking"; OortObject.Factory factory = OortObjectFactories.forString("initial"); @@ -526,13 +526,13 @@ public void onUpdated(OortObject.Info oldInfo, OortObject.Info n @ParameterizedTest @MethodSource("transports") - public void testNodeCrashWhileOtherNodeStarts(String serverTransport) throws Exception { - prepare(serverTransport); + public void testNodeCrashWhileOtherNodeStarts(Transport transport) throws Exception { + prepare(transport); String name = "crash"; OortObject.Factory factory = OortObjectFactories.forString(""); - Server server1 = startServer(serverTransport, 0); + Server server1 = startServer(transport, 0); ServerConnector connector1 = (ServerConnector)server1.getConnectors()[0]; int port1 = connector1.getLocalPort(); oort1 = startOort(server1); @@ -543,7 +543,7 @@ public void testNodeCrashWhileOtherNodeStarts(String serverTransport) throws Exc result1.get(5, TimeUnit.SECONDS); // Simulate that node2 is starting but not yet ready to accept connections. - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); ServerConnector connector2 = (ServerConnector)server2.getConnectors()[0]; int port2 = connector2.getLocalPort(); connector2.stop(); @@ -580,7 +580,7 @@ public void onUpdated(OortObject.Info oldInfo, OortObject.Info n Assertions.assertNull(info); // Restart node1. - server1 = startServer(serverTransport, port1); + server1 = startServer(transport, port1); connector1 = (ServerConnector)server1.getConnectors()[0]; connector1.stop(); oort1 = startOort(server1); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveChannelTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveChannelTest.java index 20fea1df8b..364f3d521c 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveChannelTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveChannelTest.java @@ -32,15 +32,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class OortObserveChannelTest extends OortTest { +public class OortObserveChannelTest extends AbstractOortTest { @ParameterizedTest @MethodSource("transports") - public void testObserveChannel(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testObserveChannel(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); - Server server3 = startServer(serverTransport, 0); + Server server3 = startServer(transport, 0); Oort oort3 = startOort(server3); CountDownLatch latch = new CountDownLatch(6); @@ -104,10 +104,10 @@ public void testObserveChannel(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testObserveWildChannel(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testObserveWildChannel(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(2); @@ -152,10 +152,10 @@ public void testObserveWildChannel(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testDeobserve(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testDeobserve(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(2); @@ -205,14 +205,14 @@ public void testDeobserve(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testBinaryMessageOnObservedChannel(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testBinaryMessageOnObservedChannel(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); BayeuxServer bayeux1 = (BayeuxServer)server1.getAttribute(BayeuxServer.ATTRIBUTE); bayeux1.addExtension(new BinaryExtension()); Oort oort1 = startOort(server1); oort1.getOortSession().addExtension(new org.cometd.client.ext.BinaryExtension()); oort1.setBinaryExtensionEnabled(true); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); BayeuxServer bayeux2 = (BayeuxServer)server2.getAttribute(BayeuxServer.ATTRIBUTE); bayeux2.addExtension(new BinaryExtension()); Oort oort2 = startOort(server2); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveCometTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveCometTest.java index 7cc313690c..fa99a5de77 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveCometTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortObserveCometTest.java @@ -42,6 +42,7 @@ import org.cometd.client.ext.AckExtension; import org.cometd.client.transport.ClientTransport; import org.cometd.client.transport.TransportListener; +import org.cometd.oort.jakarta.OortConfigServlet; import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; import org.cometd.server.ext.AcknowledgedMessagesExtension; @@ -52,13 +53,13 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class OortObserveCometTest extends OortTest { +public class OortObserveCometTest extends AbstractOortTest { @ParameterizedTest @MethodSource("transports") - public void testObserveStartedOortAndExpectToBeObserved(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testObserveStartedOortAndExpectToBeObserved(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -78,10 +79,10 @@ public void testObserveStartedOortAndExpectToBeObserved(String serverTransport) @ParameterizedTest @MethodSource("transports") - public void testCometACometBConnectedWhenCometAConnectsToCometCThenAlsoCometBConnectsToCometC(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testCometACometBConnectedWhenCometAConnectsToCometCThenAlsoCometBConnectsToCometC(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); CountDownLatch latch = new CountDownLatch(6); @@ -92,7 +93,7 @@ public void testCometACometBConnectedWhenCometAConnectsToCometCThenAlsoCometBCon OortComet oortCometAB = oortA.observeComet(oortB.getURL()); Assertions.assertTrue(oortCometAB.waitFor(5000, BayeuxClient.State.CONNECTED)); - Server serverC = startServer(serverTransport, 0); + Server serverC = startServer(transport, 0); Oort oortC = startOort(serverC); oortC.addCometListener(listener); @@ -118,11 +119,11 @@ public void testCometACometBConnectedWhenCometAConnectsToCometCThenAlsoCometBCon @ParameterizedTest @MethodSource("transports") - public void testConnectTwoCloudsAndDisconnectOneComet(String serverTransport) throws Exception { + public void testConnectTwoCloudsAndDisconnectOneComet(Transport transport) throws Exception { // Cloud #1, A and B - Server serverA = startServer(serverTransport, 0); + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); CountDownLatch latch1 = new CountDownLatch(2); CometJoinedListener listener1 = new CometJoinedListener(latch1); @@ -135,9 +136,9 @@ public void testConnectTwoCloudsAndDisconnectOneComet(String serverTransport) th Assertions.assertTrue(oortCometBA.waitFor(5000, BayeuxClient.State.CONNECTED)); // Cloud #2, C and D - Server serverC = startServer(serverTransport, 0); + Server serverC = startServer(transport, 0); Oort oortC = startOort(serverC); - Server serverD = startServer(serverTransport, 0); + Server serverD = startServer(transport, 0); Oort oortD = startOort(serverD); CountDownLatch latch2 = new CountDownLatch(2); CometJoinedListener listener2 = new CometJoinedListener(latch2); @@ -202,9 +203,9 @@ public void testConnectTwoCloudsAndDisconnectOneComet(String serverTransport) th @ParameterizedTest @MethodSource("transports") - public void testObserveStartedOortAndDetectStop(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); - Server server2 = startServer(serverTransport, 0); + public void testObserveStartedOortAndDetectStop(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); + Server server2 = startServer(transport, 0); Oort oort1 = startOort(server1); Assertions.assertNotNull(oort1.getOortSession()); @@ -234,14 +235,14 @@ public void testObserveStartedOortAndDetectStop(String serverTransport) throws E @ParameterizedTest @MethodSource("transports") - public void testObserveNonStartedOortAndDetectStart(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testObserveNonStartedOortAndDetectStart(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); String url = (String)server1.getAttribute(OortConfigServlet.OORT_URL_PARAM); BayeuxServer bayeuxServer = (BayeuxServer)server1.getAttribute(BayeuxServer.ATTRIBUTE); Oort oort1 = new Oort(bayeuxServer, url); oort1.start(); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); String url2 = (String)server2.getAttribute(OortConfigServlet.OORT_URL_PARAM); int port = new URI(url2).getPort(); stopServer(server2); @@ -249,7 +250,7 @@ public void testObserveNonStartedOortAndDetectStart(String serverTransport) thro OortComet oortComet12 = oort1.observeComet(url2); Assertions.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.REHANDSHAKING)); - server2 = startServer(serverTransport, port); + server2 = startServer(transport, port); Oort oort2 = startOort(server2); Assertions.assertEquals(oort2.getURL(), url2); @@ -260,11 +261,11 @@ public void testObserveNonStartedOortAndDetectStart(String serverTransport) thro @ParameterizedTest @MethodSource("transports") - public void testObserveStartedOortAndDetectConnectorRestart(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testObserveStartedOortAndDetectConnectorRestart(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); @@ -301,11 +302,11 @@ public void testObserveStartedOortAndDetectConnectorRestart(String serverTranspo @ParameterizedTest @MethodSource("transports") - public void testObserveStartedOortAndDetectServerRestart(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testObserveStartedOortAndDetectServerRestart(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); OortComet oortCometAB1 = oortA.observeComet(oortB.getURL()); @@ -338,7 +339,7 @@ public void cometLeft(Event event) { sleep(1000); Assertions.assertEquals(1, leftCountA.get()); - serverB = startServer(serverTransport, port2); + serverB = startServer(transport, port2); String url2 = (String)serverB.getAttribute(OortConfigServlet.OORT_URL_PARAM); BayeuxServer bayeuxServer2 = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); bayeuxServer2.setOption(Server.class.getName(), serverB); @@ -378,17 +379,17 @@ public void cometJoined(Event event) { @ParameterizedTest @MethodSource("transports") - public void testNetworkBrokenShorterThanMaxInterval(String serverTransport) throws Exception { + public void testNetworkBrokenShorterThanMaxInterval(Transport transport) throws Exception { long sweepPeriod = 500; long maxInterval = 4000; Map options = new HashMap<>(); options.put(BayeuxServerImpl.SWEEP_PERIOD_OPTION, String.valueOf(sweepPeriod)); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server server1 = startServer(serverTransport, 0, options); + Server server1 = startServer(transport, 0, options); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); + Server server2 = startServer(transport, 0, options); Oort oort2 = startOort(server2); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); @@ -435,17 +436,17 @@ public void testNetworkBrokenShorterThanMaxInterval(String serverTransport) thro @ParameterizedTest @MethodSource("transports") - public void testNetworkBrokenLongerThanMaxInterval(String serverTransport) throws Exception { + public void testNetworkBrokenLongerThanMaxInterval(Transport transport) throws Exception { long timeout = 2000; long maxInterval = 3000; Map options = new HashMap<>(); options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server server1 = startServer(serverTransport, 0, options); + Server server1 = startServer(transport, 0, options); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); + Server server2 = startServer(transport, 0, options); Oort oort2 = startOort(server2); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); @@ -511,15 +512,15 @@ public void cometLeft(Event event) { @ParameterizedTest @MethodSource("transports") - public void testCometDownLongerThanMaxInterval(String serverTransport) throws Exception { + public void testCometDownLongerThanMaxInterval(Transport transport) throws Exception { long maxInterval = 2000; Map options = new HashMap<>(); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server server1 = startServer(serverTransport, 0, options); + Server server1 = startServer(transport, 0, options); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); + Server server2 = startServer(transport, 0, options); Oort oort2 = startOort(server2); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); @@ -572,7 +573,7 @@ public void cometJoined(Event event) { Thread.sleep(2 * maxInterval); // Restart the comet. - server1 = startServer(serverTransport, port1, options); + server1 = startServer(transport, port1, options); oort1 = startOort(server1); // Restore the connectivity. @@ -602,15 +603,15 @@ public void cometJoined(Event event) { @ParameterizedTest @MethodSource("transports") - public void testCometDownShorterThanMaxInterval(String serverTransport) throws Exception { + public void testCometDownShorterThanMaxInterval(Transport transport) throws Exception { long maxInterval = 4000; Map options = new HashMap<>(); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server server1 = startServer(serverTransport, 0, options); + Server server1 = startServer(transport, 0, options); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); + Server server2 = startServer(transport, 0, options); Oort oort2 = startOort(server2); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); @@ -638,7 +639,7 @@ public void testCometDownShorterThanMaxInterval(String serverTransport) throws E String oortId1 = oort1.getId(); // Restart the comet. - server1 = startServer(serverTransport, port1, options); + server1 = startServer(transport, port1, options); oort1 = startOort(server1); // Make sure that on reconnect the system emits a comet @@ -700,12 +701,12 @@ public void cometJoined(Event event) { @ParameterizedTest @MethodSource("transports") - public void testDeobserve(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testDeobserve(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); - Server serverC = startServer(serverTransport, 0); + Server serverC = startServer(transport, 0); Oort oortC = startOort(serverC); CountDownLatch latch1 = new CountDownLatch(6); @@ -772,8 +773,8 @@ public void testDeobserve(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testObserveSameCometWithDifferentURL(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testObserveSameCometWithDifferentURL(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); String urlA = oortA.getURL(); String urlAA = urlA.replace("localhost", "127.0.0.1"); @@ -785,12 +786,12 @@ public void testObserveSameCometWithDifferentURL(String serverTransport) throws @ParameterizedTest @MethodSource("transports") - public void testObserveDifferentCometWithDifferentURL(String serverTransport) throws Exception { + public void testObserveDifferentCometWithDifferentURL(Transport transport) throws Exception { Assumptions.assumeTrue(ipv6Available()); - Server serverA = startServer(serverTransport, 0); + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); String urlB = oortB.getURL(); @@ -857,14 +858,14 @@ public void cometJoined(Event event) { @ParameterizedTest @MethodSource("transports") - public void testSingleCometsJoinsTheCloud(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testSingleCometsJoinsTheCloud(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); - Server serverC = startServer(serverTransport, 0); + Server serverC = startServer(transport, 0); Oort oortC = startOort(serverC); - Server serverD = startServer(serverTransport, 0); + Server serverD = startServer(transport, 0); Oort oortD = startOort(serverD); CountDownLatch latch1 = new CountDownLatch(2); @@ -930,8 +931,8 @@ public void testSingleCometsJoinsTheCloud(String serverTransport) throws Excepti @ParameterizedTest @MethodSource("transports") - public void testAckExtensionConfiguration(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testAckExtensionConfiguration(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); stopOort(oortA); oortA.setAckExtensionEnabled(true); @@ -946,7 +947,7 @@ public void testAckExtensionConfiguration(String serverTransport) throws Excepti } Assertions.assertEquals(1, ackExtensions); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); BayeuxServer bayeuxServerB = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); bayeuxServerB.addExtension(new AcknowledgedMessagesExtension()); Oort oortB = startOort(serverB); @@ -992,8 +993,8 @@ public void testAckExtensionConfiguration(String serverTransport) throws Excepti @ParameterizedTest @MethodSource("transports") - public void testPublishDuringCometJoined(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testPublishDuringCometJoined(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); BayeuxServer bayeuxServerA = oortA.getBayeuxServer(); @@ -1011,7 +1012,7 @@ public void cometJoined(Event event) { }); oortA.observeChannel(channelName); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); Oort oortB = startOort(serverB); oortB.observeChannel(channelName); @@ -1036,13 +1037,13 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag @ParameterizedTest @MethodSource("transports") - public void testConfigureMaxMessageSize(String serverTransport) throws Exception { + public void testConfigureMaxMessageSize(Transport transport) throws Exception { int maxMessageSize = 1024; Map options = new HashMap<>(); options.put("ws.maxMessageSize", String.valueOf(maxMessageSize)); - Server serverA = startServer(serverTransport, 0, options); + Server serverA = startServer(transport, 0, options); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0, options); + Server serverB = startServer(transport, 0, options); Oort oortB = startOort(serverB); CountDownLatch latch = new CountDownLatch(2); @@ -1088,10 +1089,10 @@ public void testConfigureMaxMessageSize(String serverTransport) throws Exception @ParameterizedTest @MethodSource("transports") - public void testHandshakeReplyFailureDoesNotDisconnectOortComet(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testHandshakeReplyFailureDoesNotDisconnectOortComet(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); long maxNetworkDelay = 1000; BayeuxServer bayeuxServerB = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); bayeuxServerB.addExtension(new BayeuxServer.Extension() { @@ -1147,10 +1148,10 @@ public void onMessage(ClientSessionChannel channel, Message message) { @ParameterizedTest @MethodSource("transports") - public void testJoinMessageFailure(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testJoinMessageFailure(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); BayeuxServer bayeuxServerB = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); ServerChannel joinChannel = bayeuxServerB.createChannelIfAbsent(Oort.OORT_SERVICE_CHANNEL).getReference(); AtomicBoolean joinMessage = new AtomicBoolean(); @@ -1193,10 +1194,10 @@ public void cometJoined(Event event) { @ParameterizedTest @MethodSource("transports") - public void testHandshakeFailureDoesNotDisconnectOortComet(String serverTransport) throws Exception { - Server serverA = startServer(serverTransport, 0); + public void testHandshakeFailureDoesNotDisconnectOortComet(Transport transport) throws Exception { + Server serverA = startServer(transport, 0); Oort oortA = startOort(serverA); - Server serverB = startServer(serverTransport, 0); + Server serverB = startServer(transport, 0); BayeuxServer bayeuxServerB = (BayeuxServer)serverB.getAttribute(BayeuxServer.ATTRIBUTE); bayeuxServerB.addExtension(new BayeuxServer.Extension() { private final AtomicInteger handshakes = new AtomicInteger(); @@ -1221,7 +1222,7 @@ public boolean rcvMeta(ServerSession session, ServerMessage.Mutable message) { @ParameterizedTest @MethodSource("transports") - public void testMessagesDroppedOnlyInOneDirection(String serverTransport) throws Exception { + public void testMessagesDroppedOnlyInOneDirection(Transport transport) throws Exception { long sweepPeriod = 1000; long maxNetworkDelay = 1000; long timeout = 2000; @@ -1231,7 +1232,7 @@ public void testMessagesDroppedOnlyInOneDirection(String serverTransport) throws options.put(ClientTransport.MAX_NETWORK_DELAY_OPTION, String.valueOf(maxNetworkDelay)); options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server serverA = startServer(serverTransport, 0, options); + Server serverA = startServer(transport, 0, options); String urlA = (String)serverA.getAttribute(OortConfigServlet.OORT_URL_PARAM); BayeuxServerImpl bayeuxServerA = (BayeuxServerImpl)serverA.getAttribute(BayeuxServer.ATTRIBUTE); bayeuxServerA.setOption(Server.class.getName(), serverA); @@ -1264,7 +1265,7 @@ protected void configureOortComet(OortComet oortComet) { bayeuxServerA.addExtension(new HalfNetworkDownExtension(oortA, halfNetworkDown)); oortA.start(); oorts.add(oortA); - Server serverB = startServer(serverTransport, 0, options); + Server serverB = startServer(transport, 0, options); Oort oortB = startOort(serverB); AtomicInteger joinCount = new AtomicInteger(); @@ -1325,8 +1326,8 @@ public void cometLeft(Event event) { @ParameterizedTest @MethodSource("transports") - public void testProtectedOortChannels(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testProtectedOortChannels(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); BayeuxClient client = startClient(oort1, null); @@ -1374,7 +1375,7 @@ public void testProtectedOortChannels(String serverTransport) throws Exception { Assertions.assertTrue(allSubscribeLatch.await(5, TimeUnit.SECONDS)); // Cause an Oort message to be broadcast. - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); oort1.observeComet(oort2.getURL()); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortPrimaryLongTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortPrimaryLongTest.java index 10f4f71b86..0fe81c0475 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortPrimaryLongTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortPrimaryLongTest.java @@ -25,8 +25,8 @@ public class OortPrimaryLongTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testCount(String serverTransport) throws Exception { - prepare(serverTransport); + public void testCount(Transport transport) throws Exception { + prepare(transport); String name = "test"; long initial = 3; diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortServiceTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortServiceTest.java index fa62e3b424..67d579ea2a 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortServiceTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortServiceTest.java @@ -26,8 +26,8 @@ public class OortServiceTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testActionIsForwarded(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionIsForwarded(Transport transport) throws Exception { + prepare(transport); CountDownLatch latch1 = new CountDownLatch(1); Service service1 = new Service(oort1, latch1); @@ -52,8 +52,8 @@ public void testActionIsForwarded(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testActionIsNotForwardedForUnknownURL(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionIsNotForwardedForUnknownURL(Transport transport) throws Exception { + prepare(transport); Service service1 = new Service(oort1, null); service1.start(); @@ -65,8 +65,8 @@ public void testActionIsNotForwardedForUnknownURL(String serverTransport) throws @ParameterizedTest @MethodSource("transports") - public void testActionIsBroadcast(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionIsBroadcast(Transport transport) throws Exception { + prepare(transport); CountDownLatch latch1 = new CountDownLatch(1); BroadcastService service1 = new BroadcastService(oort1, latch1); @@ -105,8 +105,8 @@ public void testActionIsBroadcast(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testActionFailsOnRuntimeException(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionFailsOnRuntimeException(Transport transport) throws Exception { + prepare(transport); CountDownLatch latch1 = new CountDownLatch(1); Service service1 = new Service(oort1, latch1) { @@ -141,8 +141,8 @@ protected Result onForward(Request request) { @ParameterizedTest @MethodSource("transports") - public void testActionFailsOnFailure(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionFailsOnFailure(Transport transport) throws Exception { + prepare(transport); String failure = "failure"; CountDownLatch latch1 = new CountDownLatch(1); @@ -178,8 +178,8 @@ protected Result onForward(Request request) { @ParameterizedTest @MethodSource("transports") - public void testActionBroadcastTimeout(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionBroadcastTimeout(Transport transport) throws Exception { + prepare(transport); long timeout = 1000; CountDownLatch latch1 = new CountDownLatch(1); @@ -219,8 +219,8 @@ protected Result onForward(Request request) { @ParameterizedTest @MethodSource("transports") - public void testActionForwardTimeout(String serverTransport) throws Exception { - prepare(serverTransport); + public void testActionForwardTimeout(Transport transport) throws Exception { + prepare(transport); long timeout = 1000; CountDownLatch latch1 = new CountDownLatch(1); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStartupTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStartupTest.java index ade7f6183f..63f02dc995 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStartupTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStartupTest.java @@ -29,11 +29,13 @@ import org.cometd.client.http.okhttp.OkHttpClientTransport; import org.cometd.client.websocket.okhttp.OkHttpWebSocketTransport; import org.cometd.common.JettyJSONContextClient; +import org.cometd.oort.jakarta.OortConfigServlet; +import org.cometd.oort.jakarta.OortStaticConfigServlet; import org.cometd.server.AbstractServerTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; import org.cometd.server.JettyJSONContextServer; -import org.cometd.server.http.AsyncJSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -41,6 +43,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.ajax.JSON; +import org.eclipse.jetty.util.component.LifeCycle; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; @@ -54,7 +57,7 @@ public class OortStartupTest { @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); private final Map servers = new ConcurrentHashMap<>(); private final Map contexts = new ConcurrentHashMap<>(); @@ -89,7 +92,6 @@ private void startNode(Class startupServletClass, Map transports() { return Stream.of( Arguments.of(WebSocketTransport.class.getName(), org.cometd.client.websocket.jakarta.WebSocketTransport.Factory.class.getName()), Arguments.of(WebSocketTransport.class.getName(), OkHttpWebSocketTransport.Factory.class.getName()), - Arguments.of(AsyncJSONTransport.class.getName(), JettyHttpClientTransport.Factory.class.getName()), - Arguments.of(AsyncJSONTransport.class.getName(), OkHttpClientTransport.Factory.class.getName()) + Arguments.of(JSONHttpTransport.class.getName(), JettyHttpClientTransport.Factory.class.getName()), + Arguments.of(JSONHttpTransport.class.getName(), OkHttpClientTransport.Factory.class.getName()) ); } @@ -265,6 +267,11 @@ public void init() throws ServletException { throw new ServletException(x); } } + + @Override + public void destroy() { + LifeCycle.stop(ids); + } } public static class OortMapStartupServlet extends HttpServlet { @@ -282,6 +289,11 @@ public void init() throws ServletException { throw new ServletException(x); } } + + @Override + public void destroy() { + LifeCycle.stop(users); + } } public static class UserInfo { @@ -306,7 +318,7 @@ public void toJSON(Object obj, JSON.Output output) { } @Override - public Object fromJSON(Map map) { + public Object fromJSON(Map map) { System.err.println("fromJSON() = " + map); String userId = (String)map.get("userId"); return new UserInfo(userId); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapDisconnectTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapDisconnectTest.java index 3d2b20d5ce..b207872ead 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapDisconnectTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapDisconnectTest.java @@ -42,7 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OortStringMapDisconnectTest extends OortTest { +public class OortStringMapDisconnectTest extends AbstractOortTest { private final Logger logger = LoggerFactory.getLogger(getClass()); private final List setis = new ArrayList<>(); private final List> oortStringMaps = new ArrayList<>(); @@ -72,13 +72,13 @@ public void dispose() throws Exception { @ParameterizedTest @MethodSource("transports") - public void testMassiveDisconnect(String serverTransport) throws Exception { + public void testMassiveDisconnect(Transport transport) throws Exception { int nodes = 4; int usersPerNode = 500; int totalUsers = nodes * usersPerNode; // One event in a node is replicated to other "nodes" nodes. int totalEvents = nodes * totalUsers; - prepareNodes(serverTransport, nodes); + prepareNodes(transport, nodes); // Register a service so that when a user logs in, // it is recorded in the users OortStringMap. @@ -159,7 +159,7 @@ public void onRemoved(OortObject.Info> info, OortM } } - private void prepareNodes(String serverTransport, int nodes) throws Exception { + private void prepareNodes(Transport transport, int nodes) throws Exception { int edges = nodes * (nodes - 1); // Create the Oorts. CountDownLatch joinLatch = new CountDownLatch(edges); @@ -172,7 +172,7 @@ public void cometJoined(Event event) { Map options = new HashMap<>(); options.put("ws.maxMessageSize", String.valueOf(1024 * 1024)); for (int i = 0; i < nodes; i++) { - Server server = startServer(serverTransport, 0, options); + Server server = startServer(transport, 0, options); Oort oort = startOort(server); oort.addCometListener(joinListener); } diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapTest.java index a8687f40ec..f119bb0e32 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/OortStringMapTest.java @@ -36,8 +36,8 @@ public class OortStringMapTest extends AbstractOortObjectTest { @ParameterizedTest @MethodSource("transports") - public void testEntryPut(String serverTransport) throws Exception { - prepare(serverTransport); + public void testEntryPut(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -82,8 +82,8 @@ public void onPut(OortObject.Info> info, OortMap.E @ParameterizedTest @MethodSource("transports") - public void testEntryRemoved(String serverTransport) throws Exception { - prepare(serverTransport); + public void testEntryRemoved(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -126,8 +126,8 @@ public void onRemoved(OortObject.Info> info, OortM @ParameterizedTest @MethodSource("transports") - public void testDeltaListener(String serverTransport) throws Exception { - prepare(serverTransport); + public void testDeltaListener(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -199,8 +199,8 @@ public void onRemoved(OortObject.Info> info, OortM @ParameterizedTest @MethodSource("transports") - public void testGetFind(String serverTransport) throws Exception { - prepare(serverTransport); + public void testGetFind(Transport transport) throws Exception { + prepare(transport); String name = "test"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -250,8 +250,8 @@ public void onPut(OortObject.Info> info, OortMap.E @ParameterizedTest @MethodSource("transports") - public void testConcurrent(String serverTransport) throws Exception { - prepare(serverTransport); + public void testConcurrent(Transport transport) throws Exception { + prepare(transport); String name = "concurrent"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -303,8 +303,8 @@ public void onPut(OortObject.Info> info, OortMap.E @ParameterizedTest @MethodSource("transports") - public void testEntryBeforeMap(String serverTransport) throws Exception { - prepare(serverTransport); + public void testEntryBeforeMap(Transport transport) throws Exception { + prepare(transport); String name = "entry_before_map"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -370,8 +370,8 @@ public void onPut(OortObject.Info> info, OortMap.E @ParameterizedTest @MethodSource("transports") - public void testLostEntry(String serverTransport) throws Exception { - prepare(serverTransport); + public void testLostEntry(Transport transport) throws Exception { + prepare(transport); String name = "lost_entry"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -440,10 +440,10 @@ public void onRemoved(OortObject.Info> info, OortM @ParameterizedTest @MethodSource("transports") - public void testNodeSyncWithLargeMap(String serverTransport) throws Exception { + public void testNodeSyncWithLargeMap(Transport transport) throws Exception { Map options = new HashMap<>(); options.put("ws.maxMessageSize", String.valueOf(64 * 1024 * 1024)); - prepare(serverTransport, options); + prepare(transport, options); String name = "large_sync"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); @@ -509,13 +509,13 @@ public void onUpdated(OortObject.Info> oldInfo, Oo @ParameterizedTest @MethodSource("transports") - public void testNodeHalfDisconnectedWillReconnect(String serverTransport) throws Exception { + public void testNodeHalfDisconnectedWillReconnect(Transport transport) throws Exception { long timeout = 5000; long maxInterval = 3000; Map options = new HashMap<>(); options.put("timeout", String.valueOf(timeout)); options.put("maxInterval", String.valueOf(maxInterval)); - prepare(serverTransport, options); + prepare(transport, options); String name = "half_disconnection"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); OortStringMap oortMap1 = new OortStringMap<>(oort1, name, factory); @@ -573,13 +573,13 @@ public void onUpdated(OortObject.Info> oldInfo, Oo @ParameterizedTest @MethodSource("transports") - public void testNodeHalfDisconnectedWillResync(String serverTransport) throws Exception { + public void testNodeHalfDisconnectedWillResync(Transport transport) throws Exception { long timeout = 5000; long maxInterval = 3000; Map options = new HashMap<>(); options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - prepare(serverTransport, options); + prepare(transport, options); String name = "half_disconnection_resync"; OortObject.Factory> factory = OortObjectFactories.forConcurrentMap(); String key2B = "key2B"; diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiStartupTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiStartupTest.java index 6b34483b9c..be764a2693 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiStartupTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiStartupTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class SetiStartupTest extends OortTest { +public class SetiStartupTest extends AbstractOortTest { private final List setis = new ArrayList<>(); @AfterEach @@ -44,7 +44,7 @@ public void dispose() throws Exception { @ParameterizedTest @MethodSource("transports") - public void testSetiStartup(String serverTransport) throws Exception { + public void testSetiStartup(Transport transport) throws Exception { int nodes = 4; int edges = nodes * (nodes - 1); CountDownLatch joinLatch = new CountDownLatch(edges); @@ -57,7 +57,7 @@ public void cometJoined(Event event) { Map options = new HashMap<>(); options.put("ws.maxMessageSize", String.valueOf(1024 * 1024)); for (int i = 0; i < nodes; i++) { - Oort oort = startOort(startServer(serverTransport, 0, options)); + Oort oort = startOort(startServer(transport, 0, options)); oort.addCometListener(joinListener); } Oort oort1 = oorts.get(0); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiTest.java index 169d1d0e47..e36e6bb3cb 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/java/org/cometd/oort/SetiTest.java @@ -28,8 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.config.Configurator; import org.cometd.bayeux.Channel; import org.cometd.bayeux.Message; import org.cometd.bayeux.client.ClientSessionChannel; @@ -37,11 +35,11 @@ import org.cometd.bayeux.server.LocalSession; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; -import org.cometd.bayeux.server.ServerTransport; import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.client.transport.ClientTransport; import org.cometd.client.transport.TransportListener; +import org.cometd.oort.jakarta.OortConfigServlet; import org.cometd.server.AbstractServerTransport; import org.cometd.server.AbstractService; import org.cometd.server.BayeuxServerImpl; @@ -54,7 +52,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -public class SetiTest extends OortTest { +public class SetiTest extends AbstractOortTest { private final List setis = new ArrayList<>(); protected Seti startSeti(Oort oort) throws Exception { @@ -77,10 +75,10 @@ protected void stopSeti(Seti seti) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testAssociateAndSendMessage(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testAssociateAndSendMessage(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -139,10 +137,10 @@ public void testAssociateAndSendMessage(String serverTransport) throws Exception @ParameterizedTest @MethodSource("transports") - public void testAssociateWithAllChannelsSubscription(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testAssociateWithAllChannelsSubscription(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -212,10 +210,10 @@ public void testAssociateWithAllChannelsSubscription(String serverTransport) thr @ParameterizedTest @MethodSource("transports") - public void testDisassociate(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testDisassociate(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -275,10 +273,10 @@ public void testDisassociate(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testAutomaticDisassociation(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testAutomaticDisassociation(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -337,7 +335,7 @@ protected void processConnect(Message.Mutable connect) { // Wait for the server to expire client2 and for Seti to disassociate it CountDownLatch removedLatch = new CountDownLatch(1); oort2.getBayeuxServer().getSession(session2.get()).addListener((ServerSession.RemovedListener)(s, m, t) -> removedLatch.countDown()); - long maxTimeout = ((ServerTransport)oort2.getBayeuxServer().getTransport("websocket")).getMaxInterval(); + long maxTimeout = oort2.getBayeuxServer().getTransport("websocket").getMaxInterval(); Assertions.assertTrue(removedLatch.await(maxTimeout + 5000, TimeUnit.MILLISECONDS)); Assertions.assertTrue(absenceLatch.await(5, TimeUnit.SECONDS)); @@ -347,12 +345,12 @@ protected void processConnect(Message.Mutable connect) { @ParameterizedTest @MethodSource("transports") - public void testAssociationWithMultipleSessions(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testAssociationWithMultipleSessions(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); - Server server3 = startServer(serverTransport, 0); + Server server3 = startServer(transport, 0); Oort oort3 = startOort(server3); CountDownLatch latch = new CountDownLatch(6); @@ -488,10 +486,10 @@ public void testAssociationWithMultipleSessions(String serverTransport) throws E @ParameterizedTest @MethodSource("transports") - public void testIsPresent(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testIsPresent(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -560,8 +558,8 @@ public void presenceRemoved(Event event) { @ParameterizedTest @MethodSource("transports") - public void testIsPresentWhenNodeJoins(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testIsPresentWhenNodeJoins(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); Seti seti1 = startSeti(oort1); new SetiService(seti1); @@ -579,7 +577,7 @@ public void testIsPresentWhenNodeJoins(String serverTransport) throws Exception // Now user1 is associated on node1, start node2 - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -611,10 +609,10 @@ public void presenceRemoved(Event event) { @ParameterizedTest @MethodSource("transports") - public void testPresenceFiresEventLocally(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testPresenceFiresEventLocally(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -704,10 +702,10 @@ public void presenceRemoved(Event event) { @ParameterizedTest @MethodSource("transports") - public void testStopRemovesAssociationsAndPresences(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testStopRemovesAssociationsAndPresences(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -773,10 +771,10 @@ public void testStopRemovesAssociationsAndPresences(String serverTransport) thro @ParameterizedTest @MethodSource("transports") - public void testNetworkDisconnectAndReconnect(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testNetworkDisconnectAndReconnect(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -875,10 +873,10 @@ public void testNetworkDisconnectAndReconnect(String serverTransport) throws Exc @ParameterizedTest @MethodSource("transports") - public void testMultipleServerCrashes(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testMultipleServerCrashes(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch oortLatch = new CountDownLatch(1); @@ -936,7 +934,7 @@ public void testMultipleServerCrashes(String serverTransport) throws Exception { Assertions.assertTrue(loginLatch2.await(5, TimeUnit.SECONDS)); // Bring node1 back online - server1 = startServer(serverTransport, port1); + server1 = startServer(transport, port1); oort1 = startOort(server1); oortLatch = new CountDownLatch(1); oort2.addCometListener(new CometJoinedListener(oortLatch)); @@ -977,7 +975,7 @@ public void testMultipleServerCrashes(String serverTransport) throws Exception { Assertions.assertTrue(loginLatch3.await(5, TimeUnit.SECONDS)); // Bring node2 back online - server2 = startServer(serverTransport, port2); + server2 = startServer(transport, port2); oort2 = startOort(server2); oortLatch = new CountDownLatch(1); oort1.addCometListener(new CometJoinedListener(oortLatch)); @@ -1000,20 +998,20 @@ public void testMultipleServerCrashes(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testMessageToObservedChannelIsForwarded(String serverTransport) throws Exception { - testForwardBehaviour(serverTransport, true); + public void testMessageToObservedChannelIsForwarded(Transport transport) throws Exception { + testForwardBehaviour(transport, true); } @ParameterizedTest @MethodSource("transports") - public void testMessageToNonObservedChannelIsNotForwarded(String serverTransport) throws Exception { - testForwardBehaviour(serverTransport, false); + public void testMessageToNonObservedChannelIsNotForwarded(Transport transport) throws Exception { + testForwardBehaviour(transport, false); } - private void testForwardBehaviour(String serverTransport, boolean forward) throws Exception { - Server server1 = startServer(serverTransport, 0); + private void testForwardBehaviour(Transport transport, boolean forward) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -1101,10 +1099,10 @@ public void process(ServerSession session, ServerMessage message) { @ParameterizedTest @MethodSource("transports") - public void testConcurrent(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testConcurrent(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0); + Server server2 = startServer(transport, 0); Oort oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(1); @@ -1176,8 +1174,8 @@ public void testConcurrent(String serverTransport) throws Exception { @ParameterizedTest @MethodSource("transports") - public void testDisassociationRemovesListeners(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testDisassociationRemovesListeners(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); Seti seti1 = startSeti(oort1); @@ -1195,8 +1193,8 @@ public void testDisassociationRemovesListeners(String serverTransport) throws Ex @ParameterizedTest @MethodSource("transports") - public void testDisassociateAllSessions(String serverTransport) throws Exception { - Server server1 = startServer(serverTransport, 0); + public void testDisassociateAllSessions(Transport transport) throws Exception { + Server server1 = startServer(transport, 0); Oort oort1 = startOort(server1); Seti seti1 = startSeti(oort1); @@ -1246,390 +1244,378 @@ public void presenceRemoved(Event event) { @ParameterizedTest @MethodSource("transports") - public void testShortHalfNetworkDisconnectionBetweenNodes(String serverTransport) throws Exception { - String loggerName = "org.cometd"; - Configurator.setLevel(loggerName, Level.DEBUG); - try { - Map options = new HashMap<>(); - long timeout = 2000; - options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); - Server server1 = startServer(serverTransport, 0, options); - BayeuxServerImpl bayeuxServer1 = (BayeuxServerImpl)server1.getAttribute(BayeuxServer.ATTRIBUTE); - bayeuxServer1.setDetailedDump(true); - Oort oort1 = startOort(server1); - Server server2 = startServer(serverTransport, 0, options); - String url2 = (String)server2.getAttribute(OortConfigServlet.OORT_URL_PARAM); - BayeuxServerImpl bayeuxServer2 = (BayeuxServerImpl)server2.getAttribute(BayeuxServer.ATTRIBUTE); - bayeuxServer2.setDetailedDump(true); - bayeuxServer2.setOption(Server.class.getName(), server2); - AtomicBoolean halfNetworkDown = new AtomicBoolean(); - Oort oort2 = new Oort(bayeuxServer2, url2) { - @Override - protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { - return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { - { - addTransportListener(new TransportListener() { - @Override - public void onMessages(List messages) { - if (halfNetworkDown.get()) { - logger.info("Network down for client receive {}", messages); - messagesFailure(new Exception(), messages); - messages.clear(); - } + public void testShortHalfNetworkDisconnectionBetweenNodes(Transport transport) throws Exception { + Map options = new HashMap<>(); + long timeout = 2000; + options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); + Server server1 = startServer(transport, 0, options); + BayeuxServerImpl bayeuxServer1 = (BayeuxServerImpl)server1.getAttribute(BayeuxServer.ATTRIBUTE); + bayeuxServer1.setDetailedDump(true); + Oort oort1 = startOort(server1); + Server server2 = startServer(transport, 0, options); + String url2 = (String)server2.getAttribute(OortConfigServlet.OORT_URL_PARAM); + BayeuxServerImpl bayeuxServer2 = (BayeuxServerImpl)server2.getAttribute(BayeuxServer.ATTRIBUTE); + bayeuxServer2.setDetailedDump(true); + bayeuxServer2.setOption(Server.class.getName(), server2); + AtomicBoolean halfNetworkDown = new AtomicBoolean(); + Oort oort2 = new Oort(bayeuxServer2, url2) { + @Override + protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { + return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { + { + addTransportListener(new TransportListener() { + @Override + public void onMessages(List messages) { + if (halfNetworkDown.get()) { + logger.info("Network down for client receive {}", messages); + messagesFailure(new Exception(), messages); + messages.clear(); } - }); - } - }; - } - }; - bayeuxServer2.addExtension(new HalfNetworkDownExtension(oort2, halfNetworkDown)); - oort2.start(); - oorts.add(oort2); - - CountDownLatch latch = new CountDownLatch(1); - oort2.addCometListener(new CometJoinedListener(latch)); - OortComet oortComet12 = oort1.observeComet(oort2.getURL()); - Assertions.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.CONNECTED)); - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - OortComet oortComet21 = oort2.findComet(oort1.getURL()); - Assertions.assertTrue(oortComet21.waitFor(5000, BayeuxClient.State.CONNECTED)); + } + }); + } + }; + } + }; + bayeuxServer2.addExtension(new HalfNetworkDownExtension(oort2, halfNetworkDown)); + oort2.start(); + oorts.add(oort2); - Seti seti1 = startSeti(oort1); - Seti seti2 = startSeti(oort2); + CountDownLatch latch = new CountDownLatch(1); + oort2.addCometListener(new CometJoinedListener(latch)); + OortComet oortComet12 = oort1.observeComet(oort2.getURL()); + Assertions.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.CONNECTED)); + Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); + OortComet oortComet21 = oort2.findComet(oort1.getURL()); + Assertions.assertTrue(oortComet21.waitFor(5000, BayeuxClient.State.CONNECTED)); - new SetiService(seti1); - new SetiService(seti2); + Seti seti1 = startSeti(oort1); + Seti seti2 = startSeti(oort2); - BayeuxClient client1 = startClient(oort1, null); - Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); - BayeuxClient client2 = startClient(oort2, null); - Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); + new SetiService(seti1); + new SetiService(seti2); - // Wait for the /meta/connects to be held. - Thread.sleep(1000); + BayeuxClient client1 = startClient(oort1, null); + Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); + BayeuxClient client2 = startClient(oort2, null); + Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); - CountDownLatch presenceAddedLatch = new CountDownLatch(4); - seti1.addPresenceListener(new UserPresentListener(presenceAddedLatch)); - seti2.addPresenceListener(new UserPresentListener(presenceAddedLatch)); + // Wait for the /meta/connects to be held. + Thread.sleep(1000); - // Login user1 - CountDownLatch loginLatch1 = new CountDownLatch(1); - Map login1 = new HashMap<>(); - String userId1 = "user1"; - login1.put("user", userId1); - ClientSessionChannel loginChannel1 = client1.getChannel("/service/login"); - loginChannel1.publish(login1, message -> loginLatch1.countDown()); - Assertions.assertTrue(loginLatch1.await(5, TimeUnit.SECONDS)); + CountDownLatch presenceAddedLatch = new CountDownLatch(4); + seti1.addPresenceListener(new UserPresentListener(presenceAddedLatch)); + seti2.addPresenceListener(new UserPresentListener(presenceAddedLatch)); - // Login user2 - CountDownLatch loginLatch2 = new CountDownLatch(1); - Map login2 = new HashMap<>(); - String userId2 = "user2"; - login2.put("user", userId2); - ClientSessionChannel loginChannel2 = client2.getChannel("/service/login"); - loginChannel2.publish(login2, message -> loginLatch2.countDown()); - Assertions.assertTrue(loginLatch2.await(5, TimeUnit.SECONDS)); + // Login user1 + CountDownLatch loginLatch1 = new CountDownLatch(1); + Map login1 = new HashMap<>(); + String userId1 = "user1"; + login1.put("user", userId1); + ClientSessionChannel loginChannel1 = client1.getChannel("/service/login"); + loginChannel1.publish(login1, message -> loginLatch1.countDown()); + Assertions.assertTrue(loginLatch1.await(5, TimeUnit.SECONDS)); - // Make sure all Setis see all users. - Assertions.assertTrue(presenceAddedLatch.await(5, TimeUnit.SECONDS)); + // Login user2 + CountDownLatch loginLatch2 = new CountDownLatch(1); + Map login2 = new HashMap<>(); + String userId2 = "user2"; + login2.put("user", userId2); + ClientSessionChannel loginChannel2 = client2.getChannel("/service/login"); + loginChannel2.publish(login2, message -> loginLatch2.countDown()); + Assertions.assertTrue(loginLatch2.await(5, TimeUnit.SECONDS)); - // Wait for the /meta/connects to be held after logins. - Thread.sleep(1000); + // Make sure all Setis see all users. + Assertions.assertTrue(presenceAddedLatch.await(5, TimeUnit.SECONDS)); - // Disconnect network between the nodes temporarily. - halfNetworkDown.set(true); + // Wait for the /meta/connects to be held after logins. + Thread.sleep(1000); - // Logout user1 and login user3, node2 won't see these changes. - CountDownLatch logoutLatch1 = new CountDownLatch(1); - Map logout1 = new HashMap<>(); - logout1.put("user", userId1); - ClientSessionChannel logoutChannel1 = client1.getChannel("/service/logout"); - logoutChannel1.publish(logout1, message -> logoutLatch1.countDown()); - Assertions.assertTrue(logoutLatch1.await(5, TimeUnit.SECONDS)); - CountDownLatch loginLatch3 = new CountDownLatch(1); - Map login3 = new HashMap<>(); - String userId3 = "user3"; - login3.put("user", userId3); - loginChannel1.publish(login3, message -> loginLatch3.countDown()); - Assertions.assertTrue(loginLatch3.await(5, TimeUnit.SECONDS)); + // Disconnect network between the nodes temporarily. + halfNetworkDown.set(true); - // Network is down, so nodes are out of sync. - Set userIds1 = seti1.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); - Set userIds2 = seti2.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user1", "user2")), userIds2, seti2.dump()); - - CountDownLatch presenceLatch2 = new CountDownLatch(2); - seti2.addPresenceListener(new Seti.PresenceListener() { - @Override - public void presenceAdded(Event event) { - if (!event.isLocal() && "user3".equals(event.getUserId())) { - presenceLatch2.countDown(); - } + // Logout user1 and login user3, node2 won't see these changes. + CountDownLatch logoutLatch1 = new CountDownLatch(1); + Map logout1 = new HashMap<>(); + logout1.put("user", userId1); + ClientSessionChannel logoutChannel1 = client1.getChannel("/service/logout"); + logoutChannel1.publish(logout1, message -> logoutLatch1.countDown()); + Assertions.assertTrue(logoutLatch1.await(5, TimeUnit.SECONDS)); + CountDownLatch loginLatch3 = new CountDownLatch(1); + Map login3 = new HashMap<>(); + String userId3 = "user3"; + login3.put("user", userId3); + loginChannel1.publish(login3, message -> loginLatch3.countDown()); + Assertions.assertTrue(loginLatch3.await(5, TimeUnit.SECONDS)); + + // Network is down, so nodes are out of sync. + Set userIds1 = seti1.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); + Set userIds2 = seti2.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user1", "user2")), userIds2, seti2.dump()); + + CountDownLatch presenceLatch2 = new CountDownLatch(2); + seti2.addPresenceListener(new Seti.PresenceListener() { + @Override + public void presenceAdded(Event event) { + if (!event.isLocal() && "user3".equals(event.getUserId())) { + presenceLatch2.countDown(); } + } - @Override - public void presenceRemoved(Event event) { - if (!event.isLocal() && "user1".equals(event.getUserId())) { - presenceLatch2.countDown(); - } + @Override + public void presenceRemoved(Event event) { + if (!event.isLocal() && "user1".equals(event.getUserId())) { + presenceLatch2.countDown(); } - }); + } + }); - // Reconnect network. - halfNetworkDown.set(false); + // Reconnect network. + halfNetworkDown.set(false); - // Wait until the nodes sync again. - Assertions.assertTrue(presenceLatch2.await(3 * timeout, TimeUnit.MILLISECONDS)); + // Wait until the nodes sync again. + Assertions.assertTrue(presenceLatch2.await(3 * timeout, TimeUnit.MILLISECONDS)); - userIds1 = seti1.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); - userIds2 = seti2.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds2, seti2.dump()); - } finally { - Configurator.setLevel(loggerName, Level.INFO); - } + userIds1 = seti1.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); + userIds2 = seti2.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds2, seti2.dump()); } @ParameterizedTest @MethodSource("transports") - public void testLongHalfNetworkDisconnectionBetweenNodes(String serverTransport) throws Exception { - String loggerName = "org.cometd"; - Configurator.setLevel(loggerName, Level.DEBUG); - try { - Map options = new HashMap<>(); - long maxNetworkDelay = 1000; - options.put(ClientTransport.MAX_NETWORK_DELAY_OPTION, String.valueOf(maxNetworkDelay)); - long timeout = 2000; - options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); - long maxInterval = timeout + maxNetworkDelay + 1000; - options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); - Server server1 = startServer(serverTransport, 0, options); - String url1 = (String)server1.getAttribute(OortConfigServlet.OORT_URL_PARAM); - BayeuxServerImpl bayeuxServer1 = (BayeuxServerImpl)server1.getAttribute(BayeuxServer.ATTRIBUTE); - bayeuxServer1.setOption(Server.class.getName(), server1); - bayeuxServer1.setDetailedDump(true); - AtomicBoolean networkDown21 = new AtomicBoolean(); - Oort oort1 = new Oort(bayeuxServer1, url1) { - @Override - protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { - return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { - { - addTransportListener(new TransportListener() { - @Override - public void onMessages(List messages) { - if (networkDown21.get()) { - logger.info("Network down for client receive {}", messages); - messagesFailure(new Exception(), messages); - messages.clear(); - } + public void testLongHalfNetworkDisconnectionBetweenNodes(Transport transport) throws Exception { + Map options = new HashMap<>(); + long maxNetworkDelay = 1000; + options.put(ClientTransport.MAX_NETWORK_DELAY_OPTION, String.valueOf(maxNetworkDelay)); + long timeout = 2000; + options.put(AbstractServerTransport.TIMEOUT_OPTION, String.valueOf(timeout)); + long maxInterval = timeout + maxNetworkDelay + 1000; + options.put(AbstractServerTransport.MAX_INTERVAL_OPTION, String.valueOf(maxInterval)); + Server server1 = startServer(transport, 0, options); + String url1 = (String)server1.getAttribute(OortConfigServlet.OORT_URL_PARAM); + BayeuxServerImpl bayeuxServer1 = (BayeuxServerImpl)server1.getAttribute(BayeuxServer.ATTRIBUTE); + bayeuxServer1.setOption(Server.class.getName(), server1); + bayeuxServer1.setDetailedDump(true); + AtomicBoolean networkDown21 = new AtomicBoolean(); + Oort oort1 = new Oort(bayeuxServer1, url1) { + @Override + protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { + return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { + { + addTransportListener(new TransportListener() { + @Override + public void onMessages(List messages) { + if (networkDown21.get()) { + logger.info("Network down for client receive {}", messages); + messagesFailure(new Exception(), messages); + messages.clear(); } - }); - } - }; - } + } + }); + } + }; + } - @Override - protected void configureOortComet(OortComet oortComet) { - super.configureOortComet(oortComet); - oortComet.setOption(BayeuxClient.BACKOFF_INCREMENT_OPTION, 250L); - } - }; - bayeuxServer1.addExtension(new HalfNetworkDownExtension(oort1, networkDown21)); - oort1.start(); - oorts.add(oort1); - Server server2 = startServer(serverTransport, 0, options); - String url2 = (String)server2.getAttribute(OortConfigServlet.OORT_URL_PARAM); - BayeuxServerImpl bayeuxServer2 = (BayeuxServerImpl)server2.getAttribute(BayeuxServer.ATTRIBUTE); - bayeuxServer2.setOption(Server.class.getName(), server2); - bayeuxServer2.setDetailedDump(true); - AtomicBoolean networkDown12 = new AtomicBoolean(); - Oort oort2 = new Oort(bayeuxServer2, url2) { - @Override - protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { - return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { - { - addTransportListener(new TransportListener() { - @Override - public void onMessages(List messages) { - if (networkDown12.get()) { - logger.info("Network down for client receive {}", messages); - messagesFailure(new Exception(), messages); - messages.clear(); - } + @Override + protected void configureOortComet(OortComet oortComet) { + super.configureOortComet(oortComet); + oortComet.setOption(BayeuxClient.BACKOFF_INCREMENT_OPTION, 250L); + } + }; + bayeuxServer1.addExtension(new HalfNetworkDownExtension(oort1, networkDown21)); + oort1.start(); + oorts.add(oort1); + Server server2 = startServer(transport, 0, options); + String url2 = (String)server2.getAttribute(OortConfigServlet.OORT_URL_PARAM); + BayeuxServerImpl bayeuxServer2 = (BayeuxServerImpl)server2.getAttribute(BayeuxServer.ATTRIBUTE); + bayeuxServer2.setOption(Server.class.getName(), server2); + bayeuxServer2.setDetailedDump(true); + AtomicBoolean networkDown12 = new AtomicBoolean(); + Oort oort2 = new Oort(bayeuxServer2, url2) { + @Override + protected OortComet newOortComet(String cometURL, ClientTransport transport, ClientTransport[] otherTransports) { + return new OortComet(this, cometURL, getScheduler(), transport, otherTransports) { + { + addTransportListener(new TransportListener() { + @Override + public void onMessages(List messages) { + if (networkDown12.get()) { + logger.info("Network down for client receive {}", messages); + messagesFailure(new Exception(), messages); + messages.clear(); } - }); - } - }; - } + } + }); + } + }; + } - @Override - protected void configureOortComet(OortComet oortComet) { - super.configureOortComet(oortComet); - oortComet.setOption(BayeuxClient.BACKOFF_INCREMENT_OPTION, 250L); - } - }; - bayeuxServer2.addExtension(new HalfNetworkDownExtension(oort2, networkDown12)); - oort2.start(); - oorts.add(oort2); - - CountDownLatch latch = new CountDownLatch(1); - oort2.addCometListener(new CometJoinedListener(latch)); - OortComet oortComet12 = oort1.observeComet(oort2.getURL()); - Assertions.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.CONNECTED)); - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - OortComet oortComet21 = oort2.findComet(oort1.getURL()); - Assertions.assertTrue(oortComet21.waitFor(5000, BayeuxClient.State.CONNECTED)); + @Override + protected void configureOortComet(OortComet oortComet) { + super.configureOortComet(oortComet); + oortComet.setOption(BayeuxClient.BACKOFF_INCREMENT_OPTION, 250L); + } + }; + bayeuxServer2.addExtension(new HalfNetworkDownExtension(oort2, networkDown12)); + oort2.start(); + oorts.add(oort2); - Seti seti1 = startSeti(oort1); - Seti seti2 = startSeti(oort2); + CountDownLatch latch = new CountDownLatch(1); + oort2.addCometListener(new CometJoinedListener(latch)); + OortComet oortComet12 = oort1.observeComet(oort2.getURL()); + Assertions.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.CONNECTED)); + Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); + OortComet oortComet21 = oort2.findComet(oort1.getURL()); + Assertions.assertTrue(oortComet21.waitFor(5000, BayeuxClient.State.CONNECTED)); - new SetiService(seti1); - new SetiService(seti2); + Seti seti1 = startSeti(oort1); + Seti seti2 = startSeti(oort2); - BayeuxClient client1 = startClient(oort1, null); - Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); - BayeuxClient client2 = startClient(oort2, null); - Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); + new SetiService(seti1); + new SetiService(seti2); - // Wait for the /meta/connects to be held. - Thread.sleep(1000); + BayeuxClient client1 = startClient(oort1, null); + Assertions.assertTrue(client1.waitFor(5000, BayeuxClient.State.CONNECTED)); + BayeuxClient client2 = startClient(oort2, null); + Assertions.assertTrue(client2.waitFor(5000, BayeuxClient.State.CONNECTED)); - CountDownLatch presenceAddedLatch = new CountDownLatch(4); - seti1.addPresenceListener(new UserPresentListener(presenceAddedLatch)); - seti2.addPresenceListener(new UserPresentListener(presenceAddedLatch)); + // Wait for the /meta/connects to be held. + Thread.sleep(1000); - // Login user1 - CountDownLatch loginLatch1 = new CountDownLatch(1); - Map login1 = new HashMap<>(); - String userId1 = "user1"; - login1.put("user", userId1); - ClientSessionChannel loginChannel1 = client1.getChannel("/service/login"); - loginChannel1.publish(login1, message -> loginLatch1.countDown()); - Assertions.assertTrue(loginLatch1.await(5, TimeUnit.SECONDS)); + CountDownLatch presenceAddedLatch = new CountDownLatch(4); + seti1.addPresenceListener(new UserPresentListener(presenceAddedLatch)); + seti2.addPresenceListener(new UserPresentListener(presenceAddedLatch)); - // Login user2 - CountDownLatch loginLatch2 = new CountDownLatch(1); - Map login2 = new HashMap<>(); - String userId2 = "user2"; - login2.put("user", userId2); - ClientSessionChannel loginChannel2 = client2.getChannel("/service/login"); - loginChannel2.publish(login2, message -> loginLatch2.countDown()); - Assertions.assertTrue(loginLatch2.await(5, TimeUnit.SECONDS)); + // Login user1 + CountDownLatch loginLatch1 = new CountDownLatch(1); + Map login1 = new HashMap<>(); + String userId1 = "user1"; + login1.put("user", userId1); + ClientSessionChannel loginChannel1 = client1.getChannel("/service/login"); + loginChannel1.publish(login1, message -> loginLatch1.countDown()); + Assertions.assertTrue(loginLatch1.await(5, TimeUnit.SECONDS)); - // Make sure all Setis see all users. - Assertions.assertTrue(presenceAddedLatch.await(5, TimeUnit.SECONDS)); + // Login user2 + CountDownLatch loginLatch2 = new CountDownLatch(1); + Map login2 = new HashMap<>(); + String userId2 = "user2"; + login2.put("user", userId2); + ClientSessionChannel loginChannel2 = client2.getChannel("/service/login"); + loginChannel2.publish(login2, message -> loginLatch2.countDown()); + Assertions.assertTrue(loginLatch2.await(5, TimeUnit.SECONDS)); - // Wait for the /meta/connects to be held after logins. - Thread.sleep(1000); + // Make sure all Setis see all users. + Assertions.assertTrue(presenceAddedLatch.await(5, TimeUnit.SECONDS)); - CountDownLatch leftLatch1 = new CountDownLatch(1); - oort1.addCometListener(new CometLeftListener(leftLatch1)); + // Wait for the /meta/connects to be held after logins. + Thread.sleep(1000); - // Disconnect network between the nodes temporarily. - networkDown12.set(true); - networkDown21.set(true); + CountDownLatch leftLatch1 = new CountDownLatch(1); + oort1.addCometListener(new CometLeftListener(leftLatch1)); - // Logout user1 and login user3, node2 won't see this change. - CountDownLatch logoutLatch1 = new CountDownLatch(1); - Map logout1 = new HashMap<>(); - logout1.put("user", userId1); - ClientSessionChannel logoutChannel1 = client1.getChannel("/service/logout"); - logoutChannel1.publish(logout1, message -> logoutLatch1.countDown()); - Assertions.assertTrue(logoutLatch1.await(5, TimeUnit.SECONDS)); - CountDownLatch loginLatch3 = new CountDownLatch(1); - Map login3 = new HashMap<>(); - String userId3 = "user3"; - login3.put("user", userId3); - loginChannel1.publish(login3, message -> loginLatch3.countDown()); - Assertions.assertTrue(loginLatch3.await(5, TimeUnit.SECONDS)); + // Disconnect network between the nodes temporarily. + networkDown12.set(true); + networkDown21.set(true); - // Network is down, so nodes are out of sync. - Set userIds1 = seti1.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); - Set userIds2 = seti2.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user1", "user2")), userIds2, seti2.dump()); - - // Restore half network. - networkDown12.set(false); - logger.info("NETWORK12 UP"); - - // Wait for node2 left event on node1. - // We need to explicitly remove the session, simulating that node1 does - // not receive messages from node2 and therefore times out the session. - bayeuxServer1.removeServerSession(bayeuxServer1.getSession(oortComet21.getId()), true); - Assertions.assertTrue(leftLatch1.await(timeout + 2 * maxInterval, TimeUnit.MILLISECONDS)); - - AtomicInteger presenceAddedCount1 = new AtomicInteger(); - AtomicInteger presenceRemovedCount1 = new AtomicInteger(); - CountDownLatch presenceLatch1 = new CountDownLatch(1); - seti1.addPresenceListener(new Seti.PresenceListener() { - @Override - public void presenceAdded(Event event) { - logger.info("presence added on node1 {}", event); - presenceAddedCount1.incrementAndGet(); - if (!event.isLocal() && "user2".equals(event.getUserId())) { - presenceLatch1.countDown(); - } + // Logout user1 and login user3, node2 won't see this change. + CountDownLatch logoutLatch1 = new CountDownLatch(1); + Map logout1 = new HashMap<>(); + logout1.put("user", userId1); + ClientSessionChannel logoutChannel1 = client1.getChannel("/service/logout"); + logoutChannel1.publish(logout1, message -> logoutLatch1.countDown()); + Assertions.assertTrue(logoutLatch1.await(5, TimeUnit.SECONDS)); + CountDownLatch loginLatch3 = new CountDownLatch(1); + Map login3 = new HashMap<>(); + String userId3 = "user3"; + login3.put("user", userId3); + loginChannel1.publish(login3, message -> loginLatch3.countDown()); + Assertions.assertTrue(loginLatch3.await(5, TimeUnit.SECONDS)); + + // Network is down, so nodes are out of sync. + Set userIds1 = seti1.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); + Set userIds2 = seti2.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user1", "user2")), userIds2, seti2.dump()); + + // Restore half network. + networkDown12.set(false); + logger.info("NETWORK12 UP"); + + // Wait for node2 left event on node1. + // We need to explicitly remove the session, simulating that node1 does + // not receive messages from node2 and therefore times out the session. + bayeuxServer1.removeServerSession(bayeuxServer1.getSession(oortComet21.getId()), true); + Assertions.assertTrue(leftLatch1.await(timeout + 2 * maxInterval, TimeUnit.MILLISECONDS)); + + AtomicInteger presenceAddedCount1 = new AtomicInteger(); + AtomicInteger presenceRemovedCount1 = new AtomicInteger(); + CountDownLatch presenceLatch1 = new CountDownLatch(1); + seti1.addPresenceListener(new Seti.PresenceListener() { + @Override + public void presenceAdded(Event event) { + logger.info("presence added on node1 {}", event); + presenceAddedCount1.incrementAndGet(); + if (!event.isLocal() && "user2".equals(event.getUserId())) { + presenceLatch1.countDown(); } + } - @Override - public void presenceRemoved(Event event) { - presenceRemovedCount1.incrementAndGet(); - } - }); - - AtomicInteger presenceAddedCount2 = new AtomicInteger(); - AtomicInteger presenceRemovedCount2 = new AtomicInteger(); - CountDownLatch presenceLatch2 = new CountDownLatch(2); - seti2.addPresenceListener(new Seti.PresenceListener() { - @Override - public void presenceAdded(Event event) { - logger.info("presence added on node2 {}", event); - presenceAddedCount2.incrementAndGet(); - if (!event.isLocal() && "user3".equals(event.getUserId())) { - presenceLatch2.countDown(); - } + @Override + public void presenceRemoved(Event event) { + presenceRemovedCount1.incrementAndGet(); + } + }); + + AtomicInteger presenceAddedCount2 = new AtomicInteger(); + AtomicInteger presenceRemovedCount2 = new AtomicInteger(); + CountDownLatch presenceLatch2 = new CountDownLatch(2); + seti2.addPresenceListener(new Seti.PresenceListener() { + @Override + public void presenceAdded(Event event) { + logger.info("presence added on node2 {}", event); + presenceAddedCount2.incrementAndGet(); + if (!event.isLocal() && "user3".equals(event.getUserId())) { + presenceLatch2.countDown(); } + } - @Override - public void presenceRemoved(Event event) { - logger.info("presence removed on node2 {}", event); - presenceRemovedCount2.incrementAndGet(); - if (!event.isLocal() && "user1".equals(event.getUserId())) { - presenceLatch2.countDown(); - } + @Override + public void presenceRemoved(Event event) { + logger.info("presence removed on node2 {}", event); + presenceRemovedCount2.incrementAndGet(); + if (!event.isLocal() && "user1".equals(event.getUserId())) { + presenceLatch2.countDown(); } - }); + } + }); - // Restore network. - networkDown21.set(false); - logger.info("NETWORK UP"); + // Restore network. + networkDown21.set(false); + logger.info("NETWORK UP"); - // Wait until the nodes sync again. - Assertions.assertTrue(presenceLatch1.await(15, TimeUnit.SECONDS)); - Assertions.assertTrue(presenceLatch2.await(15, TimeUnit.SECONDS)); + // Wait until the nodes sync again. + Assertions.assertTrue(presenceLatch1.await(15, TimeUnit.SECONDS)); + Assertions.assertTrue(presenceLatch2.await(15, TimeUnit.SECONDS)); - // Wait a bit more to be sure no other presence events are delivered. - Thread.sleep(1000); - Assertions.assertEquals(1, presenceAddedCount1.get()); - Assertions.assertEquals(0, presenceRemovedCount1.get()); - Assertions.assertEquals(1, presenceAddedCount2.get()); - Assertions.assertEquals(1, presenceRemovedCount2.get()); - - userIds1 = seti1.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); - userIds2 = seti2.getUserIds(); - Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds2, seti2.dump()); - } finally { - Configurator.setLevel(loggerName, Level.INFO); - } + // Wait a bit more to be sure no other presence events are delivered. + Thread.sleep(1000); + Assertions.assertEquals(1, presenceAddedCount1.get()); + Assertions.assertEquals(0, presenceRemovedCount1.get()); + Assertions.assertEquals(1, presenceAddedCount2.get()); + Assertions.assertEquals(1, presenceRemovedCount2.get()); + + userIds1 = seti1.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds1, seti1.dump()); + userIds2 = seti2.getUserIds(); + Assertions.assertEquals(new HashSet<>(List.of("user2", "user3")), userIds2, seti2.dump()); } @ParameterizedTest @MethodSource("transports") - public void testProtectedSetiChannels(String serverTransport) throws Exception { - Server server = startServer(serverTransport, 0); + public void testProtectedSetiChannels(Transport transport) throws Exception { + Server server = startServer(transport, 0); Oort oort = startOort(server); Seti seti = startSeti(oort); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/log4j2-test.properties deleted file mode 100644 index 03e25ba9ec..0000000000 --- a/cometd-java/cometd-java-tests/cometd-java-tests-oort/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,19 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info - -#logger.oort.name=org.cometd.oort -#logger.oort.level=debug diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/pom.xml b/cometd-java/cometd-java-tests/cometd-java-tests-spring/pom.xml index 37c8da6ce8..4db708a43b 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/pom.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/pom.xml @@ -13,18 +13,6 @@ CometD :: Java :: Tests :: Spring - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - jakarta.servlet jakarta.servlet-api @@ -55,8 +43,8 @@ test - org.eclipse.jetty.ee10.websocket - jetty-ee10-websocket-jetty-server + org.eclipse.jetty.websocket + jetty-websocket-jetty-server ${jetty-version} test @@ -80,7 +68,7 @@ org.cometd.java - cometd-java-oort + cometd-java-oort-common ${project.version} test diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/SpringFrameworkConfigurationTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/SpringFrameworkConfigurationTest.java index b78782c01d..cf8cfea178 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/SpringFrameworkConfigurationTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/SpringFrameworkConfigurationTest.java @@ -22,7 +22,7 @@ import org.cometd.client.BayeuxClient; import org.cometd.client.http.jetty.JettyHttpClientTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -78,7 +78,7 @@ public void testXMLSpringConfiguration() throws Exception { String url = startServer(context -> { // Add Spring listener context.addEventListener(new ContextLoaderListener()); - context.getInitParams().put(ContextLoader.CONFIG_LOCATION_PARAM, "classpath:/applicationContext-server.xml"); + context.getInitParams().put(ContextLoader.CONFIG_LOCATION_PARAM, "classpath:/applicationContext-http.xml"); }); WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context.getServletContext()); @@ -91,7 +91,7 @@ public void testXMLSpringConfiguration() throws Exception { Assertions.assertTrue(bayeuxServer.isStarted()); Assertions.assertEquals(sweepPeriod, bayeuxServer.getOption("sweepPeriod")); - Assertions.assertSame(bayeuxServer, cometdServlet.getBayeux()); + Assertions.assertSame(bayeuxServer, cometdServlet.getBayeuxServer()); CountDownLatch latch = new CountDownLatch(1); BayeuxClient bayeuxClient = new BayeuxClient(url, new JettyHttpClientTransport(null, httpClient)); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/annotation/Configurator.java b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/annotation/Configurator.java index 023c12e358..350c8728d0 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/annotation/Configurator.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/annotation/Configurator.java @@ -17,10 +17,11 @@ import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; + import org.cometd.annotation.server.ServerAnnotationProcessor; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.http.AsyncJSONTransport; +import org.cometd.server.http.JSONHttpTransport; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; import org.springframework.context.annotation.Bean; @@ -81,7 +82,7 @@ public BayeuxServer bayeuxServer() { BayeuxServerImpl bayeuxServer = new BayeuxServerImpl(); // Don't initialize the WebSocket transports, since for // this test we don't have the required ServletContext. - bayeuxServer.setOption("transports", AsyncJSONTransport.class.getName()); + bayeuxServer.setOption("transports", JSONHttpTransport.class.getName()); return bayeuxServer; } } diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/websocket/SpringFrameworkWebSocketConfigurationTest.java b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/websocket/SpringFrameworkWebSocketConfigurationTest.java index cc33f5c0f4..80a038e511 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/websocket/SpringFrameworkWebSocketConfigurationTest.java +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/java/org/cometd/tests/spring/websocket/SpringFrameworkWebSocketConfigurationTest.java @@ -27,21 +27,21 @@ import org.cometd.client.transport.ClientTransport; import org.cometd.client.websocket.okhttp.OkHttpWebSocketTransport; import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; -import org.cometd.server.http.AsyncJSONTransport; +import org.cometd.server.http.JSONHttpTransport; +import org.cometd.server.http.jakarta.CometDServlet; import org.cometd.server.websocket.jakarta.WebSocketTransport; import org.cometd.server.websocket.jetty.JettyWebSocketTransport; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; -import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.websocket.client.WebSocketClient; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.web.context.ContextLoader; import org.springframework.web.context.ContextLoaderListener; @@ -67,7 +67,8 @@ private String startServer(Class wsTransportClass, String springConfig) throw if (WebSocketTransport.class.equals(wsTransportClass)) { JakartaWebSocketServletContainerInitializer.configure(context, null); } else if (JettyWebSocketTransport.class.equals(wsTransportClass)) { - JettyWebSocketServletContainerInitializer.configure(context, null); + // TODO: +// JettyWebSocketServletContainerInitializer.configure(context, null); } else { throw new IllegalArgumentException(); } @@ -75,12 +76,11 @@ private String startServer(Class wsTransportClass, String springConfig) throw context.addEventListener(new ContextLoaderListener()); context.getInitParams().put(ContextLoader.CONFIG_LOCATION_PARAM, "classpath:" + springConfig); - // CometD servlet String cometdServletPath = "/cometd"; String cometdURLMapping = cometdServletPath + "/*"; ServletHolder cometdServletHolder = new ServletHolder(CometDServlet.class); - String transports = wsTransportClass + "," + AsyncJSONTransport.class.getName(); + String transports = wsTransportClass + "," + JSONHttpTransport.class.getName(); cometdServletHolder.setInitParameter("transports", transports); cometdServletHolder.setInitParameter("timeout", "10000"); cometdServletHolder.setInitParameter("ws.cometdURLMapping", cometdURLMapping); @@ -114,6 +114,7 @@ public void testXMLSpringConfigurationWithOkHttpWebSocket() throws Exception { } @Test + @Disabled("Spring's applicationContext.xml somehow implies Jakarta (can we avoid Jakarta?), and we don't have anymore a Jetty Jakarta WebSocket transport.") public void testXMLSpringConfigurationWithJettyWebSocket() throws Exception { String url = startServer(JettyWebSocketTransport.class, "applicationContext-jetty-websocket.xml"); WebSocketClient wsClient = new WebSocketClient(); diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-server.xml b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-http.xml similarity index 91% rename from cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-server.xml rename to cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-http.xml index 11e38fac3a..ffe6b90968 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-server.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-http.xml @@ -12,7 +12,7 @@ - + diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jakarta-websocket.xml b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jakarta-websocket.xml index 039a06a00a..7fd5ada82e 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jakarta-websocket.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jakarta-websocket.xml @@ -16,10 +16,10 @@ - + - + diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jetty-websocket.xml b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jetty-websocket.xml index 8f5457db67..9b131b5258 100644 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jetty-websocket.xml +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/applicationContext-jetty-websocket.xml @@ -16,10 +16,10 @@ - + - + diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/jetty-logging.properties b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..6a0fcfb868 --- /dev/null +++ b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/log4j2-test.properties b/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/log4j2-test.properties deleted file mode 100644 index a5e1087291..0000000000 --- a/cometd-java/cometd-java-tests/cometd-java-tests-spring/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,19 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.spring.name=org.springframework -logger.spring.level=info - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info diff --git a/cometd-javascript/tests/pom.xml b/cometd-javascript/tests/pom.xml index 41c7f958fc..2d2b4edfd7 100644 --- a/cometd-javascript/tests/pom.xml +++ b/cometd-javascript/tests/pom.xml @@ -71,18 +71,6 @@ slf4j-api - - org.junit.jupiter - junit-jupiter - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j2-impl - org.cometd.javascript cometd-javascript-dojo diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/AbstractCometDTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/AbstractCometDTest.java index 0197865f04..916fc8cd8c 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/AbstractCometDTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/AbstractCometDTest.java @@ -21,8 +21,8 @@ import java.util.Locale; import java.util.Map; -import org.cometd.server.BayeuxServerImpl; -import org.cometd.server.CometDServlet; +import org.cometd.bayeux.server.BayeuxServer; +import org.cometd.server.http.jakarta.CometDServlet; import org.eclipse.jetty.ee10.servlet.DefaultServlet; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; @@ -41,7 +41,7 @@ public abstract class AbstractCometDTest { @RegisterExtension - final BeforeTestExecutionCallback printMethodName = context -> + public final BeforeTestExecutionCallback printMethodName = context -> System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName()); private final HttpCookieStore cookieStore = new HttpCookieStore.Default(); private final Map sessionStore = new HashMap<>(); @@ -54,7 +54,7 @@ public abstract class AbstractCometDTest { protected int port; protected String contextURL; protected String cometdURL; - protected BayeuxServerImpl bayeuxServer; + protected BayeuxServer bayeuxServer; protected int expirationPeriod = 2500; protected JavaScript javaScript; private XMLHttpRequestClient xhrClient; @@ -112,7 +112,7 @@ protected void startServer() throws Exception { connector.setPort(port); server.start(); port = connector.getLocalPort(); - bayeuxServer = cometdServlet.getBayeux(); + bayeuxServer = cometdServlet.getBayeuxServer(); } @AfterEach diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDAdviceTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDAdviceTest.java index 1471f8f17a..4adca39f94 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDAdviceTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDAdviceTest.java @@ -24,7 +24,6 @@ import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; -import org.cometd.server.BayeuxServerImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -49,7 +48,7 @@ public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { evaluateScript("const HandshakeListener = Java.type('" + HandshakeListener.class.getName() + "')"); evaluateScript("const handshakeListener = new HandshakeListener();"); HandshakeListener handshakeListener = javaScript.get("handshakeListener"); - handshakeListener.server = bayeuxServer; + handshakeListener.bayeuxServer = bayeuxServer; evaluateScript("const connectLatch = new Latch(1);"); Latch connectLatch = javaScript.get("connectLatch"); @@ -72,7 +71,7 @@ public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { public static class HandshakeListener { private final CountDownLatch latch = new CountDownLatch(1); - private BayeuxServerImpl server; + private BayeuxServer bayeuxServer; private int handshakes; public void handle(Object jsMessage) { @@ -81,7 +80,7 @@ public void handle(Object jsMessage) { if ((Boolean)message.get("successful")) { ++handshakes; if (handshakes == 1) { - server.removeSession(server.getSession((String)message.get("clientId"))); + bayeuxServer.removeSession(bayeuxServer.getSession((String)message.get("clientId"))); } else if (handshakes == 2) { latch.countDown(); } diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCallbackPollingTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCallbackPollingTest.java index 61405f80b9..44615aef64 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCallbackPollingTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCallbackPollingTest.java @@ -177,7 +177,6 @@ public void testURLMaxLengthThreeMessagesBatchedAreSplitOrderIsKept() throws Exc Latch connectLatch = javaScript.get("connectLatch"); Assertions.assertTrue(connectLatch.await(5000)); - evaluateScript(""" const subscribeLatch = new Latch(1); const publishLatch = new Latch(12); diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCrossOriginReHandshakeTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCrossOriginReHandshakeTest.java index 319d9b45ba..d71961ed38 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCrossOriginReHandshakeTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDCrossOriginReHandshakeTest.java @@ -32,6 +32,7 @@ import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; +import org.cometd.server.BayeuxServerImpl; import org.eclipse.jetty.ee10.servlet.FilterHolder; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlets.CrossOriginFilter; @@ -89,7 +90,7 @@ public boolean sendMeta(ServerSession session, ServerMessage.Mutable message) { int connects = this.connects.incrementAndGet(); if (connects == 1) { // Fake the removal of the session due to timeout - bayeuxServer.removeServerSession(session, true); + ((BayeuxServerImpl)bayeuxServer).removeServerSession(session, true); } } return true; diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDDeliverTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDDeliverTest.java index 0df7b6bdd2..183de6306e 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDDeliverTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDDeliverTest.java @@ -18,10 +18,10 @@ import java.util.Map; import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; import org.cometd.server.AbstractService; -import org.cometd.server.BayeuxServerImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -80,7 +80,7 @@ public void testDeliver(String transport) throws Exception { } public static class DeliverService extends AbstractService { - public DeliverService(BayeuxServerImpl bayeux) { + public DeliverService(BayeuxServer bayeux) { super(bayeux, "deliver"); addService("/service/deliver", "deliver"); } diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDHandshakeDynamicPropsTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDHandshakeDynamicPropsTest.java index 1d8f629d40..06bf35c6fa 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDHandshakeDynamicPropsTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDHandshakeDynamicPropsTest.java @@ -28,6 +28,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.cometd.bayeux.server.ServerSession; +import org.cometd.server.BayeuxServerImpl; import org.eclipse.jetty.ee10.servlet.FilterHolder; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.util.thread.AutoLock; @@ -133,7 +134,7 @@ private void doFilter(HttpServletRequest request, HttpServletResponse response, // send "unknown_session" and the JavaScript will re-handshake. ServerSession session = bayeuxServer.getSession(clientId); if (session != null) { - bayeuxServer.removeServerSession(session, false); + ((BayeuxServerImpl)bayeuxServer).removeServerSession(session, false); } } } else { diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDRemoteCallTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDRemoteCallTest.java index 7eda54f917..9ca638736c 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDRemoteCallTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDRemoteCallTest.java @@ -36,11 +36,10 @@ public class CometDRemoteCallTest extends AbstractCometDTransportsTest { public void testRemoteCallWithResult(String transport) throws Exception { initCometDServer(transport); - ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeux()); + ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeuxServer()); String response = "response"; processor.process(new RemoteCallWithResultService(response)); - evaluateScript("cometd.init({url: '$U', logLevel: '$L'});" .replace("$U", cometdURL).replace("$L", getLogLevel())); Thread.sleep(1000); // Wait for /meta/connect @@ -83,7 +82,7 @@ public void service(RemoteCall.Caller caller, Object data) { public void testRemoteCallWithFailure(String transport) throws Exception { initCometDServer(transport); - ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeux()); + ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeuxServer()); String failure = "response"; processor.process(new RemoteCallWithFailureService(failure)); @@ -130,7 +129,7 @@ public void testRemoteCallTimeout(String transport) throws Exception { initCometDServer(transport); long timeout = 1000; - ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeux()); + ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeuxServer()); boolean processed = processor.process(new RemoteCallTimeoutService(timeout)); Assertions.assertTrue(processed); @@ -194,7 +193,7 @@ public void testRemoteCallWithCustomDataClass(String transport) throws Exception String request = "request"; String response = "response"; - ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeux()); + ServerAnnotationProcessor processor = new ServerAnnotationProcessor(cometdServlet.getBayeuxServer()); boolean processed = processor.process(new RemoteCallWithCustomDataClassService(request, response)); Assertions.assertTrue(processed); diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDTransportNegotiationFailureTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDTransportNegotiationFailureTest.java index d8d80229e5..a980d57034 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDTransportNegotiationFailureTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/CometDTransportNegotiationFailureTest.java @@ -20,6 +20,7 @@ import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; +import org.cometd.server.BayeuxServerImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; @@ -32,7 +33,7 @@ public void testTransportNegotiationFailureForClientLongPollingServerCallbackPol initCometDServer(transport); // Only callback-polling on server (via extension), only long-polling on client. - bayeuxServer.setAllowedTransports("long-polling", "callback-polling"); + ((BayeuxServerImpl)bayeuxServer).setAllowedTransports("long-polling", "callback-polling"); bayeuxServer.addExtension(new BayeuxServer.Extension() { @Override public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) { @@ -70,7 +71,7 @@ public void testTransportNegotiationFailureForClientLongPollingServerWebSocket(S initCometDServer(transport); // Only websocket on server, only long-polling on client. - bayeuxServer.setAllowedTransports("websocket"); + ((BayeuxServerImpl)bayeuxServer).setAllowedTransports("websocket"); evaluateScript(""" cometd.unregisterTransports(); @@ -100,7 +101,7 @@ public void testTransportNegotiationFailureForClientWebSocketServerLongPolling(S initCometDServer(transport); // Only long-polling on server, only websocket on client. - bayeuxServer.setAllowedTransports("long-polling"); + ((BayeuxServerImpl)bayeuxServer).setAllowedTransports("long-polling"); evaluateScript(""" cometd.unregisterTransports(); diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckAndReloadExtensionsTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckAndReloadExtensionsTest.java index f00be3e367..65949361af 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckAndReloadExtensionsTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckAndReloadExtensionsTest.java @@ -16,10 +16,10 @@ package org.cometd.javascript.extension; import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxServer; import org.cometd.javascript.AbstractCometDTransportsTest; import org.cometd.javascript.Latch; import org.cometd.server.AbstractService; -import org.cometd.server.BayeuxServerImpl; import org.cometd.server.ext.AcknowledgedMessagesExtension; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; @@ -108,7 +108,7 @@ public void testAckAndReloadExtensions(String transport) throws Exception { } public static class AckService extends AbstractService { - private AckService(BayeuxServerImpl bayeux) { + private AckService(BayeuxServer bayeux) { super(bayeux, "ack-test"); } diff --git a/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckExtensionTest.java b/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckExtensionTest.java index b689e12606..4af8ee14b4 100644 --- a/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckExtensionTest.java +++ b/cometd-javascript/tests/src/test/java/org/cometd/javascript/extension/CometDAckExtensionTest.java @@ -16,10 +16,10 @@ package org.cometd.javascript.extension; import org.cometd.bayeux.Promise; +import org.cometd.bayeux.server.BayeuxServer; import org.cometd.javascript.AbstractCometDTransportsTest; import org.cometd.javascript.Latch; import org.cometd.server.AbstractService; -import org.cometd.server.BayeuxServerImpl; import org.cometd.server.ext.AcknowledgedMessagesExtension; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; @@ -143,7 +143,7 @@ public void testAcknowledgement(String transport) throws Exception { } public static class AckService extends AbstractService { - private AckService(BayeuxServerImpl bayeux) { + private AckService(BayeuxServer bayeux) { super(bayeux, "ack-test"); } diff --git a/cometd-javascript/tests/src/test/resources/jetty-logging.properties b/cometd-javascript/tests/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..4c5ffb4286 --- /dev/null +++ b/cometd-javascript/tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,4 @@ +## Levels: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF. +#org.cometd.LEVEL=DEBUG +#org.eclipse.jetty.LEVEL=DEBUG +#org.cometd.javascript.LEVEL=DEBUG diff --git a/cometd-javascript/tests/src/test/resources/log4j2-test.properties b/cometd-javascript/tests/src/test/resources/log4j2-test.properties deleted file mode 100644 index fe44ee5c55..0000000000 --- a/cometd-javascript/tests/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,19 +0,0 @@ -# LOG4J2 levels: fatal, error, warn, info, debug, trace -# -appender.console.type=Console -appender.console.name=console -appender.console.target=SYSTEM_ERR -appender.console.layout.type=PatternLayout -appender.console.layout.pattern=%d %t [%5p][%c{2}] %m%n - -rootLogger.level=debug -rootLogger.appenderRef.console.ref=console - -logger.jetty.name=org.eclipse.jetty -logger.jetty.level=info - -logger.cometd.name=org.cometd -logger.cometd.level=info - -#logger.cometdjs.name=org.cometd.javascript -#logger.cometdjs.level=debug diff --git a/pom.xml b/pom.xml index f5ea2a8f9c..c5c22d9f87 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,6 @@ 23.0.1 2.0.9 - 2.20.0 6.0.12 3.1.4 2.15.2 @@ -552,18 +551,27 @@ test - org.apache.logging.log4j - log4j-core - ${log4j2-version} - test - - - org.apache.logging.log4j - log4j-slf4j2-impl - ${log4j2-version} + org.eclipse.jetty + jetty-slf4j-impl + ${jetty-version} test + + + org.junit.jupiter + junit-jupiter + + + org.eclipse.jetty + jetty-slf4j-impl + + + org.awaitility + awaitility + + +