Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FELIX-6692 jetty 12.x websockets new approach (based on #309) #310

Conversation

paulrutter
Copy link
Contributor

@paulrutter paulrutter commented Apr 26, 2024

Based on the Jetty 11.x websocket work in #309, a new PR that incorporates a similar style for Jetty 12.
It adds two new classifiers:

  • with-jetty-ee10-websockets: jar with the additional Jetty EE10 websocket classes
  • with-jakarta-ee10-websockets: jar with the additional Jakarta EE10 websocket classes

The main jar and the light jar remain the same.
Two new configuration options:

org.apache.felix.jakarta.ee10.websocket.enable
org.apache.felix.jetty.ee10.websocket.enable

Needs additional tests/examples though, not a finished PR yet.

- Apply 11.x approach to jetty12 bundle
- Add two new classifiers 'with-jetty-ee10-websockets' and 'with-jakarta-ee10-websockets' to have a fat jar containing the appropriate websocket classes
Do note that the workaround in FelixJettyWebSocketServlet are still required; the initialization code in the Jetty12 bundle doesn't seem to work
@paulrutter
Copy link
Contributor Author

paulrutter commented Apr 26, 2024

I tried to adapt the example i had and remove the workarounds that we had before, but these are still required to get it to work. The initialization code in the JettyService does not seem to be enough for Jetty12:

In the example from @enapps-enorman:

    private static final class MyWebSocketInitServlet extends HttpServlet {
        private static final long serialVersionUID = -6893620059263229183L;

        @Override
        public void init(ServletConfig config) throws ServletException {
            super.init(config);

            // The websocket container is attached to the main servlet context, not the per-bundle one.
            //  Lookup the ServletContext for the context path where the websocket server is attached.
            ServletContext servletContext = config.getServletContext();
            ServletContext rootContext = servletContext.getContext("/");

            // Retrieve the JettyWebSocketServerContainer.
            JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(rootContext);
            assertNotNull(container);
            container.addMapping("/mywebsocket1", (upgradeRequest, upgradeResponse) -> new MyServerWebSocket());
        }
    }

ServletContext rootContext = servletContext.getContext("/"); returns null, when i tried it in the whiteboard example bundle.
Any ideas?

@cziegeler
Copy link
Contributor

As we use the same Apache Felix code base for both, maybe this is something that changed in Jetty 12? Although that sounds a little bit wired

@paulrutter
Copy link
Contributor Author

paulrutter commented Apr 29, 2024

I do see jetty/jetty.project#9925, but that has already been fixed. Maybe i can debug the jetty code a bit to see where it fails.

@paulrutter
Copy link
Contributor Author

paulrutter commented Apr 29, 2024

I found out that https://github.com/jetty/jetty.project/blob/jetty-12.0.x/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java#L510 is the culprit, and setting context.setCrossContextDispatchSupported(true); in JettyService will solve it.

I can get the example to work now 👍 One downside is that the current servlet context is irrelevant to the websocket being registered.

container.addMapping("/websocket", (upgradeRequest, upgradeResponse) -> new TestWebSocket());

Registers the websocket on ws://localhost:8080/websocket, while the init servlet is registered on ws://localhost:8080/filtersample/websocket/*.

Not sure if this is a big problem though.
I will commit my changes in the code so we have two examples:

  • my example, which is not based on the initialization code in JettyService. It it's then properly registered to ws://localhost:8080/filtersample/websocket/example
  • the example from @enapps-enorman, which registeres the websocket to the main servlet context ("/")

Also, i will try to incorporate the same units tests.

@paulrutter
Copy link
Contributor Author

## [class org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket] Opened session: WebSocketSession[to=PT30S,WebSocketCoreSession@7946968{SERVER,WebSocketSessionState@7eddbcb3{CONNECTED,i=NO-OP,o=NO-OP,c=null},[ws://localhost:8080/filtersample/websocket1/example,null,false.[]],af=true,i/o=4096/4096,fs=65536}->JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket],JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket]]
## [class org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket] Received message: abc
## [class org.apache.felix.http.samples.whiteboard.TestWebSocketServletMainContext$TestWebSocket] Opened session: WebSocketSession[to=PT30S,WebSocketCoreSession@691aa27d{SERVER,WebSocketSessionState@73f6ef48{CONNECTED,i=NO-OP,o=NO-OP,c=null},[ws://localhost:8080/websocket/example,null,false.[]],af=true,i/o=4096/4096,fs=65536}->JettyWebSocketFrameHandler@11f83f04[org.apache.felix.http.samples.whiteboard.TestWebSocketServletMainContext$TestWebSocket],JettyWebSocketFrameHandler@11f83f04[org.apache.felix.http.samples.whiteboard.TestWebSocketServletMainContext$TestWebSocket]]
## [class org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket] Error on session: WebSocketSession[to=PT30S,WebSocketCoreSession@7946968{SERVER,WebSocketSessionState@7eddbcb3{CLOSED,i=NO-OP,o=NO-OP,c={1001=SHUTDOWN,Connection Idle Timeout}},[ws://localhost:8080/filtersample/websocket1/example,null,false.[]],af=true,i/o=4096/4096,fs=65536}->JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket],JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket]] - org.eclipse.jetty.websocket.api.exceptions.WebSocketTimeoutException: Connection Idle Timeout
## [class org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket] Closed session: WebSocketSession[to=PT30S,WebSocketCoreSession@7946968{SERVER,WebSocketSessionState@7eddbcb3{CLOSED,i=NO-OP,o=NO-OP,c={1001=SHUTDOWN,Connection Idle Timeout}},[ws://localhost:8080/filtersample/websocket1/example,null,false.[]],af=true,i/o=4096/4096,fs=65536}->JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket],JettyWebSocketFrameHandler@4e6fb6d0[org.apache.felix.http.samples.whiteboard.TestWebsocketServletBundleContext$TestWebSocket]] - 1001 - Connection Idle Timeout
## [class org.apache.felix.http.samples.whiteboard.TestWebSocketServletMainContext$TestWebSocket] Received message: abc

Both examples work, i will push the changes and move on to the unit tests.

@paulrutter
Copy link
Contributor Author

@enapps-enorman @cziegeler I took the unit tests from #309 and adjusted these to run on Jetty12.
All succeed now.

I think we have a solid solution in place now. Let me know what you think.

…let context once available

This removes the need to set setCrossContextDispatchSupported, as the WS container is available on the proper servlet context itself
Removed other WebSocket example, as this is no longer needed with the new approach.
Updated documentation.
…o register a WebSocket endpoint that abides to the servlet context it's registered to.
@paulrutter
Copy link
Contributor Author

I kept both examples in the whiteboard bundle, as both have value:

For my own project, the first approach wouldn't work, as we register multiple instances of the same servlet class which would then overwrite the WS mapping on the WebSocket container. Using the JettyWebSocketServlet approach, this does not happen, as JettyWebSocketServlet is used to upgrade a regular HttpServletRequest to a WebSocket request.

enapps-enorman added a commit to enapps-enorman/felix-dev that referenced this pull request May 1, 2024
Rename org.apache.felix.jetty.websocket.enable to org.apache.felix.jetty.ee9.websocket.enable
Incorporate the changes for using maybeStoreWebSocketContainerAttributes
Copy link
Contributor

@enapps-enorman enapps-enorman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

@paulrutter
Copy link
Contributor Author

paulrutter commented May 1, 2024

@cziegeler can you check out this PR and #309? Both are now aligned to use the same approach.
Let me know if you agree and if this is good to merge for the next HTTP Jetty/Jetty12 release.

If you're ok with having the two additional classifiers for Jetty12, could these also be published to the maven repo?
Or would you rather just have one classifier containing both jakarta and jetty websocket classes?

cziegeler pushed a commit that referenced this pull request May 1, 2024
* FELIX-6692 Add Jetty WebSocket support for jetty 11.x

* FELIX-6692 rename jakarta websocket enable config for future expansion

* FELIX-6692 add paxexam integration tests to verify the functionality

* FELIX-6692 cleanup

* FELIX-6692 merge changes from PR #310

Rename org.apache.felix.jetty.websocket.enable to org.apache.felix.jetty.ee9.websocket.enable
Incorporate the changes for using maybeStoreWebSocketContainerAttributes

* FELIX-6692 renamed for consistency
@cziegeler cziegeler merged commit 0444ac4 into apache:master May 1, 2024
@paulrutter paulrutter deleted the feature/FELIX-6692-Jetty-12.x-websockets-new-approach branch May 1, 2024 07:04
@cziegeler
Copy link
Contributor

@paulrutter The additional classifiers look good to me, they should be pushed automatically to maven central when we do the release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants