Announcement Announcement Module
No announcement yet.
How to access classpath resources of another bundle? Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to access classpath resources of another bundle?


    I'm trying to understand how can I access classpath resources of a bundle from other ones.

    I've created 2 test bundles, one of them tries to access resources of another by using getClass().getClassLoader().getResource(), but it fails to do that. I tried to add Eclipse-BundlePolicy and Eclipse-RegisterBuddy to manifests of the bundles, it didn't help. Also I tried to archive both bundles into a single par, but it didn't help either.

    Please point me to documentation/article/whatever

    Last edited by diggerk; Jun 8th, 2009, 10:37 AM.

  • #2
    The modularity chapter of the OSGi core spec. explains resource loading and bundle classpath in some detail.

    In short, you need to export a package corresponding to the directory relative to a bundle classpath entry containing the resource and then import that package from the other bundle.

    Note that although '-' isn't allowed in package names, some OSGi implementations, such as Equinox, permit it. So, for example, you can export "META-INF" should you need to.


    • #3
      Glyn, thanks for the tip. I've got the idea - OSGi doesn't let to import resources which are in the default package of other bundles. OK, I moved all resources from default package to specific ones, but I still have problems with resources.

      Here is the description of my testcase.

      I have 3 modules:

      1. testres. It contains a resource in a package "com.testres" and exports this package.
      2. testlib. It contains a resource in a package "com.tetlib", exports this package. Also it contains class TestLib with a static method checkResources which tries to find all three resources I have in different bundles and print the results.
      3. testclient. It contains a resource in a package "com.testclient", exports this package. Also it has OSGi activator ClientActivator which calls com.testlib.TestLib.checkResources and also repeats the logic of this method by using ClientAtivator class loader.

      I packaged all these three bundles in a par and deployed it under SpringDM 1.0.2.

      Results: ClientActivator sees all resources, but TestLib class sees only a testlib resource and doesn't see test and testclient resources. What I need is that TestLib should see all the resources. IMHO this behaviour is similar to Hibernate which should see resources and classes defined in bundles which use it. As I read in the dmserver spec, packaging bundles in a par should solve these problems with resources but it doesn't That's what the spec says:

      The modules of a PAR have their exported packages imported by the synthetic context bundle which is used for thread context class loading. So, for example, hibernate will be able to load classes of any of the exported packages of the modules in a PAR file using Class.forName() (or equivalent).
      So how to make it work?



      • #4
        The bundles of a PAR need to share resources between them using import-package and export-package rather than relying on the synthetic context bundle. The synthetic context is provided so that 3rd party libraries *outside* the PAR will get suitable thread context class loading for the PAR.

        As described, I would expect each bundle to be able to see only its own resources, which I think matches the behaviour you are finding. So you need to add import-package statements to the bundles that need to see resources in other bundles.

        Please try that and see what progress you make.


        • #5

          If I add Import-Package:testclient,testres to testlib manifest, than it works well, but it's not what I need.

          I have a third-party library which could be configured by providing a configuration file which name is defined via special system property. So I have a third-part library bundle and I have my client bundle. I want library bundle to see configuration file which lives inside my client bundle. I can't modify library's manifest definition by importing every client's package which uses it.

          BTW the library I'm talking about is Oracle Coherence. I think it should be supported...



          • #6
            Ok, then the next step is to remove the 3rd party library from the PAR file and add it to the bundles/usr directory so that when it is called, it should perform class and resource loading from the thread context class loader of the PAR (which will import all the resource packages exported by the PARs bundles).

            Note that the PAR bundles will need to have some OSGi dependency on the 3rd party library to ensure that the 3rd party library is installed (and started).

            Please try that and see how close you get to the desired behaviour. I am not familiar with Oracle Coherence and its class/resource loading strategy, so I'm afraid you may have to do some investigation of that.

            BTW, if/when you are ready, you may like to submit a request for the 3rd party library to be added to the Enterprise Bundle Repository. See the EBR FAQ for details.

            Hope that helps!


            • #7
              Unfortunately it doesn't help.

              I've tried to deploy testlib as a separate bundle. One of the bundles inside PAR performs import-bundle on that bundle. It didn't changed my results - library bundle didn't see client's resources.

              Also I tried to import my library as an OSGi library, i.e. I created .libd file and changed import-bundle to import-library accordingly. It didn't help either.


              • #8
                Bear in mind that import-library and import-bundle end up importing packages, so switching between them won't make much difference.

                Let's slow down and analyse your application a bit. The PAR now contains testRes and testClient which export their resource packages. So the synthetic context bundle generated for the PAR will import those resource packages and get wired to testRes and testClient.

                The normal use case is that the PAR is invoked via a servlet in which case dm Server sets the TCCL to the class loader of the synthetic context bundle while processing the request.

                So I'm wondering how your setup invokes the PAR file and whether the synthetic context is the TCCL when testLib gets control. You could stop inside testLib.checkResources using a debugger and take a look at the TCCL. You should be able to see whether it is set and, if it is set, which bundle it was obtained from.


                • #9
                  In my case PAR is not invoked via a servlet.

                  In my testcase I invoke LibTest.checkResources from a class which implements BundleActivator interface and which sits in my client bundle.

                  In real-world scenario Coherence configuration code is triggered by some Spring bean's afterPropertiesSet() method which is invoked when bundle starts. So in both cases there's no any servlet request. Is there a way to force dmserver to use TCCL in this case?

                  As for Hibernate - if it's used via Spring, then it's being initialized when bundles start and there's no any http requests. So how does it work then?


                  • #10
                    Originally posted by Glyn Normington View Post
                    So I'm wondering how your setup invokes the PAR file and whether the synthetic context is the TCCL when testLib gets control. You could stop inside testLib.checkResources using a debugger and take a look at the TCCL. You should be able to see whether it is set and, if it is set, which bundle it was obtained from.
                    Yeah, you're right - TCCL is set to the synthetic context of the PAR. So thanks a lot, now I understand how this could work at all. Still looks like the problem is that Coherence doesn't use TCCL to find resources, probably it just uses current classloader. Well at least now I know what to ask Oracle guys for :-)



                    • #11
                      Congratulations on narrowing this down. Good luck with Oracle...


                      • #12
                        Hi Andrew

                        One other approach which might help is to put the configuration file in a fragment which specifies a host of the Oracle coherence bundle. Then the configuration file can be loaded directly from the coherence bundle's class loader. Just a thought...