2010-04-25 10 views
6

Ceci est une biggie.JDBC/OSGi et comment charger dynamiquement les pilotes sans indiquer explicitement les dépendances dans le bundle?

J'ai une base de code bien structurée mais monolithique qui a une architecture modulaire primitive (tous les modules implémentent des interfaces mais partagent le même chemin de classe). Je réalise la folie de cette approche et les problèmes qu'elle représente quand je vais déployer sur des serveurs d'applications qui peuvent avoir différentes versions conflictuelles de ma bibliothèque.

Je suis dépendant d'environ 30 bocaux en ce moment et je suis à mi-chemin, mais je les trouve. Maintenant, certains de mes modules sont faciles à déclarer les dépendances versionnées de, tels que mes composants réseau. Ils référencent statiquement les classes dans les bibliothèques JRE et autres bibliothèques BND, mais mes composants liés à JDBC sont instanciés via Class.forName (...) et peuvent utiliser un nombre quelconque de pilotes. Je suis en train de tout casser en paquets OSGi par zone de service.

  • Mes classes/interfaces de base.
  • Signalement des composants associés.
  • Composants liés à l'accès à la base de données (via JDBC).
  • etc ....

Je souhaite que mon code pour pouvoir utiliser toujours sans OSGi par simple fichier jar avec toutes mes dépendances et sans OSGi du tout (via Jarjar) et aussi être modulaire via les méta-données OSGi et les bundles granulaires avec des informations de dépendance.

  • Comment puis-je configurer mon paquet et mon code afin qu'il puisse utiliser dynamiquement un pilote sur le classpath et/ou dans l'environnement du conteneur OSGi (Felix/Equinox/etc.)?

  • Existe-t-il une méthode d'exécution pour détecter si je cours dans un conteneur OSGi compatible avec les conteneurs (Felix/Equinox/etc.)? Dois-je utiliser un mécanisme de chargement de classe différent si je suis dans un conteneur OSGi?

  • Ai-je besoin d'importer des classes OSGi dans mon projet pour pouvoir charger un pilote JDBC at-bundle-time-inconnu via mon module de base de données? J'ai également une deuxième méthode pour obtenir un pilote (via JNDI, qui n'est vraiment applicable que sur un serveur d'application), dois-je changer mon code d'accès JNDI pour les serveurs d'applications compatibles avec OSGi?

Répondre

7
  • Utilisant un pilote dans l'environnement OSGi vous oblige à l'aide d'un DynamicImport-Package: * déclaration afin que votre paquet peut résoudre ces paquets lorsque vous chargez un pilote avec Class.forName (..).
  • Probablement le moyen le plus simple est d'essayer d'accéder à une classe qui se trouve dans le paquet org.osgi.framework. Ceux-ci devraient au moins toujours être dans un environnement OSGi (voir l'extrait ci-dessous). Il existe des mécanismes plus sophistiqués, alors laissez-moi savoir si vous avez besoin de quelque chose de plus avancé. Jetez également un coup d'œil à la spécification de base OSGi R4.2, paragraphe 3.8.9 qui montre quelques méthodes pour trouver le Bundle et BundleContext d'une classe et donc indirecte aide à déterminer si vous êtes dans un cadre ou non.
  • Cela dépend de ce que vous faites, pas de réponse générique "oui" ou "non" ici. OSGi utilise des chargeurs de classe et le fait d'une manière qui n'est pas "typique" pour une application Java standard, mais en fonction de ce que vous faites, vous ne le remarquerez peut-être pas.
  • n °
  • Jetez un oeil aux spécifications d'entreprise OSGi récemment publiées. Ils ont un chapitre sur l'intégration JNDI dans OSGi qui vous permet probablement de laisser votre code (en grande partie) non modifié.

Un simple exemple extrait:

public static boolean inOSGi() { 
    try { 
    Class.forName("org.osgi.framework.FrameworkUtil"); 
    return true; 
    } 
    catch (ClassNotFoundException e) { 
    return false; 
    } 
} 

Assurez-vous que si vous mettez ce code dans un paquet, le paquet doit importer org.osgi.framework (sinon il ne trouvera jamais cette classe) .

+0

Merci pour l'information, en particulier le DynamicImport-Package: * pointe qui étonnamment je ne pouvais pas trouver via la recherche Internet. En ce qui concerne la deuxième réponse, un extrait pourrait être utile si vous avez le temps. Je signalerai ceci comme réponse approuvée quand même que vous avez répondu à mes questions principales. Merci. – Chris

0

J'ai fait un gestionnaire de pilotes JDBC pour OSGI dans un RCP Eclipse et je vais vous expliquer comment jouer avec OSGI. Tout d'abord, oubliez DynamicImport-Package, la seule bonne façon d'utiliser OSGI est d'installer/démarrer/arrêter les bundles et d'utiliser le mécanisme OSGI comme il a été conçu.

  1. Vous avez votre paquet JDBC, et créer un autre « paquet Driver » qui a l'initialisation du DriverClass, la logique de connexion et ajouter les bibliothèques communes nécessaires tels que dbcp2 et pool2.

  2. Exportez l'ensemble de pilotes en tant que fichier JAR/ZIP et incluez-le dans votre ensemble JDBC en tant que ressource.

  3. Laissez votre kit JDBC décompresser le kit de pilotes dans sa zone de travail.

    String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString(); 
    
  4. Programmatically ajouter des pots de pilote et modifier le fichier MANIFEST.MF de kit de pilotes en conséquence.

  5. Charger le faisceau de conducteur par programmation à partir de la zone de travail

    getBundleContext().installBundle("file:/"+workdir); 
    
  6. utilisation bundle.start(), stop(), désinstaller() comme nécessaire lors de la modification par programme de la liste des pilotes.

0

La pax-jdbc peut être utilisé pour déléguer DataSources par voie déclarative, signifie que vous pouvez créer une entrée de configuration en service ConfigAdmin et la source de données sont accessibles via JNDI. Le pilote JDBC est déployé en tant que groupe. (La plupart d'entre eux ont la version OSGi)

Par exemple:

L'entrée de configuration PID est org.ops4j.datasource test

Propriétés:

osgi.jdbc.driver.name=H2 
databaseName=test 
user=sa 
password= 
dataSourceName=testds-h2 

Le service est identifié par le donné dataSourceName. Vous pouvez donc filtrer avec (& (objectClass = javax.sql.DataSource) (dataSourceName = test2)).

Et vous pouvez accéder à la source de données via JNDI:

osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=test2)