Announcement Announcement Module
Collapse

Spring Dynamic Modules forum decommissioned in favor of Eclipse Gemini Blueprint

With the official first release of Eclipse Gemini Blueprint shipped, the migration of the Spring Dynamic Modules code base to the Eclipse Foundation, as part of the Gemini project, has been completed.

As such, this forum has been decommissioned in favour of the Eclipse Gemini forums.
See more
See less
RMI fails with Spring DM when passing a domain object as a method argument Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • RMI fails with Spring DM when passing a domain object as a method argument

    Hi

    I'm having a problem making an RMI call using Spring DM when I pass my domain objects as method arguments. RMI calls work fine when I call methods that don't take arguments, or ones that take Java types as arguments. However when I pass my own domain objects as arguments, I get the error shown at the end of this post. It appears that the Spring classes cant find my domain classes. My domain objects are stored in a single bundle with the necessary packages exported in the manifest. All my bundles are running in the same OSGi container.

    As a test I added DynamicImport-Package: * to the manifests of the Spring jars shipped with Spring DM (spring-beans, spring-context, spring-core etc.), and this resolved the problem. I tested this with both the 2.5.5 and 2.5.6.A versions of the jars, with the same results in both cases.

    I also tested with version 2.5.6 of spring.jar, and the tests failed unless I added DynamicImport-Package: * to its' manifest. When I ran my tests using the org.springframework.bundle.spring_2.5.6 bundle that ships with Spring IDE, they worked. The manifest of that bundle already has a DynamicImport-Package: * entry. Do the spring-beans, spring-core jars etc need this line to be added too? (Or at least some fix to be made, as I know dynamic imports are not OSGi best practice).

    I know the stack trace below indicates I've no security manager enabled, but this is not the source of the issue. The server is attempting to download the class because it can't find it, but it should be able to find it as it is exported by my domain bundle.

    Has anyone come across this issue before? Is this an issue with the Spring jars or am I doing something wrong? If anyone is interested I can email an example to illustrate this problem.

    Thanks in advance for your help.

    David

    org.springframework.beans.factory.BeanCreationExce ption: Error creating bean wit
    h name 'rmiTestClient' defined in URL [bundleentry://16/META-INF/spring/bundle-c
    ontext.xml]: Error setting property values; nested exception is org.springframew
    ork.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:

    PropertyAccessException 1: org.springframework.beans.MethodInvocationExceptio n:
    Property 'rmiTestService' threw exception; nested exception is org.springframewo
    rk.remoting.RemoteAccessException: Could not access remote service [rmi://localh
    ost:50042/rmiTestServiceRmi]; nested exception is java.rmi.ServerException: Remo
    teException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested excep
    tion is:
    [B]java.lang.ClassNotFoundException: rmitest.common.RmiTestBean (no securit
    y manager: RMI class loader disabled)

    at org.springframework.beans.factory.support.Abstract AutowireCapableBean
    Factory.applyPropertyValues(AbstractAutowireCapabl eBeanFactory.java:1279)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBean
    Factory.populateBean(AbstractAutowireCapableBeanFa ctory.java:1010)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBean
    Factory.doCreateBean(AbstractAutowireCapableBeanFa ctory.java:472)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBean
    Factory$1.run(AbstractAutowireCapableBeanFactory.j ava:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBean
    Factory.createBean(AbstractAutowireCapableBeanFact ory.java:380)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getOb
    ject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistr
    y.getSingleton(DefaultSingletonBeanRegistry.java:2 22)
    at org.springframework.beans.factory.support.Abstract BeanFactory.doGetBe
    an(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean
    (AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean
    (AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.DefaultL istableBeanFactory.
    preInstantiateSingletons(DefaultListableBeanFactor y.java:429)
    at org.springframework.context.support.AbstractApplic ationContext.finish
    BeanFactoryInitialization(AbstractApplicationConte xt.java:728)
    at org.springframework.osgi.context.support.AbstractD elegatedExecutionAp
    plicationContext.completeRefresh(AbstractDelegated ExecutionApplicationContext.ja
    va:288)
    at org.springframework.osgi.extender.internal.depende ncies.startup.Depen
    dencyWaiterApplicationContextExecutor$CompleteRefr eshTask.run(DependencyWaiterAp
    plicationContextExecutor.java:145)
    at java.lang.Thread.run(Unknown Source)

  • #2
    David, RMI and serialization can be difficult inside OSGi due to the modularity constraints that can go head to head with the dynamic class loading that RMI offers. This being said, one can go around it by providing the specific import/export for known packages.
    In your case, the problem seems to be a basic one - in order for RMI to work properly a security manager (even a dummy one) needs to be set. This has nothing to do with Spring or OSGi, it's just a best practice enforced so that malicious code doesn't get loaded over the wire.

    Note that the security manager gets checked when new classes need to be downloaded - there are plenty of materials over internet but here is one I found googling around (which I recommend you do as well):http://is.gd/gVUE :

    If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path) for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations performed by downloaded code are subject to a security policy.

    Comment


    • #3
      Hi Costin

      Thanks a lot for the reply. However as I said in my original post, I am sure that the security manager is unrelated to the problem I'm having. Here's an extract from the stack trace I get when I set a security manager:

      org.springframework.beans.factory.BeanCreationExce ption: Error creating bean wit
      h name 'rmiTestClient' defined in URL [bundleentry://16/META-INF/spring/bundle-c
      ontext.xml]: Error setting property values; nested exception is org.springframew
      ork.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:

      PropertyAccessException 1: org.springframework.beans.MethodInvocationExceptio n:
      Property 'rmiTestService' threw exception; nested exception is org.springframewo
      rk.remoting.RemoteAccessException: Could not access remote service [rmi://localh
      ost:50042/rmiTestServiceRmi]; nested exception is java.rmi.ServerException: Remo
      teException occurred in server thread; nested exception is:
      java.rmi.UnmarshalException: error unmarshalling arguments; nested excep
      tion is:
      java.lang.ClassNotFoundException: rmitest.domain.RmiTestBean
      at org.springframework.beans.factory.support.Abstract AutowireCapableBean
      Factory.applyPropertyValues(AbstractAutowireCapabl eBeanFactory.java:1279)
      at org.springframework.beans.factory.support.Abstract AutowireCapableBean
      Factory.populateBean(AbstractAutowireCapableBeanFa ctory.java:1010)
      at org.springframework.beans.factory.support.Abstract AutowireCap

      It's almost identical to the previous one I posted - the class is still not found, but now the security manager isn't mentioned in the stack trace. The reason the class isn't found is because, as you said, there are class-loading problems between the bundle and the RMI class-loaders.

      I also posted this message on the OSGi Developer mailing list and have had confirmation from BJ Hargrave and others that they are aware that this problem exists with OSGi and RMI. Other posters on that thread confirmed that they have seen the same issue I've reported here. The general opinion was that it's possible to get around it by manipulating classloaders etc, but that this is very difficult. Most people recommended that we should use something like Newton or r-osgi instead.

      BJ Hargrave also confirmed that while the OSGi committee is aware of the issue, they aren't working on it at present. So for now I'm getting round the issue by adding dynamic imports to the Spring bundles. Do you think in future that Spring will try to address the RMI/OSGi classloading conflict so that developers will not be affected by it?

      Thanks
      David

      Comment


      • #4
        Have you looked at dm Server ? - it aims to solve exactly this sort of problems. I recommend you post a quick question on the forum and take the server for a spin.

        Comment


        • #5
          a solution

          I have faced the same problem, and solved it.

          My OSGi bundle expose a service in RMI via spring. The method exposed take as method arg a domain object contained in another bundle.

          The client (non OSGi) uses the bundle with the domain object as a plain old JAR.

          I got the same exception, and my diagnostic (thanks to the read of Spring source code) was that the Spring bundle that does the magic, ie. the real stuff (exposing service and marshall/unmarshall) has no rights to view the domain bundle.

          Then I have modified the MANIFEST.MF of the bundles org.springframework.context and org.springframework.aop to make them "omniscient" : i have added at the end of the MANIFEST "DynamicImport-Package: *". Maybe it is not the "good" way, but it worked like a charm.

          Costin may suggest a better way ?

          We are not using Spring DM server but Equinox with only the required spring bundles for our application. (To be honnest, i've not really understood the added value of DM server.)

          Comment


          • #6
            Instead of modifying the manifest, you can create a 'bridge' classloader between the two. It's more complicated but if done right, it can provide better control.

            dm Server aim is to address these cases where existing use cases clash with the modularity constrain and provide a proper way of solving them. bouil, there are some webinars and docs about dm Server. Additionally some demos and even blog entries but Rob and Adrian that explain the difference.
            You can also take a look at the samples and the sources.

            I'm not saying that dm Server is the answer, that's your choice to make. I'm just pointing out where to find more information about dm Server.

            Comment


            • #7
              Costin,

              Thanks for your reply. can you be more precise or do you have some wb links about
              create a 'bridge' classloader between the two
              ?

              Best regards.

              Comment


              • #8
                I know any resources out there - Spring DM and especially dm Server use this internally. I gave a presentation on such patterns at JavaZone last year but I'm not sure if they've published the sessions/slides.
                I guess good guess is to google for this topic and take a look at the sources. The basic idea is simple but getting it to behave properly (from a dynamic and concurrent point of view) is hard.

                Comment


                • #9
                  Originally posted by Costin Leau View Post
                  Have you looked at dm Server ? - it aims to solve exactly this sort of problems. I recommend you post a quick question on the forum and take the server for a spin.
                  Im using DM Server 1.0.2 but getting the same issue. And Solving with the same work around (changing the manifest).

                  How can I get it rigth with the DM Server? Where can I find samples or docs about?

                  Comment


                  • #10
                    A good starting page is dm Server home page: http://www.springsource.org/dmserver
                    There are also the forums where you can find help in case you encounter issues or need guidance: http://forum.springframework.org/forumdisplay.php?f=53

                    Comment


                    • #11
                      Hello Costin,

                      ist it somehow possible to get us a little more help about how to build a "bridge" classloader for theRMI usage ....
                      I do not want to modify the springframework/spring dm Bundles ... I have invested several hours now I do not get any further ...

                      Regards

                      Comment


                      • #12
                        Hello all,

                        a collegue gave me the most effective hint for this problem.

                        I did not want to manipulate the 3rd party spring bundles, but to build the bridge-classloader I was not smart enough :-).
                        So the poor man's, solution is to create a fragment for each spring bundle (core, beans, context) and add the DynamicImport-Package: * statement to the manifest ...

                        And by miracle and wonder everything works fine :-)

                        Cheers

                        Comment

                        Working...
                        X