Pengantar OSGi

1. Perkenalan

Beberapa aplikasi Java mission-critical dan middleware memiliki beberapa persyaratan teknologi yang sulit.

Beberapa harus mendukung penerapan panas, agar tidak mengganggu layanan yang sedang berjalan - dan yang lainnya harus dapat bekerja dengan versi berbeda dari paket yang sama demi mendukung sistem lama eksternal.

The OSGi platform merupakan solusi yang layak untuk mendukung semacam ini persyaratan.

The Open Service Gateway Initiative adalah spesifikasi mendefinisikan sistem komponen berbasis Java. Saat ini dikelola oleh OSGi Alliance , dan versi pertamanya berasal dari tahun 1999.

Sejak itu, telah terbukti menjadi standar yang bagus untuk sistem komponen, dan banyak digunakan saat ini. The Eclipse IDE , misalnya, adalah sebuah OSGi aplikasi berbasis.

Pada artikel ini, kita akan membahas beberapa fitur dasar OSGi yang memanfaatkan implementasi yang disediakan oleh Apache .

2. Dasar-dasar OSGi

Di OSGi, satu komponen disebut bundel.

Logikanya, bundel adalah bagian dari fungsionalitas yang memiliki siklus hidup independen - yang berarti dapat dimulai, dihentikan, dan dihapus secara independen.

Secara teknis, bundel hanyalah file jar dengan file MANIFEST.MF yang berisi beberapa header khusus OSGi.

The OSGi Platform menyediakan cara untuk menerima pemberitahuan tentang bundel menjadi tersedia atau ketika mereka dihapus dari platform. Ini akan memungkinkan klien yang dirancang dengan baik untuk tetap bekerja, mungkin dengan fungsionalitas yang terdegradasi, bahkan ketika layanan yang bergantung padanya, untuk sementara tidak tersedia.

Karena itu, bundel harus secara eksplisit menyatakan paket apa yang perlu diaksesnya dan platform OSGi akan memulainya hanya jika dependensi tersedia dalam bundel itu sendiri atau dalam bundel lain yang sudah diinstal di platform.

3. Mendapatkan Alat

Kami akan memulai perjalanan kami di OSGi dengan mengunduh Apache Karaf versi terbaru dari tautan ini. Apache Karaf adalah platform yang menjalankan aplikasi berbasis OSG ; hal ini didasarkan pada Apache pelaksanaan 's dari OSGi spesifikasi yang disebut Apache Felix .

Karaf menawarkan beberapa fitur praktis di atas Felix yang akan membantu kita mengenal OSGi , misalnya, antarmuka baris perintah yang memungkinkan kita berinteraksi dengan platform.

Untuk menginstal Karaf , Anda dapat mengikuti instruksi instalasi dari dokumentasi resmi.

4. Titik Masuk Bundel

Untuk menjalankan aplikasi dalam lingkungan OSGi, kita harus mengemasnya sebagai bundel OSGi dan menentukan titik masuk aplikasi, dan itu bukan metode public static void main (String [] args) yang biasa.

Jadi, mari kita mulai dengan membangun aplikasi “Hello World” berbasis OSG .

Kami mulai menyiapkan ketergantungan sederhana pada inti OSGi API :

 org.osgi org.osgi.core 6.0.0 provided 

Dependensi dideklarasikan sebagai disediakan karena akan tersedia pada runtime OSGi , dan bundle tidak perlu menyematkannya.

Sekarang mari kita tulis kelas HelloWorld sederhana :

public class HelloWorld implements BundleActivator { public void start(BundleContext ctx) { System.out.println("Hello world."); } public void stop(BundleContext bundleContext) { System.out.println("Goodbye world."); } }

BundleActivator adalah antarmuka yang disediakan oleh OSGi yang harus diimplementasikan oleh kelas yang merupakan titik masuk untuk sebuah bundel.

Metode start () dipanggil oleh platform OSGi saat bundel yang berisi kelas ini dimulai. Di sisi lain, stop () dipanggil sebelum sebelum bundel dihentikan.

Ingatlah bahwa setiap bundel dapat berisi paling banyak satu BundleActivator . The BundleContext objek yang disediakan untuk kedua metode memungkinkan berinteraksi dengan OSGi runtime. Kami akan segera kembali.

5. Membangun Bundel

Mari memodifikasi pom.xml dan menjadikannya bundel OSGi yang sebenarnya.

Pertama-tama, kita harus secara eksplisit menyatakan bahwa kita akan membuat bundel, bukan toples:

bundle

Kemudian kami memanfaatkan maven-bundle-plugin, milik komunitas Apache Felix , untuk mengemas kelas HelloWorld sebagai bundel OSGi :

 org.apache.felix maven-bundle-plugin 3.3.0 true    ${pom.groupId}.${pom.artifactId}  ${pom.name} ${pom.version}  com.baeldung.osgi.sample.activator.HelloWorld   com.baeldung.osgi.sample.activator    

Di bagian instruksi, kami menetapkan nilai header OSGi yang ingin kami sertakan dalam file MANIFEST bundel.

Bundle-Activator adalah nama yang sepenuhnya memenuhi syarat dari implementasi BundleActivator yang akan digunakan untuk memulai dan menghentikan bundel, dan ini merujuk ke kelas yang baru saja kita tulis.

Private-Package bukan header OSGi, tetapi digunakan untuk memberi tahu plugin agar menyertakan paket dalam bundel tetapi tidak membuatnya tersedia untuk yang lain. Kita sekarang dapat membangun bundel dengan perintah biasa mvn clean install .

6. Memasang dan Menjalankan Bundel

Mari kita mulai Karaf dengan menjalankan perintah:

/bin/karaf start

dimana adalah folder tempat Karaf diinstal. Ketika prompt konsol Karaf muncul, kita dapat menjalankan perintah berikut untuk menginstal bundel:

> bundle:install mvn:com.baeldung/osgi-intro-sample-activator/1.0-SNAPSHOT Bundle ID: 63

Ini menginstruksikan Karaf untuk memuat bundel dari repositori Maven lokal.

In return Karaf prints out the numeric ID assigned to the bundle that depends on the number of bundles already installed and may vary. The bundle is now just installed, we can now start it with the following command:

> bundle:start 63 Hello World

“Hello World” immediately appears as soon the bundle is started. We can now stop and uninstall the bundle with:

> bundle:stop 63 > bundle:uninstall 63

“Goodbye World” appears on the console, accordingly to the code in the stop() method.

7. An OSGi Service

Let's go on writing a simple OSGi service, an interface that exposes a method for greeting people:

package com.baeldung.osgi.sample.service.definition; public interface Greeter { public String sayHiTo(String name); }

Let's write an implementation of it that is a BundleActivator too, so we'll be able to instantiate the service and register it on the platform when the bundle is started:

package com.baeldung.osgi.sample.service.implementation; public class GreeterImpl implements Greeter, BundleActivator { private ServiceReference reference; private ServiceRegistration registration; @Override public String sayHiTo(String name) { return "Hello " + name; } @Override public void start(BundleContext context) throws Exception { System.out.println("Registering service."); registration = context.registerService( Greeter.class, new GreeterImpl(), new Hashtable()); reference = registration .getReference(); } @Override public void stop(BundleContext context) throws Exception { System.out.println("Unregistering service."); registration.unregister(); } }

We use the BundleContext as a mean of requesting the OSGi platform to register a new instance of the service.

We should also provide the type of the service and a map of the possible configuration parameters, which aren't needed in our simple scenario. Let's now proceed with the configuration of the maven-bundle-plugin:

 org.apache.felix maven-bundle-plugin true    ${project.groupId}.${project.artifactId}   ${project.artifactId}   ${project.version}   com.baeldung.osgi.sample.service.implementation.GreeterImpl   com.baeldung.osgi.sample.service.implementation   com.baeldung.osgi.sample.service.definition    

It's worth noting that only the com.baeldung.osgi.sample.service.definition package has been exported this time, through the Export-Package header.

Thanks to this, OSGi will allow other bundles to invoke only the methods specified in the service interface. Package com.baeldung.osgi.sample.service.implementation is marked as private, so no other bundle will be able to access the members of the implementation directly.

8. An OSGi Client

Let's now write the client. It simply looks up the service at startup and invokes it:

public class Client implements BundleActivator, ServiceListener { }

Let's implement the BundleActivator start() method:

private BundleContext ctx; private ServiceReference serviceReference; public void start(BundleContext ctx) { this.ctx = ctx; try { ctx.addServiceListener( this, "(objectclass=" + Greeter.class.getName() + ")"); } catch (InvalidSyntaxException ise) { ise.printStackTrace(); } }

The addServiceListener() method allows the client to ask the platform to send notifications about the service that complies with the provided expression.

The expression uses a syntax similar to the LDAP's one, and in our case, we're requesting notifications about a Greeter service.

Let's go on to the callback method:

public void serviceChanged(ServiceEvent serviceEvent) { int type = serviceEvent.getType(); switch (type){ case(ServiceEvent.REGISTERED): System.out.println("Notification of service registered."); serviceReference = serviceEvent .getServiceReference(); Greeter service = (Greeter)(ctx.getService(serviceReference)); System.out.println( service.sayHiTo("John") ); break; case(ServiceEvent.UNREGISTERING): System.out.println("Notification of service unregistered."); ctx.ungetService(serviceEvent.getServiceReference()); break; default: break; } }

When some modification involving the Greeter service happens, the method is notified.

When the service is registered to the platform, we get a reference to it, we store it locally, and we then use it to acquire the service object and invoke it.

When the server is later unregistered, we use the previously stored reference to unget it, meaning that we tell the platform that we are not going to use it anymore.

We now just need to write the stop() method:

public void stop(BundleContext bundleContext) { if(serviceReference != null) { ctx.ungetService(serviceReference); } }

Here again, we unget the service to cover the case in which the client is stopped before the service is being stopped. Let's give a final look at the dependencies in the pom.xml:

 com.baeldung osgi-intro-sample-service 1.0-SNAPSHOT provided   org.osgi org.osgi.core 6.0.0 

9. Client and Service

Let's now install the client and service bundles in Karaf by doing:

> install mvn:com.baeldung/osgi-intro-sample-service/1.0-SNAPSHOT Bundle ID: 64 > install mvn:com.baeldung/osgi-intro-sample-client/1.0-SNAPSHOT Bundle ID: 65

Always keep in mind that the identifier numbers assigned to each bundle may vary.

Let's now start the client bundle:

> start 65

Therefore, nothing happens because the client is active and it's waiting for the service, that we can start with:

> start 64 Registering service. Service registered. Hello John

What happens is that as soon as the service's BundleActivator starts, the service is registered to the platform. That, in turn, notifies the client that the service it was waiting for is available.

Klien kemudian mendapatkan referensi ke layanan dan menggunakannya untuk menjalankan implementasi yang dikirimkan melalui paket layanan.

10. Kesimpulan

Pada artikel ini, kami mengeksplorasi fitur-fitur penting OSGi dengan contoh langsung yang cukup untuk memahami potensi OSGi.

Kesimpulannya, kapan pun kami harus menjamin bahwa satu aplikasi harus diperbarui tanpa merugikan, OSGi dapat menjadi solusi yang layak.

Kode untuk posting ini dapat ditemukan di GitHub.