< 目次

第13章: サービス・プロバイダ・インタフェースの概要

 

注:

バージョン5.0の場合、新規コンストラクタのAudioFormatAudioFileFormat、およびMidiFileFormatにより、さらに高度な形式での記述が可能になっています。


サービスとは

サービスとは、アプリケーション・プログラムでJava Sound APIの実装を使用すると自動的に利用可能になるサウンド処理機能の総称です。サービスを構成するのは、オーディオ・データとMIDIデータの読み込み、書き込み、ミキシング、処理、変換の各作業を行うオブジェクト群です。Java Sound APIの実装では、通常は、基本サービス・セットが提供されていますが、さらに、APIに新しいメカニズムも組み込まれて、サード・パーティ開発者(または実装自体のベンダー)を対象にした新しいサウンド・サービスの開発もサポートされています。これらの新しいサービスを、既存の導入済み実装に「プラグイン」の形で組み込むと、新規リリースとしなくても機能を拡張することができます。Java Sound APIアーキテクチャは、サード・パーティ・サービスをシステムに統合する方法として、アプリケーション・プログラムのサード・パーティ・サービスへのインタフェースを「ビルトイン(組み込み)」サービスへのインタフェースと同じにしました。場合によっては、javax.sound.sampledパッケージやjavax.sound.midiパッケージを使用するアプリケーション開発者が、サード・パーティ・サービスを使用していることに気づかないこともあります。

サード・パーティのサンプリング・オーディオ・サービスの例として、次のようなものが挙げられます。

サード・パーティのMIDIサービスは、次のようなものです。

サービスの動作

javax.sound.sampledパッケージおよびjavax.sound.midiパッケージは、アプリケーション・プログラムにサウンド・サービスを付加することを考えているアプリケーション開発者に必要な機能を提供するものです。この2つのパッケージはサウンド・サービスの消費者(コンシューマ)を対象に、オーディオ、MIDIの両サービスに関する情報の取得、制御、およびアクセスに必要なインタフェースを提供します。また、Java Sound APIは、サウンド・サービスの提供者(プロバイダ)を対象に、抽象クラスを定義するための2つのパッケージであるjavax.sound.sampled.spijavax.sound.midi.spiを提供しています。

新しいサウンド・パッケージの開発者は、SPIパッケージの中の、使用するクラスの具象サブクラスを実装します。これらのサブクラスと、新しいサービスのサポートに必要な任意のクラスは、含まれているサービスの説明とともに、Java Archive (JAR)アーカイブ・ファイルに置かれます。このJARファイルがユーザーのCLASSPATHにインストールされると、実行システムは、自動的に新しいサービスを利用可能にして、Javaプラットフォームの実行システムの機能性を拡張します。

インストールされた新しいサービスには、すでにインストールされている他のサービスと同様にアクセスできます。サービスの消費者は、新しいサービスに関する情報、または新しいサービス・クラス自体のインスタンスを取得することができます。そのためには、AudioSystemクラスとMidiSystemクラスのメソッド群(前者はjavax.sound.sampledパッケージ、後者はjavax.sound.midiパッケージに収録)を呼び出して、新しいサービスに関する情報、あるいは新規または既存のサービス・クラス自体のインスタンスを戻します。アプリケーション・プログラムはインストールされたサービスを利用するために、SPIパッケージ内のクラス(およびそのサブクラス)を直接参照する必要はないので、直接参照すべきではありません。

たとえば、Acme Software, Inc. という架空のサービス・プロバイダが、アプリケーション・プログラムで新しい形式のサウンド・ファイル(ただし、オーディオ・データは標準のデータ形式)を読み込むパッケージを提供できないかと考えたとします。SPIクラスAudioFileReaderは、たとえばAcmeAudioFileReaderというクラスにサブクラス化できます。新しいサブクラスで、AcmeはAudioFileReaderに定義されているすべてのメソッドの実装を提供します。この場合は、getAudioFileFormatgetAudioInputStreamの2つのメソッド(引数バリアント付き)だけです。次に、アプリケーション・プログラムが読み込もうとしたサウンド・ファイルがAcmeのファイル形式だった場合は、javax.sound.sampled内のAudioSystemクラスのメソッドを呼び出してファイルとそのファイル情報にアクセスします。AudioSystem.getAudioInputStreamメソッドとAudioSystem.getAudioFileFormatメソッドは、オーディオ・ストリームを読み込む標準APIを提供します。AcmeAudioFileReaderクラスがインストールされている場合は、このインタフェースは拡張され、新しいファイル・タイプを透過的にサポートします。アプリケーション開発者は、新しく登録したSPIクラスに直接アクセスする必要はありません。AudioSystemオブジェクトのメソッドが、インストールされているAcmeAudioFileReaderクラスについてのクエリーを渡します。

これらの「ファクトリ」クラスを持つことの利点は何でしょうか。また、新しく提供されるサービスへの直接アクセスをアプリケーション開発者に許可しない理由は何でしょうか。直接アクセスも可能性としては考えられますが、オブジェクトにサービスの管理とインスタンス化をすべてパススルーするゲートキーパー・システムが備わっているため、アプリケーション開発者は、インストールされている各サービスについて知る必要がありません。アプリケーション開発者は、自覚することさえなく、自分にとって使用価値のあるサービスのみを使用します。同時に、このアーキテクチャにより、サービス・プロバイダはパッケージ内の利用可能なリソースを効率的に管理することができます。

新しいサウンド・サービスの使用は、多くの場合、アプリケーション・プログラムからは見えません。たとえば、アプリケーション開発者がファイルからオーディオのストリームで読み込む場合を考えます。thePathNameによりオーディオ入力ファイルを識別すると仮定すると、プログラムは次のようになります。

    File theInFile = new File(thePathName);
    AudioInputStream theInStream = AudioSystem.getAudioInputStream(theInFile); 
バックグラウンドで、AudioSystemは、ファイルを読み込むことができるインストール・サービスを判別し、そのサービスに対して、データをAudioInputStreamオブジェクトとして提供するよう要請します。開発者は、入力オーディオ・ファイルが新しいファイル形式(Acme形式など)になっていて、インストールされているサード・パーティ・サービスでサポートされていることを知る必要も気にする必要もありません。プログラムは、最初にAudioSystemオブジェクトを介してストリームにアクセスします。その後、ストリームとプロパティには常にAudioInputStreamのメソッドを介してアクセスします。これらはどちらもjavax.sound.sampled APIの標準オブジェクトであり、新しいファイル形式に必要な特別な処理は、完全に隠されています。

プロバイダが新しいサービスを準備する方法

サービス・プロバイダは新しいサービスを特別な形式のJARファイルで提供します。このファイルは、JavaランタイムがJARファイルを検索するユーザーのシステム上のディレクトリにインストールされます。JARファイルはアーカイブ・ファイルで、各ファイルにはアーカイブ内で階層ディレクトリ構造に編成されているファイル・セットが含まれます。これらのアーカイブに保存されるクラス・ファイルの準備方法の詳細については、第14章と第15章のオーディオ・パッケージとMIDI SPIパッケージの仕様を参照してください。ここでは、JARファイルの作成プロセスの概要を説明します。

新しいサービスに使用するJARファイルには、そのJARファイルでサポートされる各サービス用のクラス・ファイルが含まれていなければなりません。Javaプラットフォームの規約に従い、各クラス・ファイルは新しく定義されたクラスの名前を持ちます。この新しく定義されたクラスは、サービス・プロバイダの抽象クラスのうちのいずれかの具象サブクラスです。JARファイルには、新しいサービスの実装に必要なサポート・クラスも含める必要があります。また、実行システムのサービス・プロバイダ・メカニズムで新しいサービスの位置を特定できるようにするため、JARファイルには、定義されている新しいサブクラスにSPIクラス名をマップする特殊ファイル(次に説明)も含める必要があります。

前述の例の続きで、Acme Software, Inc. は新しいサンプリング・オーディオ・サービスのパッケージを配布しているとします。このパッケージは、次の2つの新しいサービスにより構成されるものとします。

まず、ビルドを行う/develという名前のディレクトリの下にサブディレクトリ群を作成し、そこに新しいクラス・ファイルを置きます。新しいクラスを参照できるパス名を使用して編成する必要があります。
    com/acme/AcmeAudioFileReader.class
    com/acme/AcmeAudioFileWriter.class
さらに、サブクラス化されている新しい各SPIクラス用に、META-INF/servicesという特別な名前のディレクトリにマッピング・ファイルを作成します。このファイル名はサブクラス化されているSPIクラスの名前で、ファイルには、そのSPI抽象クラスの新しいサブクラスの名前が含まれています。

次の内容で構成される

META-INF/services/javax.sound.sampled.spi.AudioFileReaderファイルを作成します。

    # Providers of sound file-reading services 
    # (a comment line begins with a pound sign)
    com.acme.AcmeAudioFileReader

および、次の内容で構成される

META-INF/services/javax.sound.sampled.spi.AudioFileWriter,ファイルを作成します。

   # Providers of sound file-writing services 
    com.acme.AcmeAudioFileWriter

ここで、任意のディレクトリから、次のコマンド行によりjarを実行します。

jar cvf acme.jar -C /devel .
-Cオプションにより、jarはコマンドが実行されたディレクトリを使用しないで、/develディレクトリを使用します。最後の引数のピリオドは、そのディレクトリ(/devel)のすべての内容をアーカイブするようjarに指示します。ただし、ディレクトリそのものはアーカイブしません。

これにより、次の内容のacme.jarファイルが作成されます。

com/acme/AcmeAudioFileReader.class
com/acme/AcmeAudioFileWriter.class
META-INF/services/javax.sound.sampled.spi.AudioFileReader
META-INF/services/javax.sound.sampled.spi.AudioFileWriter
META-INF/Manifest.mf
jarユーティリティ自体により生成されるManifest.mf,ファイルは、アーカイブに含まれるすべてのファイルのリストです。

ユーザーが新しいサービスをインストールする方法

アプリケーション・プログラムから新しいサービスにアクセスしようとするエンド・ユーザー(またはシステム管理者)は、インストールを簡単に行うことができます。ユーザーは提供されたJARファイルをCLASSPATH内のディレクトリに置きます。実行されるとすぐに、Java ランタイムは必要に応じて参照クラスを検出します。

同じサービスに複数のプロバイダをインストールするのは誤りではありません。たとえば、2つの異なるサービス・プロバイダが同じタイプのサウンド・ファイルの読込みをサポートする場合があります。このような場合、システムはいずれかのプロバイダを任意に選択します。選択するプロバイダをユーザーが決める場合は、そのプロバイダのみをインストールします。

 


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.