jersey
  1. jersey
  2. JERSEY-1409

Extended WADL generation fail under OSGI

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.13
    • Fix Version/s: 2.0-m10, 2.0
    • Component/s: osgi
    • Labels:
      None
    • Environment:

      Linux, Equinox 3.7, OpenJDK 1.7.0_03

      Description

      Using code based on [1]:

      @Override
      public List<WadlGeneratorDescription> configure() {
      	return generator(WadlGeneratorResourceDocSupport.class).prop("resourceDocStream", "resourcedoc.xml").descriptions();
      }
      

      i get the following stacktrace:

      java.lang.RuntimeException: Could not load wadl generators from wadlGeneratorDescriptions.
              at com.sun.jersey.api.wadl.config.WadlGeneratorConfig.createWadlGenerator(WadlGeneratorConfig.java:184) ~[na:na]
              at com.sun.jersey.server.impl.wadl.WadlApplicationContextImpl.<init>(WadlApplicationContextImpl.java:92) ~[na:na]
              at com.sun.jersey.server.impl.wadl.WadlFactory.init(WadlFactory.java:96) ~[na:na]
              at com.sun.jersey.server.impl.application.RootResourceUriRules.initWadl(RootResourceUriRules.java:169) ~[na:na]
              at com.sun.jersey.server.impl.application.RootResourceUriRules.<init>(RootResourceUriRules.java:106) ~[na:na]
              at com.sun.jersey.server.impl.application.WebApplicationImpl._initiate(WebApplicationImpl.java:1300) ~[na:na]
              at com.sun.jersey.server.impl.application.WebApplicationImpl.access$700(WebApplicationImpl.java:163) ~[na:na]
              at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:769) ~[na:na]
              at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:765) ~[na:na]
              at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193) ~[na:na]
              at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:765) ~[na:na]
              at com.sun.jersey.guice.spi.container.servlet.GuiceContainer.initiate(GuiceContainer.java:121) ~[na:na]
              at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:319) ~[na:na]
              at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:609) ~[na:na]
              at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:210) ~[na:na]
              at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:374) ~[na:na]
              at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:557) ~[na:na]
              [snip]
      Caused by: java.lang.RuntimeException: The resource 'resourcedoc.xml' does not exist.
              at com.sun.jersey.api.wadl.config.WadlGeneratorLoader.setProperty(WadlGeneratorLoader.java:203) ~[na:na]
              at com.sun.jersey.api.wadl.config.WadlGeneratorLoader.loadWadlGenerator(WadlGeneratorLoader.java:139) ~[na:na]
              at com.sun.jersey.api.wadl.config.WadlGeneratorLoader.loadWadlGeneratorDescriptions(WadlGeneratorLoader.java:114) ~[na:na]
              at com.sun.jersey.api.wadl.config.WadlGeneratorConfig.createWadlGenerator(WadlGeneratorConfig.java:182) ~[na:na]
              ... 66 common frames omitted
      

      The same code works perfectly if used outside of OSGI (under Grizzly).

      [1]: https://wikis.oracle.com/display/Jersey/HowToConfigureExtendedWADL

        Activity

        Hide
        Mikhail Mazursky added a comment - - edited

        The problem is in com.sun.jersey.api.wadl.config.WadlGeneratorLoader.setProperty() that uses wrong (for OSGI) classloader:

        final String resource = propertyValue.toString();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = WadlGeneratorLoader.class.getClassLoader();
        }
        final InputStream is = loader.getResourceAsStream(resource);
        if (is == null) {
            String message = "The resource '" + resource + "' does not exist.";
            throw new RuntimeException(message);
        }
        

        I see some possible workarounds/fixes:

        • Somehow pass a Classloader to use to load specified resource;
        • Improve parameter passing to property method so that InputStream can be passed - i tried to load the resource myself, then pass it's contents as ByteArrayInputStream to the .prop("resourceDocStream", bais) but it fails because of a too strick type check:
          final Class<?> paramClazz = method.getParameterTypes()[0];
          if (paramClazz == propertyValue.getClass()) {
              method.invoke(generator, propertyValue);
          

          I propose to change this code to:

          final Class<?> paramClazz = method.getParameterTypes()[0];
          -- if (paramClazz == propertyValue.getClass()) {
          ++ if (paramClazz.isAssignableFrom(propertyValue.getClass())) {
              method.invoke(generator, propertyValue);
          

          This also looks like the right thing to do anyway.

        • Add WadlGeneratorResourceDocSupport.setResourceDocArray(byte[]) so that resource contents can be passed directly (this is not relevant if the previous fix is implemented).

        p.s. looks like a possible NPE in

        if (loader == null) {
            loader = WadlGeneratorLoader.class.getClassLoader();
        }
        final InputStream is = loader.getResourceAsStream(resource);
        

        because .getClassLoader() can return null.

        Show
        Mikhail Mazursky added a comment - - edited The problem is in com.sun.jersey.api.wadl.config.WadlGeneratorLoader.setProperty() that uses wrong (for OSGI) classloader: final String resource = propertyValue.toString(); ClassLoader loader = Thread .currentThread().getContextClassLoader(); if (loader == null ) { loader = WadlGeneratorLoader.class.getClassLoader(); } final InputStream is = loader.getResourceAsStream(resource); if (is == null ) { String message = "The resource '" + resource + "' does not exist." ; throw new RuntimeException(message); } I see some possible workarounds/fixes: Somehow pass a Classloader to use to load specified resource; Improve parameter passing to property method so that InputStream can be passed - i tried to load the resource myself, then pass it's contents as ByteArrayInputStream to the .prop("resourceDocStream", bais) but it fails because of a too strick type check: final Class <?> paramClazz = method.getParameterTypes()[0]; if (paramClazz == propertyValue.getClass()) { method.invoke(generator, propertyValue); I propose to change this code to: final Class <?> paramClazz = method.getParameterTypes()[0]; -- if (paramClazz == propertyValue.getClass()) { ++ if (paramClazz.isAssignableFrom(propertyValue.getClass())) { method.invoke(generator, propertyValue); This also looks like the right thing to do anyway. Add WadlGeneratorResourceDocSupport.setResourceDocArray(byte[]) so that resource contents can be passed directly (this is not relevant if the previous fix is implemented). p.s. looks like a possible NPE in if (loader == null ) { loader = WadlGeneratorLoader.class.getClassLoader(); } final InputStream is = loader.getResourceAsStream(resource); because .getClassLoader() can return null.
        Hide
        Jakub Podlesak added a comment -

        Do you have a reproducible test case handy that you could attach to this report? That would help us a lot to speed up fixing this. Thanks for understanding!

        Show
        Jakub Podlesak added a comment - Do you have a reproducible test case handy that you could attach to this report? That would help us a lot to speed up fixing this. Thanks for understanding!
        Hide
        Mikhail Mazursky added a comment -

        You may take a look at this sample [1]. It reproduces the problem, but i failed to make it work for non-extended WADL too. It have some weird OSGi-related problem that my original setup do not have. You can launch it using the provided instructions on the page. It seems that due to some Jetty-related issue you have to stop/start the application from the console using:
        stop com.ash2k.example.osgi-wadl
        start com.ash2k.example.osgi-wadl

        Hope that helps.

        [1]: https://github.com/ash2k/osgi-jetty-playground

        Show
        Mikhail Mazursky added a comment - You may take a look at this sample [1] . It reproduces the problem, but i failed to make it work for non-extended WADL too. It have some weird OSGi-related problem that my original setup do not have. You can launch it using the provided instructions on the page. It seems that due to some Jetty-related issue you have to stop/start the application from the console using: stop com.ash2k.example.osgi-wadl start com.ash2k.example.osgi-wadl Hope that helps. [1] : https://github.com/ash2k/osgi-jetty-playground
        Hide
        Jakub Podlesak added a comment -

        Thanks! I am now able to reproduce.

        Show
        Jakub Podlesak added a comment - Thanks! I am now able to reproduce.
        Hide
        Jakub Podlesak added a comment -

        Going to relax the parameter check as suggested above so that you can pass an InputStream in.
        Please keep in mind that in OSGi environment, you would need to get the input stream via OSGi API, e.g. like follows:

        InputStream resourceStream = FrameworkUtil.getBundle(this.getClass()).getEntry(RESOURCEDOC_FILE).openStream();
        

        If there is demand we might want to wire better OSGi support directly into the Jersey WADL codebase,
        but that would not be doable in 1.15 timeframe.

        Show
        Jakub Podlesak added a comment - Going to relax the parameter check as suggested above so that you can pass an InputStream in. Please keep in mind that in OSGi environment, you would need to get the input stream via OSGi API, e.g. like follows: InputStream resourceStream = FrameworkUtil.getBundle( this .getClass()).getEntry(RESOURCEDOC_FILE).openStream(); If there is demand we might want to wire better OSGi support directly into the Jersey WADL codebase, but that would not be doable in 1.15 timeframe.
        Hide
        Jakub Podlesak added a comment -

        Fixed in the main trunk:

        Sending changes.txt
        Sending jersey-server/src/main/java/com/sun/jersey/api/wadl/config/WadlGeneratorLoader.java
        Transmitting file data ..
        Committed revision 5797.

        Show
        Jakub Podlesak added a comment - Fixed in the main trunk: Sending changes.txt Sending jersey-server/src/main/java/com/sun/jersey/api/wadl/config/WadlGeneratorLoader.java Transmitting file data .. Committed revision 5797.
        Hide
        Jakub Podlesak added a comment -

        Re-opening to be able to implement a better fix. It should not be required to pass an input stream in.

        Show
        Jakub Podlesak added a comment - Re-opening to be able to implement a better fix. It should not be required to pass an input stream in.
        Hide
        Jakub Podlesak added a comment -

        Jersey 1 codebase left intact, but applied a fix to Jersey 2 codebase, where you should not need to provide an input stream directly,
        if required resource files are located in the very same bundle as the WadlGeneratorConfigurator class itself.
        Added a test case to the extended wadl webapp example.

        Show
        Jakub Podlesak added a comment - Jersey 1 codebase left intact, but applied a fix to Jersey 2 codebase, where you should not need to provide an input stream directly, if required resource files are located in the very same bundle as the WadlGeneratorConfigurator class itself. Added a test case to the extended wadl webapp example.

          People

          • Assignee:
            Jakub Podlesak
            Reporter:
            Mikhail Mazursky
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - Not Specified
              Not Specified
              Remaining:
              Remaining Estimate - 0 minutes
              0m
              Logged:
              Time Spent - 10 hours
              10h