6
votes

I am currently testing out using OSGi. I am running this through Eclipse. I want to have my DAO layer as part of an OSGi solution, but my first stumbling block is this error:

Jun 29, 2009 6:12:37 PM org.hibernate.cfg.annotations.Version <clinit>
INFO: Hibernate Annotations 3.3.0.GA
Jun 29, 2009 6:12:37 PM org.hibernate.ejb.Version <clinit>
INFO: Hibernate EntityManager 3.3.0.GA
Jun 29, 2009 6:12:37 PM org.hibernate.ejb.Ejb3Configuration configure
INFO: Could not find any META-INF/persistence.xml file in the classpath

I have tried putting the persistence.xml file in a lot of different places, to no avail. Any ideas on what I am doing wrong?

Is there a way to manually load the persistence.xml?

The activator looks like this:

package com.activator;


public class PersistenceActivator implements BundleActivator {

    @Override
    public void start(BundleContext arg0) throws Exception {

        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("postgres");
        EntityManager em = emf.createEntityManager();

        SimpleDaoImpl dao = new SimpleDaoImpl();
        dao.setEntityManager(em);

    }

    @Override
    public void stop(BundleContext arg0) throws Exception {
        // TODO Auto-generated method stub

    }

}

Here is what my directory structure looks like:

alt text http://www.freeimagehosting.net/uploads/7b7b7d2d30.jpg

Here is my Manifest.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Dao Plug-in
Bundle-SymbolicName: Dao
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version="1.4.0"
Bundle-Activator: com.activator.PersistenceActivator
Export-Package: com.dao.service
Require-Bundle: HibernateBundle;bundle-version="1.0.0"

HibernateBundle contains all of the Hibernate and Persistence Jars.

Here is my Persistence.xml

<?xml version="1.0" encoding="UTF-8"?>

<persistence>

    <!-- Sample persistence using PostgreSQL. See postgres.txt. -->
    <persistence-unit name="postgres" transaction-type="RESOURCE_LOCAL">

        <properties>


            <property name="hibernate.archive.autodetection" value="class" />

            <!--
                Comment out if schema exists & you don't want the tables dropped.
            -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <!-- drop/create tables @startup, drop tables @shutdown -->


            <!-- Database Connection Settings -->
            <property name="hibernate.connection.autocommit">true</property>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="hibernate.connection.username" value="postgres" />
            <property name="hibernate.connection.password" value="postgres" />
            <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/test" />

            <!-- Not sure about these...  -->
            <property name="hibernate.max_fetch_depth">16</property>
            <property name="hibernate.jdbc.batch_size">1000</property>
            <property name="hibernate.use_outer_join">true</property>
            <property name="hibernate.default_batch_fetch_size">500</property>

            <!-- Hibernate Query Language (HQL) parser. -->
            <property name="hibernate.query.factory_class">
                org.hibernate.hql.ast.ASTQueryTranslatorFactory</property>

            <!-- Echo all executed SQL to stdout -->
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">false</property>

            <!-- Use c3p0 for the JDBC connection pool -->
            <property name="hibernate.c3p0.min_size">3</property>
            <property name="hibernate.c3p0.max_size">100</property>
            <property name="hibernate.c3p0.max_statements">100</property>

            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />

        </properties>
    </persistence-unit>



</persistence>

Things I have tried in the Manifest's Classpath with no luck:

Bundle-ClassPath: ., META-INF/persistence.xml

Bundle-ClassPath: ., ../META-INF/persistence.xml

Bundle-ClassPath: ., /META-INF/persistence.xml

Bundle-ClassPath: ., ./META-INF/persistence.xml

Bundle-ClassPath: ., META-INF

Bundle-ClassPath: ., ../META-INF

Bundle-ClassPath: ., /META-INF

Bundle-ClassPath: ., ./META-INF

Bundle-ClassPath: ., C:\Workspaces\OSGiJPA\Dao\META-INF\persistence.xml

Bundle-ClassPath: ., C:\Workspaces\OSGiJPA\Dao\META-INF

8

8 Answers

6
votes

Use EclipseLink and forget about Hibernate and other implementations, because :

  • You'll have to play with the classloader too much... Thread.currentThread().setContextClassLoader(...)

  • You'll be tempted to set the bundle-classpath attribute and add dependencies manually instead of installing jar bundles.

  • You'll get provider not found errors or you might not be able to find persistence.xml

All the above efforts might not work after many attempts.

However, with EclipseLink it's a no brainer, the implementation was designed to work out of the box in an OSGI environment and there aren't any class loading headaches.

2
votes
  1. (only a suggestion): Better if you use a lazy loader instead do the job into the activator. For example use a singleton that is invoked into SimpleDaoImpl contructor.
  2. Move META-INF/persistent.xml under src folder (src/META-INF/persistent.xml) because under develop META-INF folder is not in classpath, it works only in runtime mode.
  3. If you are using EclipseLink jpa OSGi, your MANIFEST.MF missing of JPA-PersistenceUnits entry. Add

    JPA-PersistenceUnits: postgres

    into the MANIFEST.MF.

  4. Then in your launch configuration set the start level of org.eclipse.persistence.jpa.osgi (for ecliselink 2.3.x otherwise org.eclipse.persistence.jpa for 2.1.x) to 2 and start level of javax.persistence to 1.

GOOD LUCK, actually 2.3 has a problem in deployment, doesn't handle bundleresource://xxxx URLs :(, 2.1.2 works very well ;)

1
votes

I am not using persistence.xml but hibernate.cfg.xml which is similar:

src/main/resource/hibernate/hibernate.cfg.xml

In my Activator I am getting the file via the bundle context: Here is some example code how I do it and also reference that file:>

private void initHibernate(BundleContext context) {
        try {
            final AnnotationConfiguration cfg = new AnnotationConfiguration();
            cfg.configure(context.getBundle().getEntry("/src/main/resource/hibernate/hibernate.cfg.xml"));
            sessionFactory = cfg.buildSessionFactory();

        } catch (Exception e) {
            // TODO Auto-generated catch block
        }
    }

As you can see line which gets the config file is:

context.getBundle().getEntry("/src/main/resource/hibernate/hibernate.cfg.xml")

As you can see my hibernate.cfg.xml is NOT inside the META-INF folder. It is just in the root folder under /src/......

Hope that helps.

Christoph

1
votes

You need to have the directory that contains META-INF on the classpath. Each directory is searched for META-INF and if found, then persistence.xml is searched for.

If you put "META-INF" on the classpath, then you'd need another META-INF in that directory.

0
votes

Try using Bundle-ClassPath like this in your manifest

Bundle-ClassPath: ., /location/of/persistence.xml

0
votes

The Meta-inf directory is not on the classpath. This should work by simply placing it under your src dirctory. If you want it in a separate location, then you will have to specify the Bundle-Classpath to include that directory. By default the classpath is '.'.

0
votes

I'm getting the same problem.

I think eclipse link is the best option to use in a OSGi Environment. And there are no problem because you will work basically with the JPA implementation. When you need to move to Hibernate, just replace persintece.xml config and some libs.

0
votes

you need to set property (for hibernate it will be different):

javax.persistence.provider=org.apache.openjpa.persistence.PersistenceProviderImpl

for call:

Persistence.createEntityManagerFactory(entityManagerFactoryName, properties)

to make it work.

And as mentioned before, you need classloader wrapping. You can use ClassloaderEntityManager from https://issues.apache.org/jira/browse/OPENJPA-1783 to do that.

Regards