Što je OSGi? Drugačiji pristup modularnosti Java

OSGi olakšava stvaranje i upravljanje modularnim Java komponentama (zvanim snopovi ) koje se mogu rasporediti u spremnik. Kao programer koristite OSGi specifikaciju i alate za stvaranje jednog ili više snopova. OSGi definira životni ciklus ovih snopova. Također ih ugošćuje i podržava njihovu interakciju u spremniku. Možete smatrati OSGi spremnik otprilike analognim JVM-u, s dodatnim ovlastima. Isto tako, mislite na snopove kao Java programe s jedinstvenim sposobnostima. Paketi se izvode unutar OSGi spremnika kao klijentske i poslužiteljske komponente.

OSGi savez

OSGi je započeo 1999. godine, a za razliku od mnogih drugih specifikacija, standardom ne upravlja Oracle, Java Community Process ili Eclipse Foundation. Umjesto toga, njime upravlja savezništvo OSGi.

Po čemu se OSGi razlikuje

Filozofija OSGi-a razlikuje se od filozofije ostalih okvira temeljenih na Javi, ponajviše Proljeća. U OSGi, više aplikacija može postojati unutar istog spremnika: okruženje izvršavanja OSGi snopa . Spremnik osigurava da je svaka komponenta dovoljno izolirana i ima pristup svim ovisnostima koje zahtijeva. OSGi može podržati ubrizgavanje ovisnosti, što je standardizirano projektom Aries Blueprint. Pored pružanja OSGi-jeve inverzije kontrole (IoC) spremnika, Aries podržava standardne Java okvire poput Java Persistence API (JPA).

U OSGi, snopovi mogu izložiti usluge koje drugi paketi koriste. Snop također može deklarirati verziju i može definirati o kojim drugim snopovima ovisi. Tada će se izvršavanje automatski učitati sve svoje snopove redoslijedom ovisnosti. U OSGi, više verzija istog snopa može postojati jedna pored druge, ako to zahtijevaju ovisnosti snopa.

OSGi u Eclipse IDE-u i Equinoxu

OSGi postoji u nekom obliku već nekoliko desetljeća. Koristi se za mnoge dobro poznate programe, od ugrađenih mobilnih uređaja do aplikacijskih poslužitelja i IDE-a.

Popularni Eclipse IDE izgrađen je na vrhu OSGi-a. Eclipseova implementacija OSGi spremnika naziva se Equinox. To je sjajan primjer za razumijevanje OSGi-a. Baziranje na OSGi znači da je Equinox modularna platforma. U njemu se pružaju razne usluge koje programeri mogu dodati po volji. Svaki od ovih nudi sposobnost koja bi programeru trebala u njegovom IDE-u. Možete dodati uređivače za Javu i JavaScript, poslužitelj aplikacija i konektor baze podataka. Svaki od njih implementiran je kao OSGi paket koji se dodaje u spremnik i može komunicirati s drugim uslugama u spremniku.

Nedavno se povećao interes za korištenjem OSGi-a za Internet stvari (IoT). OSGi je prirodan oblik za ovu vrstu razvoja, koji ima razne softverske komponente koje se usporedno pokreću na uređajima, a da pritom nužno ne znaju jedni za druge. Spremnik OSGi pruža jednostavan i standardiziran način za smještaj ovih dinamičnih softverskih komponenti.

Korištenje OSGi-a u Java projektu: Knoplerfish OSGi

Radit ćemo na primjeru aplikacije koja će OSGi koncepte učiniti konkretnijima. Naš se primjer temelji na izvođenju Knoplerfish OSGi, koje se koristi u mnogim proizvodnim implementacijama. Knoplerfish uključuje GUI i sučelje naredbenog retka (CLI) za upravljanje OSGi spremnikom i njegovim snopovima.

Prvo što ćete učiniti je preuzeti Knoplerfish. Trenutna verzija u vrijeme pisanja ovog članka je Knoplerfish OSGi 6.1.3. Tu verziju možete zamijeniti onim što je najaktualnije kada pročitate ovaj članak.

Nakon što ste preuzeli i instalirali Knoplerfish, koristite CLI da ispadne u direktoriju gdje ste preuzeli datoteku JAR i unesite: java -jar framework.jar. To će pokrenuti izvršni JAR i trebao bi vas dočekati GUI prozor.

Grafički korisnički priručnik Knoplerfish OSGi

GUI za Knoplerfish OSGi u početku se može činiti neodoljivim, ali osnove su jednostavne:

  • Na vrhu zaslona nalazi se izbornik.
  • S lijeve strane nalazi se skup snopova koji su učitani u vrijeme izvođenja.
  • Desno je informativni prozor.
  • Na dnu je konzola za izlaz teksta.
  • Na samom dnu je ulazna konzola.
Matthew Tyson

Upišite helpu ulaznu konzolu ako želite vidjeti opcije pomoći.

Prije nego što prijeđemo na primjer, pogledajte skup pokrenutih snopova. Vidjet ćete paket nazvan HTTP Server, što znači da je paket koji pokreće HTTP poslužitelj pokrenut. Idite u svoj preglednik i pogledajte // localhost: 8080. Svakako, vidjet ćete web stranicu Knoplerfish.

Paket "Hello JavaWorld"

Upotrijebimo OSGi vrijeme izvođenja za izgradnju jednostavnog snopa, koji ću nazvati Hello JavaWorld. Ovaj paket izbacuje poruku na konzolu.

U Popisu 1 koristimo Maven za izradu snopa. Ima samo jednu ovisnost, koju pruža savez OSGi.

Popis 1. OSGi ovisnost u Maven POM-u

   org.osgi org.osgi.core   

Sad ćemo koristiti i dodatak, zahvaljujući projektu Apache Felix. Ovaj dodatak brine se za pakiranje aplikacije kao OSGi paketa za upotrebu. Popis 2 prikazuje konfiguraciju koju ćemo koristiti.

Popis 2. OSGi Felix dodatak u Maven POM-u

   org.apache.felix maven-bundle-plugin true   org.javaworld.osgi org.javaworld.osgi.Hello     

Sada možemo pogledati jednostavnu klasu koja će prikazati "Hello".

Popis 3. Pozdrav paket JavaWorld OSGi

 package com.javaworld.osgi; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class HelloJavaWorld implements BundleActivator { public void start(BundleContext ctx) { System.out.println("Hello JavaWorld."); } public void stop(BundleContext bundleContext) { } } 

Izgradite snop odlaskom na naredbeni redak i upisivanjem mvn clean install. To će dati JAR datoteku koja sadrži paket. Sada idite na Fileizbornik u Knoplerfish GUI-u i odaberite Add Bundle. Ovo će pružiti preglednik datoteka. Pronađite JAR koji smo upravo napravili i odaberite ga.

Upravljanje OSGi snopovima u spremniku

U izlaznom prozoru korisničkog sučelja Knoplerfish vidjet ćete poruku "Hello, JavaWorld". Kliknite paket u GUI-ju Knoplerfish i vidjet ćete ID koji mu je dodijelio spremnik. Kada budete spremni zaustaviti paket, možete kliknuti stavku izbornika Stop. Drugi način je ulazak stop [bundle number]na naredbeni redak. Možete upravljati snopovima u spremniku koristeći GUI ili naredbeni redak.

Sada imate predodžbu o tome kako jednostavan paket radi u OSGi spremniku. Gdje god postoji OSGi spremnik, naći ćete istu jednostavnost u pokretanju i zaustavljanju snopova. OSGi stvara okruženje i životni ciklus za paket.

Interakcije s paketom: usluge i klijenti

Dalje ćemo pogledati kako svežnji međusobno komuniciraju.

The first thing we’ll do is create a service bundle. A service bundle is analogous to an EJB session bean: It provides a component that can be accessed by other bundles via a remote interface. To create a service bundle, we need to provide both an interface and an implementation class.

Listing 4. The service bundle interface

 package com.javaworld.osgi.service; public interface WhatIsOsgi { public Integer addNum(Integer x, Integer y); } 

Listing 4 is a simple interface. The only method is a addNum() method that will do what it implies: return the addition of two numbers. The implementation shown in Listing 5 is equally simple but adds a couple of OSGi-specific methods.

Listing 5. The service bundle implementation

 package com.javaworld.osgi.service; public class WhatIsOsgiImpl implements WhatIsOsgi, BundleActivator { private ServiceReference ref; private ServiceRegistration reg; @Override public Integer addNum(Integer x, Integer y){ return x + y; } @Override public void start(BundleContext context) throws Exception { reg = context.registerService( WhatIsOsgi.class, new WhatIsOsgiImpl(), new Hashtable()); ref = reg.getReference(); } @Override public void stop(BundleContext context) throws Exception { reg.unregister(); } } 

Let’s look closer at what’s happening in Listing 5:

  1. public class WhatIsOsgiImpl implements WhatIsOsgi, BundleActivator: Here we are implementing the interface we created. Note that we also implement the BundleActivator interface, as we did with the HelloJavaWorld example. The latter is because this bundle will activate itself.
  2. private ServiceReference ref; private ServiceRegistration reg;: These are variables for the OSGi registration service and the bundle reference for this service, respectively.
  3. public Integer addNum(Integer x, Integer y): This is the simple implementation of the add method.
  4. public void start(BundleContext context): This start method is part of the BundleActivator interface, and is executed by the container. In this example, we obtain a reference to the OSGi registration service and apply it to our WhatIsOsgi interface and implementation. The empty Hashtable is for config params, which we aren’t using here. We also get a reference to the service we have just created.
  5. public void stop(BundleContext context): Here, we simply unregister the service. This simple service just manages the barest elements of its lifecycle. Its main purpose is to expose the addNum method to the OSGi container.

The OSGi client

Next up, let’s write a client that can use the service. This client will again make use of the BundleActivator interface. It will also add the ServiceListener interface, as shown in Listing 6.

Listing 6. The OSGi service client bundle

 public class OsgiClient implements BundleActivator, ServiceListener { private BundleContext ctx; private ServiceReference service; public void start(BundleContext ctx) { this.ctx = ctx; try { ctx.addServiceListener(this, "(objectclass=" + WhatIsOsgi.class.getName() + ")"); } catch (InvalidSyntaxException ise) { ise.printStackTrace(); } } } 

Listing 6 has a start method that will add a service listener. This listener is filtered by the class name of the service we created in Listing 5. When the service is updated, it will call the serviceChanged() method, as shown in Listing 7.

Listing 7. serviceChanged method

 public void serviceChanged(ServiceEvent event) { int type = event.getType(); switch (type){ case(ServiceEvent.REGISTERED): serviceReference = event.getServiceReference(); Greeter service = (Greeter)(ctx.getService(service)); System.out.println("Adding 10 and 100: " + service.addNum(10, 100) ); break; case(ServiceEvent.UNREGISTERING): System.out.println("Service unregistered."); ctx.ungetService(event.getServiceReference()); // Releases reference to service so it can be GC'd break; default: break; } } 

Note that the serviceChanged method is used to determine what event has occurred for a service we are interested in. The service will then respond as specified. In this case, when the REGISTERED event appears, we make use of the addNum() method.

The OSGi alternative

This has been a quick introduction to OSGi, the Open Services Gateway Initiative. As you’ve seen through the Knoplerfish example, OSGi provides a runtime environment where you can define modular Java components (bundles). It provides a defined lifecycle for hosting bundles in the client, and it supports bundles interacting as clients and services within the container. All of these capabilities taken together provide an interesting alternative to standard Java runtimes and frameworks, especially for mobile and IoT applications.

Na kraju, imajte na umu da je prethodni članak u seriji “Što je: Java” predstavio sustav modula Java Platform, koji nudi drugačiji pristup istom izazovu Java modularnosti.

Ovu priču "Što je OSGi? Drugačiji pristup modularnosti Jave" izvorno je objavio JavaWorld.