OSGi bietet ein Konzept zur Modularisierung und Komponentisierung von Java-Applikationen, und zwar nicht nur zur Entwicklungszeit, sondern auch zur Laufzeit. Abhängigkeiten zwischen Komponenten werden explizit auf Package-Ebene deklariert. Versionierung wird unterstützt. Zu einer Komponente können gleichzeitig mehrere Versionen in Betrieb sein. Komponenten können während des laufenden Betriebs hinzugefügt und ausgetauscht werden ("Hot Deployment", "Hot Plugging"), auch übers Internet. Eine Service Registry bietet die Suche nach passenden Komponenten. Service-Orientierung und lose Kopplung werden unterstützt und die Testbarkeit verbessert.
Zu den bekanntesten OSGi-Implementierungen zählen Eclipse Equinox, Apache Felix, Knopflerfish und Prosyst mBedded.
Im Folgenden werden kleine OSGi-Programmierbeispiele mit Eclipse für Equinox erstellt.
Provider | Consumer | |
---|---|---|
Package-Abhängigkeiten | ||
Die einfachste Möglichkeit ist, in den jeweiligen MANIFEST.MF-Dateien das Package des Dienstes beim Dienstanbieter zu exportieren und beim Konsument zu importieren | Export-Package: ... | Import-Package: ... |
Falls Sie erst zur Laufzeit einen Klassennamen erhalten und die Klasse beispielsweise per Class.forName() laden wollen, können Sie hierfür einen dynamischen Import definieren (inkl. '*'-Wildcards), für den erst dann ein passendes Package gesucht wird, wenn die Klasse benötigt wird | DynamicImport-Package: ... | |
Statt des Imports einzelner Packages kann auch definiert werden, dass alle exportierten Packages eines Bundles importiert werden sollen | Require-Bundle: ... | |
Sie können die Exporte des importierten Bundles weiterreichen | Require-Bundle: ... visibility:=reexport |
|
Fragment-Bundles | ||
Fragment-Bundles sind Bundles, die nicht eigenständig verwendet werden können, sondern nur der Erweiterung anderer "Host"-Bundles dienen.
Fragment-Bundles haben keinen eigenen Lebenszyklus und keinen Activator.
In der MANIFEST.MF des Fragment-Bundles muss der "Host" eingetragen sein.
Das "Host"-Bundle weiß nichts vom Fragment-Bundle. Ein typischer Einsatzbereich für Fragment-Bundles sind JavaSE-ResourceBundle zur Lokalisierung. Aber auch JUnit-Tests können so hinzugefügt werden (inkl. Zugriff auf private-Methoden). |
Fragment-Host: ... | |
Service-Abhängigkeiten | ||
Wenn der Dienstanbieter seinen Service bei der OSGi Service Registry registriert, können andere Bundles diesen Dienst suchen und verwenden. Hierfür muss der Konsument weder den Dienstanbieter kennen noch eine Package-Abhängigkeit deklarieren. Allerdings wird häufig ein gemeinsam vom Anbieter und Konsumenten verwendetes Schnittstellen-Interface benötigt, welches beispielsweise in einem dritten Bundle angeboten werden kann, wie es weiter unten einige Programmierbeispiele zeigen (z.B. Tracker, Declarative Services). | BundleContext. registerService() |
getServiceReferences(), getServiceReference(), getService() |
Wenn der Service Tracker verwendet wird, können Services auch über den ServiceTrackerCustomizer ermittelt werden, wie es das Tracker-Programmierbeispiel zeigt. | ServiceTrackerCustomizer. addingService() |
|
Bei Declarative Services erfolgt die Veröffentlichung und Verwendung von Services über Einträge in XML-Konfigurationsdateien (z.B. OSGI-INF/ds-component.xml), wie im Declarative-Services-Programmierbeispiel u.a. gezeigt wird |
<service> <provide interface=... |
<reference interface=... bind=... |
Führen Sie für einen ersten Test folgende Schritte durch:
Öffnen Sie im Equinox-SDK-Verzeichnis ein Kommandozeilenfenster und geben Sie ein:
cd /D C:\Tools\equinox-SDK
java -jar plugins\org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -console -clean
?
ss
close
Setzen Sie dabei statt org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar den org.eclipse.osgi_...jar-Dateinamen von Ihrer Equinox-Version ein.
Das "ss"-Kommando ("short status") listet die registrierten Bundles auf: org.eclipse.osgi_... ist als "ACTIVE" gelistet.
Sie können wahlweise auch einen etwas aufwändigeren Test inklusive Webserver durchführen:
Öffnen Sie wieder im Equinox-SDK-Verzeichnis
ein Kommandozeilenfenster und führen Sie folgende Kommandos aus
(setzen Sie wieder bei allen .jar-Dateien die korrekten zu Ihrer Equinox-Version passenden Versionsbezeichnungen ein)
(falls der Port 8080 auf Ihrem PC bereits belegt ist, ersetzen Sie ihn durch eine freie Nummer):
cd /D C:\Tools\equinox-SDK
java -jar plugins\org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -console -clean
install file:plugins/org.eclipse.osgi.services_3.3.0.v20110513.jar start
install file:plugins/org.eclipse.equinox.util_1.0.300.v20110502.jar start
install file:plugins/org.eclipse.equinox.ds_1.3.1.R37x_v20110701.jar start
install file:plugins/javax.servlet_2.5.0.v201103041518.jar start
setprop org.osgi.service.http.port=8080
install file:plugins/org.eclipse.equinox.http_1.0.500.v20110413.jar start
install http://www.aqute.biz/uploads/Code/aQute.webrpc.jar start
install http://www.aqute.biz/uploads/Code/aQute.sudoku.jar start
ss
Das "ss"-Kommando listet die registrierten Bundles auf: Sie erhalten acht Bundles mit dem State "ACTIVE".
Wenn Sie fertig sind, beenden Sie OSGi mit:
close
Bei diesem Beispiel wurden die beiden Bundles "webrpc.jar" und "sudoku.jar" über "install http:..." direkt übers Internet installiert. Falls Sie das nicht wollen, können Sie die benötigten .jar-Dateien natürlich auch zuerst von http://www.aqute.biz/uploads/Code downloaden und dann per "install file:..." installieren. Weitere Infos zu den beiden Bundles finden Sie auf der genannten Webseite und bei Peter Kriens.
Bei diesem Beispiel wurden die Bundles einzeln installiert. Wie man solche Installationen mit Hilfe einer "configuration" zusammenfassen und vereinfachen kann, wird weiter unten gezeigt.
In den folgenden Beispielen werden der Einfachheit halber "verkürzte" Bezeichnungen für Bundle-SymbolicNames, Packages und Event-Topics verwendet (z.B. "osgihelloworld"). Dies ist für lokale Prototypen ok, aber denken Sie bitte daran, in ernsthaften Anwendungen stattdessen dem Internet-Domainnamen entsprechende Bezeichnungen zu verwenden (z.B. "de.meinefirma.meineabteilung.meinprojekt.meinservice").
Sie können wahlweise die Sourcedateien als Zip-Archiv OSGi.zip laden, oder, wie im Folgenden beschrieben, die Dateien selbst erstellen.
In der Eclipse-IDE werden Bundles als Plug-in bezeichnet. Um ein OSGi-Bundle zu erzeugen, wählen Sie in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >' und tragen ein:
Project name: | OsgiHelloWorld | ||
Target Platform This plug-in is targeted to run with: |
an OSGi framework: standard | ("standard" für Standard-OSGi ohne spezielle Equinox-Erweiterungen) |
|
'Next >' | |||
ID: | HelloWorld | ||
Version: | 1.0.0 | ||
Name: | HelloWorld-Bundle | ||
Activator: | osgihelloworld.Activator | ||
'Finish' |
Öffnen Sie im Eclipse Package Explorer die Verzeichnisse 'OsgiHelloWorld' | 'src' | 'osgihelloworld' und die Datei 'Activator.java' und ersetzen Sie den Inhalt durch:
package osgihelloworld; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { @Override public void start( BundleContext context ) throws Exception { System.out.println( context.getBundle().getSymbolicName() + ": Hallo OSGi-Welt." ); } @Override public void stop( BundleContext context ) throws Exception { System.out.println( context.getBundle().getSymbolicName() + ": Tschau OSGi-Welt." ); } }
Sie erhalten als Ergebnis im Eclipse-Konsolenfenster:
osgi> HelloWorld: Hallo OSGi-Welt.
Geben Sie im Eclipse-Konsolenfenster ein:
uninstall HelloWorld
Sie erhalten:
HelloWorld: Tschau OSGi-Welt.
Hiermit können Sie das Bundle wieder installieren (passen Sie den Pfad D:\MeinWorkspace\ an):
install file:D:\MeinWorkspace\OsgiHelloWorld
ss
start HelloWorld
ss
Beenden Sie die OSGi-Sitzung durch Eingabe von:
close
(Wenn Sie keinen "ordentlichen Shutdown" wollen, können Sie auch ein "exit immediately" mit "exit" oder durch Klick auf das rote 'Terminate'-Quadrat erzwingen.)
Öffnen Sie im Equinox-SDK-Verzeichnis ein Kommandozeilenfenster und geben Sie ein (ersetzen Sie C:\Tools\equinox-SDK\MeineBundles durch Ihr Zielverzeichnis sowie org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar durch den org.eclipse.osgi_...jar-Dateinamen von Ihrer Equinox-Version):
cd /D C:\Tools\equinox-SDK
java -jar plugins\org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -console -clean
install file:C:\Tools\equinox-SDK\MeineBundles\plugins\HelloWorld_1.0.0.jar start
ss
uninstall 1
ss
close
Sie erhalten:
HelloWorld: Hallo OSGi-Welt.
und
HelloWorld: Tschau OSGi-Welt.
Entzippen Sie das exportierte Bundle HelloWorld_1.0.0.jar und sehen Sie sich den Inhalt an. Es enthält lediglich zwei Dateien in folgender Struktur:
[HelloWorld_1.0.0.jar] |- [osgihelloworld] | '- Activator.class '- [META-INF] '- MANIFEST.MF
Die Manifest-Datei MANIFEST.MF hat ungefähr folgenden Inhalt:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: HelloWorld-Bundle Bundle-SymbolicName: HelloWorld Bundle-Version: 1.0.0 Bundle-Activator: osgihelloworld.Activator Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.osgi.framework;version="1.3.0"
Unter OSGi-Bundle mit dem Maven-Bundle-Plugin finden Sie eine Beschreibung, wie Sie das HelloWorld-Programmierbeispiel ohne Eclipse und mit Maven durchführen können.
Im folgenden Programmierbeispiel gibt es einen Konsumenten, der per ServiceTracker dynamisch auf einen Dienst (= Service) zur Ermittlung des Datums reagiert. Konsument und Dienst-Provider sind in getrennten Bundles. Damit der Konsument auch dann bereits gestartet werden kann, wenn der Dienst-Provider noch nicht läuft, wird das Interface in einem separaten dritten Bundle angelegt.
Genaueres zum "Service Tracker" finden Sie im OSGi Service Platform Service Compendium.
Bitte beachten Sie, dass der ServiceTracker nur eine der möglichen Varianten darstellt, um auf Änderungen dynamisch zu reagieren. Oft werden stattdessen Declarative Services bevorzugt, wie es das anschließende Programmierbeispiel zeigt (siehe auch obigen Vergleich).
Erstellen Sie ein neues OSGi-Bundle-Projekt in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >':
Project name: | OsgiTrackerInterface |
Target Platform This plug-in is targeted to run with: |
an OSGi framework: standard |
'Next >' | |
ID: | Datum-Service-Interface |
Version: | 1.0.0 |
Name: | Datum-Service-Interface-Bundle |
Plug-in Options Generate an activator: |
nein |
'Finish' |
Klicken Sie im Eclipse Package Explorer im Projekt 'OsgiTrackerInterface' mit der rechten Maustaste auf 'src' und wählen Sie: 'New' | 'Package' | 'Name = datumservice'.
Klicken Sie mit der rechten Maustaste auf das entstandene Package 'datumservice' und wählen Sie: 'New' | 'Interface' | 'Name = DatumService'.
Ersetzen Sie den Inhalt von 'DatumService.java' durch:
package datumservice; public interface DatumService { String getDatum(); }
Öffnen Sie im Eclipse Package Explorer im Projekt 'OsgiTrackerInterface' das 'META-INF'-Verzeichnis und doppelklicken Sie auf die 'MANIFEST.MF'-Datei. Schalten Sie am unteren Rand auf den Tabulatorreiter 'Runtime'. Klicken Sie im 'Exported Packages'-Fenster auf 'Add...'. Doppelklicken Sie auf das angezeigte Package 'datumservice' und speichern Sie mit 'Strg + S'.
Erstellen Sie ein neues OSGi-Bundle-Projekt in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >':
Project name: | OsgiTrackerImpl |
Target Platform This plug-in is targeted to run with: |
an OSGi framework: standard |
'Next >' | |
ID: | Datum-Service-Impl |
Version: | 1.0.0 |
Name: | Datum-Service-Impl-Bundle |
Activator: | datumservice.impl.Activator |
'Finish' |
Öffnen Sie im Eclipse Package Explorer im Projekt 'OsgiTrackerImpl' das 'META-INF'-Verzeichnis und doppelklicken Sie auf die 'MANIFEST.MF'-Datei. Schalten Sie am unteren Rand auf den Tabulatorreiter 'Dependencies'. Klicken Sie im 'Imported Packages'-Fenster auf 'Add...'. Doppelklicken Sie in der Liste auf das Package 'datumservice' und speichern Sie mit 'Strg + S'.
Öffnen Sie im Eclipse Package Explorer die Verzeichnisse 'OsgiTrackerImpl' | 'src' | 'datumservice.impl'. Klicken Sie mit der rechten Maustaste auf das Package 'datumservice.impl' und wählen Sie: 'New' | 'Class' | 'Name = DatumServiceImpl'. Ersetzen Sie den Inhalt von 'DatumServiceImpl.java' durch:
package datumservice.impl; import java.text.SimpleDateFormat; import java.util.Date; import datumservice.DatumService; public class DatumServiceImpl implements DatumService { @Override public String getDatum() { return (new SimpleDateFormat( "yyyy-MM-dd HH:mm" )).format( new Date() ); } }
Öffnen Sie im Eclipse Package Explorer die Verzeichnisse 'OsgiTrackerImpl' | 'src' | 'datumservice.impl' und die Datei 'Activator.java' und ersetzen Sie den Inhalt durch:
package datumservice.impl; import org.osgi.framework.*; import datumservice.DatumService; public class Activator implements BundleActivator { @Override public void start( BundleContext context ) throws Exception { System.out.println( context.getBundle().getSymbolicName() + " startet ..." ); context.registerService( DatumService.class.getName(), new DatumServiceImpl(), null ); System.out.println( context.getBundle().getSymbolicName() + " gestartet und Dienst registriert." ); } @Override public void stop( BundleContext context ) throws Exception { System.out.println( context.getBundle().getSymbolicName() + " gestoppt." ); } }
Erstellen Sie ein neues OSGi-Bundle-Projekt in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >':
Project name: | OsgiTrackerKonsument |
Target Platform This plug-in is targeted to run with: |
an OSGi framework: standard |
'Next >' | |
ID: | Datum-Service-Konsument |
Version: | 1.0.0 |
Name: | Datum-Service-Konsument-Bundle |
Activator: | datumservice.consumer.Activator |
'Finish' |
Öffnen Sie im Eclipse Package Explorer im Projekt 'OsgiTrackerKonsument' das 'META-INF'-Verzeichnis und doppelklicken Sie auf die 'MANIFEST.MF'-Datei. Schalten Sie am unteren Rand auf den Tabulatorreiter 'Dependencies'. Klicken Sie im 'Imported Packages'-Fenster auf 'Add...'. Doppelklicken Sie in der Liste auf das Package 'datumservice'. Klicken Sie erneut auf 'Add...' und doppelklicken Sie diesmal auf 'org.osgi.util.tracker'. Speichern Sie mit 'Strg + S'.
Öffnen Sie im Eclipse Package Explorer die Verzeichnisse 'OsgiTrackerKonsument' | 'src' | 'datumservice.consumer' und die Datei 'Activator.java' und ersetzen Sie den Inhalt durch:
package datumservice.consumer; import org.osgi.framework.*; import org.osgi.util.tracker.*; import datumservice.DatumService; public class Activator implements BundleActivator { private ServiceTracker datumServiceTracker; @Override public void start( final BundleContext context ) { System.out.println( context.getBundle().getSymbolicName() + " startet ..." ); datumServiceTracker = new ServiceTracker( context, DatumService.class.getName(), new ServiceTrackerCustomizer() { @Override public Object addingService( final ServiceReference reference ) { final DatumService datumService = (DatumService) context.getService( reference ); if( datumService != null ) System.out.println( "Konsument-ServiceTracker liest Datum-Service: " + datumService.getDatum() ); return datumService; } @Override public void modifiedService( final ServiceReference reference, final Object service ) {/*ok*/} @Override public void removedService( final ServiceReference reference, final Object service ) {/*ok*/} }); datumServiceTracker.open(); System.out.println( context.getBundle().getSymbolicName() + " gestartet und Tracker geoeffnet." ); } @Override public void stop( final BundleContext context ) { if( datumServiceTracker != null ) datumServiceTracker.close(); System.out.println( context.getBundle().getSymbolicName() + " gestoppt." ); } }
(Sehen Sie sich die API-Doku zum ServiceTracker an.)
Wenn Sie die Eclipse-spezifischen Verzeichnisse und Dateien außer Acht lassen, sieht Ihre Verzeichnisstruktur jetzt im Wesentlichen folgendermaßen aus (kontrollieren Sie es mit "tree /F"):
[\MeinWorkspace] |- [OsgiTrackerImpl] | |- [bin] | | '- ... | |- [META-INF] | | '- MANIFEST.MF | '- [src] | '- [datumservice] | '- [impl] | |- Activator.java | '- DatumServiceImpl.java |- [OsgiTrackerInterface] | |- [bin] | | '- ... | |- [META-INF] | | '- MANIFEST.MF | '- [src] | '- [datumservice] | '- DatumService.java '- [OsgiTrackerKonsument] |- [bin] | '- ... |- [META-INF] | '- MANIFEST.MF '- [src] '- [datumservice] '- [consumer] '- Activator.java
Sehen Sie sich die Export- und Import-Deklarationen in den MANIFEST.MF-Dateien der drei Bundles an:
Ausschnitt aus der MANIFEST.MF vom OsgiTrackerInterface-Bundle:
Bundle-SymbolicName: Datum-Service-Interface Export-Package: datumservice ...
Ausschnitt aus der MANIFEST.MF vom OsgiTrackerImpl-Bundle:
Bundle-SymbolicName: Datum-Service-Impl Import-Package: datumservice, org.osgi.framework;version="1.3.0" ...
Ausschnitt aus der MANIFEST.MF vom OsgiTrackerKonsument-Bundle:
Bundle-SymbolicName: Datum-Service-Konsument Import-Package: datumservice, org.osgi.framework;version="1.3.0", org.osgi.util.tracker;version="1.3.3" ...
Beachten Sie, dass der Konsument nichts von der Implementierung importiert, sondern lediglich das datumservice-Interface-Package.
Die beiden Bundles 'Datum-Service-Impl' und 'Datum-Service-Konsument' melden sich. Lassen Sie sich die IDs, SymbolicNames und Stati der Bundles anzeigen:
ss
Stoppen Sie 'Datum-Service-Impl':
stop Datum-Service-Impl
Sie erhalten:
Datum-Service-Impl gestoppt.
Starten Sie 'Datum-Service-Impl' erneut:
start Datum-Service-Impl
Sie erhalten:
Datum-Service-Impl startet ...
Konsument-ServiceTracker liest Datum-Service: 2009-01-02 11:22
Datum-Service-Impl gestartet und Dienst registriert.
Der Konsument hat also bemerkt, dass der Service neu gestartet wurde.
Ein ähnliches Verhalten können Sie auch mit "refresh Datum-Service-Impl", "update Datum-Service-Impl" und "update *" beobachten.
Lassen Sie sich mit bundle Informationen zu Bundles anzeigen.
Das Datum-Service-Impl-Bundle hat einen "Registered Service", aber "No services in use":
bundle Datum-Service-Impl
-->
...
Registered Services
{datumservice.DatumService}={service.id=26}
No services in use.
...
Und das Datum-Service-Konsument-Bundle hat "No registered services", aber einen "Service in use":
bundle Datum-Service-Konsument
-->
...
No registered services.
Services in use:
{datumservice.DatumService}={service.id=26}
...
Lassen Sie sich mit packages anzeigen, welche anderen Bundles vom angegebenen Bundle abhängen:
packages Datum-Service-Interface
Sie erfahren, dass OsgiTrackerImpl und OsgiTrackerKonsument von OsgiTrackerInterface abhängen.
Lassen Sie sich mit diag unerfüllte Bedingungen anzeigen:
diag Datum-Service-Konsument
Lassen Sie sich mit headers den Inhalt der Bundle-MANIFEST.MF anzeigen, zum Beispiel:
headers Datum-Service-Konsument
Suchen Sie mit services nach Services. Verwenden Sie dabei die oben erläuterten filter-Ausdrücke, bei denen auch *-Wildcards erlaubt sind. Beispiele (unter der Annahme, dass für den DatumService service.id=26 gilt):
services (objectClass=*Datum*)
services (objectClass=datumservice.DatumService)
services (service.id=26)
services (& (objectClass=datumservice.*) (service.id>=22) )
services (& (service.id>=20) (service.id<=30) )
Lassen Sie sich mit status, bundles, services, threads und props weitere Informationen anzeigen und sehen Sie sich mit ? an, welche Kommandos es sonst noch gibt.
Erzeugen Sie eine "Equinox-Configuration": Legen Sie im Zielverzeichnis (z.B. MeinDatumService) das Verzeichnis config und darin die Datei config.ini mit folgendem Inhalt an (passen Sie die Pfade an):
osgi.bundles=\ ../MeinDatumService/plugins/Datum-Service-Interface@start,\ ../MeinDatumService/plugins/Datum-Service-Impl@start,\ ../MeinDatumService/plugins/Datum-Service-Konsument@start eclipse.ignoreApp=true
Ihre Verzeichnisstruktur sieht jetzt im Wesentlichen folgendermaßen aus (kontrollieren Sie es mit "tree /F"):
[C:\Tools\equinox-SDK] '- [MeinDatumService] |- [config] | '- config.ini '- [plugins] |- Datum-Service-Impl_1.0.0.jar |- Datum-Service-Interface_1.0.0.jar '- Datum-Service-Konsument_1.0.0.jar
Öffnen Sie im Equinox-SDK-Verzeichnis (z.B. C:\Tools\equinox-SDK) ein Kommandozeilenfenster und geben Sie ein (setzen Sie dabei wieder statt org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar den org.eclipse.osgi_...jar-Dateinamen von Ihrer Equinox-Version ein) (in einer Zeile):
java -jar plugins\org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -configuration MeinDatumService\config -console -clean
Sie erhalten:
osgi> Datum-Service-Impl startet ... Datum-Service-Impl gestartet und Dienst registriert. Datum-Service-Konsument startet ... Konsument-ServiceTracker liest Datum-Service: 2009-01-02 11:22 Datum-Service-Konsument gestartet und Tracker geoeffnet.
Falls Sie dies nicht erhalten: Dann finden Sie im C:\Tools\equinox-SDK\MeinDatumService\config-Verzeichnis eine .log-Datei mit der entsprechenden Fehlermeldung.
Im letzten Programmierbeispiel wurde gezeigt, wie mit einem Service Tracker dynamisch auf Änderungen reagiert werden kann. Im folgenden Programmierbeispiel wird stattdessen eine durch "Declarative Services" ("DS") definierte "Service Component" verwendet, was häufig die bessere und einfachere Variante darstellt.
Per Declarative Services definierte Service Components bestehen aus einer XML-Beschreibung (siehe z.B. Provider / Consumer) und der Dienst-Implementierung (siehe z.B. DatumServiceImpl). Falls in der Dienst-Implementierung auf die Aktivierung reagiert werden soll, kann optional eine activate()-Methode hinzugefügt werden (siehe ComponentContext-Beschreibung). Im Konsumenten können bind...()- und unbind...()-Methoden in der XML-Beschreibung definiert und im Konsument implementiert werden, damit der Konsument dynamisch auf den Service reagieren kann (siehe z.B. DatumServiceKonsument).
Einige Vorteile der Declarative Services sind weiter oben aufgezählt. Genaueres zu "Declarative Services" finden Sie im OSGi Service Platform Service Compendium.
Die Beschreibungen erfolgen diesmal etwas kürzer, um Wiederholungen zu vermeiden.
Erstellen Sie in Eclipse das neue OSGi-Bundle-Projekt "OsgiComponentInterface":
Project name: | OsgiComponentInterface |
Plug-in ID: | Datum-Component-Interface |
Plug-in Options Generate an activator: |
nein |
Legen Sie im OsgiComponentInterface-Projekt das Package datumservice und darin das Interface DatumService.java an:
package datumservice; public interface DatumService { String getDatum(); }
Ersetzen Sie im OsgiComponentInterface-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Datum-Component-Interface-Bundle Bundle-SymbolicName: Datum-Component-Interface Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Export-Package: datumservice
Erstellen Sie das neue OSGi-Bundle-Projekt "OsgiComponentImpl":
Project name: | OsgiComponentImpl |
Plug-in ID: | Datum-Component-Impl |
Plug-in Options Generate an activator: |
nein |
Ersetzen Sie im OsgiComponentImpl-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Datum-Component-Impl-Bundle Bundle-SymbolicName: Datum-Component-Impl Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: datumservice, org.osgi.framework;version="1.3.0", org.osgi.service.component;version="1.0.0" Service-Component: OSGI-INF/ds-component.xml MeinBundleMfSpezialKey: MeinBundleMfSpezialValue
Legen Sie im OsgiComponentImpl-Projekt das Verzeichnis OSGI-INF und darin die Datei ds-component.xml an:
<?xml version="1.0"?> <component name="Datum-Component-Impl"> <implementation class="datumservice.impl.DatumServiceImpl" /> <property name="MeinCompDescrSpezialKey" value="MeinCompDescrSpezialValue" /> <service> <provide interface="datumservice.DatumService" /> </service> </component>
Legen Sie im OsgiComponentImpl-Projekt das Package datumservice.impl und darin die Datei DatumServiceImpl.java an:
package datumservice.impl; import java.text.SimpleDateFormat; import java.util.*; import org.osgi.service.component.ComponentContext; import datumservice.DatumService; public class DatumServiceImpl implements DatumService { protected void activate( ComponentContext componentContext ) { System.out.println( "\nDatumServiceImpl aktiviert mit folgenden Spezial-Properties:" ); System.out.println( " MeinCompDescrSpezialKey = " + componentContext.getProperties().get( "MeinCompDescrSpezialKey" ) ); System.out.println( " MeinPropSpezialKey = " + componentContext.getBundleContext().getProperty( "MeinPropSpezialKey" ) ); System.out.println( " MeinBundleMfSpezialKey = " + componentContext.getBundleContext().getBundle().getHeaders().get( "MeinBundleMfSpezialKey" ) ); } protected void deactivate( ComponentContext componentContext ) { System.out.println( "DatumServiceImpl deaktiviert." ); } @Override public String getDatum() { return (new SimpleDateFormat( "yyyy-MM-dd HH:mm" )).format( new Date() ); } }
Erstellen Sie ein neues OSGi-Bundle-Projekt in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >':
Project name: | OsgiComponentKonsument |
Plug-in ID: | Datum-Component-Konsument |
Plug-in Options Generate an activator: |
nein |
Ersetzen Sie im OsgiComponentKonsument-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Datum-Component-Konsument-Bundle Bundle-SymbolicName: Datum-Component-Konsument Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: datumservice, org.osgi.framework;version="1.3.0", org.osgi.service.component;version="1.0.0" Service-Component: OSGI-INF/ds-component.xml
Legen Sie im OsgiComponentKonsument-Projekt das Verzeichnis OSGI-INF und darin die Datei ds-component.xml an:
<?xml version="1.0"?> <component name="Datum-Component-Konsument"> <implementation class="datumservice.consumer.DatumServiceKonsument" /> <reference name="Datum-Component-Interface" interface="datumservice.DatumService" bind="bindServiceComponent" unbind="unbindServiceComponent" /> </component>
Legen Sie im OsgiComponentKonsument-Projekt das Package datumservice.consumer und darin die Datei DatumServiceKonsument.java an:
package datumservice.consumer; import org.osgi.service.component.ComponentContext; import datumservice.DatumService; public class DatumServiceKonsument { private DatumService datumService; protected void bindServiceComponent( DatumService datumService ) { this.datumService = datumService; System.out.println( "DatumServiceKonsument: DatumService wurde uebergeben." ); } protected void unbindServiceComponent( DatumService datumService ) { this.datumService = null; System.out.println( "DatumServiceKonsument: DatumService wurde entfernt." ); } protected void activate( ComponentContext componentContext ) { System.out.println( "DatumServiceKonsument aktiviert." ); System.out.println( "DatumServiceKonsument liest Datum-Service: " + datumService.getDatum() ); } protected void deactivate( ComponentContext componentContext ) { System.out.println( "DatumServiceKonsument deaktiviert." ); } }
Bitte beachten Sie, dass diese Methoden Multithreading-sicher gestaltet werden müssen. Eventuell müssen Sie Teile der Methoden in synchronized-Blöcken implementieren.
Wenn Sie die Eclipse-spezifischen Verzeichnisse und Dateien außer Acht lassen, sieht Ihre Verzeichnisstruktur jetzt im Wesentlichen folgendermaßen aus (kontrollieren Sie es mit "tree /F"):
[\MeinWorkspace] |- [OsgiComponentImpl] | |- [bin] | | '- ... | |- [META-INF] | | '- MANIFEST.MF | |- [OSGI-INF] | | '- ds-component.xml | '- [src] | '- [datumservice] | '- [impl] | '- DatumServiceImpl.java |- [OsgiComponentInterface] | |- [bin] | | '- ... | |- [META-INF] | | '- MANIFEST.MF | '- [src] | '- [datumservice] | '- DatumService.java '- [OsgiComponentKonsument] |- [bin] | '- ... |- [META-INF] | '- MANIFEST.MF |- [OSGI-INF] | '- ds-component.xml '- [src] '- [datumservice] '- [consumer] '- DatumServiceKonsument.java
Wählen Sie in Eclipse: 'Run' | 'Run Configurations...'. Klicken Sie mit der rechten Maustaste auf 'OSGi Framework' und wählen Sie 'New'. Tragen Sie bei 'Name' 'OSGi-Component' ein. Klicken Sie auf den Button 'Deselect All' und aktivieren Sie anschließend folgende Bundles:
(x) Datum-Component-Impl
(x) Datum-Component-Interface
(x) Datum-Component-Konsument
(x) org.eclipse.equinox.ds
(x) org.eclipse.equinox.util
(x) org.eclipse.osgi
(x) org.eclipse.osgi.services
Klicken Sie auf 'Run'.
'DatumServiceImpl' und 'DatumServiceKonsument' melden ihre Aktivierungen und
der 'DatumServiceKonsument' liest den Datum-Service.
Lassen Sie sich die IDs, SymbolicNames und Stati der Bundles anzeigen:
ss
Setzen Sie eine Spezial-Property und Stoppen und Starten Sie 'Datum-Component-Impl':
setprop MeinPropSpezialKey=MeinPropSpezialValue
stop Datum-Component-Impl
start Datum-Component-Impl
Sie erhalten:
DatumServiceImpl aktiviert mit folgenden Spezial-Properties:
MeinCompDescrSpezialKey = MeinCompDescrSpezialValue
MeinPropSpezialKey = MeinPropSpezialValue
MeinBundleMfSpezialKey = MeinBundleMfSpezialValue
DatumServiceKonsument: DatumService wurde uebergeben.
DatumServiceKonsument aktiviert.
DatumServiceKonsument liest Datum-Service: 2009-01-02 11:22
Der Konsument hat also bemerkt, dass der Service neu gestartet wurde.
Ähnliches können Sie auch mit "refresh Datum-Component-Impl", "update Datum-Component-Impl" und "update *" beobachten.
Sehen Sie sich an, wie die speziellen Properties MeinBundleMfSpezialKey in der MANIFEST.MF, MeinPropSpezialKey über das setprop-Kommando und MeinCompDescrSpezialKey in ds-component.xml eingetragen und in DatumServiceImpl.java ausgelesen werden können (der einzige Sinn dieser Properties ist diese Demonstration, ansonsten können sie entfallen).
Falls Sie weitere ComponentContext-Properties sehen wollen, rufen Sie folgende Methode auf:
private static void printComponentContextProperties( ComponentContext componentContext ) { final String[] BCP = { Constants.FRAMEWORK_OS_NAME, Constants.FRAMEWORK_VENDOR, "MeinPropSpezialKey" }; System.out.println( "ComponentContext-Properties: " ); Dictionary<?,?> props = componentContext.getProperties(); for( Enumeration<?> keys = props.keys(); keys.hasMoreElements(); ) { String key = "" + keys.nextElement(); System.out.println( " " + key + " = " + props.get( key ) ); } System.out.println( "ComponentContext-BundleContext-Properties: " ); BundleContext bundleContext = componentContext.getBundleContext(); for( String key : BCP ) System.out.println( " " + key + " = " + bundleContext.getProperty( key ) ); System.out.println( "ComponentContext-BundleContext-Bundle-Properties: " ); props = bundleContext.getBundle().getHeaders(); for( Enumeration<?> keys = props.keys(); keys.hasMoreElements(); ) { String key = "" + keys.nextElement(); System.out.println( " " + key + " = " + props.get( key ) ); } }
Falls Sie noch mehr Properties sehen wollen, rufen Sie folgende Kommandos auf:
getprop MeinPropSpezialKey
getprop org.osgi
getprop osgi
getprop
Lassen Sie sich mit packages anzeigen, welche anderen Bundles vom angegebenen Bundle abhängen:
packages Datum-Component-Interface
Sie erfahren, dass OsgiComponentImpl und OsgiComponentKonsument von OsgiComponentInterface abhängen.
Suchen Sie mit services nach Services. Verwenden Sie dabei die oben erläuterten filter-Ausdrücke, bei denen auch *-Wildcards erlaubt sind. Beispiele (unter der Annahme, dass für den DatumService service.id=26 gilt):
services (objectClass=*Datum*)
services (objectClass=datumservice.DatumService)
services (service.id=26)
services (& (objectClass=datumservice.*) (service.id>=22) )
services (& (service.id>=20) (service.id<=40) )
Falls Sie die Bundles exportieren wollen: Vergessen Sie nicht, vorher die jeweiligen build.properties-Dateien (z.B. über den Eclipse-build.properties-Editor) so zu erweitern, dass die OSGI-INF-Verzeichnisse mit eingebunden werden.
Mit dem "Event Admin Service" können Events (= Ereignisse) Bundle-übergreifend versendet werden, und zwar wahlweise synchron oder asynchron. Genaueres zum "Event Admin Service" finden Sie im OSGi Service Platform Service Compendium.
Die Beschreibungen erfolgen wieder etwas kürzer, um Wiederholungen zu vermeiden.
Erstellen Sie das neue OSGi-Bundle-Projekt "OsgiEventSender":
Project name: | OsgiEventSender |
Plug-in ID: | Datum-Event-Sender |
Plug-in Options Generate an activator: |
nein |
Ersetzen Sie im OsgiEventSender-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Datum-Event-Sender-Bundle Bundle-SymbolicName: Datum-Event-Sender Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.osgi.framework;version="1.4.0", org.osgi.service.component;version="1.0.0", org.osgi.service.event;version="1.1.0" Service-Component: OSGI-INF/ds-component.xml
Legen Sie im OsgiEventSender-Projekt das Verzeichnis OSGI-INF und darin die Datei ds-component.xml an:
<?xml version="1.0"?> <component name="Datum-Event-Sender"> <implementation class="datumservice.eventsender.DatumServiceSender" /> <reference name="eventAdmin" interface="org.osgi.service.event.EventAdmin" bind="bindEventAdmin" unbind="unbindEventAdmin" /> </component>
Legen Sie im OsgiEventSender-Projekt das Package datumservice.eventsender und darin die Datei DatumServiceSender.java an:
package datumservice.eventsender; import java.text.SimpleDateFormat; import java.util.*; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.*; public class DatumServiceSender extends TimerTask { private EventAdmin eventAdmin; private Timer timer; public void bindEventAdmin( EventAdmin eventAdmin ) { this.eventAdmin = eventAdmin; } public void unbindEventAdmin( EventAdmin eventAdmin ) { this.eventAdmin = null; } protected void activate( ComponentContext componentContext ) { timer = new Timer(); timer.scheduleAtFixedRate( this, 0, 5000 ); System.out.println( "\nDatumServiceSender aktiviert." ); } protected void deactivate( ComponentContext componentContext ) { timer.cancel(); System.out.println( "DatumServiceSender deaktiviert." ); } @Override public void run() { String dateTime = (new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" )).format( new Date() ); Dictionary<String,String> eventProps = new Hashtable<String,String>(); eventProps.put( "Datum/Zeit", dateTime ); Event event = new Event( "datumservice/eventsender/Timer", eventProps ); // "sendEvent()" fuer synchron, "postEvent()" fuer asynchron: eventAdmin.sendEvent( event ); } }
Erstellen Sie ein neues OSGi-Bundle-Projekt in Eclipse: 'File' | 'New' | 'Project...' | 'Plug-in Development' | 'Plug-in Project' | 'Next >':
Project name: | OsgiEventEmpfaenger |
Plug-in ID: | Datum-Event-Empfaenger |
Plug-in Options Generate an activator: |
nein |
Ersetzen Sie im OsgiEventEmpfaenger-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Datum-Event-Empfaenger-Bundle Bundle-SymbolicName: Datum-Event-Empfaenger Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.osgi.framework;version="1.4.0", org.osgi.service.event;version="1.1.0" Service-Component: OSGI-INF/ds-component.xml
Legen Sie im OsgiEventEmpfaenger-Projekt das Verzeichnis OSGI-INF und darin die Datei ds-component.xml an:
<?xml version="1.0"?> <component name="Datum-Event-Empfaenger"> <implementation class="datumservice.eventempfaenger.DatumServiceEmpfaenger" /> <property name="event.topics" value="datumservice/eventsender/Timer" /> <service> <provide interface="org.osgi.service.event.EventHandler" /> </service> </component>
Legen Sie im OsgiEventEmpfaenger-Projekt das Package datumservice.eventempfaenger und darin die Datei DatumServiceEmpfaenger.java an:
package datumservice.eventempfaenger; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class DatumServiceEmpfaenger implements EventHandler { @Override public void handleEvent( Event event ) { System.out.println( event.getProperty( "Datum/Zeit" ) ); } }
Wenn Sie die Eclipse-spezifischen Verzeichnisse und Dateien außer Acht lassen, sieht Ihre Verzeichnisstruktur jetzt im Wesentlichen folgendermaßen aus (kontrollieren Sie es mit "tree /F"):
[\MeinWorkspace] |- [OsgiEventSender] | |- [bin] | | '- ... | |- [META-INF] | | '- MANIFEST.MF | |- [OSGI-INF] | | '- ds-component.xml | '- [src] | '- [datumservice] | '- [eventsender] | '- DatumServiceSender.java '- [OsgiEventEmpfaenger] |- [bin] | '- ... |- [META-INF] | '- MANIFEST.MF |- [OSGI-INF] | '- ds-component.xml '- [src] '- [datumservice] '- [eventempfaenger] '- DatumServiceEmpfaenger.java
Wählen Sie in Eclipse: 'Run' | 'Run Configurations...'. Klicken Sie mit der rechten Maustaste auf 'OSGi Framework' und wählen Sie 'New'. Tragen Sie bei 'Name' 'OSGi-Event' ein. Klicken Sie auf den Button 'Deselect All' und aktivieren Sie anschließend folgende Bundles:
(x) Datum-Event-Empfaenger
(x) Datum-Event-Sender
(x) org.eclipse.equinox.ds
(x) org.eclipse.equinox.event
(x) org.eclipse.equinox.util
(x) org.eclipse.osgi
(x) org.eclipse.osgi.services
Klicken Sie auf 'Run'.
Der 'DatumServiceSender' meldet seine Aktivierungen und der 'DatumServiceEmpfaenger' empfängt alle fünf Sekunden den "Datum/Zeit"-String.
Führen Sie folgende Kommandos in der OSGi-Konsole aus:
ss | → | Anzeige der IDs, SymbolicNames und Stati der Bundles: → sieben "ACTIVE" Bundles |
stop Datum-Event-Sender | → | Die Ausgabe der "Datum/Zeit"-Strings stoppt |
start Datum-Event-Sender | → | Die Ausgabe der "Datum/Zeit"-Strings beginnt wieder |
bundle Datum-Event-Sender | → | Services in use: {...EventAdmin}=... |
bundle Datum-Event-Empfaenger | → | Registered Services: {...EventHandler}={event.topics=datumservice/eventsender/Timer ...} |
services (objectClass=*Event*) | → |
...EventAdmin Bundles using service: initial@reference:file:.../OsgiEventSender/ ...EventHandler {event.topics=datumservice/eventsender/Timer, component.name=Datum-Event-Empfaenger, ...} Registered by bundle: initial@reference:file:.../OsgiEventEmpfaenger/ |
Falls Sie die Bundles exportieren wollen: Vergessen Sie nicht, vorher die jeweiligen build.properties-Dateien (z.B. über den Eclipse-build.properties-Editor) so zu erweitern, dass die OSGI-INF-Verzeichnisse mit eingebunden werden.
Mit dem "Http Service" können einfache Servlets als OSGi-Bundle realisiert werden. Der Http Service basiert bislang allerdings lediglich auf der Version 2.1 des Servlet API. Falls Sie weitergehende Optionen (z.B. ServletFilter) oder JSPs (JavaServer Pages) benötigen, sollten Sie sich Alternativen ansehen, zum Beispiel: Embedding an HTTP server in Equinox (z.B. "equinox.http.jetty"), Equinox in a Servlet Container ("servletbridge") oder Pax Web Extender.
Genaueres zum "Http Service" finden Sie im OSGi Service Platform Service Compendium.
Die Beschreibungen erfolgen wieder etwas kürzer, um Wiederholungen zu vermeiden.
Erstellen Sie das neue OSGi-Bundle-Projekt "OsgiServlet":
Project name: | OsgiServlet |
Plug-in ID: | OsgiServlet |
Plug-in Options Generate an activator: |
nein |
Ersetzen Sie im OsgiServlet-Projekt die META-INF/MANIFEST.MF-Datei durch:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: OsgiServlet-Bundle Bundle-SymbolicName: OsgiServlet Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.osgi.framework;version="1.4.0", javax.servlet;version="2.4.0", javax.servlet.http;version="2.4.0", org.osgi.service.http;version="1.2.0" Service-Component: OSGI-INF/ds-component.xml
Legen Sie im OsgiServlet-Projekt das Verzeichnis OSGI-INF und darin die Datei ds-component.xml an:
<?xml version="1.0"?> <component name="servletComponent"> <implementation class="servlet.ServletComponent" /> <reference name="httpService" interface="org.osgi.service.http.HttpService" bind="bindHttpService" unbind="unbindHttpService" cardinality="0..n" policy="dynamic" /> </component>
Legen Sie im OsgiServlet-Projekt das Package servlet und darin die Java-Klasse MeinServlet.java an:
package servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; public class MeinServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet( HttpServletRequest requ, HttpServletResponse resp ) throws ServletException, IOException { resp.setContentType( "text/html" ); resp.getOutputStream().print( "<html><h1>Hallo " + requ.getParameter( "name" ) + "!</h1></html>" ); resp.getOutputStream().flush(); } }
Legen Sie im Package servlet die Java-Klasse ServletComponent.java an:
package servlet; import org.osgi.service.http.HttpService; public class ServletComponent { protected void bindHttpService( HttpService httpService ) { try { httpService.registerServlet( "/meinservlet", new MeinServlet(), null, null ); httpService.registerResources( "/", "/html", null ); httpService.registerResources( "/img", "/images", null ); } catch( Exception ex ) { ex.printStackTrace(); } } protected void unbindHttpService( HttpService httpService ) { httpService.unregister( "/meinservlet" ); httpService.unregister( "/" ); httpService.unregister( "/img" ); } }
(Sehen Sie sich die API-Doku zu registerServlet() und registerResources() an.)
Legen Sie im OsgiServlet-Projekt das Verzeichnis html und darin die Datei MeinFormular.html an:
<html> <h1>Hallo</h1> <form name="Formular" method="get" action="meinservlet"> Name: <input name="name" type="text" /> <input value="Servlet anfordern" type="submit" /> </form> <img src="img/MeinBild.jpg" /> </html>
Legen Sie im OsgiServlet-Projekt das Verzeichnis images an und und kopieren Sie dorthinein eine beliebige JPEG-Bilddatei. Umbenennen Sie die Bilddatei zu MeinBild.jpg.
Wenn Sie die Eclipse-spezifischen Verzeichnisse und Dateien außer Acht lassen, sieht Ihre Verzeichnisstruktur jetzt im Wesentlichen folgendermaßen aus (kontrollieren Sie es mit "tree /F"):
[\MeinWorkspace\OsgiServlet] |- [bin] | '- ... |- [html] | '- MeinFormular.html |- [images] | '- MeinBild.jpg |- [META-INF] | '- MANIFEST.MF |- [OSGI-INF] | '- ds-component.xml '- [src] '- [servlet] |- MeinServlet.java '- ServletComponent.java
Wählen Sie in Eclipse: 'Run' | 'Run Configurations...'. Klicken Sie mit der rechten Maustaste auf 'OSGi Framework' und wählen Sie 'New'. Tragen Sie bei 'Name' 'OSGi-Servlet' ein. Klicken Sie auf den Button 'Deselect All' und aktivieren Sie anschließend folgende Bundles:
(x) OsgiServlet
(x) javax.servlet
(x) org.eclipse.equinox.ds
(x) org.eclipse.equinox.http
(x) org.eclipse.equinox.util
(x) org.eclipse.osgi
(x) org.eclipse.osgi.services
Klicken Sie auf 'Run'.
Rufen Sie das Servlet direkt auf über:
http://localhost/meinservlet.
Es meldet sich mit: "Hallo null!".
Rufen Sie die vorgeschaltete HTML-Seite auf:
http://localhost/MeinFormular.html.
Geben Sie einen Namen ein und betätigen Sie den Button.
Das Servlet antwortet zum Beispiel mit: "Hallo MeinName!".
Falls Sie nicht den Port 80 verwenden wollen, stellen Sie einen anderen ein (z.B. 8080):
Wählen Sie in Eclipse 'Run' | 'Run Configurations...' | 'OSGi Framework' | 'OSGi-Servlet'.
Unter dem Tabulatorreiter 'Arguments' fügen Sie im Feld 'VM arguments' -Dorg.osgi.service.http.port=8080 hinzu
(alternativ könnten Sie auch in der OSGi-Konsole eingeben:
setprop org.osgi.service.http.port=8080).
Anschließend rufen Sie die OSGi-Servlet-Anwendung auf über:
http://localhost:8080/MeinFormular.html.
Falls Sie die eingestellte Portnummer bei der Aktivierung ausgeben wollen:
Erweitern Sie die Import-Liste in META-INF/MANIFEST.MF um:
org.osgi.service.component;version="1.0.0"
Und fügen Sie folgende Methode zu ServletComponent.java hinzu:
protected void activate( ComponentContext componentContext ) { String port = componentContext.getBundleContext().getProperty( "org.osgi.service.http.port" ); if( port == null || port.trim().length() == 0 ) port = "80"; System.out.println( "ServletComponent aktiviert: http://localhost:" + port + "/MeinFormular.html" ); }
Führen Sie folgende Kommandos in der OSGi-Konsole aus:
ss | → | Anzeige der IDs, SymbolicNames und Stati der Bundles: → sieben "ACTIVE" Bundles |
bundle OsgiServlet | → | Services in use: {...HttpService}={http.port=8080, ... |
services (objectClass=*Http*) | → |
{...HttpService}={http.port=8080, ... Bundles using service: initial@reference:file:.../OsgiServlet/ |
Falls Sie die Bundles exportieren wollen: Vergessen Sie nicht, vorher die build.properties-Datei (z.B. über den Eclipse-build.properties-Editor) so zu erweitern, dass die html-, images- und OSGI-INF-Verzeichnisse mit eingebunden werden.