Community   SpringSource   Projects    Downloads    Documentation    Forums    Training   Exchange   Blogs

Go Back   Spring Community Forums > Core Spring Projects > Spring Dynamic Modules

Reply
 
Thread Tools Display Modes
  #1  
Old Jun 5th, 2008, 05:07 AM
regunath regunath is offline
Junior Member
 
Join Date: Jun 2008
Posts: 5
Default Running sample bundle on Equinox - NPE at BundleLoader.createBCL

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>
I then wrote a sample class like this:

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();
	}
	
	}
}
I was able to see a ServiceReference for the simple-service bundle. I however get an error trace like below :

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
I wonder why I get a NullPointerException in the Eclipse BundleLoader.createBCL() method. Any pointers or help is much appreciated.
Reply With Quote
  #2  
Old Jun 5th, 2008, 01:34 PM
Costin Leau's Avatar
Costin Leau Costin Leau is offline
Spring DM Lead
Spring Modules TeamSpring Team
 
Join Date: Jan 2005
Location: Bucharest, Romania
Posts: 5,015
Default

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;
    }
If you're using this version then it's likely a nasty bug (maybe caused by threading if the error doesn't occur repeatedly).
__________________
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
Reply With Quote
  #3  
Old Jun 6th, 2008, 01:26 AM
regunath regunath is offline
Junior Member
 
Join Date: Jun 2008
Posts: 5
Default

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 was not sure if the way I have used the Spring-DM platform is OK. My need is to invoke an OSGi service (Spring bean exposed as service) from a non-OSGi environment.

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 got a ClassCastException on the MyService interface implementation. I guess that was because the bundle and the test class load the MyService type using different classloaders. How can I share classes between OSGi bundles and non OSGi code like this class that wants to invoke an OSGi service?

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);
before the lookup and it came through.
Finally, these are the issues:
  • Potential threading issue. Dirty hack was to call Thread.sleep(). Need a better option
  • ClassCastException if the service is looked up using BundleContext.getService(ServiceReference). Need a solution to share classes easily between an OSGi bundle and a non OSGi piece of code that invokes the bundle. Are fragment packages/extensions the solution? Does Spring DM have any support to create these?
  • The NPE in createBCL() method of Equinox BundleLoader class when the Spring DM OsgiBundleXmlApplicationContext is refreshed

Appreciate your response and any help in resolving the above issues.
Reply With Quote
  #4  
Old Jun 6th, 2008, 02:25 AM
Costin Leau's Avatar
Costin Leau Costin Leau is offline
Spring DM Lead
Spring Modules TeamSpring Team
 
Join Date: Jan 2005
Location: Bucharest, Romania
Posts: 5,015
Default

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
Reply With Quote
  #5  
Old Jun 9th, 2008, 06:02 AM
regunath regunath is offline
Junior Member
 
Join Date: Jun 2008
Posts: 5
Default

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
An in the simple service sample's manifest , I import the package like:

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
It would have been good if I was able to access the service via the OsgiBundleXmlApplicationContext though.
Reply With Quote
  #6  
Old Jun 20th, 2008, 07:25 AM
Costin Leau's Avatar
Costin Leau Costin Leau is offline
Spring DM Lead
Spring Modules TeamSpring Team
 
Join Date: Jan 2005
Location: Bucharest, Romania
Posts: 5,015
Default

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
Reply With Quote
  #7  
Old Jun 20th, 2008, 08:09 AM
regunath regunath is offline
Junior Member
 
Join Date: Jun 2008
Posts: 5
Default

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.
Reply With Quote
  #8  
Old Jun 20th, 2008, 08:33 AM
Costin Leau's Avatar
Costin Leau Costin Leau is offline
Spring DM Lead
Spring Modules TeamSpring Team
 
Join Date: Jan 2005
Location: Bucharest, Romania
Posts: 5,015
Default

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
Reply With Quote
  #9  
Old Jun 20th, 2008, 08:51 AM
regunath regunath is offline
Junior Member
 
Join Date: Jun 2008
Posts: 5
Default

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
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 10:09 AM.


Contegix provides first-class managed hosting and partial sponsorship of these forums.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.