Dzięki serii artykułów Getting started with OSGi, w ostatnich dniach coraz więcej mówi się na temat OSGi. Ponieważ zajmuję się od jakiegoś czasu tym tematem, postanowiłem – w myśl zasady Jak wszyscy to i Wania – dorzucić coś do tego co zostało już napisane.
Zanim przejdę dalej, zachęcam do lektury krótkiego wprowadzenia w temat na blogu Jacka Laskowskiego, oraz wspomnianej wyżej serii artykułów.
Rzecz, o której chcę napisać, to możliwość śledzenia aktywności interesujących nas serwisów OSGi. Wyobraźmy sobie, że w momencie pojawienia się serwisu pewne przyciski aplikacji stają się dostępne, a w momencie zniknięcia serwisu – niedostępne. Możemy też skorzystać z usług serwisu tuż przed jego wyłaczeniem oraz natychmiast po jego pojawieniu się.
Na początku utworzymy trzy nowe projekty wtyczek: osgi1, osgi2, osgi3 w następujący sposób.
W projektach osgi2 i osgi3 dodajemy pakiety osgi.iface oraz osgi.impl. W pakietach osgi.iface umieszczamy następujący interfejs:
package osgi.iface;
public interface OsgiTest {
String show();
}
Natomiast w pakietach osgi.impl następującą klasę:
package osgi.impl;
import osgi.iface.OsgiTest;
public class OsgiTestImpl implements OsgiTest {
public String show() {
return "Hej! Jestem osgi2.";
}
}
Podstawiając oczywiście w projekcie osgi3 ciąg „Hej! Jestem osgi3.” w zwracanym stringu.
Teraz musimy zarejestrować nasze serwisy przy starcie wtyczki. W klasach Activator projektów osgi2 i osgi3 dodajemy następujący kod:
public void start(BundleContext context) throws Exception {
System.out.println("Witaj, jestem " + this.getClass().getName());
OsgiTest osgiTest = new OsgiTestImpl();
registration = context.registerService(
OsgiTest.class.getName(),
osgiTest, null);
System.out.println(this.getClass().getName() + ": Serwis zarejestrowany");
}
Natomiast przy zatrzymaniu, wyrejestrowujemy serwis:
public void stop(BundleContext context) throws Exception {
System.out.println("Pa pa "+ this.getClass().getName());
registration.unregister();
System.out.println(this.getClass().getName() + ": Serwis wyrejestrowany");
}
Następnie w metodzie start klasy Activator projektu osgi1 umieszczamy następujący kod:
final ServiceTracker tracker = new ServiceTracker(context,
"osgi.iface.OsgiTest", new ServiceTrackerCustomizer() {
public Object addingService(ServiceReference reference) {
System.out.println("pojawił się nowy serwis: "
+ reference);
Object service = context.getService(reference);
if (service != null) {
try {
Method method = service.getClass().getMethod(
"show", new Class[]{});
String wynik = (String) method.invoke(service,
new Object[]{});
System.out
.println("korzystam z niego:" + wynik);
} catch (Exception e) {
e.printStackTrace();
}
}
return service;
}
public void modifiedService(ServiceReference reference,
Object service) {
}
public void removedService(ServiceReference reference,
Object service) {
System.out.println("serwis zostanie usuniŕty: "
+ reference + ": " + service);
if (service != null) {
try {
Method method = service.getClass().getMethod(
"show", new Class[]{});
String wynik = (String) method.invoke(service,
new Object[]{});
System.out
.println("korzystam z niego:" + wynik);
} catch (Exception e) {
e.printStackTrace();
}
}
};
});
tracker.open();
Teraz już możemy uruchomić nasz przykład. Klikamy Wykonaj…/Środowisko Equinox OSG/Nowa konfiguracja startowa. Na zakładce wtyczki zaznaczamy nasze 3 wtyczki i klikamy wykonaj. Na konsoli powinniśmy zobaczyć coś takiego:
osgi> Witaj, jestem OSGi1!
Witaj, jestem osgi2.Activator
pojawił się nowy serwis: {osgi.iface.OsgiTest}={service.id=20}
korzystam z niego:Hej! Jestem osgi2.
osgi2.Activator: Serwis zarejestrowany
Witaj, jestem osgi3.Activator
pojawił się nowy serwis: {osgi.iface.OsgiTest}={service.id=21}
korzystam z niego:Hej! Jestem osgi3.
osgi3.Activator: Serwis zarejestrowany
Jak widać nasz pierwszy plugin skorzystał z dwóch serwisów dostarczających implementację interfejsu osgi.iface.OsgiTest. Listę aktualnie dostępnych serwisów zwraca nam metoda getService klasy ServiceTracker.
Spróbujmy teraz zatrzymać i uruchomić jeden z serwisów:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE system.bundle_3.2.1.R32x_v20060919
8 ACTIVE osgi1_1.0.0
9 ACTIVE osgi2_1.0.0
10 ACTIVE osgi3_1.0.0
osgi> stop 9
Pa pa osgi2.Activator
serwis zostanie usunięty: {osgi.iface.OsgiTest}={service.id=22}: osgi.impl.OsgiTestImpl@c5c3ac
korzystam z niego:Hej! Jestem osgi2.
osgi2.Activator: Serwis wyrejestrowany
osgi> start 9
Witaj, jestem osgi2.Activator
pojawił się nowy serwis: {osgi.iface.OsgiTest}={service.id=23}
korzystam z niego:Hej! Jestem osgi2.
osgi2.Activator: Serwis zarejestrowany
osgi> close
Pa pa osgi3.Activator
serwis zostanie usunięty: {osgi.iface.OsgiTest}={service.id=21}: osgi.impl.OsgiTestImpl@17fa65e
korzystam z niego:Hej! Jestem osgi3.
osgi3.Activator: Serwis wyrejestrowany
Pa pa osgi2.Activator
serwis zostanie usunięty: {osgi.iface.OsgiTest}={service.id=23}: osgi.impl.OsgiTestImpl@18385e3
korzystam z niego:Hej! Jestem osgi2.
osgi2.Activator: Serwis wyrejestrowany
Pa pa OSGi1!!
Jak widać nasz plugin jest w stanie reagować na start i zatrzymywanie śledzonych serwisów.
Mam nadzieję, że ten przykład zachęci was do zainteresowania się bliżej standardem OSGi.