2010-04-25 8 views
6

Questo è un grosso problema.JDBC/OSGi e come caricare i driver in modo dinamico senza dichiarare esplicitamente le dipendenze nel pacchetto?

Ho una base di codice ben strutturata ma monolitica con un'architettura modulare primitiva (tutti i moduli implementano interfacce ma condividono lo stesso percorso di classe). Mi rendo conto della follia di questo approccio e dei problemi che rappresenta quando vado a distribuire su server di applicazioni che potrebbero avere versioni in conflitto diverse della mia libreria.

Sono dipendente da circa 30 vasetti in questo momento e sono a metà strada pur trovandoli in su. Ora alcuni dei miei moduli sono facili da dichiarare come dipendenti dalle versioni, come i miei componenti di rete. Esse fanno riferimento a classi all'interno di JRE e altre librerie BNDded, ma i miei componenti relativi a JDBC creano un'istanza tramite Class.forName (...) e possono utilizzare uno qualsiasi dei numerosi driver.

Sto suddividendo tutto in bundle OSGi per area di servizio.

  • Le mie classi principali/interfacce.
  • Segnalazione dei componenti correlati.
  • Componenti relativi all'accesso al database (tramite JDBC).
  • ecc ....

Vorrei per il mio codice per poter essere ancora utilizzato senza OSGi tramite file jar singola con tutte le mie dipendenze e senza OSGi a tutti (via JARJAR) ed anche per essere modulare tramite i meta-dati OSGi e i pacchetti granulari con informazioni sulle dipendenze.

  • Come si configura il mio fagotto e il mio codice in modo che possa utilizzare in modo dinamico qualsiasi driver sul classpath e/o all'interno dell'ambiente container OSGi (Felix/Equinox/etc.)?

  • Esiste un metodo di runtime per rilevare se sono in esecuzione in un contenitore OSGi compatibile con i contenitori (Felix/Equinox/ecc.)?

  • Devo utilizzare un meccanismo di caricamento di classe diversa se sono in un contenitore OSGi?

  • Sono obbligato ad importare classi OSGi nel mio progetto per poter caricare un driver JDBC at-bundle-time-unknown tramite il modulo del mio database?

  • Ho anche un secondo metodo per ottenere un driver (tramite JNDI, che è realmente applicabile solo quando è in esecuzione in un app server), devo cambiare il mio codice di accesso JNDI per i server app compatibili con OSGi?

risposta

7
  • Utilizzando qualsiasi driver all'interno dell'ambiente OSGi richiede di utilizzare un DynamicImport-Pacchetto: * dichiarazione in modo che il bundle può risolvere questi pacchetti quando si carica un driver con Class.forName (..).
  • Probabilmente il modo più semplice è provare ad accedere a una classe che si trova nel pacchetto org.osgi.framework. Questi dovrebbero almeno essere sempre in giro in un ambiente OSGi (vedere lo snippet sotto). Ci sono meccanismi più sofisticati, quindi fammi sapere se hai bisogno di qualcosa di più avanzato. Inoltre, dai un'occhiata alla specifica del core OSGi R4.2, paragrafo 3.8.9 che mostra alcuni metodi per trovare il Bundle e il BundleContext di una classe e quindi aiuta indirettamente a determinare se ti trovi in ​​un framework o meno.
  • Dipende da cosa stai facendo, nessuna risposta generica "sì" o "no" qui. OSGi utilizza classloader e lo fa in un modo che non è "tipico" per un'applicazione Java standard, ma a seconda di cosa stai facendo, potresti non accorgertene.
  • No.
  • Dai un'occhiata alle specifiche aziendali OSGi rilasciate di recente. Hanno un capitolo sull'integrazione JNDI in OSGi che probabilmente ti permette di lasciare il tuo codice (in gran parte) non modificato.

Un esempio semplice frammento:

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

Basta fare in modo che se si mette il codice in un fascio, il fascio dovrebbe importare org.osgi.framework (altrimenti non troverà mai quella classe) .

+0

Grazie per l'informazione, in particolare il DynamicImport-Pacchetto: * suggerimento che sorprendentemente non riuscivo a trovare tramite ricerca su Internet. Riguardo alla seconda risposta, uno snippet potrebbe essere bello se avete tempo. Lo segnalerò comunque come risposta approvata, sebbene tu abbia risposto alle mie domande principali. Grazie. – Chris

0

Ho creato un gestore di driver JDBC per OSGI in un Eclipse RCP e ti spiegherò come giocare con OSGI. Innanzitutto, dimentica DynamicImport-Package, l'unico buon modo per utilizzare OSGI è installare/avviare/arrestare i pacchetti e utilizzare il meccanismo OSGI nel modo in cui è stato progettato.

  1. avete il vostro pacco JDBC, e creare un altro "pacchetto Driver", che ha l'inizializzazione del DriverClass, la logica di connessione e aggiungere i beni comuni librerie necessarie, come dbcp2 e pool2.

  2. Esportare il pacchetto Driver come JAR/ZIP e includerlo nel pacchetto JDBC come risorsa.

  3. Consenti al bundle JDBC di decomprimere il pacchetto Driver nell'area di lavoro.

    String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString(); 
    
  4. programmazione aggiungere vasetti conducente e modificare file MANIFEST.MF del pacchetto driver di conseguenza.

  5. Caricare il pacchetto driver programmazione dalla zona di lavoro

    getBundleContext().installBundle("file:/"+workdir); 
    
  6. Uso bundle.start(), stop(), disinstallare() come necessario quando programmazione modificare l'elenco dei driver.

0

La pax-jdbc può essere utilizzato per delegare origini dati tramite modo dichiarativo, significa che è possibile creare una voce di configurazione in servizio ConfigAdmin, e l'origine dati si può accedere tramite JNDI. Il driver JDBC è distribuito come pacchetto. (La maggior parte di loro hanno versione OSGi)

Ad esempio:

La voce di configurazione PID è org.ops4j.datasource-test

Proprietà:

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

Il servizio è identificato dal dato dataSourceName. Quindi puoi filtrarlo con (& (objectClass = javax.sql.DataSource) (dataSourceName = test2)).

E si può accedere tramite l'origine dati JNDI:

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