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
Classloading in the form of
Class.forName()
is not a problem in any OSGi container. You problem here is that theMANIFEST.MF
file does not contain the right import declarations. One bundle should export theorg.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.
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 tobundle
.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).