2 Replies Latest reply on Mar 12, 2009 1:55 PM by wjbustraan

    Resource loading problem related to OSGi

    wjbustraan

      I'm stumped on an OSGi issue with ServiceMix and the way the ClassLoaders load resources. Here's some background:

       

      I have to deal with some legacy XML messages that it's difficult to change the format for. To workaround that limitation, I'm trying to run an XSL transform  with Camel to convert the legacy format to the proper format for a web service call.

       

      Sounds good in theory. Unfortunately, the XML files have a DTD declaration that is incorrect. Here's a snippet:

       

      <!DOCTYPE MPRequestCredit SYSTEM "file://MPReqCredit.dtd">

       

      When I runs this through the XSLT, the underlying parser tries to contact a host named "MPReqCredit.dtd" and everything fails.

       

      After much research, I discovered that the proper way to handle this is to implement an "EntityHandler" and pass that to the XML parser. The EntityHandler then handles locating and retrieving the resource.

       

      I discovered the Apache xml-commons resolver library and it seemed like it would do the trick. I just supply it with a catalog file that maps the (incorrect) system uri's to valid local paths.

       

      I did end up having to extend several Camel components to get the XSLT transform properly configured with the Apache CatalogResolver, but everything seems to be working fine in my proof of concept.

       

      So, now I'm at the point where I want to extract the new Camel components and the resolver setup into a separate bundle for general use by other bundles.

       

      I discovered that ServiceMix already has xml-commons resolver installed in the form of the "org.apache.servicemix.bundles.xmlresolver" bundle, so I figured I could just import the classes and use that.

       

      That's when I started encountering problems.

       

      The Apache CatalogResolver class looks for a file named "CatalogManager.properties" on the classpath. In particular, the code looks like:

       

      propertyFileURI = CatalogManager.class.getResource("/"+propertyFile);

      InputStream in =

           CatalogManager.class.getResourceAsStream("/"+propertyFile);

       

      Where 'propertyFile' == "CatalogManager.properties"

       

      The problem is that "CatalogManager.properties" file that I want it to load exists in my bundle. But, as far as I can tell, this code causes it to look in the bundle that the class was loaded from, aka 'org.apache.servicemix.bundles.xmlresolver', where the necessary files are not present.

       

      I had thought maybe I could maybe solve the problem by creating a fragment bundle and then attaching it to org.apache.servicemix.bundles.xmlresolver so that the required files would then show up on the classpath, but I get the error message in ServiceMix:

       

      org.osgi.framework.BundleException: Unresolved constraint in bundle 172: host; (bundle-symbolic-name=org.apache.servicemix.bundles.xmlresolver)

       

       

      Any ideas on how to solve this?

        • 1. Re: Resource loading problem related to OSGi
          socallag

          The error:  unresolved constraint in bundle 172: host; (bundle-symbolic-name=org.apache.servicemix.bundles.xmlresolver) indicates that the host bundle cannot be found.

           

          Has this bundle been installed?

          • 2. Re: Resource loading problem related to OSGi
            wjbustraan

            Yes, it shows up in the bundle listing, when doing an 'osgi list -s'. From what I can tell, support  for fragments in Apache Felix is just not complete. I tried creating a non-fragment bundle and setting Require-Bundle: org.apache.servicemix.bundles.xmlresolver and it resolved that bundle just fine.

             

            However, I came up with a working solution about an hour ago. On the ServiceMix forums, it was suggested that I bypass that particular properties file and instantiate and configure a CatalogResolver directly.

             

            This ended up working reasonably well. I had Spring pass in a file URL to my custom camel component that pointed to "classpath:catalog.xml". Internally, Spring transformed that into a bundle reference, so the URL ended up looking like: "bundle://168.0:1/catalog.xml". My custom camel component then used that to configure the CatalogResolver and use it to manufacture XSLT endpoints.