Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Equinox » RCP: Registering Jetty websocket servlets via HttpServiceImpl is broken after Jetty upgrade 9.4->
RCP: Registering Jetty websocket servlets via HttpServiceImpl is broken after Jetty upgrade 9.4-> [message #1850207] Mon, 21 February 2022 17:20 Go to next message
Balint Pamer is currently offline Balint PamerFriend
Messages: 1
Registered: February 2022
Junior Member
Hello!

After upgrading from Jetty 9.4->10.0.5, In my RCP-project, which registers servlets (both regular- and WebSocket-ones) in Jetty via the Equinox whiteboard HTTP service:
(i.e.: HttpServiceImpl.registerServlet())

I've noticed that the JettyWebSocketServlet's init()-calls started throwing exceptions, saying:
"WebSocketComponents has not been created"
Despite having written a JettyCustomizer, invoking:
JettyWebSocketServletContainerInitializer.configure(contextHandler, null);
(This gets executed during HttpServerManager.updated(), so before the Jetty Server.start())

After lengthy debugging, the problem seems to be the Whiteboard HTTP service's ServletContextAdaptor creating a ProxyContext, which does *not* fall back onto the parent Jetty context, which has the necessary servlet attributes (the WebSocketComponents above)

After looking (and hacking) around, I've also noticed that the ServletContextAdaptor creates a dynamic proxy, which at the end of the day will throw an exception if I try to manually upgrade the WebSocket request, because under the hood, Jetty explicitly casts the to-be-upgraded ServletContext to its internal one (ContextHandler.Context):
https://git.eclipse.org/r/plugins/gitiles/equinox/rt.equinox.bundles/+/f58c0735df08bd1449282ab0e1c60caa12e9e570/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java#85
public ServletContext createServletContext() {
Class<?> clazz = getClass();
ClassLoader curClassLoader = clazz.getClassLoader();
Class<?>[] interfaces = new Class[] {ServletContext.class};

return (ServletContext)Proxy.newProxyInstance(
curClassLoader, interfaces, new AdaptorInvocationHandler());
}

https://github.com/eclipse/jetty.project/blob/jetty-10.0.x/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/CreatorNegotiator.java#L63
((ContextHandler.Context)servletContext).getContextHandler().handle(() ->
result.set(creator.createWebSocket(upgradeRequest, upgradeResponse)));

So my question is: how are Jetty 10 WebSockets supposed to work in Eclipse:
Should one directly use Jetty, and forget the whiteboard HTTP service, or is there some code that can be added to add the Jetty-specific WebSocket components?

Thanks:
Balint
Re: RCP: Registering Jetty websocket servlets via HttpServiceImpl is broken after Jetty upgrade 9.4- [message #1851806 is a reply to message #1850207] Sun, 17 April 2022 13:31 Go to previous messageGo to next message
Todor Dimitrov is currently offline Todor DimitrovFriend
Messages: 2
Registered: April 2022
Junior Member
We are facing the same issue. Are there any updates?
Re: RCP: Registering Jetty websocket servlets via HttpServiceImpl is broken after Jetty upgrade 9.4- [message #1851817 is a reply to message #1850207] Mon, 18 April 2022 14:56 Go to previous messageGo to next message
Balint Pamer is currently offline Balint PamerFriend
Messages: 3
Registered: June 2013
Junior Member
Ultimately, we ended up managing jetty ourselves...
(starting jetty, registering a resourcehandler for static resources, a servletcontexthandler for servlets and configuring the JettyWebSocketServletContainerInitializer for the latter)
Re: RCP: Registering Jetty websocket servlets via HttpServiceImpl is broken after Jetty upgrade 9.4- [message #1852503 is a reply to message #1851817] Thu, 19 May 2022 06:57 Go to previous message
Todor Dimitrov is currently offline Todor DimitrovFriend
Messages: 2
Registered: April 2022
Junior Member
We came back to this problem recently. Here is a servlet implementation, which seems to work:


class WebSocketServletImpl extends JettyWebSocketServlet {

	private static final long serialVersionUID = -8292051630200394714L;

	/** The websocket creator */
	private final JettyWebSocketCreator creator;

	/** The underlying Jetty context */
	private ServletContextHandler context;

	/** Used to get attributes from the Jetty context */
	private ServletContext proxiedContext;

	/**
	 * @param creator the non-null creator
	 */
	WebSocketServletImpl(JettyWebSocketCreator creator) {
		if (creator == null)
			throw new IllegalArgumentException("creator is null");

		this.creator = creator;
	}

	@Override
	public void init() throws ServletException {
		final ServletContext osgiServletContext = super.getServletContext();
		context = ServletContextHandler.getServletContextHandler(osgiServletContext, "WebSockets");

		final JettyWebSocketServerContainer serverContainer = JettyWebSocketServerContainer
				.getContainer(osgiServletContext);
		if (serverContainer == null) {
			final Context jettyServletContext = context.getServletContext();
			WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), jettyServletContext);
			WebSocketUpgradeFilter.ensureFilter(jettyServletContext);
			WebSocketMappings.ensureMappings(jettyServletContext);
			JettyServerFrameHandlerFactory.getFactory(jettyServletContext);
			JettyWebSocketServerContainer.ensureContainer(jettyServletContext);
		}

		super.init();
	}

	@Override
	public synchronized ServletContext getServletContext() {
		if (proxiedContext == null) {
			proxiedContext = (ServletContext) Proxy.newProxyInstance(WebSocketServletImpl.class.getClassLoader(),
					new Class[] { ServletContext.class }, (proxy, method, methodArgs) -> {
						final ServletContext osgiServletContext = super.getServletContext();
						if (!"getAttribute".equals(method.getName())) {
							return method.invoke(osgiServletContext, methodArgs);
						}

						final String name = (String) methodArgs[0];
						Object value = osgiServletContext.getAttribute(name);
						if (value == null && context != null) {
							final Context jettyServletContext = context.getServletContext();
							value = jettyServletContext.getAttribute(name);
						}
						return value;
					});
		}

		return proxiedContext;
	}

	@Override
	public void configure(JettyWebSocketServletFactory factory) {
		factory.setMaxBinaryMessageSize(1024 * 1024);
		factory.setMaxTextMessageSize(128 * 1024);
		// factory.setAsyncWriteTimeout(5000);
		factory.setCreator(creator);
		getServletContext().setAttribute(DecoratedObjectFactory.ATTR, new DecoratedObjectFactory());
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		final HttpServletRequest proxiedReq = (HttpServletRequest) Proxy.newProxyInstance(
				WebSocketServletImpl.class.getClassLoader(), new Class[] { HttpServletRequest.class },
				(proxy, method, methodArgs) -> {
					if (!"getServletContext".equals(method.getName())) {
						return method.invoke(req, methodArgs);
					}

					if (context != null)
						return context.getServletContext();

					return req.getServletContext();
				});

		super.service(proxiedReq, resp);
	}
}



It is not pretty but gets the job done :-)
Previous Topic:Accessing a P2 repository with SSO authentication
Next Topic:I have problem building my application because of artifact org.eclipse.osgi not found
Goto Forum:
  


Current Time: Fri Apr 26 09:35:01 GMT 2024

Powered by FUDForum. Page generated in 0.02435 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top