OSGi – śledzenie aktywności serwisów

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.

Dodaj komentarz