OSGI è un framework, frutto del lavoro di un consorzio di aziende tra cui Oracle, IBM, Ericsson ed altre, il cui scopo è semplificare la realizzazione di applicazioni modulari in java.
Applicazioni modulari
OSGI consente la definizione e l'utilizzo dell'intero ciclo di vita (registrazione, pubblicazione, deploy, etc) di servizi, tramite l'implementazione di moduli (in questo contesto chiamati bundles), di un service registry, e di un ambiente di esecuzione.
L'idea è migliorare il supporto degli ambienti java alla creazione e all'utilizzo di software modulare, partendo dall'osservazione di alcune carenze tutt'ora presenti nel linguaggio, in particolare:
1. limiti dei modificatori di accesso
Java ha i modificatori di accesso default
(implicito), public
, protected
e private
che limitano l'accesso alle classi ed al relativo codice, ma le stesse regole di definizione delle regole non possono ad esempio essere applicate ad un package. Questo limite si traduce ad esempio nel fatto che se consideriamo due package A e B distinti, con A contenente soltanto l'interfaccia (le api) e B contenente soltanto la rispettiva implementazione, è necessario garantire che A e B siano visibili tra di loro, il che comporta in genere esserlo praticamente per tutti.
(clic per ingrandire)

Consideriamo una interfaccia di esempio:
package org.foo.hello;
public interface Hello {
void sayHello();
}
quindi in un altro package una classe che la implementa:
package org.foo.hello.impl;
import org.foo.hello.Greeting;
public class HelloImpl implements Hello {
final String name;
public HelloImpl(String name) {
this.name = name;
}
public void sayHello() {
System.out.println("Hello, " + this.name + "!");
}
}
ed infine una classe di test nel terzo package:
package org.foo.hello.main;
import org.foo.hello.Hello;
import org.foo.hello.impl.HelloImpl;
public class Main {
public static void main(String[] args) {
Hello greet = new HelloImpl("Hello World");
greet.sayHello();
}
}
L'obiettivo era in questo caso rendere accessibile la classe di implementazione creata attraverso l'interfaccia, ma se ribaltassimo il problema, purtroppo è evidente che non esiste un meccanismo che ci consente di impedire di accedere alla classe direttamente.
Il problema è parzialmente risolvibile utilizzando il pattern Inversion Of Control
2. il classloader di java
Il class loader di java non tiene conto della versione delle classi e degli archivi (vedi jar) che carica. Ad esempio supponiamo che una nostra applicazione necessiti di una classe memorizzata in un jar che chiamiamo 'mioarchivio.jar
', presente sul classpath in due versioni: 1.0 e 1.1. In questo caso non abbiamo modo di specificare esplicitamente quale versione caricare escludendo l'altra; semplicemente dovremo assicurarci che il class loader carichi la versione corretta, provvedendo ad escludere quella sbagliata dal class path, o utilizzando dei sistemi di gestione delle dipendenze (come maven, ivy, etc), in modo da intervenire a monte del problema.
Cosa è OSGI
OSGI (Open Service Gateway Initiative) è una specifica che permette di costruire applicazioni modulari a componenti (i Bundle) e che introduce una programmazione Service Oriented, permettendo una separazione tra interfaccia ed implementazione molto più rigorosa di quella nativa Java.
Esistono diverse implementazioni (container) di OSGI, conformi alle specifiche e qui tra di loro equivalenti:
L'interfaccia prevede l'esistenza di un registro dove pubblicare e ricercare i servizi e di cambiare l'implementazione degli stessi a runtime in maniera dinamica e trasparente.
OSGI è composto dal framework vero e proprio, e dai servizi standard
Il framework prevede una separazione
- module layer
- lifecycle layer
- service layer
come è fatto un bundle
Un bundle semplicemente è un archivio jar contenente informazioni aggiuntive nel suo file MANIFEST.MF
(il contenuto è descritto dalle specifiche di OSGI).
Nel caso dell'interfaccia relativa al nostro esempio:
Prima di addentrarci in un esempio che chiarirà in maniera esaustiva i diversi aspetti esposti notiamo che nel MANIFEST.MF
Export-Package: org.foo.hello;version="1.0"
questa riga indica al container che il bundle esporta all'esterno (cioè rende visibile) unicamente il package org.foo.hello
non sarà possibile accedere a classi contenute in altri package
OSGI
In particolare i due parametri che identificano univocamente un bundle sono i seguenti:
Esempio: un bundle osgi con Eclipse
Vediamo una semplice applicazione di esempio, riprendiamo il semplice esempio 'helloWorld' e realizziamolo attraverso OSGI ed Eclipse.
Realizziamo per primo il modulo che contiene l'interfaccia della nostra semplice classe, avviamo eclipse e scegliamo file/new Plugin-> project
Abbiamo usato come nome del progetto org.foo.hello
equinox
OSGI
rigoroso è molto importante in termini di modularità e consistenza tra i moduli stessi:
deselezionare la voce 'generate an activator...
Il cerchio rosso evidenzia la versione del bundle che OSGI considera suddivisi in questo formato: major.micro.minor.qualifier
Premere il tasto 'finish' ed eclipse creerà il progetto.
Creiamo adessp un package con lo stesso nome del progetto, cioè di nome org.foo.hello
package org.foo.hello;
public interface Hello {
void sayHello();
}
fatto questo clicchiamo due volte sul file MANIFEST.MF
selezioniamo il tab Runtime
exported package
add
org.foo.hello
quindi salviamo il progetto e clicchiamo sulla tab MANIFEST.MF
A questo punto creiamo un secondo bundle org.foo.hello.impl
Stavolta però dopo aver creato il bundle dovremo specificare la dipendenza dalla nostra interfaccia, perché la nostra nuova classe possa implementarla!
Selezioniamo il tab 'dependencies
org.foo.hello
... ed abbiamo specificato che il bundle org.foo.hello.impl
org.foo.hello
Questo il contenuto del MANIFEST.MF: Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Impl Bundle-SymbolicName: org.foo.hello.impl Bundle-Version: 1.0.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.foo.hello
Nell'ultima riga di codice è facile riconoscere la definizione della dipendenza.