I'm migrating an existing GWT app running on OSGi (Equinox) and Pax-web to use Declarative Services instead of programmatic Service Tracker.
I'm using Pax-Web in Equinox. A WAR-based GWT application is loaded with no problems by PAX-WEB War extender, but you cannot have Declarative Services in this modus operandis.
I successfully refactored all servlets out of the war and converted them into declarative OSGi services (<provide interface="javax.servlet.Servlet"/>
). That way I got rid of all the messy ServiceTracker code and specific OSGi dependencies in the servlets.
I further replicated all other web.xml functionality to register a filter, serve static content and welcome page using the info on [1]
At this point, it normally should work, but I'm having issues with PAX-WEB and the way GWT tries to load its resources:
While loading the serialization descriptors, GWT loads the serialization policy file from the local context. In my case it tries to resolve resources like this: /ctx/ctx/62394587E47773FB1594FF.gwt.rpc This resource is created by the GWT compiler and placed under : /war/ctx/ctx/resource...
Before, using the standard wab mapping (Webapp-Context: /ctx, Webapp-Root: /war
) gwt would find its resources correctly.
Now that I'm using the programmatic resource mapping:
DefaultResourceMapping resourceMapping = new DefaultResourceMapping();
resourceMapping.setAlias( "/ctx" );
resourceMapping.setPath( "/war" );
GWT fails to load the resouce and produces the following error:
2012-06-20 12:46:36.283:INFO:/:AbcProxy: ERROR: The serialization policy file '/ctx/ctx/600000000000000773FB1594FF.gwt.rpc' was not found; did you forget to include it in this deployment?
2012-06-20 12:46:36.283:INFO:/:AbcProxy: WARNING: Failed to get the SerializationPolicy '600000000000000773FB1594FF' for module 'https://localhost:8443/ctx/ctx/'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.
[N.B. The last sentence should read "you will experience a hell of serialization issues as a result"]
I've tracked the issue to the HttpServiceContext loading the resource and intrepreting the path as a file and not as an url relative to the programmatic web context:
getting resource: [/mx/mx/6ECAD5B3A6F908CE17E47773FB1594FF.gwt.rpc]
HttpServiceContext | not a URL or invalid URL: [/ctx/ctx/600000000000000773FB1594FF.gwt.rpc], treating as a file path
DefaultHttpContext | Searching bundle [bundle] for resource [/ctx/ctx/600000000000000773FB1594FF.gwt.rpc]
This obviously fails, as this resource is located under /war/ctx/ctx/ in bundle file system. This seems to relate to bug PAXWEB-314 [2] which implementation is to turn the relative path into a file path:
// IMPROVEMENT start PAXWEB-314
257 try {
258 resource = new URL(path);
259 LOG.debug( "resource: [" + path + "] is already a URL, returning" );
260 return resource;
261 }
262 catch (MalformedURLException e) {
263 // do nothing, simply log
264 LOG.debug( "not a URL or invalid URL: [" + path + "], treating as a file path" );
265 }
266 // IMPROVEMENT end PAXWEB-314
Is there a way to work around this issue? Is somebody using GWT and PAX-WEB using OSGi DS instead of a WAB? One possible way is to copy the /war/ctx produced by the GWT compiler back to /ctx, but I'd like to find a decent solution before going into the hack direction.
Any ideas?
1 - https://github.com/ops4j/org.ops4j.pax.web/blob/master/samples/whiteboard/src/main/java/org/ops4j/pax/web/extender/samples/whiteboard/internal/Activator.java [2] - http://team.ops4j.org/browse/PAXWEB-314
I did some further digging.
On GWT, this is the relevant piece of code in charge of loading those policy files: [1]
protected SerializationPolicy doGetSerializationPolicy(
HttpServletRequest request, String moduleBaseURL, String strongName) {
// The request can tell you the path of the web app relative to the
// container root.
String contextPath = request.getContextPath();
String modulePath = null;
if (moduleBaseURL != null) {
try {
modulePath = new URL(moduleBaseURL).getPath();
} catch (MalformedURLException ex) {
// log the information, we will default
log("Malformed moduleBaseURL: " + moduleBaseURL, ex);
}
}
...
I suspected the contextPath to be a potential candidate suspect in this case. To test that theory, I deployed a simple servlet that dumps its context. I deployed it using WAB (MANIFEST: Webapp-Context + web.xml). In this deployment, the servlet reports: [getContextPath]->[/ctx]
Then, changed the deployment to OSGi-ds with a programmatic activator containing the resource mapping. DefaultResourceMapping resourceMapping = new DefaultResourceMapping(); resourceMapping.setAlias( "/ctx" ); resourceMapping.setPath( "/war" );
In this case, the servlet reports: [getContextPath]->[]
Translated to the gwt issue --> when gwt is deployed with a WAB, it finds its config in /ctx/app and when I use the programmatic resource mapping it is looking into /app and therefore does not find its resources.
Bottom line: In PAX-WEB, Webapp-Context is not equivalent to the alias. The alias does not populate ContextPath the same way Webapp-Context does.
The only current work-around for this situation is to let the build copy the GWT-generated files one level down (eliminating the application context path)
PS: Following Achim Nierbeck from Pax-web, the OSGi spec is evolving to manage the app-ctx issue: http://wiki.osgi.org/wiki/WebExperience