Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Equinox » Classloader Issue
Classloader Issue [message #103510] Mon, 07 January 2008 07:44 Go to next message
Eclipse User
Originally posted by: ysralmasri.yahoo.com

Hi,

Please bear with me the long message, but it's almost all code.

I'm trying to use Equinox in a desktop application where I need first to
start a connection pool, store it in the registry using one service, then
pull it out of the registry in other services. For this purpose, I chose
Spring and dbcp to handle pooling for me. I'm using JDK 1.4, and HSQL.

The service that starts and registers the pool looks like this:

package com.company.project.service;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationC ontext;

public class PoolProvider implements BundleActivator {

public void start(BundleContext context) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "connector-data.xml" });

context.registerService(ApplicationContext.class.getName(),
ctx, null);
}
}

In connector-data.xml (which resides on /resources) I only define the
datasource. The METAINF.MF has this inside of it:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: InitialIdeas Plug-in
Bundle-SymbolicName: InitialIdeas
Bundle-Version: 1.0.0
Bundle-Activator: com.company.project.service.PoolProvider
Import-Package: org.osgi.framework;version="1.4.0"
Export-Package: org.springframework.context,
org.springframework.context.support
Bundle-ClassPath: .,
resources/,
lib/hsqldb.jar,
lib/commons-dbcp.jar,
lib/commons-pool.jar,
lib/spring.jar,
lib/commons-logging.jar,
lib/xalan.jar,
lib/xercesImpl.jar,
lib/xml-apis.jar

This service started well, and log messages indicated that Spring has
picked up the definition and initiated successfully the datasource bean.

In another service I have domain objects, interfaces, and implementations
for accessing the database. The implementation is simple:

package com.company.project.dao.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import com.company.project.dao.AccountDao;
import com.company.project.dao.domain.Customer;

public class JdbcAccountDao extends JdbcDaoSupport implements AccountDao {
private static final String CUSTOMER_BY_ID_SELECT = "select firstName,
lastName, street, city from customer where id=?";

public Customer findCustomerById(Integer id) {

List matches = getJdbcTemplate().query(CUSTOMER_BY_ID_SELECT,
new Object[] { id }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException, DataAccessException {
Customer cusotmer = new Customer();
cusotmer.setFirstName(rs.getString(1));
cusotmer.setLastName(rs.getString(2));
cusotmer.setStreet(rs.getString(3));
cusotmer.setCity(rs.getString(3));
return cusotmer;
}
});

return matches.size() > 0 ? (Customer) matches.get(0) : null;
}

}

And this how MANIFEST.MF looks like:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: AccountResources Plug-in
Bundle-SymbolicName: AccountResources
Bundle-Version: 1.0.0
Export-Package: com.company.project.dao,
com.company.project.dao.domain,
com.company.project.dao.jdbc
Bundle-ClassPath: .,
lib/spring.jar,

This one is simple and its sole purpose is to expose some classes to the
consumers. The consumer is a third service that has this as activator:

package com.company.project.service;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationC ontext;

import com.company.project.dao.AccountDao;

public class AccountFinder implements BundleActivator {

public void start(BundleContext context) {
System.out.println("Entering start for AccountFinder");
ServiceTracker finderTracker = new ServiceTracker(context,
ApplicationContext.class
.getName(), null);
finderTracker.open();
ApplicationContext ctx = (ApplicationContext)
finderTracker.getService();
if (ctx == null)
ctx = new ClassPathXmlApplicationContext(new String[] {
"connector-data.xml", "connector-data-jdbc.xml" });
else
ctx = new ClassPathXmlApplicationContext(
new String[] { "connector-data-jdbc.xml" }, ctx);
context.registerService(ApplicationContext.class
.getName(), ctx, null);

AccountDao dao = (AccountDao) ctx.getBean("accountDao");
System.out.println("Residence street is: "
+ dao.findCustomerById(new Integer(6)).getStreet());
}
}

Here I'm picking up the pool, if present, I just add the wiring between
the pool and my bean declared in connector-data-jdbc.xml, otherwise I load
definitions for both datasource and my bean together, then I send the
whole thing back to the registry. The manifest reads:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: AccountService Plug-in
Bundle-SymbolicName: AccountService
Bundle-Version: 1.0.0
Bundle-Activator: com.company.project.service.AccountFinder
Import-Package: org.osgi.framework;version="1.4.0",
org.osgi.util.tracker;version="1.3.3",
org.springframework.context,
org.springframework.context.support,
com.company.project.dao,
com.company.project.dao.domain,
com.company.project.dao.jdbc
Bundle-ClassPath: .,
resources/,
bin/,
lib/hsqldb.jar,
lib/commons-dbcp.jar,
lib/commons-pool.jar,
lib/commons-logging.jar,
lib/xalan.jar,
lib/xercesImpl.jar,
lib/xml-apis.jar

And connector-data-jdbc.xml has the following bean definition:

<bean id="accountDao"
class="com.company.project.dao.jdbc.JdbcAccountDao">
<property name="dataSource" ref="dataSource" />
</bean>

Now to the problem. When I run the third service I get the following
error (part of the stack omitted for clarity):

java.lang.ClassNotFoundException:
com.company.project.dao.jdbc.JdbcAccountDao
at java.lang.ClassLoader.findClass(ClassLoader.java:341)
at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
at
org.eclipse.core.runtime.internal.adaptor.ContextFinder.load Class(ContextFinder.java:124)
at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
at org.springframework.util.ClassUtils.forName(ClassUtils.java: 230)
...

Nested Exception:
org.springframework.beans.factory.CannotLoadBeanClassExcepti on: Cannot
find class [com.company.project.dao.jdbc.JdbcAccountDao] for bean with
name 'accountDao' defined in class path resource
[connector-data-jdbc.xml]; nested exception is
java.lang.ClassNotFoundException:
com.company.project.dao.jdbc.JdbcAccountDao
at
org.springframework.beans.factory.support.AbstractBeanFactor y.resolveBeanClass(AbstractBeanFactory.java:1160)

I'm wondering why Spring is unable to find JdbcAccountDao even though it's
exported using "Export-Package: com.company.project.dao.jdbc"? Is there
anything wrong I'm doing here? Do I need to tell Spring anything special
about its classloader?

Help is greatly appreciated as we are about to decide the path we should
pursue based on this POC.

Many thanx,

Yasser
Re: Classloader Issue [message #103736 is a reply to message #103510] Fri, 11 January 2008 20:13 Go to previous messageGo to next message
Thomas Watson is currently offline Thomas Watson
Messages: 436
Registered: July 2009
Senior Member
Hi Yasser,

Spring Source has been working on OSGi/Spring integration for a while
now. Have you had a look at the Spring Dynamic Modules subproject at
Spring Source http://www.springframework.org/osgi

I think part of the problem is that you are using the spring libraries
which expect a J2EE environment where the context classloader has a
clear application binding. These types of libraries generally run into
classloader issues when migrated over to an OSGi environment. The good
new here is that the Spring DM project is making great progress with
Spring/OSGi integration.

HTH.

Tom.
Re: Classloader Issue [message #103759 is a reply to message #103736] Sat, 12 January 2008 15:22 Go to previous message
Eclipse User
Originally posted by: ysralmasri.yahoo.com

Thanks Tom for taking the time to read all this.

Your suggestion is valid, but I thought I could give it sometime to mature
while playing with my own simple look for serving Spring-based beans for
the rest of the bundles.

Anyway I discovered the problem, it was due to context switching for the
class loader outlined here:

http://wiki.eclipse.org/Context_Class_Loader_Enhancements

There you can also find the solution.

Regardless whether I'm going to use Spring-OSGi or not, this kind of
issues does exist for two-way dependent frameworks like Hibernate, so a
solution has to be found.

Many thanks again.

Yasser
Previous Topic:Unresolved imports in OSGi servlet
Next Topic:Equinox JSP example - how to run it?
Goto Forum:
  


Current Time: Thu Oct 23 14:39:05 GMT 2014

Powered by FUDForum. Page generated in 0.02565 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software