X

An Oracle blog about WebLogic Channel

Java Servlet 3.1の新機能――クラウド対応のJava EE 7でどう変わるのか?【Java EEエキスパート・シリーズ】

Java EEの次期仕様である「Java EE 7」では、そのメインテーマとして「クラウド対応」が掲げられている。すなわち、Java EEのプラットフォームをPaaSの基盤にしようというのだ。それでは、Java EE 7において、その最も基本的な構成要素である「Java Servlet」の仕様はどのように生まれ変わるのだろうか? Java EE 7に含まれるJava Servlet 3.1の新機能を俯瞰しながら、その特徴を紹介しよう(編集部)。

「Java EEエキスパート・シリーズ」は、WebLogic ServerユーザーをはじめとするJava EE開発者に対し、Java EEに関する最新の技術情報をお届けする技術解説シリーズです。

Java EE 7のメインテーマは「クラウド対応」

 すでにJavaOneなどのイベントでもアナウンスされているように、Java EE 7の仕様策定のメインテーマは「クラウド対応」である。言い換えれば、Java EEのプラットフォームをPaaSの基盤にしようという取り組みが進んでいるのだ。そのクラウド環境を実現するうえで最も重要なことは、「マルチテナンシーを可能にする」ということである。すなわち、1つのアプリケーション・プログラムを複数のテナントで利用できるようにしなければならない。

 マルチテナンシーに対応したJava EE環境において、テナントごとに1つのアプリケーション・インスタンスを利用するとしよう。その場合、アプリケーションのルック&フィールはテナントごとにある程度までカスタマイズできる。その際に必要となる処理は、Java EEプラットフォームによって実行される。カスタマイズにかかわるリクエストに応じ、適切なインスタンスに対して適切にリソースのマッピングが行われるので、ユーザー側で特に何かを行う必要はない。こうして単一のインフラを使って複数のテナントに対応するわけだが、テナントの数が増えた場合でも、既存のインスタンスとは別のインスタンスにアクセスするので問題は生じない。つまり、テナントごとのアプリケーションの分離が実現されるわけである。

 また、マルチテナンシーでは、「Metadata for Services」という概念も実現しなければならない。一般に、1つのアプリケーション実装は、いくつかのサービスに依存したものとなる。例えば、データベースやロード・バランサ、メッセージ・キューイングなどのサービスに依存するということだ。Java EE 7では、こうした依存性をアプリケーション実行時に動的にマッピングし、反映させることが可能になるのである。

Java Servlet 3.1の特徴

 Java EE 6に含まれるJava Servlet 3.0は、「EoD(Ease of Development:開発容易性)の実現」、「プラッガビリティの実現」、「非同期処理のサポート」、「サーブレット/サーブレット・フィルタ/リスナなどの動的な登録」、「セキュリティの向上」を目標として策定された。それに対し、Java EE 7に含まれるJava Servlet 3.1では、簡単に言えば「クラウド対応」というプラットフォームの特性を実現できるものを目指して改良が進められている。

 まず、テナントごと、つまりアプリケーションのインスタンスごとに仮想サーバを生成することが可能になる。また、テナントごとに、各種リソースをカスタマイズして適用できるようになる。例えば、テナントごとにLDAPサーバを用意し、それぞれに異なるユーザー認証方法を適用するといったことが、単一のインフラを共有しているのにもかかわらず行えるようになるのだ。

 そのほかに、Java Servlet 3.1の大きな特徴として、次の3つを挙げることができる。

●新たなI/O APIの追加
●プロトコルのアップグレードへの対応
●セキュリティ機能の強化

 以下、これら3点について、それぞれ概観していこう。

ノンブロッキング処理が可能な新I/O API

 Java Servlet 3.1では、拡張性を高めるために新たなI/O APIが用意される。クラウドを利用して、より大規模なアプリケーションを構築したい場合に役立つ非同期のAPIだ。具体的には、ノンブロッキングでのデータの読み書きを可能にするリスナの定義に用いるイベントAPIが追加される。その1つは読み込みを行うためのインタフェースReadListenerで、もう1つは書き込みを行うためのインタフェースWriteListenerだ。ノンブロッキングでデータの読み書きが行えることから、それによってアプリケーション/アプリケーション・サーバの拡張性が担保される。両インタフェースの宣言は、それぞれ次のようになる。

インタフェースReadListenerの宣言
public interface ReadListener extends EventListener {
public void onDataAvailable(ServletRequest request);
public void onAllDataRead(ServletRequest request);
public void onError(Throwable t);
}



インタフェースWriteListenerの宣言
public interface WriteListener extends EventListener {
public void onWritePossible(ServletResponse response);
public void onError(Throwable t);
}


 また、その際に用いるストリーム・データの読み書き用インタフェースとしてAsyncIOInputSource、AsyncIOOutputSinkも追加される。両インタフェースの宣言は、それぞれ次のようになる。


インタフェースAsyncIOInputSourceの宣言
public interface AsyncIOInputSource {
public int dataAvailable();
public boolean isFinished();
public isReady();
}



インタフェースAsyncIOOutputSinkの宣言
public interface AsyncIOOutputSink {
public boolean canWrite(int size);
public void complete();
}



 参考までに、各インタフェースの継承関係を表すクラス図を以下に示しておこう。

インタフェースAsyncIOInputSourceのクラス図

wls_column_120514_01_04.jpg

インタフェースAsyncIOOutputSinkのクラス図

wls_column_120514_01_04.jpg

 ここで、上述した新APIを使ったサーブレットのサンプル・コードをご覧いただきたい。


新たなI/O APIを利用したサーブレットの実装例(1)
public class NIOSampleServlet extends HttpServlet 
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
request.addListener(new ReadListener() {
public void onDataAvailable(ServletRequest request) {
ServletInputStream nis = request.getServletInputStream();
try {
nis.read(new byte[nis.dataAvailable()]);
…略…
}



新たなI/O APIを利用したサーブレットの実装例(2)
         public void onAllDataRead(ServletRequest request) {
try {
request.getServletInputStream().close();
….
}
public void onError(Throwable t) { … }
});
final byte[] b = new byte[100];
…略…



新たなI/O APIを利用したサーブレットの実装例(3)
response.addListener(new WriteListener() {
public void onWritePossible(ServletResponse response) {
AsyncIOOutputStream nos = response.getAsyncIOOutputStream();
try {
nos.write(b);
nos.complete();
…略…
}
public void onError(Throwable t) { … }
});
}
}


 このサンプルでは、入出力ストリームとして、それぞれServletInputStreamとServletOutputStreamのオブジェクトを生成し、それらに対してリスナ(ReadListener/WriteListener)を追加している。その後、上で紹介した各インタフェースのメソッドを定義したうえで呼び出し、データの処理を行っている。データの読み書きに関しては、データをバッファリングするための仕組みが用意されており、ノンブロッキングでの処理が可能となっている。

 なお、これらの新I/O APIについては現在も活発な議論が続いており、日々、変更が生じている。実際、上に示した例に関しても、すでに変更が入っているので注意されたい。

HTTP以外のプロトコルの利用が可能に

 続いて、Java Servlet 3.1におけるプロトコルのアップグレード機能について説明する。

 周知のとおり、サーブレットでは、基本的にHTTP 1.1を用いて通信を行う。HTTPによる接続が確立されたら、情報のやり取りが行われるわけだが、その際、HTTP 1.1とは互換性のない、より高次元のプロトコルを使いたいというケースもあるだろう。そのようなニーズに対応できるよう、Java Servlet 3.1ではHTTPからWebSocketへのアップグレードがサポートされる。WebSocketのプロトコルはIETFが定義しており、W3CによってJavaScriptのAPIが定義されている。

 Java Servlet 3.1では、サーブレットからメソッドupgradeを呼び出すことにより、HTTPからWebSocketにプロトコルをアップグレードすることができる。このメソッドからのリクエストはProtocolHandlerが受け取るが、このハンドラはマルチプロトコル対応となっている。すなわち、WebSocket専用のものではなく、将来誕生するかもしれない別のプロトコルにも対応できる。つまり、サーブレット・コンテナにおける処理により、WebSocket以外のプロトコルへのアップグレードも可能になるということだ。

プロトコルのアップグレードの概念図

wls_column_120514_01_04.jpg

セキュリティ機能のさらなる強化

 セキュリティ機能に関しては、Java Servlet 3.0の段階で非常に大きな進化が見られた。Java Servlet 3.1では、それを発展させるかたちで、さらなる機能強化が図られる。

 まず、クロス・サイト・リクエスト・フォージェリ(CSRF)やクロス・サイト・スクリプティング(XSS)に対する予防策がサポートされる。また、HTTPメソッドに対するアクセス制限の機能が強化される。例えば、サーブレットでHTTPのGETメソッドを使っているとしよう。このとき、GET以外のメソッドを第三者が実行するのを拒否するよう指定することが可能になるのだ。

求む! 読者からのフィードバック

 言うまでもなく、以上のようなJava Servlet 3.1の仕様は、Contexts and Dependency Injection(CDI)やBean Validation、JCacheなど、他の仕様と歩調を合わせて策定されている。java.netでは、Java Servlet 3.1仕様の情報を閲覧できるほか、Wikiやソース・リポジトリ、メーリング・リストのアーカイブ、サンプル・コードなど、あらゆる方法で情報が公開されている。開発者にとってより使いやすい仕様とするためには、開発者からのフィードバック情報が重要だ。次に示すWebサイトでJava Servlet 3.1に関する情報を入手するとともに、ぜひ積極的に意見をフィードバックしていただきたい。



本記事は、2012年4月に開催されたJavaOne Tokyo 2012における米国オラクル・コーポレーション米国オラクル・コーポレーション Product Management, Fusion Middleware Principal Product Manager John Clingan氏のセッション「Java EE Web Container in the Cloud -What's New in Servlet 3.1」の内容を基に作成しています。

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services