martin-g/wicket-webjars

WicketWebjars cannot be located on WebSphere

heryqk opened this issue · 20 comments

When using Wicket-Bootstrap 0.9.16 on WebSphere 8.0.0.12, WicketWebjars cannot be located.

INFO  - wicket-webjars             - initialize wicket webjars with given settings: WebjarsSettings{readFromCacheTimeout=3 seconds, resourceStreamProvider=ClassLoader, recentVersionPlaceHolder='current', assetPathCollectors=[de.agilecoders.wicket.webjars.collectors.FileAssetPathCollector@98505993, de.agilecoders.wicket.webjars.collectors.JarAssetPathCollector@3ce9b3aa, de.agilecoders.wicket.webjars.collectors.VfsAssetPathCollector@2bfdf819], webjarsPackage='META-INF.resources.webjars', webjarsPath='META-INF/resources/webjars', resourcePattern=.*, webjarsPathPattern=/webjars/([^/]*)/([^/]*)/(.*), useCdnResources=false, cdnUrl='//cdn.jsdelivr.net:80'}
DEBUG - WicketWebjars              - no version found for webjars resource: /webjars/bootstrap/current/js/bootstrap.js
DEBUG - WicketWebjars              - no version found for webjars resource: /webjars/modernizr/current/modernizr.js
DEBUG - WicketWebjars              - no version found for webjars resource: /webjars/bootstrap/current/css/bootstrap.css
WARN  - ResourceReferenceRegistry  - A ResourceReference wont be created for a resource with key [scope: de.agilecoders.wicket.webjars.request.resource.WebjarsCssResourceReference; name: webjars/bootstrap/null/css/bootstrap.css; locale: null; style: null; variation: null] because it cannot be located.
WARN  - ResourceReferenceRegistry  - A ResourceReference wont be created for a resource with key [scope: de.agilecoders.wicket.webjars.request.resource.WebjarsJavaScriptResourceReference; name: webjars/bootstrap/null/js/bootstrap.js; locale: null; style: null; variation: null] because it cannot be located.

[6/9/16 11:54:59:913 EDT] 00000020 filter        E com.ibm.ws.webcontainer.filter.FilterInstanceWrapper doFilter SRVE8109W: Uncaught exception thrown by filter wicket.WebSphereWebjars: java.io.FileNotFoundException: SRVE0190E: File not found: /wicket/resource/de.agilecoders.wicket.webjars.request.resource.WebjarsCssResourceReference/webjars/bootstrap/null/css/bootstrap.css
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor._processEDR(DefaultExtensionProcessor.java:967)
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.processEDR(DefaultExtensionProcessor.java:948)
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.handleRequest(DefaultExtensionProcessor.java:485)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:136)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:97)
    at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:267)
    at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:201)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:282)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:195)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:964)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1104)
    at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3819)
    at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:304)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1002)
    at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1662)
    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:456)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:518)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:309)
    at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:84)
    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1731)


[6/9/16 11:54:59:913 EDT] 0000002d filter        E com.ibm.ws.webcontainer.filter.FilterInstanceWrapper doFilter SRVE8109W: Uncaught exception thrown by filter wicket.WebSphereWebjars: java.io.FileNotFoundException: SRVE0190E: File not found: /wicket/resource/de.agilecoders.wicket.webjars.request.resource.WebjarsJavaScriptResourceReference/webjars/bootstrap/null/js/bootstrap.js
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor._processEDR(DefaultExtensionProcessor.java:967)
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.processEDR(DefaultExtensionProcessor.java:948)
    at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.handleRequest(DefaultExtensionProcessor.java:485)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:136)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:97)
    at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:267)
    at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:201)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:282)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:195)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:964)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1104)
    at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3819)
    at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:304)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1002)
    at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1662)
    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:456)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:518)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:309)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:280)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1731)

I'm not sure how relevant this is, but someone mentions at webjars/webjars-locator#78 something about how

Websphere uses a proprietary jar protocol that is prefixed with wsjar: instead of jar:.

Is there a comparable code change that could be done in wicket-webjars ? I looked at the code, but nothing jumps at me.

Does anyone have any insight on this issue ?

You will need to put a breakpoint at ClasspathAssetPathCollector#collect() and see what goes wrong.

After adding a lot of DEBUG statements and comparing with the running version of samples on Jetty, it appears ClasspathAssetPathCollector#collect() is never called on WebSphere.

What would be the cause of this ?

Adding log files for jetty and web sphere for the same sample web app.

jetty.txt
websphere.txt

I expect ClasspathAssetPathCollector#collect() to be called because CAPC#accept() always returns true.
I have the feeling that https://github.com/l0rdn1kk0n/wicket-webjars/blob/d65b01d36c11e2ac7e02eda9a2b6dfd3b511f77b/library/src/main/java/de/agilecoders/wicket/webjars/collectors/ClasspathAssetPathCollector.java#L44 returns false and that's why it looks like it is not even called.

Is it possible to put breakpoints and follow the logic instead of using logging statements ?

Another way is to explain me how to do this myself.
Where to download WebSphere from?
A trial version or the Liberty edition ?!
How to deploy webjars-examples app on it?

I don't have much spare time so please be as detailed as possible in the steps to reproduce.

@martin-g I'll try to find a way to put breakpoints on WAS and get back to you. At first glance, with DEBUG statements, I can see ClasspathAssestPathCollector is called. I added a constructor and a debug statement. If you look at the web sphere log provided, you can see:

[DEBUG] 2016-06-27 12:47:41,364 wicket-webjars - ClasspathAssetPathCollector()

however, the debug statements in the accept() and collect() methods are never called, whereas the jetty logs do show the methods being called.

I'd like to explain how to install WebSphere, but we are running on Enterprise Edition and the product is not available publicly. Unfortunately, Liberty is a completely different product.

@martin-g I finally found some time to look into this and with the help of a colleague, I was able to setup breakpoints.

As of now, I can confirm that the ClasspathAssestPathCollector.collect() method is never called because listWebjarsParentURLs() in AssetsMap.getAssetPaths() return an empty set.

With that said, looking at this issue, it is said:

In addition Websphere will not allow access to META-INF without a trailing "/" when calling getResources(...).

So I changed the settings to:
WebjarsSettings settings = new WebjarsSettings(); settings.webjarsPath(settings.webjarsPath() + "/");

and listWebjarsParentURLs() now returns data, but the outcome is still the same and I still have null resource references.

I'm not sure where to go from there.

Does ClasspathAssestPathCollector properly collect the webjars resources on the classpath ?
I'm afraid you will have to debug a bit deeper to see what is the next difference from the standards.

@martin-g ClasspathAssestPathCollector does not collect the web jars resources on WebSphere. The collectFromWebJarPath returns an empty set because the urlConnection returned by WebSphere is of type com.ibm.ws.classloader.Handler$ClassLoaderURLConnection which is incompatible with java.net.JarURLConnection.

This explains it!
If you are able to create a version of ClasspathAssestPathCollector for WebSphere then I'd be happy to add it to the project!

So I now have it working on WebSphere. There were 2 main issues and 1 side effect.

  1. The web jar path needs a trailing slash as stated elsewhere
  2. com.ibm.ws.classloader.Handler$ClassLoaderURLConnection is incompatible with java.net.JarURLConnection
  3. Adding the trailing slash to webjarPath, causes a duplicate "/" in AssetsMap.listAssets()

There is no easy way to fix no 2, as we definitely don't want hard dependencies on IBM libraries. Also, there's no easy of instantiating a JarURLConnection. To address the issue, I had to add a dependency to a 3rd party library on MVN Repo.

Take a look at what I did. There is a WebSphere Configuration, but it seems to work also on Jetty, the changes are generic enough that I believe they work across the board.

Let me know what you think. (Submitting soon)

Also a big thank you to Eric Gulatee for his help with this. I would've never managed on my own.

The PR + some improvements have been applied to branches wicket-6.x, wicket-7.x and wicket-8.x!
Please double check that I didn't break anything and I will release new versions.
Thank you!

@martin-g I'm trying to complete the final testing which includes updating wicket-bootstrap to use wicket-webjars 0.4.10-SNAPSHOT, however, the initialization of WicketWebjars.install() is embedded within the Bootstrap.install() method, so theres no way right now to install web jars with a custom WebjarSettings. Should we create an overridable method in Bootstrap that allows a user to pass its own version of Webjarssettnings ?

I see!
Yes, please create an issue/PR for this at wicket-bootstrap!
Thank you!

Will do. Seems I missed the fact that Bootstrap class is all static methods. Are you okay with the following before I make the change ?

 public static void install(final Application app, IBootstrapSettings settings) {
    install(app, settings, null);
 }

 public static void install(final Application app, IBootstrapSettings settings, IWebjarsSettings           webjarSettings) {
      ...
             if (settings.useWebjars() && app instanceof WebApplication) {
                WicketWebjars.install((WebApplication) app, webjarSettings);
            }
     ...
}

Sure!
We will figure out better API later.

Everything is tested on my end if you want to release 0.4.10. Wicket-Bootstrap 0.9.18 should depend on that version.

Thank you for your help on this.

How urgent is this for you ?

I can build my own versions for now, so no rush. I just want to make sure 0.4.10 makes it in the next Wicket-Bootstrap release.