This month the first major update of WildFly 8 (the base for a future JBoss EAP 7) was released; WildFly 8.1.0.Final.

I tried to get zeef.com running on it, which currently runs on JBoss AS 7. Zeef.com is a relatively new Java EE 6 based web application that was started about a year ago. As such there is not yet that much legacy code present in it.

This article is about the issues I encountered during this initial migration.

In broad lines the issues fell into the following categories:

Datasource

JASPIC

Tomcat/Undertow differences

Valves

Datasource

The first issue I run into was a failed deployment. WildFly spitted out page upon page of unintelligible mumble jumble. Upon a closer look there was something about our datasource in the middle of all of this. Apparently WildFly was trying to tell me that the datasource couldn’t be found. For zeef.com we define our datasource in application.xml (the Java EE standard way) and switch between stages uses a delegating switcheable datasource.

Moving the datasource definition to ejb-jar.xml solved the problem. Now WildFly 8.1 does support the definition of datasources in application.xml as demonstrated by this test (although a small workaround is needed). It might be an issue with loading the SwitchableXADataSource from the EAR level, but I didn’t investigate this further.

The WildFly team however has done a fair amount of work to make sure its JASPIC implementation is reasonably correct, among others by using an external set of tests designed to verify that JASPIC does the most basic things right (like actually authenticating). Unfortunately one case slipped through, and that mainly concerned the behavior of HttpServletRequest#authenticate.

(the fix for this last issue was committed rather fast by WildFly developers and fixes it in a better way)

Tomcat/Undertow differences

The next problems were about (small) differences between Tomcat/JBossWeb that JBoss previously used and the new Undertow that’s used in WildFly 8.

The first of those issues (UNDERTOW-348) are about what HttpServletRequest#getRequestURI and HttpServletRequest#getServletPath return when a welcome file is requested. Tomcat will return the requested location for getRequestURI and the welcome file resource for getServletPath, while Undertow will return the welcome file resource for both calls.

and when requesting the context root of an application (e.g. http://localhost:8080 for a root deployment), the results are as follows:

getRequestURI

getServletPath

Tomcat/JBossWeb

/

/welcome

Undertow

/welcome

/welcome

The information about the requested resource can be used to redirect the user to the root (“/”) when for some reason the welcome file resource is directly requested. With such a redirect the website will always display a ‘clean’ URL in the address bar. With the way Undertow does things there’s no way to distinguish a request to “/” from a request to “/welcome” and thus no opportunity to redirect. If a redirect was already in place based on the Tomcat/JBossWeb behavior an endless redirect loop will be the result.

This handler too has to be registered like we did for the JaspicHandler, but this time as an initialHandler.

(update: The behavior of welcome files was changed back to how it was in WildFly 9.0)

Another difference (likely a bug) between JBossWeb and Undertow is that for a root deployment the former will write the JSESSIONID cookie with the path set to “/”. Undertow however leaves the path empty.

An empty path is however interpreted by the browser as being the requested URI, meaning that the JSESSIONID cookie is set on each path where the user happens to do something that creates a session. It doesn’t require much imagination to understand this causes chaos in an application.

As it appears the fact that APIs for getting the context root often return the empty string for the root deployment (instead of “/”), but the path name for other deployments (e.g. “/foo”) is the culprit here. Undertow is not the first one to fall for this. Mojarra once had an identical bug with respect to setting a cookie for The Flash.

We can workaround this issue by setting the path explicitly in web.xml as follows:

Valves

Tomcat (and thus JBossWeb) has a low level mechanism called a Valve, which is a kind of Filter like element but at a much lower level and with access to some of the internal server APIs.

Ideally an application wouldn’t have to resort to using these, but sometimes there’s no choice. For instance a Filter can not change the outcome of the Servlet pipeline. It’s already fully established when the Filter is called. A Filter can redirect or forward, but these mechanisms have various side-effects. There’s also no mechanism in Servlet to intercept ALL cookies being written. By wrapping the HttpServletResponse you can catch a lot, but not these emitted by lower level components like the server generated JSESSIONID and cookies set by e.g. a SAM.

For zeef.com we had to resort to use a few of these. As Valves are highly specific to Tomcat it’s only logical that Undertow can’t support them. It does have another construct called HttpHandler, which we already used above for some workarounds.

Those handlers are quite powerful. There are ones that are called before the request pipeline is set up (initial handlers) and ones that execute during this pipeline (inner and outer handlers).

One of the things where we used a Valve for in Tomcat/JBossWeb is to do universal cookie rewriting. Unfortunately Undertow doesn’t have a way to rewrite a cookie right away. There is an opportunity to have a kind of listener called right before the response is being written, but it’s a bit non-obvious.

Via a handler and some reflective code we can do this more directly, as shown by the following code:

Of course using reflection to hack into the internals of a server is rarely a good idea and this handler is at risk of breaking with every minor update to Undertow.

Conclusion

During the initial attempt to get our application running on WildFly I certainly encountered a fair number of issues. It certainly wasn’t the case of just deploying the app and having everything working.

Of course we do have to realize that the Java EE standard datasource and authentication mechanism are unfortunately still not used that much as most vendors keep documenting their proprietary mechanisms first and foremost, which likely causes users to use those most, which on its turn may cause these standard ways to get less testing hours.

The Tomcat/WildFly differences initially looked major, but are after all just small bugs.

The Valves issue is debatable. It’s a major change in the product JBoss, but most Java EE applications should maybe not have used them in the first place. Purely from the point of view of the Java EE spec it doesn’t matter that Red Hat changed this, but looking from the point of view of JBoss itself it does matter and people have little choice but to rewrite their code if they want to upgrade.

Finally we have to realize that WildFly from a certain point of view is like an open beta. It has freely downloadable binaries, but the product is early in its lifecycle and there’s no commercial support available for it yet. When the WildFly branch transitions to JBoss EAP 7 many bugs that the community discovers now will undoubtedly have been fixed and commercial support will be available then. In a way this is the price we pay for a free product such as this. As David Blevins wrote “Open Source Isn’t Free”. Users “pay” by testing the software and producing bug reports and perhaps patches, which IMHO is a pretty good deal.

At any length there’s the eternal tradeoff to be made: adopt the new Java EE 7 spec early with WildFly 8 but be prepared to run into some issues, or wait a good deal longer for JBoss EAP 7 but then have a much more stable product to begin with. This is of course a choice everyone has to make for themselves.

Arjan Tijms

This entry was posted
on Tuesday, June 24th, 2014 at 12:44 am and is filed under Java.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.

5 comments to “Experiences with migrating from JBoss AS 7 to WildFly 8.1”

We are having Apache Web Server 2.2.25 as front end http handler.
Apache connects to jBoss 7.1.1 via AJP port and
now we have Wildfly 8.2 installed with same port numbers.. Just switching to Wildfly, apache is getting into an error .. Note jboss7.1.1 Final is down while testing the apache to Wildfly

Thanks for article…!
I am migrating the application from Jboss4.2.3 to Wildfly8.2.0. For authentication tomcat used with Jboss4.2.3 I believe tomcat is part of it. Is there any alternative of tomcat in Wildfly for LDAP & token based Authentication ?
Kindly suggest..!

I am getting below error. could you please help me to identify why i am getting this error on 8.1

16:06:55,750 ERROR [io.undertow.request] (default I/O-1) Blocking request failed HttpServerExchange{ GET /smareporting/pirpt}: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1871) [rt.jar:1.7.0_65]
at io.undertow.servlet.handlers.ServletPathMatches.setupServletChains(ServletPathMatches.java:311)
at io.undertow.servlet.handlers.ServletPathMatches.getData(ServletPathMatches.java:124)
at io.undertow.servlet.handlers.ServletPathMatches.getServletHandlerByPath(ServletPathMatches.java:75)
at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:108)
at io.undertow.server.handlers.HttpContinueReadHandler.handleRequest(HttpContinueReadHandler.java:43)
at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:56)
at io.undertow.server.handlers.HttpContinueReadHandler.handleRequest(HttpContinueReadHandler.java:43)
at io.undertow.server.handlers.SetHeaderHandler.handleRequest(SetHeaderHandler.java:49)
at io.undertow.server.handlers.SetHeaderHandler.handleRequest(SetHeaderHandler.java:49)
at io.undertow.server.handlers.NameVirtualHostHandler.handleRequest(NameVirtualHostHandler.java:53)
at io.undertow.server.handlers.error.SimpleErrorPageHandler.handleRequest(SimpleErrorPageHandler.java:76)
at io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:43)
at io.undertow.server.handlers.ChannelUpgradeHandler.handleRequest(ChannelUpgradeHandler.java:158)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:177)
at io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:156)
at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:91)
at io.undertow.server.protocol.http.HttpOpenListener.handleEvent(HttpOpenListener.java:92)
at io.undertow.server.protocol.http.HttpOpenListener.handleEvent(HttpOpenListener.java:43)
at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) [xnio-api-3.2.2.Final.jar:3.2.2.Final]
at org.xnio.ChannelListeners$10.handleEvent(ChannelListeners.java:291) [xnio-api-3.2.2.Final.jar:3.2.2.Final]
at org.xnio.ChannelListeners$10.handleEvent(ChannelListeners.java:286) [xnio-api-3.2.2.Final.jar:3.2.2.Final]
at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) [xnio-api-3.2.2.Final.jar:3.2.2.Final]
at org.xnio.nio.NioTcpServerHandle.handleReady(NioTcpServerHandle.java:53) [xnio-nio-3.2.2.Final.jar:3.2.2.Final]
at org.xnio.nio.WorkerThread.run(WorkerThread.java:539) [xnio-nio-3.2.2.Final.jar:3.2.2.Final]