|
#1
|
|||
|
|||
|
Hi,
I am experimenting with Spring-DM to serve as a container for my Spring beans exposed as services. Contrary to the samples provided, I would like to deploy and invoke a bundle standalone and actually outside of Eclipse. As per the documentation, I built the bundle for the "simple-service" sample. Again, in order to access the service, I created another Spring bean XML with relevant contents like Code:
<osgi:reference id="service" interface="org.springframework.osgi.samples.simpleservice.MyService"/> <bean id="consumerBean" class="org.springframework.osgi.samples.simpleservice.ServiceConsumer"> <property name="service" ref="service"/> </bean> Code:
package org.springframework.osgi.samples.simpleservice;
public class OSGiTest {
private static final String[] paths = new String[] {
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/log4j.osgi-1.2.15-SNAPSHOT.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/commons-logging_all-2.0.0.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/aopalliance.osgi-1.0-SNAPSHOT.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-core-2.5.4.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-beans-2.5.4.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-context-2.5.4.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-aop-2.5.4.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-io-1.1.0-m2.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-core-1.1.0-m2.jar",
"D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-extender-1.1.0-m2.jar",
};
public static void main(String args[]) throws Exception {
EquinoxPlatform runtime = new EquinoxPlatform();
runtime.start();
BundleContext context = runtime.getBundleContext();
for (int i = 0; i < paths.length; i++) {
FileInputStream fis = new FileInputStream(paths[i]);
Bundle bundle = context.installBundle("Test " + i,fis);
bundle.start();
}
FileInputStream fis = new FileInputStream("D:/WorkTools/spring-osgi-1.1.0-m2/src/samples/simple-service/simple-service-bundle/target/simple-service-bundle-1.1.0-m2.jar");
Bundle bundle = context.installBundle("Simple-Service-Sample",fis);
bundle.start();
Bundle[] bundles = context.getBundles();
for (int j = 0; j < bundles.length; j++) {
ServiceReference[] sr = bundles[j].getRegisteredServices();
if (sr != null) {
for (int i = 0; i < sr.length; i++) {
System.out.println("Service Reference ---> " + sr[i]);
}
}
}
OsgiBundleXmlApplicationContext applicationContext = new OsgiBundleXmlApplicationContext(
new String[] {"file:///D:/WorkTools/spring-osgi-1.1.0-m2/src/samples/simple-service/simple-service-bundle/testbean.xml"});
applicationContext.setBundleContext(context);
applicationContext.refresh();
((ServiceConsumer)applicationContext.getBean("consumerBean")).foo();
bundle.stop();
//runtime.stop();
}
}
}
Code:
Service Reference ---> {org.springframework.osgi.samples.simpleservice.MyService}={org.springframework.osgi.bean.name=simpleService, Bundle-SymbolicName=org.springframework.osgi.samples.simpleservice, Bundle-Version=1.0, service.id=21}
Service Reference ---> {org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext, org.springframework.osgi.context.ConfigurableOsgiBundleApplicationContext, org.springframework.context.ConfigurableApplicationContext, org.springframework.context.ApplicationContext, org.springframework.context.Lifecycle,
........< other interfaces listed here >
org.springframework.beans.factory.DisposableBean}={org.springframework.context.service.name=org.springframework.osgi.samples.simpleservice, Bundle-SymbolicName=org.springframework.osgi.samples.simpleservice, Bundle-Version=1.0.0, service.id=22}
2008-06-05 14:27:17,031 [main] INFO [factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from OSGi resource[file:///D:/WorkTools/spring-osgi-1.1.0-m2/src/samples/simple-service/simple-service-bundle/testbean.xml|bnd.id=0|bnd.sym=system.bundle]
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from OSGi resource[file:///D:/WorkTools/spring-osgi-1.1.0-m2/src/samples/simple-service/simple-service-bundle/testbean.xml|bnd.id=0|bnd.sym=system.bundle]; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)
...... <stack trace from Spring framework followed by>
Caused by: java.lang.NullPointerException
at org.eclipse.osgi.framework.internal.core.BundleLoader.createBCL(BundleLoader.java:664)
at org.eclipse.osgi.framework.internal.core.BundleLoader.createBCLPrevileged(BundleLoader.java:639)
at org.eclipse.osgi.framework.internal.core.BundleLoader.createClassLoader(BundleLoader.java:313)
at org.eclipse.osgi.framework.internal.core.BundleLoader.getResources(BundleLoader.java:304)
at org.eclipse.osgi.framework.internal.core.BundleHost.getResources(BundleHost.java:270)
at org.springframework.osgi.util.BundleDelegatingClassLoader.findResources(BundleDelegatingClassLoader.java:137)
at java.lang.ClassLoader.getResources(ClassLoader.java:1015)
at org.springframework.core.io.support.PropertiesLoaderUtils.loadAllProperties(PropertiesLoaderUtils.java:103)
at org.springframework.beans.factory.xml.PluggableSchemaResolver.getSchemaMapping(PluggableSchemaResolver.java:128)
at org.springframework.beans.factory.xml.PluggableSchemaResolver.resolveEntity(PluggableSchemaResolver.java:107)
at org.springframework.beans.factory.xml.DelegatingEntityResolver.resolveEntity(DelegatingEntityResolver.java:85)
at org.springframework.osgi.context.support.DelegatedEntityResolver.resolveEntity(DelegatedEntityResolver.java:59)
at com.sun.org.apache.xerces.internal.util.EntityResolverWrapper.resolveEntity(EntityResolverWrapper.java:148)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.resolveEntity(XMLEntityManager.java:701)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.resolveDocument(XMLSchemaLoader.java:599)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.findSchemaGrammar(XMLSchemaValidator.java:2454)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1807)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:705)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:324)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(XMLNSDocumentScannerImpl.java:773)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1794)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:368)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:834)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:250)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:292)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)
... 14 more
|
|
#2
|
||||
|
||||
|
This is indeed odd. What version of Equinox are you using? Try using another version and see if that helps. Inside Spring-DM we're testing against Equinox 3.2.2 for example.
For the record this how the code looks like in Equinox 3.2.2: Code:
BundleClassLoader createBCL(final BundleProtectionDomain pd, final String[] cp) {
BundleClassLoader bcl = bundle.getBundleData().createClassLoader(BundleLoader.this, pd, cp);
// attach existing fragments to classloader
org.osgi.framework.Bundle[] fragments = bundle.getFragments();
if (fragments != null)
for (int i = 0; i < fragments.length; i++) {
AbstractBundle fragment = (AbstractBundle) fragments[i];
try {
bcl.attachFragment(fragment.getBundleData(), fragment.domain, fragment.getBundleData().getClassPath());
} catch (BundleException be) {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
}
}
// finish the initialization of the classloader.
bcl.initialize(); <-- NPE occurs
return bcl;
}
__________________
Costin Leau SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source" http://twitter.com/costinl Please use [ c o d e ] [ / c o d e ] tags |
|
#3
|
|||
|
|||
|
Thanks for the response. I use the Equinox version that came bundled with "spring-osgi-1.1.0-m2" distribution and the jar says "org.eclipse.osgi-3.2.2.jar". Btw, I use JDK 1.5.
The classpath entries for this project in my Eclipse environment(v 3.1.0) looks like this: Code:
<?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="simple-service-bundle/src/main/java"/> <classpathentry kind="src" path="simple-service-bundle/src/test/java"/> <classpathentry kind="src" path="simple-service-integration-test/src/test/java"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-context-2.5.4.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-core-2.5.4.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-test-2.5.4.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-beans-2.5.4.jar"/> <classpathentry exported="true" kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/org.eclipse.osgi-3.2.2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/junit.osgi-3.8.2-SNAPSHOT.jar"/> <classpathentry kind="lib" path="D:/projects/momentum/buildscripts/lib/build/log4j-1.2.14.jar"/> <classpathentry kind="lib" path="D:/projects/momentum/buildscripts/lib/build/commons-logging-1.0.4.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/slf4j-log4j12-1.4.3.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/slf4j-api-1.4.3.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-web-extender-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-core-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-extender-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-io-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-mock-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-test-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/dist/spring-osgi-web-1.1.0-m2.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/spring-aop-2.5.4.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/aopalliance.osgi-1.0-SNAPSHOT.jar"/> <classpathentry kind="lib" path="D:/WorkTools/spring-osgi-1.1.0-m2/lib/org.apache.felix.main-1.0.4.jar"/> <classpathentry kind="output" path="simple-service-bundle/target/test-classes"/> </classpath> I even tried looking up the service directly like: Code:
ServiceReference sr =context.getServiceReference(MyService.class.getName()); System.out.println(((MyService)context.getService(sr)).stringValue()); I also noticed a threading issue. The above code fails at the ServiceReference lookup with a NPE. I suspected a threading issue and added a line like Code:
Thread.sleep(3000); Finally, these are the issues:
Appreciate your response and any help in resolving the above issues. |
|
#4
|
||||
|
||||
|
If you need to share information between OSGi and non-OSGi the consider either doing some serialization/deserialization or delegating the common classes to a common/root classloader (boot path delegation).
For your case, Spring-DM could simply be installed as a bundle rather then creating it from outside OSGi. The synchronization issue appears because the context is created in a asynch manner so you have to wait for the application context to published as a service if you want to be sure that everything is in place. As for the NPE, as I said, it's a strange case which indicates a bug - you are probably using the OSGi platform in the wrong way but still you should get a validation error rather then a cryptic NPE.
__________________
Costin Leau SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source" http://twitter.com/costinl Please use [ c o d e ] [ / c o d e ] tags |
|
#5
|
|||
|
|||
|
Costin,
Thanks for the tip around the boot path delegation. I am now able to access an OSGi service(exposed via Spring DM) from a non OSGi class. The NPE with the BundleLoader class still exists though. I do a direct ServiceReference lookup on the BundleContext and then get the Service object from it. This works. Creating an extension to the system bundle (fragment) works. The manifest of my extension looks like this: Code:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Created-By: Apache Maven Built-By: m1000350 Build-Jdk: 1.5.0 Bundle-Version: 1.0 Bundle-SymbolicName: org.springframework.osgi.samples.simpleservice.boot Bundle-Name: Simple-Service-Sample-boot Bundle-Vendor: Spring Framework Fragment-Host: system.bundle Export-Package: org.springframework.osgi.samples.simpleservice Bundle-ManifestVersion: 2 Code:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Created-By: Apache Maven Built-By: m1000350 Build-Jdk: 1.5.0 Bundle-Version: 1.0 Spring-Context: *;create-asynchronously=false Bundle-SymbolicName: org.springframework.osgi.samples.simpleservice Bundle-Name: Simple-Service-Sample Bundle-Vendor: Spring Framework Bundle-ManifestVersion: 2 Import-Package: org.springframework.osgi.samples.simpleservice |
|
#6
|
||||
|
||||
|
Spring-DM app ctx (as the rest of the other OSGi entities) can access the services available in the OSGi service registry. So as long as the service is available it can be properly accessed however, my understanding is that due to your configuration of accessing the service from outside OSGi, you might be running into class cast exceptions.
Basically, as long as your code simply interacts with the OSGi service registry, Spring-DM can do the same.
__________________
Costin Leau SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source" http://twitter.com/costinl Please use [ c o d e ] [ / c o d e ] tags |
|
#7
|
|||
|
|||
|
Costin,
Thanks for the response. Your suggestion to use fragment bundles to get around the ClassCastException works. But as highlighted in my post, I was able to access the service via the OSGi interfaces of ServiceReference and Service and not via the OsgiBundleXmlApplicationContext due to the NPE as shown in the stack trace. |
|
#8
|
||||
|
||||
|
Right - have you tried using a different Equinox version or reporting the problem? I assume the problem might be caused by the fact that you are attaching a fragment to the system bundle which might be handled differently.
__________________
Costin Leau SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source" http://twitter.com/costinl Please use [ c o d e ] [ / c o d e ] tags |
|
#9
|
|||
|
|||
|
Costin,
You might have noticed from the classpath details in my post that I use Equinox from "spring-osgi-1.1.0-m2/lib/org.eclipse.osgi-3.2.2.jar". FYI, I got the NPE error even when I didnot have the fragment bundle. The error comes when I do a App context refresh() after creating it. As you can see, this is before I do an appContext.getBean() Code:
OsgiBundleXmlApplicationContext applicationContext = new OsgiBundleXmlApplicationContext(new String[] {"file:///D:/WorkTools/spring-osgi-1.1.0-m2/src/samples/simple-service/simple-service-bundle/testbean.xml"});
applicationContext.setBundleContext(context);
applicationContext.refresh(); <--- get NPE when this is called
((ServiceConsumer)applicationContext.getBean("consumerBean")).foo(); <-- ClassCastException can occur only after i.e here
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|