2010-04-25 4 views
6

Dies ist ein großes Problem.JDBC/OSGi und wie man Treiber dynamisch lädt, ohne Abhängigkeiten explizit im Bündel anzugeben?

Ich habe eine gut strukturierte und dennoch monolithische Code-Basis, die eine primitive modulare Architektur hat (alle Module implementieren Schnittstellen, die den gleichen Klassenpfad teilen). Ich erkenne die Torheit dieses Ansatzes und die Probleme, die es bei der Bereitstellung auf Anwendungsservern darstellt, die möglicherweise unterschiedliche Versionen meiner Bibliothek widersprechen.

Ich bin auf etwa 30 Gläser im Moment abhängig und bin auf halbem Weg obwohl sie abbindet. Jetzt können einige meiner Module die versionierten Abhängigkeiten von beispielsweise meinen Netzwerkkomponenten einfach deklarieren. Sie verweisen statisch auf Klassen innerhalb der JRE und anderer BNDded-Bibliotheken, aber meine JDBC-Komponenten instanziieren über Class.forName (...) und können einen beliebigen Anzahl von Treibern verwenden.

Ich breche alles in OSGi-Bundles nach Servicebereich auf.

  • Meine wichtigsten Klassen/Schnittstellen.
  • Berichterstattung im Zusammenhang mit Komponenten.
  • Datenbankzugriff bezogene Komponenten (über JDBC).
  • etc ....

Ich wünsche mein Code der Lage sein, noch überhaupt über einzige JAR-Datei mit allen meinen Abhängigkeiten und ohne OSGi ohne OSGi verwendet wird (über Jarjar) und auch modular zu sein über die OSGi-Metadaten und granularen Bundles mit Abhängigkeitsinformationen.

  • Wie konfiguriere ich mein Bündel und meinen Code, so dass es dynamisch jeden Treiber auf dem Classpath nutzen und/oder innerhalb der OSGi Containerumgebung (Felix/Equinox/etc.)?

  • Gibt es eine Laufzeitmethode, um festzustellen, ob ich in einem OSGi-Container laufe, der über Container hinweg kompatibel ist (Felix/Equinox/etc.)?

  • Muss ich einen anderen Klassenlademechanismus verwenden, wenn ich in einem OSGi-Container bin?

  • Muss ich OSGi-Klassen in mein Projekt importieren, um einen at-bundle-unknown JDBC-Treiber über mein Datenbankmodul laden zu können?

  • Ich habe auch eine zweite Methode zum Abrufen eines Treibers (über JNDI, die nur wirklich beim Ausführen auf einem App-Server anwendbar ist), muss ich meinen JNDI-Zugriffscode für OSGi-fähige App-Server ändern?

Antwort

7
  • jeden Treiber innerhalb der OSGi-Umgebung Verwendung erfordert, dass Sie ein DynamicImport-Paket mit: diese Pakete * Anweisung, damit Ihr Bündel kann lösen, wenn Sie einen Treiber mit Class.forName (..) laden.
  • Der einfachste Weg besteht wahrscheinlich darin, auf eine Klasse zuzugreifen, die sich im org.osgi.framework-Paket befindet. Diese sollten zumindest immer in einer OSGi-Umgebung vorhanden sein (siehe Abschnitt unten). Es gibt ausgeklügeltere Mechanismen, also lassen Sie mich wissen, wenn Sie etwas fortgeschritteneres brauchen. Sehen Sie sich auch die OSGi R4.2-Kernspezifikation an, Abschnitt 3.8.9, die einige Methoden zum Finden des Bundle und BundleContext einer Klasse zeigt und daher indirekt hilft festzustellen, ob Sie in einem Framework sind oder nicht.
  • Das hängt davon ab, was Sie tun, keine generische "Ja" oder "Nein" Antwort hier. OSGi verwendet Classloader und tut dies auf eine Weise, die für eine Standard-Java-Anwendung nicht "typisch" ist, aber je nachdem, was Sie gerade tun, werden Sie es vielleicht nicht bemerken.
  • Nr.
  • Werfen Sie einen Blick auf die kürzlich veröffentlichten OSGi Enterprise-Spezifikationen. Sie haben ein Kapitel zur JNDI-Integration in OSGi, mit dem Sie Ihren Code (weitgehend) unverändert lassen können.

Ein einfaches Beispiel Schnipsel:

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

einfach sicher, dass Sie, wenn Sie diesen Code in einem Bündel setzen, sollte das Bündel importieren org.osgi.framework (sonst wird es nie diese Klasse finden) .

+0

Vielen Dank für die Informationen, insbesondere die DynamicImport-Package: * Tipp, der überraschend konnte ich nicht über Internet-Suche finden. In Bezug auf die zweite Antwort könnte ein Snippet schön sein, wenn Sie Zeit haben. Ich werde dies als die genehmigte Antwort trotzdem kennzeichnen, obwohl Sie meine Hauptfragen beantwortet haben. Vielen Dank. – Chris

0

Ich habe einen JDBC-Treibermanager für OSGI in einem Eclipse RCP erstellt und ich werde Ihnen zeigen, wie man mit OSGI nett spielt. Erstens, vergessen Sie DynamicImport-Package, die einzige gute Möglichkeit, OSGI zu verwenden, ist das Installieren/Starten/Stoppen von Bundles und die Verwendung des OSGI-Mechanismus, so wie er entworfen wurde.

  1. Sie haben Ihre JDBC-Bündel, und erstellen Sie einen anderen „Treiberpaket“, das die Initialisierung des Driver hat, die Verbindungslogik und fügen Sie die erforderlichen commons Bibliotheken wie dbcp2 und pool2.

  2. Exportieren Sie das Treiberpaket als JAR/ZIP und fügen Sie es als Ressource in Ihr JDBC-Paket ein.

  3. Lassen Sie Ihr JDBC-Bundle das Driver-Bundle in seinem Arbeitsbereich entpacken.

    String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString(); 
    
  4. Programmatically Treiber Gläser hinzufügen und ändern die entsprechend MANIFEST.MF-Datei des Treiberpaket.

  5. Laden das Treiberpaket programmatisch aus dem Arbeitsbereich

    getBundleContext().installBundle("file:/"+workdir); 
    
  6. Verwenden bundle.start(), Stop(), Deinstallation(), wie erforderlich, wenn programmatisch die Liste der Treiber zu ändern.

0

Das Pax-jdbc kann verwendet werden, über deklarative Weise datasources zu delegieren, bedeutet, dass Sie einen Config-Eintrag in ConfigAdmin Service erstellen können, und die Datenquelle kann über JNDI zugegriffen werden. Der JDBC-Treiber wird als Bundle bereitgestellt. (Die meisten von ihnen haben OSGi-Version)

Zum Beispiel:

Der Konfigurationseintrag PID ist org.ops4j.datasource-Test

Eigenschaften:

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

Der Service durch die identifiziert wird gegeben dataSourceName. Sie können also mit (& (objectClass = javax.sql.DataSource) (dataSourceName = test2)) danach filtern.

Und Sie können die Datenquelle über JNDI zugreifen:

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