Blog

Mise en place de JPA/Hibernate dans un bundle OSGI-Equinox

Dans le cadre d’un projet, j’avais besoin de mettre en place un bundle OSGI (implémentation EQUINOX) qui utilise JPA / Hibernate.

Les versions de départs sont les suivantes :

  • OSGI Equinox org.eclipse.osgi_3.5.2
  • Hibernate : hibernate-4.2.6.Final
  • Hibernate envers : hibernate-envers-4.2.6.Final

Ici : l’utilisation hibernate-envers n’est pas obligatoire

Suivi de la doc d’hibernate

Lorsque vous voulez mettre en place Hibernate dans un bundle vous avez plusieurs possibilités :

  • Container-Managed JPA
  • Unmanaged JPA
  • Unmanaged Native

(cf doc hibernate)

Pour mon cas, j’ai utilisé la solution du « Unmanaged JPA », pas besoin d’ajouter la couche « blueprint » pour l’instant.

Il y a des modifications à apporter au niveau du code (pour le chargement de l’entitymanager) ainsi qu’au niveau du MANIFEST.MF de votre bundle.

Pour le MANIFEST.MF il faut ajouter les Import-Package nécessaires et le chemin dans le Meta-Persistence :

...
Export-Package: ...
Import-Package: ...
Meta-Persistence: META-INF/persistence.xml

Voici le code pour pouvoir créer l’EntityManager dans le contexte d’un bundle OSGI. (Exemple de code issue de la doc d’hibernate).

package fr.mydevworld.webapp.util;

import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;

 public class Registry {

	private static Registry instance;

	public  static Registry getInstance(){
		if(instance == null ) instance = new Registry();
		return instance;
	}
 
	private EntityManagerFactory emf;

	private Registry() {
		if ( this.emf == null ) {
			Bundle thisBundle = FrameworkUtil.getBundle( Registry.class );
			// Could get this by wiring up OsgiTestBundleActivator as well.
			BundleContext context = thisBundle.getBundleContext();

			ServiceReference serviceReference = context.getServiceReference( PersistenceProvider.class.getName() );
			PersistenceProvider persistenceProvider = (PersistenceProvider) context.getService( serviceReference );
			this.emf = persistenceProvider.createEntityManagerFactory( "mydevworld", null );
		}
 	}

	public EntityManagerFactory getEmf() {
		return emf;
	}
}

Dans le constructeur du Registry ; on récupère le contexte du bundle courant pour pouvoir récupérer les services enregistrés de type « javax.persistence.spi.PersistenceProvider ». Une fois le service récupérer, on va pouvoir créer notre entityManager définit dans le fichier META-INF/persistence.xml de notre bundle (voilà pour l’explication du code).

Première montée de version

La problématique que j’ai rencontrée suite à la modification du code est que la version d’hibernate que j’utilisais n’était plus compatible (packages manquants). J’ai du faire une montée de version d’hibernate 4.2.6.Final -> 4.3.0.Final.

La montée en version d’hibernate ma obligé à faire une montée de version d’Equinox de 3.5.2 -> 3.8.2.

Une fois qu’on a résolu toutes les dépendances, on obtient les versions principales suivantes :

  • OSGI Equinox org.eclipse.osgi_3.8.2
  • Hibernate : hibernate-4.3.0.Final
  • Hibernate OSGI: hibernate-osgi-4.3.0.Final
  • Hibernate envers : hibernate-envers-4.3.0.Final

Et l’on peut relancer notre bundle.
Attention : si vous avez un NullPointException au niveau de la résolution des services de référence dans votre registry, c’est que vous avez oublié de démarrer le bundle Hibernate-OSGI. En effet, c’est lui qui est en charge d’enregistrer les services de type « javax.persistence.spi.PersistenceProvider ».

Donc démarrer ce bundle (hibernate-osgi) avant le votre.

Après avoir redémarré dans le bon ordre les bundles, j’ai rencontré l’erreur suivante :

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lorg.hibernate.integrator.spi.Integrator;
    at org.hibernate.osgi.OsgiPersistenceProvider.generateSettings(OsgiPersistenceProvider.java:126)

La piste de la solution est ici : Hibernate OSGi 4.3.0.CR1 can’t discover services

Seconde montée de version

Cette erreur, je l’ai résolue en faisant une dernière montée de version d’hibernate de 4.3.0.Final -> 4.3.1.Final.

Après cette montée de version j’ai pu accéder au fichier persistence.xml de mon bundle et créer mon entitymanager.

Mon environnement final étant celui-ci :

  • OSGI Equinox org.eclipse.osgi_3.8.2
  • Hibernate : hibernate-4.3.1.Final
  • Hibernate OSGI: hibernate-osgi-4.3.1.Final
  • Hibernate envers : hibernate-envers-4.3.1.Final

A noter : je rappelle que hibernate-envers n’est aucunement obligatoire, mais que si vous l’avez utilisé (comme moi) vous devez obligatoirement faire sa montée de version aussi en 4.3.1 car sinon, il y aura un problème de compatibilité.

admin

Written by

The author didnt add any Information to his profile yet