-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
OF-2717: Allow plugins to register/unregister web context #2604
OF-2717: Allow plugins to register/unregister web context #2604
Conversation
What does not sit well with me is that when adding a When removing that same |
Does your use of Can it be a non servlet implementation? If you must use servlet features, then you are bound by the servlet environment that is provided by the |
Thanks @joakime! From your feedback, I think I can conclude that there's not a better way of registering/unregistering contexts. That weird non-symmetry between registration and de-registration made me question if this is the way this API is intended to be used. Is that fair to say? This Openfire code is part of a public API against which third-party developers can code, so there's no telling what they might use. It's certainly not unreasonable to assume that some of them want to use servlet APIs. Does it make sense to expose both options explicitly? |
* | ||
* @param handler The handler (cannot be null). | ||
*/ | ||
public void addJettyHandler( Handler handler ) | ||
public void addJettyHandler(final ContextHandler handler) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either leave this as a org.eclipse.jetty.server.Handler
or provide a new addJettyHandler(org.eclipse.jetty.server.Handler handler)
as a secondary implementation allowing your users to enable other jetty features (like GzipHandler, CompressionHandler, QoSHandler, RewriteHandler, etc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It there any reason you don't want your users to just add Servlets or Filters to your existing context instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has historically been done to somewhat isolate the functionality that is being provided by individual plugins, both from each-other, as well as from the functionality that's provided by Openfire itself on that web context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you prevent two plugins from using the same overlapping context selection rules?
A ContextHandler is selected from the ContextHandlerCollection based on ...
- The context-path declared on the ContextHandler
- The incoming path-in-context for request when it reaches the ContextHandlerCollection
- The virtual-host declarations (either direct, or named)
To oversimplify this ...
If more than one ContextHandler entry results from the selection list above, then the resulting list is sorted, and then each entry is given the request to process following Jetty Core Handler rules, stopping when one of the handlers declares itself to be the one handling the generation of the response.
Is that something you attempt to prevent? or let the plugins do what they want?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the web-based content that is provided through the API that we're discussing in this PR, I don't think that there is an explicit check that plugin-provided context doesn't overlap. It is expected that plugins provide their own unique context, eg:
CONTEXT_ROOT = "jsxc"; // Expected to be unique - typically the name of the plugin.
...
context = new WebAppContext( null, pluginDirectory.getPath() + File.separator + "classes/", "/" + CONTEXT_ROOT );
Although possibly not ideal, I believe that this is 'good enough'. We've been doing this for close to two decades now. I'm not aware of any issue that stems from a naming collision.
Just to expand on what I said before ... The The ee8 When you upgrade to ee10 or ee11 (with Jetty 12.1.x) then that "servlet-ness" goes away, as there's no old Jetty version to attempt to maintain behavior with. |
I must admit that my lack of knowhow makes it a bit hard to follow. Maybe it's easier to illustrate things with an example. One of the Openfire plugins that adds content to Jetty is a plugin that adds a web-based chat client to Openfire. This plugin (called the JSXC-plugin) uses Jetty in two distinct ways:
My approach to make the pre-existing plugin code compatible with Jetty 12 (as well as the change in this PR) can be found here: igniterealtime/openfire-jsxc-plugin#25 |
JSPs would mean you are either using a ServletContextHandler or a WebAppContext. |
Openfire uses two different mechanisms: JSPs provided by a plugin that are intended to be part of the admin console are not added through the context that's being added by the API that's the subject of this PR. Instead, the per-compilation generates a <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param><param-name>org.eclipse.jetty.ee8.jsp.precompiled</param-name><param-value>true</param-value></context-param>
<!--
Automatically created by Apache Tomcat JspC.
-->
<servlet>
<servlet-name>org.jivesoftware.openfire.plugin.jsxc.jsxc_002dconfig_jsp</servlet-name>
<servlet-class>org.jivesoftware.openfire.plugin.jsxc.jsxc_002dconfig_jsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>org.jivesoftware.openfire.plugin.jsxc.jsxc_002dconfig_jsp</servlet-name>
<url-pattern>/jsxc-config.jsp</url-pattern>
</servlet-mapping>
<!--
End of content automatically created by Apache Tomcat JspC.
-->
</web-app> This all is separate from the optional extension point that's the subject of this PR, through which a plugin could add ... whatever they want ... to Jetty, in order to make use of its functionality. In practice, that's mostly going to be servlet-based functionality, like the bit in JSXC that I pointed to in my previous commit. It uses something like this: // Add the Webchat sources to the same context as the one that's providing the BOSH interface.
context = new WebAppContext( null, pluginDirectory.getPath() + File.separator + "classes/", "/" + CONTEXT_ROOT );
context.setClassLoader( this.getClass().getClassLoader() );
HttpBindManager.getInstance().addJettyHandler( context ); To make available a web-app (as defined here). This happens on a different different Jetty embedded server instance than the one that serves the admin console (as the webapp serves user-facing, public content, while the admin console serves restricted, administrative content). |
a45bbe4
to
fe6c616
Compare
Is the following alternative approach, which may have been mentioned in part in previous comments on this PR, of keeping, the more generic addJettyHandler(Handler handler) and removeJettyHandler(Handler handler) methods something we can go with? Plugins that use WebAppContext can simply call get() to pass a Handler instance, like so:
This approach works with our current Openfire implementation and will also remain compatible if the changes in this PR are accepted. |
Is there benefit in providing both the 'old' method, as well as the new one as introduced in this PR? |
fe6c616
to
68b216d
Compare
As suggested by @joakime and @hqv126, this PR has been updated (force-push) to retain the old add/remove methods that are based on the generic Handler. As I expect many/most plugins to use a WebAppContext - which each plugin will need to update to Jetty12 EE8 - I've added a convenience overload for those methods that take instances of that class directly. |
xmppserver/src/main/java/org/jivesoftware/openfire/http/HttpBindManager.java
Outdated
Show resolved
Hide resolved
The embedded webserver (Jetty) that powers the HTTP-Bind (BOSH) and Websocket endpoints can be used by plugins, for them to add web content of their own. To do so, a plugin can dynamically add a 'handler' when it gets loaded in Openfire (that handler should be removed again when the plugin gets unloaded). Due to changes to the Jetty API (which got updated from 10 to 12, using EE8), this mechanism was broken. Prior to the upgrade, a `org.eclipse.jetty.server.handler.HandlerList` was used to maintain the collection of plugin-provided contexts. After upgrading to Jetty 12, this was replaced with a `org.eclipse.jetty.server.handler.ContextHandlerCollection`. This was part of igniterealtime@99fe5f9#diff-55709739e79c9b3141bb106d4e4cf428d2bc54e46acf59450c3d9e8cf988385b The methods used by plugins to add and remove 'handlers' were not modified in that change. The 'handler' passed to them remained of type `org.eclipse.jetty.server.Handler`. This compiles fine, but seems to be a problem. When plugins (which are stand-alone projects with their own source code repositories) get updated to use Jetty 12 instead of 10, their representation of their web-context typically switches from `org.eclipse.jetty.webapp.WebAppContext` to the Jetty 12 EE8 `org.eclipse.jetty.ee8.webapp.WebAppContext`. The former is compatible with the old implementation in Openfire, but the latter is not. The old methods to register and unregister can still be used when the 'core' context handler of the new Jetty 12 EE8 WebAppContext is used (or when the plugin does not use a WebAppContext at all, but a different type of Handler). The core handler can be obtained through `org.eclipse.jetty.ee8.nested.ContextHandler#get`. As it is expected that many/most applications use a WebAppContext, this commit adds new methods to register and unregister (Jetty 12 EE8) web contexts directly (without the need to obtain their 'core' handler).
68b216d
to
a0617b1
Compare
The embedded webserver (Jetty) that powers the HTTP-Bind (BOSH) and Websocket endpoints can be used by plugins, for them to add web content of their own.
To do so, a plugin can dynamically add a 'handler' when it gets loaded in Openfire (that handler should be removed again when the plugin gets unloaded).
Due to changes to the Jetty API (which got updated from 10 to 12, using EE8), this mechanism was broken.
Prior to the upgrade, a
org.eclipse.jetty.server.handler.HandlerList
was used to maintain the collection of plugin-provided contexts. After upgrading to Jetty 12, this was replaced with aorg.eclipse.jetty.server.handler.ContextHandlerCollection
. This was part of 99fe5f9#diff-55709739e79c9b3141bb106d4e4cf428d2bc54e46acf59450c3d9e8cf988385bThe methods used by plugins to add and remove 'handlers' were not modified in that change. The 'handler' passed to them remained of type
org.eclipse.jetty.server.Handler
. This compiles fine, but seems to be a problem.When plugins (which are stand-alone projects with their own source code repositories) get updated to use Jetty 12 instead of 10, their representation of their web-context switches from
org.eclipse.jetty.webapp.WebAppContext
to the Jetty 12 EE8org.eclipse.jetty.ee8.webapp.WebAppContext
. The former is compatible with the old implementation in Openfire, but the latter is not.This commit adds new methods to register and unregister (Jetty 12 EE8) web contexts.
I considered leaving the original methods (possibly marked as being deprecated) in hopes of providing backwards compatibility. However old plugins that are compiled against Jetty 10 won't find the Jetty classes that they need in Openfire anyway (as Jetty is a 'provided' dependency, which now got updated), causing ClassCastExceptions to be thrown. That makes retaining the original add/remove methods (for backwards compatibility) rather pointless.