4
votes

We are performing a POC in our project, where in we send SOAP based request and correspondingly get a SOAP response from a web service. We aim to leverage webservices template (client side API) provided by spring framework in our application. As per our architecture, we create an OSGI compliant bundle (for our code that uses webservices template API to interact with the web service) which is then deployed into the Apache Felix container. We have also installed all the dependent OSGI compliant bundles in the Felix container so that all the dependencies are resolved.

As per the webservices template, the default Web Service Message sender is HttpUrlConnectionMessageSender which is dynamically loaded at run time by the class loader. As per my understanding, we are getting the below exception because the Felix container is not able to load the class from the dependent OSGI bundle (web services bundle contains the HttpUrlConnectionMessageSender).Please refer to the exception logs below.

* org.springframework.beans.factory.BeanInitializationException: Could not find default strategy class for interface [org.springframework.ws.transport.WebServiceMessageSender]; nested exception is java.lang.ClassNotFoundException:org.springframework.ws.transport.http.HttpUrlConnectionMessageSender at  org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:126)

    at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:90)

    at org.springframework.ws.client.core.WebServiceTemplate.initMessageSenders(WebServiceTemplate.java:320)

    at org.springframework.ws.client.core.WebServiceTemplate.initDefaultStrategies(WebServiceTemplate.java:306)

    at org.springframework.ws.client.core.WebServiceTemplate.<init>(WebServiceTemplate.java:143)

    at test.soapservice.service.SOAPServiceImpl.<init>(SOAPServiceImpl.java:40)

    at test.soapservice.service.SOAPServiceActivator.start(SOAPServiceActivator.java:17)

    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:641)

    at org.apache.felix.framework.Felix.activateBundle(Felix.java:1977)

    at org.apache.felix.framework.Felix.startBundle(Felix.java:1895)

    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:944)

    at org.apache.felix.gogo.command.Basic.start(Basic.java:729)

Caused by: java.lang.ClassNotFoundException: org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)

    at java.security.AccessController.doPrivileged(Native Method)

    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)

    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)

    at org.springframework.util.ClassUtils.forName(ClassUtils.java:211)

    at org.springframework.util.ClassUtils.forName(ClassUtils.java:164)

    at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:114)

As per my understanding,Felix container is unable to dynamically load the class using ClassUtils.forName() which exists in another bundle. I see this as a collaboration issue where the current bundle has a different class loader as opposed to class loader of dependent bundle.

Did someone from this community have encountered the same exception? If yes, then what were steps taken by you to resolve the run time class dependency? Please share your thoughts/pointers to resolve the above issue.A quick response would be highly appreciated and may help us to make our POC successful.

Thanks in advance, Mridul Chopra

1
Have you definitely added org.springframework.ws.transport.http to the manifest?artbristol
Loading classes by name should not be a problem at all, just be aware that you cannot use bytecode-inspecting tooling (bnd) to generate your manifest. You will need to customize your manifest, and import org.springframework.ws.transport.http, as artbristol says. Could you show your manifest?Angelo van der Sijpt

1 Answers

0
votes

Classloading in the form of Class.forName() is not a problem in any OSGi container. You problem here is that the MANIFEST.MF file does not contain the right import declarations. One bundle should export the org.springframework.ws.transport package, while your bundle should import the same package.

If you are using Maven to build your bundle, you can use the Felix Bundle Plugin to generate the right manifest information.

<plugins>
  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
      <instructions>
        <Private-Package>my.private.package.*</Private-Package>
      </instructions>
    </configuration>
  </plugin>
</plugins>

This should inspect your code and add imports for anything that is not inside your "private" package scope. One other thing you should do to make this work is to set the packaging type to bundle.

<packaging>bundle</packaging>

But, the examples above is when you are using Maven as a build tool. If you are using Gradle, you can use the Gradle OSGi plugin to build manifest. Or, if using Ant you can use SpringSource Bundlor project (btw, which also has a Maven plugin).