OSGiとは何ですか?Javaモジュール性への異なるアプローチ

OSGiは、コンテナーにデプロイできるモジュラーJavaコンポーネント(バンドルと呼ばれる)の作成と管理を容易にします。開発者は、OSGi仕様とツールを使用して1つ以上のバンドルを作成します。OSGiは、これらのバンドルのライフサイクルを定義します。また、それらをホストし、コンテナー内での相互作用をサポートします。OSGiコンテナーは、JVMにほぼ類似しており、追加の機能を備えていると考えることができます。同様に、バンドルは独自の機能を備えたJavaアプリケーションと考えてください。バンドルは、クライアントおよびサーバーコンポーネントとしてOSGiコンテナー内で実行されます。

OSGiアライアンス

OSGiは1999年に開始され、他の多くの仕様とは異なり、標準はOracle、Java Community Process、またはEclipseFoundationによって管理されていません。代わりに、OSGiアライアンスによって管理されています。

OSGiの違い

OSGiの哲学は、他のJavaベースのフレームワーク、特にSpringの哲学とは異なります。OSGiでは、複数のアプリケーションが同じコンテナー内に存在する可能性があります:OSGiバンドルランタイム環境。コンテナは、各コンポーネントが十分に分離されていることを保証し、必要な依存関係にもアクセスできます。OSGiは、AriesBlueprintプロジェクトによって標準化されている依存性注入をサポートできます。Ariesは、OSGiの制御の反転(IoC)コンテナーを提供することに加えて、Java Persistence API(JPA)などの標準のJavaフレームワークをサポートします。

OSGiでは、バンドルは他のバンドルが使用するサービスを公開できます。バンドルはバージョンを宣言することもでき、それが依存する他のバンドルを定義することもできます。ランタイムは、依存関係の順にすべてのバンドルを自動的にロードします。OSGiでは、バンドルの依存関係で必要な場合、同じバンドルの複数のバージョンが並んで存在できます。

EclipseIDEおよびEquinoxのOSGi

OSGiは、数十年前から何らかの形で存在しています。組み込みモバイルデバイスからアプリケーションサーバーやIDEまで、多くの有名なアプリケーションに使用されています。

人気のあるEclipseIDEは、OSGi上に構築されています。 EclipseによるOSGiコンテナーの実装は、Equinoxと呼ばれます。これは、OSGiを理解するための優れた例です。 OSGiに基づいているということは、Equinoxがモジュラープラットフォームであることを意味します。開発者が自由に追加できるさまざまなサービスをホストします。これらはそれぞれ、開発者がIDEで必要とする可能性のある機能を提供します。 JavaとJavaScriptのエディター、アプリサーバー、データベースコネクタを追加できます。これらはそれぞれ、コンテナーに追加され、コンテナー内の他のサービスと対話できるOSGiバンドルとして実装されます。

最近、モノのインターネット(IoT)にOSGiを使用することに関心が高まっています。OSGiは、このタイプの開発に自然に適合します。OSGiには、デバイス上でさまざまなソフトウェアコンポーネントが並行して実行されており、必ずしもお互いを知る必要はありません。OSGiコンテナーは、これらの動的ソフトウェアコンポーネントをホストするためのシンプルで標準化された方法を提供します。

JavaプロジェクトでのOSGiの使用:Knoplerfish OSGi

OSGiの概念をより具体的にするサンプルアプリケーションを実行します。この例は、多くの本番デプロイメントで使用されるKnoplerfishOSGiランタイムに基づいています。Knoplerfishには、OSGiコンテナーとそのバンドルを管理するためのGUIとコマンドラインインターフェース(CLI)が含まれています。

最初に行うことは、Knoplerfishをダウンロードすることです。この記事の執筆時点での現在のバージョンは、Knoplerfish OSGi6.1.3です。この記事を読んだときに、そのバージョンを最新のものに置き換えることができます。

Knoplerfishをダウンロードしてインストールした後、CLIを使用してJARファイルをダウンロードしたディレクトリにドロップし、次のように入力しますjava -jar framework.jar。これにより実行可能JARが実行され、GUIウィンドウが表示されます。

Knoplerfish OSGi GUI

Knoplerfish OSGiのGUIは最初は圧倒されるように思えるかもしれませんが、基本は単純です。

  • 画面上部にはメニューがあります。
  • 左側は、ランタイムにロードされたバンドルのセットです。
  • 右側には情報ウィンドウがあります。
  • 下部にはテキスト出力コンソールがあります。
  • 一番下には入力コンソールがあります。
マシュータイソン

入力helpあなたはヘルプオプションを表示する場合は、入力コンソールに。

例に移る前に、実行中のバンドルのセットを見てください。と呼ばれるHTTP Serverバンドルが表示されます。これは、HTTPサーバーを実行しているバンドルが稼働していることを意味します。ブラウザに移動し、// localhost:8080を確認してください。案の定、KnoplerfishのWebページが表示されます。

「HelloJavaWorld」バンドル

OSGiランタイムを使用して、単純なバンドルを作成しましょうHello JavaWorld。これをと呼びます。このバンドルは、コンソールにメッセージを出力します。

リスト1では、Mavenを使用してバンドルをビルドします。OSGiアライアンスによって提供される依存関係は1つだけです。

リスト1.MavenPOMでのOSGiの依存関係

   org.osgi org.osgi.core   

次に、Apache Felixプロジェクトの好意により、プラグインも使用します。このプラグインは、使用するOSGiバンドルとしてアプリをパッケージ化する処理を行います。リスト2は、使用する構成を示しています。

リスト2.MavenPOMのOSGiFelixプラグイン

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

これで、「Hello」を出力する単純なクラスを見ることができます。

リスト3.Hello JavaWorldOSGiバンドル

 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) { } } 

コマンドラインに移動してmvn clean install。と入力し、バンドルをビルドします。これにより、バンドルを含むJARファイルが出力されます。次に、FileKnoplerfish GUIのメニューに移動し、を選択しますAdd Bundle。これにより、ファイルブラウザが提供されます。作成したJARを見つけて、選択します。

コンテナー内のOSGiバンドルの管理

Knoplerfish UIの出力ウィンドウに、「Hello、JavaWorld」というメッセージが表示されます。Knoplerfish GUIでバンドルをクリックすると、コンテナーがバンドルに割り当てたIDを確認できます。バンドルを停止する準備ができたら、[停止]メニュー項目をクリックできます。別の方法はstop [bundle number]、コマンドラインで入力することです。GUIまたはコマンドラインを使用して、コンテナー内のバンドルを管理できます。

これで、OSGiコンテナーで単純なバンドルがどのように機能するかを理解できました。OSGiコンテナーが存在するところならどこでも、バンドルの開始と停止に同じ単純さがあります。OSGiは、バンドルの環境とライフサイクルを作成します。

バンドルの相互作用:サービスとクライアント

次に、バンドルが互いにどのように通信するかを見ていきます。

最初に行うことは、サービスバンドルを作成することです。サービスバンドルはEJBセッションBeanに類似しています。これは、リモートインターフェイスを介して他のバンドルからアクセスできるコンポーネントを提供します。サービスバンドルを作成するには、インターフェイスと実装クラスの両方を提供する必要があります。

リスト4.サービスバンドルインターフェース

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

リスト4は単純なインターフェースです。唯一のメソッドは、addNum()それが意味することを実行するメソッドです。2つの数値の加算を返します。リスト5に示されている実装も同様に単純ですが、OSGi固有のメソッドがいくつか追加されています。

リスト5.サービスバンドルの実装

 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(); } } 

リスト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.

最後に、「What is:Java」シリーズの前回の記事では、Javaプラットフォームモジュールシステムを紹介しました。これは、Javaモジュール性の同じ課題に対して異なるアプローチを提供します。

このストーリー「OSGiとは何ですか?Javaモジュール性への異なるアプローチ」は、もともとJavaWorldによって公開されました。