ARCHIVES
アーカイブス
アーカイブス

業務アプリもJ2EE一辺倒からWeb 2.0的な軽量技術が現実解に

翔泳社『DBマガジン』2006年12月号 「Web 2.0時代を見据えた最新DBアプリ開発のすべて」

中村正弘NAKAMURA Masahiro
2006年12月01日
※内容は公開当時のものです

業務で使用されるWebアプリケーションの開発では、これまでJ2EEが独壇場とも言える地位を占めてきた。ところが最近、"Web 2.0的"と表現される軽快で生産性の高い開発手法が、現実的な実装技術として検討されつつある。本パートでは、世界中の開発者に大きなインパクトを与えたAjax やRuby on Railsをはじめ、EJB 3.0/JPA、SOAP/RESTなど、今後Webアプリケーションを変えていくであろう新技術の概要を見ていく。

業務システムとしてもすでに一般化した感のあるWebアプリケーションだが、最近新たな潮流が起こりつつある。その大きなものの1つが「Web 2.0」である。

Web 2.0は非常に抽象的な概念で、理解しづらい面があるが、本パートでは「ユーザー の参加を積極的に促す仕組みを備える双方向的なアプリケーション」と定義する。Amazonのカスタマーレビュー、Flickrのタギング (注1) 、はてなのソーシャルブックマーク (注2) などが、Web 2.0的なサービスの代表例として挙げられるだろう。このようなWeb 2.0アプリケーションは、従来のWebアプリケーションとは異なり、以下のような特徴を持っている。

  1. 頻繁にサイトの機能を追加
    非常に短い間隔(数時間~数週間程度)でシステムをアップデートすることが多い。ユーザーに積極的な参加を促す目的もある。
  2. Webサイトが持っている機能をWebサービス化して公開
    Google MapsやAmazon Web Serviceなどが代表例。こうしたWebサービスを積極的に 利用することで、アプリケーションの開発量を減らし、本質的な部分(競争力の源泉になるような部分)に注力できる。
  3. 従来のWebアプリケーションでは考えられなかったような高い操作性を実現
    Ajaxなどの技術で実現され、①と同様にユーザーの参加を促す目的もある。

こうした状況であるため、現在ではWebアプリケーションの構築に使用する要素技術を、多くの中から選択できるようになっている。少し前まで、商用/業務用のWebアプリケーションと言えばJ2EE環境 (注3) で構築するものと決まっていたが、Web 2.0アプリケーションでは非常に短いサイクルでシステムをアップデートする必要性から、RubyやPerl、PHPなどのスクリプト言語が採用されるケースが増えている。また、Windowsプラットフォームの成熟とともに、.NETも選択肢として存在を大きくしている。

また、これまでWebブラウザ間の互換性に問題があり、むしろ使用が敬遠されてきたJavaScriptが、Ajaxが実現した高機能なユーザーインターフェイス(多くの人がGoogle Mapsに衝撃を覚えたのではないだろうか)の登場により、今やWebアプリケーションのクライアント技術として重要な位置を占めている。

このように、現在のWebアプリケーションは、 企業システムとしての利用に耐える高信頼性を求められることがある一方、数時間ごとのシステムアップデートに対応できる柔軟性を求められる場合もあるのだ。また、非常にリッチなユーザーインターフェイスの実現を求められる場合もある。当然、これらの多岐にわたる要件を単一の技術でカバーすることには無理があるため、これからのWebアプリケーション構築では、適切な技術を選択するための知識が必要不可欠と言えるだろう。

そこで本パートでは、現在注目されているWebアプリケーションの構築に関係の深い技術のうち、必ず理解しておきたいものを紹介する。本文で説明できなかった技術のいくつかはコラムとして取り上げているので、そちらも併せてご覧いただきたい。

軽量EJBを追加したJava EE 5

Java EE 5(EE=Enterprise Edition)は、今年の5月にSDKが正式リリースされたエンタープライズ向けJava技術の最新仕様である。Java EE 5はServlet 2.5などの個別仕様をまとめたものだが、ここでは特に注目度が高いと思われる「EJB(Enterprise Java Beans)3.0」と「JPA(Java Persistence API)」を取り上げる。

なお、Java EE 5に含まれる仕様の1つ「JSF(JavaServer Faces)」については後ほど紹介したい。

複雑さを排除したEJB 3.0

EJBは、企業向けのアプリケーションを構築するためのテクノロジーとして登場した。ビジネスロジックをコンポーネント化し、再利用することで企業向けアプリケーションの開発生産性を高めるというのが主なねらいである。また、分散トランザクションや分散オブジェクトといった、大規模な企業向けアプリケーションで使用される技術をアプリケーション開発者から隠蔽し、ビジネスロジックの開発に集中してもらおうという目的もあった。

このようなEJB自体のコンセプトは理にかなっていたが、現時点でEJBが積極的に使われているかというと、そうとは言えない。これにはいくつか理由がある。

  • EJBコンポーネントの開発では非常に多くの規約を守る必要があり、開発そのものが難しい
  • EJBコンポーネントの動作確認にはEJBコンテナ (注4) が必要となるため、単体テストが実施しづらい
  • そもそも、分散トランザクションや分散オブジェクトを使わなければならないアプリケーションは非常に限られている。これらの技術を使う必要がないシステムの開発ではEJBが定める規約は重すぎて、かえって生産性を下げてしまう

こうした理由から、EJBを利用するシステム開発というのは数が少ないのが現状だ。大部分のシステム開発は、EJBを使わずにJSPやServlet、そのほかさまざまな永続化フレームワーク (注5) という構成で開発されている (注6) 。

これらの反省点を踏まえ、EJB 3.0では複雑さを排し、より簡単にEJBコンポーネントを開発できることを目指している。EJBにおいては、これまでで最もドラスティックな仕様変更と言えるだろう。

それでは、どの程度簡単になっているのか、少し具体的に見てみよう。図1は、EJB 3.0以前の典型的なEJBの構成を表わしたものである。

Session BeanとEntity Beanは、あらかじめ定義されているインターフェイスを実装しなければならない。ただし、EJBコンポーネントをインスタンス化するためのHomeインターフェイスや、ビジネスロジックを呼び出すためのComponentインターフェイスとEJBコンポーネント(FooBean、BarBean)との間には直接の実装関係はない。インターフェイスとEJBコンポーネントの関係は、デプロイメントディスクリプタと呼ばれる専用のXMLファイルで定義する。

このように、EJBコンポーネントの全容を把握するためには散在する情報を読み解かねばならないし、Home/RemoteインターフェイスとEJBコンポーネントとの関係のようにEJBの構造は直感的に理解しづらい。こうしたことがEJBが敬遠される原因となってきたのである。

これに対して、EJB 3.0の構成は図2のように非常にシンプルだ。

これまで、インスタンス生成とビジネスロジックの呼び出しという2種類のインターフェイスが必要だった部分が、Businessインターフェイスという1つのインターフェイスにまとめられている。また、各Beanは特定のインターフェイスを実装する必要はなくなり、代わりにJ2SE 5から導入された「アノテーション」という言語機能を使ってEJBであることを宣言している。

つまり、EJB 3.0のEJBコンポーネントは特別なクラスではなく、「POJO(Plain Old JavaObject)(注7) 」だということを意味する。POJOなら、EJBコンテナなしで動作させることができるので、単体テストも簡単に実施できる。この点は、EJBコンポーネントの生産性や信頼性の向上に大きく寄与するだろう。

図1 EJB 2.xまでの構成

図1 EJB 2.xまでの構成

図2 EJB 3.0の構成

図2 EJB 3.0の構成

O/Rマッピング機能を提供するJPA

JPAは、これまでCMP(Container-Managed Persistence)Entity Beanが担っていたJavaオブジェクトをRDBに永続化する機能(O/Rマッピング)をAPIとして独立させたものである。したがって、Java EEの一部ではあるものの、EJBとはまったく独立したAPIである (注8) 。

特筆すべきは、このAPIがJ2SEからも利用可能な点だろう。スタンドアロンアプリケーションであっても、Java標準のO/RマッピングAPIを使用できるのである。

ここからは、最も人気のあるJPA実装の1つ「Hibernate」を使った簡単なサンプルコードを見ながら、JPAの理解を深めていこう。まずは、永続化対象のコードを見てみよう。ここでは、少しのプロパティを持つ "User"というクラスを用意した。

LIST1をご覧いただきたい。Userは単なるJavaクラスである。ただし、アノテーションによってこれがEntity Beanであることと、テーブル上の主キーに関する情報が定義されている。永続化先のテーブルUSERの定義はLIST2のとおりとする。

次に、JPAを使用するクラスを見てみよう(LIST3)。このクラスは、mainメソッドを持つごく普通のクラスである。最初に、JPAで定義されているEntityManagerクラスを使い、Entity Beanに格納するデータをDBから読み出し、Userのインスタンスを取得している。

JPAでオブジェクトを永続化する場合、必ずEntity Beanが必要となる。JavaオブジェクトとDB間のマッピングに関する情報は、EntityBeanにしか書けないからだ。また、LIST3には、UserクラスとDBテーブルをマッピングするためのアノテーションがない。JPAにはマッピングのためのアノテーション@Tableが用意されているが、この例のように省略もできる。その場合は、クラス名と同じ名前のテーブルにマッピングされる。

最後にもう1つ。これはJPAの規約であるが、LIST4に示すpersistence.xmlというファイルを定義する。persistence.xmlはMETAINFディレクトリの下に配置し、CLASSPATHを通しておく必要がある。

サンプルの解説は以上だが、以前のEntityBeanに比べて記述量が大幅に減っていることや、EJBコンテナがなくてもJPAを使って永続化処理を書けることがお分かりいただけたと思う。アプリケーションサーバーが存在しなくてもEntity Beanを永続化できるので、Entity BeanをEJBと呼ぶのはもはや適切でないかもしれない。

また、Java EE 5には魅力的な機能がほかにもある。最近流行のDIコンテナなどは待望の機能と言えるだろう。

LIST1 永続化対象のUserクラス

import javax.persistence.*;
import java.io.*;
  // アノテーション。
  // このクラスがEntity Beanであることを示している
@Entity
public class User {
  private Integer id;
  private String name;
  private int age;
  public User() {
  }
    // アノテーション。
    // get/setIdメソッドでアクセス可能なプロパティ"id"がテーブル上の主キーになることを
    // 意味する。また、GenerationType.AUTOによって、"id"がJPAによって自動生成されることも
    // 意味する
@Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
}
}

LIST2 永続化先のUSERテーブル

create table user(
  id integer,
  name varchar(30),
  age integer,
  primary key(id));

LIST3 JPAを使用するクラス

import javax.persistence.*;
public class JPATest {
  public static void main(String[] args) {
      // JPAのEntityManagerのインスタンスを、EntityManagerFactoryクラスを使って取得している
EntityManagerFactory aFactory =
        Persistence.createEntityManagerFactory("jpatest");
    EntityManager aManager = aFactory.createEntityManager();
     // EntityManagerのメソッドfindを使って、データベース上に永続化されているUserを
      // インスタンス化する。第1引数にはインスタンス化するクラスのクラスオブジェクトを、
      // 第2引数には、インスタンスを識別するためのデータ(この場合は主キーの値)を指定している
User aUser = aManager.find(User.class, new Integer(1));
    System.out.println("name = " + aUser.getName());
    aManager.close();
    aFactory.close();
  }
}

LIST4 persistence.xml

<persistence>
    <!-- この部分のnameプロパティで指定している名称は、先ほどのEntityManagerFactoryに
        渡している引数と一致している必要がある。また、transaction-typeプロパティの値は
        トランザクション制御にJTAを利用しないことを意味している -->
<persistence-unit name="jpatest" transaction-type="RESOURCE_LOCAL">
     <!-- この部分はおなじみのJDBCの設定である。各自の環境に合わせて変更してほしい -->
<properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
      <property name="hibernate.connection.username" value="userid"/>
      <property name="hibernate.connection.password" value="password"/>
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpadb"/>
      <property name="hibernate.max_fetch_depth" value="3"/>
    </properties>
  </persistence-unit>
</persistence>

超効率開発が可能な Ruby on Rails

「Ruby on Rails」(以下、Rails)とは、スクリプト言語Rubyで開発されたWebアプリケーション開発用フレームワークである。2004年に公開されて以降、作者のデビッド・ハイネマイヤ・ハンソン氏が中心となって開発が続けられている。いま最も注目度が高い技術の1つであり、現場で使われるケースも増えてきている。

Railsでは、図3のように極めてシンプルな MVC(Model/View/Controller)アーキテクチャを採用している。「ルータ」はRailsが提供しているコンポーネントで、URLを解析し、適切なコントローラを探し出して処理を委譲する役割を持つ。コントローラとビューは文字どおりの意味なのであまり説明の必要はないだろう。モデルについてだけ簡単に補足しておく。

Railsのモデルクラスは「アクティブレコード」と呼ばれている。これは、マーチン・ファウラー氏の著書「エンタープライズアプリケーションアーキテクチャパターン」で紹介されているアクティブレコードというパターンを実装したもので、モデルクラスがDBの永続化処理とビジネスロジックの処理を担当する。したがって、コントローラの役割は、モデルクラスのメソッドを呼び出すことによってビジネスロジックを呼び出すことになる。図4のように、モデルクラスはDBテーブルと1対1に対応して作成される。

また、Railsは次のような特徴を持っている。

  • Convention over Configuration
  • DRY(Don't Repeat Yourself)
  • ジェネレータ
  • フルスタック

それぞれについて簡単に説明していこう。

Convention over Configuration

「設定よりも規約」と訳されるこの特徴は、Railsを理解する上で非常に重要な概念だ。Railsには、さまざまなデフォルトの振る舞いが用意されている。このデフォルトの振る舞いがうまく機能するために、さまざまな規約が定められている。プログラマは、この規約に沿ってコードを書くことが推奨されており、規約(「DBテーブル名は複数形で書く」「モデルクラス名はテーブル名の単数形にする」など)に沿ってさえいれば、コードの記述量を大幅に削減できるのである。

このような振る舞いは、例えばJ2EEのようなプラットフォームであれば、XMLファイルでプログラマが設定するような類のものである。当然、XMLファイルで任意に設定できたほうが柔軟性は増すが、プログラマの記述量は増える。Railsでは、不要な柔軟性を排除するという割り切りのもとで (注9) 、コードの記述量を削減することを選択しているのである。

DRY

DRYはDon't Repeat Yourselfの略で、「同じことを繰り返し記述するのはやめよう」という考え方である。もともとは「達人プログラマ」という書籍で紹介されている考え方である。Railsはこの思想が貫かれており、プログラマが同じような記述を繰り返し書かなくて済むようになっている。

ジェネレータ

Railsには非常に強力なコードジェネレータが付属している。MVCの各雛形クラスはもちろん、テストコードやアプリケーションを構成するさまざまなファイルを自動生成してくれる。ジェネレータで雛形ファイルを作り、それを修正していくのが、Railsの開発スタイルである。

Railsのジェネレータの強力さを端的に表わしているのが、「scaffold(足場という意味)」だろう。scaffoldは、コマンド1つでDBテーブルのCRUD操作を実現するモデル/ビュー/コントローラを生成してくれる。画面デザインにこだわらなければ、マスターテーブルをメンテナンスするアプリケーションくらいなら、コマンド1つで作れてしまうのだ。

フルスタック

Railsには、Webアプリケーションの構築に必要な以下の要素がすべて含まれている。Railsさえ入手すれば、Webアプリケーションの構築に困ることはないだろう。

  • 主に開発時に利用されるWebサーバー(WEBRick (注10)
  • 開発用/テスト用/本番用のそれぞれ独立した環境
  • 単体テストフレームワーク
  • Webサービス/Ajax/電子メールなどのサポート

このようなさまざまなメリットを持つRailsではあるが、次のような弱点もある。

  • RailsのというよりRubyの弱点であるが、変数に型が存在しないため、実行しないとデータ型の不一致が判明しない
  • 2フェーズコミットが現段階ではサポートさ れていない

これらの点を踏まえると、Railsは高信頼性システムや分散DBシステムには向いていないと言える。逆に、こうしたシステム以外にはRailsを使っても問題ないだろう。RailsとRubyが持つ高い生産性やスクリプト言語特有のターンアラウンドタイム(実装と改善の繰り返しにかかる時間)の短さを考えると、次のようなプロトタイピングを伴うシステム開発には、むしろうってつけと言えるのではないだろうか。

Web 2.0に代表されるような、短い間隔で機能を頻繁に追加するようなシステム
まったく新規のビジネスを実現しなければならないようなシステム

図1 EJB 2.xまでの構成

図3 Ruby on Railsのアーキテクチャ

図4 モデルクラスとDBテーブルは1対1に対応して作成される

図4 モデルクラスとDBテーブルは1対1に対応して作成される

コラム : 業務アプリ環境としての.NETの優位点

.NET Framework(以下、.NET)は、マイクロソフトが開発したアプリケーション開発/実行環境だ。リッチクライアントでは本命視する声もある。ここでは、筆者の考える.NETの優位点をいくつか紹介しよう。

無償版Visual Studioの提供

Visual Studioは、特にその使い勝手の良さが高い評価を得ている開発環境だ。しかし、比較的高価なため、個人が.NETの習得用にこの環境を使うのは難しかった。しかし、Visual Studio 2005から無償で利用可能なExpress版が登場した。もちろん機能制限はあるが、.NETの評価や学習用には十分な機能を備えている。これまで、.NETを習得しようと思うと、.NET SDK(Javaで言うところのJDK)を使うか、Visual Studioを買ってくるかしかなく、若干敷居が高かった 。Express 版のおかげで、.NET開発を始める技術者も増えるだろう。

ADO.NETは優れたDBアクセス技術

DBアクセス技術であるADO.NETも、.NETの優位点の1つだろう。ADO.NETはマイクロソフト製のO/Rマッピングフレームワークと言える。基本的なアーキテクチャは、マーチン・ファウラー氏が提唱したデザインパターン「テーブルデータゲートウェイ」と同様で、Railsのアクティブレコードとは異なり、1つのDataSetオブジェクトがテーブル全体を管理する。受注/受注明細テーブルのような親子関係を持つテーブルを、1 つのDataSetで管理することも可能だ。DataSetはVisual Studioのウィザード機能で 簡単に作成できるので、例えば画面に表示するデータ構造に準拠したDataSetを作ることで、画面とDB間の入出力のコードを省くことも可能だ。あくまで概念的ではあるが、図AようなDB、DataSet、画面間の接続を、Visual Studioを使えばグラフィカルに行なうことができる。

自動アップデート機能ClickOnce

ClickOnceとは、.NET Framework 2.0で追加されたアプリケーションの配布/更新技術だ。ClickOnceを利用したインストーラでアプリケーションをインストールすると、そのアプリケーションの起動時に、新バージョンの有無が自動的にチェックされ、新しいバージョンがリリースされていれば、インストールするかどうかをユーザーに問い合わせる。この仕組みにより、アプリケーションの配布やバージョンアップの手間を劇的に減らせるのである。

図A DB、DataSet、画面間を接続

図A DB、DataSet、画面間を接続

実用期を迎えたWebサービス

「マッシュアップ (注11) 」という考え方の普及とともに、Webサービスを利用したWebアプリケーション開発が急速に普及しつつある。これはAmazon、Yahoo、Google、Flickr、YouTube(動画共有サイト)といったWebサイトが、サイトの持つ機能をWebサービスとして惜しげもなく公開しているからこそ実現されたものだ。現在では、これらのWebサービスを組み合わせる(マッシュアップする)ことにより、低コストで高機能なアプリケーションを開発することも不可能ではない。

もちろん、アプリケーションからWebサービスを利用するには、サービスとやり取りするルールやプロトコルが必要だ。ここでは、その主流になりつつある「REST」と「SOAP」について解説する。

本来の意味とは異なってきているREST

RESTとは「Representational State Transfer」の略である。RESTという言葉は、HTTPの仕様策定者の1人であるロイ・フィールディング氏の論文で使われたのが最初である。この論文では、「RESTとは分散ハイパーメディアシステムのためのアーキテクチャスタイル (注12) である」と定義している。

RESTを定義したそもそもの目的は、インターネットスケールでの分散ハイパーメディアシステムの成功例であるWWWシステムを、より抽象化したアーキテクチャスタイルとして定義し、彼らによる再設計したHTTPやURIを紹介することだったようだ (注13) 。

もともとこのような経緯で定義されたRESTであるが、現在ではHTTPを使ってXMLデータを送受信することによりWebサービスを実現する仕組み「XML over HTTP」の意味で使われることが多いようだ。簡単に言うと、「http://(ホスト名)/?(パラメータ)」というリクエストをWebサービスに送り、結果をXMLデータとして受け取るということだ。確かに、AmazonやFlickrが提供しているWebサービスのXML over HTTPインターフェイスはRESTの考え方に従っていると言えると思うが、XML over HTTP=RESTではないので注意されたい。

本来の意味でのRESTは、前述したようにアーキテクチャスタイルなので、メッセージングプロトコルであるSOAPと比較するべきものではないのである。ただし、Webサービスの実装方法を比較することが目的なので、RESTをXML over HTTPの意味で使用することにする。

さて、現在インターネット上で広く公開されているWebサービスの多くはSOAP用のインターフェイスとREST用のインターフェイスの両方を備えている。Amazonのデータによれば、Webサービスリクエストのうち、85%がRESTとのことである。なぜRESTのほうが多く使われるのだろうか?

それは、非常に簡単に使えるからである。どう簡単なのかは、実際にRESTでのリクエスト記述を見てもらったほうが分かりやすいだろう。次の記述は、FlickrのAPIにアクセスするものである。

http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_...
  (個人で取得したキー)&per_page=n

これは、通常のHTTP GETリクエストそのもので、Webブラウザから開いても、画面のようにXMLのレスポンスが戻される。RESTのインターフェイスを持っているWebサービスは、Webブラウザからでも簡単に試せるのである。また、プログラムからWebサービスを利用する場合でも、わざわざSOAPメッセージを作らなくても良いので実装が簡単だ。RESTの利用率が圧倒的に多いのは、このような手軽さによるところが大きいと思う。

本格的なRPCを目指すSOAP

一方のSOAP(Simple Object AccessProtocol)は、その名前のとおり、インターネット上のオブジェクトにアクセスすることを目的として開発された、分散オブジェクトを実現するための技術である。

SOAP仕様が登場した当時、分散オブジェクト技術としてはDCOMやCORBAがあった。これらは独自の通信プロトコルを持っており、DCOMとCORBAのオブジェクト間で通信することはできない (注14) 。また、情報をやり取りするためのプロトコル(例えばCORBAならIIOP)も、企業のファイアウォールでブロックされるため、インターネット上のオブジェクトにアクセスすることは難しかった。

これらの問題点を解決するため、プラットフォームに依存せず、インターネット上のオブジェクトにアクセスする手段として策定されたのがSOAPである。SOAPの特徴は、オブジェクト間通信でやり取りするメッセージ仕様のみを定義していて、そのメッセージを送受信するためのプロトコルは規定してないことである。したがって、SMTPやFTPを使ってもSOAPメッセージをやり取りできるが、普通はHTTPが使われている。SOAPによる通信の概念図を図5に示す。

当初はインターネット上の分散オブジェクトを実現するための技術として登場したSOAPではあるが、今ではWebサービスの実装方法の1つとしてよく使われている。つまり、分散オブジェクトというよりは、インターネット上で使えるRPC(Remote Procedure Call)としての使用が多い。

それでは、SOAPメッセージの構造を見てみよう(図6)。例として、FlickrのSOAPレスポンスを使う。

レスポンスの最初の部分はプロトコルバインディングヘッダで、利用する送受信プロトコルによって異なる。図6はHTTPの例である。ヘッダの細部は正確ではないので、どんなものなのかというイメージをつかむ程度に見てほしい。

次からがSOAPメッセージの本体である。s:Envelope要素は、文字どおり封筒の役割を果たす。この中に、ヘッダとメッセージ本体が入ることになる。この例では省略されているが、本来であればs:Head要素でヘッダ部分が記述されることになる。その次のs:Body要素に、メッセージの本体で具体的なデータが入る。

実際には、SOAPのメッセージを組み立てるのは面倒なため、専用のライブラリなどを利用することになるだろう。Javaであれば、Apacheプロジェクトがリリースしている「AXIS」というライブラリを使ってWSDLファイル (注15) からスタブクラス (注16) を生成することで、Javaのローカルメソッドを呼び出すような感覚でSOAPリクエストを送信できる。

LIST5は、AXISが生成したスタブクラスを介してGoogleの検索サービス(GoogleSearch)を利用するJavaプログラムである。最初の部分で、AXISが生成したスタブクラスをインスタンス化している。GoogleSearchPortというのはインターフェイスで、このインターフェイスの中に、Googleが提供している検索用のメソッドが定義されている。これらのメソッドを使ってWebサービスを呼び出せる。

続くコードが、実際に検索サービスを呼び出している部分である。ここでは、GoogleSearchPortのdoGoogleSearchというメソッドを呼び出している。第1引数はAPIを呼び出すためのキー、第2引数は検索したい文字列である。

いかがだろうか。あたかもローカルにあるJavaのメソッドを呼び出すような感覚でリモートのWebサービスを呼び出せていることがお分かりいただけることと思う。

さまざまな要件に応えるSOAP

Webサービスの呼び出し方からも分かるように、RESTでは各呼び出しで処理が完結することが想定されている。例えば、複数のREST呼び出しを1つのトランザクションとして扱い、どちらか1つの呼び出しが失敗したらすべての呼び出しをロールバックする、といったことはできない。

また、1リクエストごとに使用料を取るようなWebサービスの場合は信頼性の高い、呼び出し元の身元確認のような仕組みが必要だろう。こういった要件に応えるために、SOAPでは仕様にセキュリティの仕組みやトランザクションの考え方を取り入れる動きがある。WS-*と呼ばれる仕様群がそれである。

以上、簡単ではあるがSOAPとRESTを比較してみた。手軽に使えるRESTに対し、SOAPはRESTでは実現できないような、セキュリティやトランザクションが求められるような要件に向いている。2つの技術は、完全に棲み分けできていると考えて良いだろう。

LIST5 Googleの検索サービスを利用するJavaプログラム

import GoogleSearch.*;
public class SOAPTest3 {
  public static void main(String[] args) throws Exception {
     // AXISが生成した、GoogleのWebサービスにアクセスするためのプロキシクラスを取得している
GoogleSearchServiceLocator aLocator = new GoogleSearchServiceLocator();
    GoogleSearchPort aService = aLocator.getGoogleSearchPort();
     // 検索を行なうメソッドdoGoogleSearchを呼び出す
GoogleSearchResult aResult = aService.doGoogleSearch(
      "API_KEY", "web service", 0, 1, true,
      "countryJP", true, "lang_ja", null, null);
    System.out.println("search time = " + aResult.getSearchTime());
    ResultElement[] theElements = aResult.getResultElements();
    System.out.println("summary : " + theElements[0].getSummary());
    System.out.println("ULR : " + theElements[0].getURL());
    System.out.println("snippet : " + theElements[0].getSnippet());
    System.out.println("title : " + theElements[0].getTitle());
  }
}
図5 SOAPによるオブジェクト間通信

図5 SOAPによるオブジェクト間通信

図6 SOAPメッセージ

図6 SOAPメッセージ

画面 Flickr APIからのレスポンス

画面 Flickr APIからのレスポンス

Webアプリに革命を起こしたAjax

Ajaxとは「Asynchronous JavaScript+XML」の略で、簡単に言ってしまうと「JavaScriptを使ってサーバーと非同期の通信を行ない、サーバーとのデータのやり取りにXMLを使うような仕組みの総称」になろう。特定の技術を指す言葉ではない。

Ajaxという言葉が初めて使われたのは、ジェシー・ジェイムズ・ギャレット氏の「Ajax:A New Approach to Web Applications」(http://www.adaptivepath.com/publications/essays/archives/000385.php)という記事である。この記事によると、Ajaxを使ったWebアプリケーションの定義は次のとおりだ。

  • XHTMLとCSSを使って画面を作る
  • DOMを使って動的に画面を更新したり、今までの静的なWebにはないユーザーインターフェイスを実現する
  • データ交換や操作にXMLやXSLTを利用する
  • XMLHttpRequestオブジェクトを利用して、非同期にデータを取得する
  • 上記すべての要素を紐づけるためにJavaScriptを使用する

Ajaxが広く認知されるようになったきっかけは、読者の方々もご存知かとは思うが、GoogleMaps(http://maps.google.co.jp/)であるのは間違いないだろう。Google Mapsを見て、実装にFlashやJavaアプレットが使われていないことに驚嘆した方も多いのではないだろうか。

さて、Ajaxの仕組みを理解するには、簡単なサンプルを見るのが最良だと思う。ここでは、Flickrが公開しているWebサービスを、Ajaxを使って利用してみる。サンプルプログラムの仕様は次のとおりとする。

  • Flickrにアップロードされた最新の写真を1枚だけ取得し表示する
  • Webブラウザが自動的に1分ごとに写真を取得し直す

Ajaxで実行される処理を知る

LIST6がサンプルアプリケーションである。なお、このサンプルはInternet Explorer(以下、IE)のバージョン6以降でのみ実行可能で、サーバー経由では動かせない(IEならほかのサーバーに接続する確認ダイアログで"はい"と答えると実行できる)。この点はご容赦いただきたい。

LIST6①のonLoad関数はページロード時に呼び出され、XMLHttpRequestオブジェクトの生成と、getRecentFlickrImage関数の呼び出しを行なう。setInterval関数は、60秒ごとにgetRecentFlickrImage関数が呼び出されるように設定するもので、放っておいても1分間隔で最新の写真がWebブラウザに表示されるようになる。

なお、LIST6で実装されているXMLHttpRequestオブジェクトの生成方法は、IE 6以上限定である。それ以前のIEや、Firefoxでは別の方法で生成しなければならない。このように、Ajaxでは実行されるWebブラウザに配慮(クロスブラウザ対応)しながら実装を行なう必要がある。ほかのWebブラウザでも動作可能にするには、 LIST7のような関数を定義して利用すると良い。

LIST6②では、XMLHttpRequestオブジェクトのopenメソッドを使い、Flickr API(REST方式)にアクセスしている。第1引数には、HTTPのメソッド"GET"を、第2引数には接続先のURLを、第3引数には同期通信を意味する "false"を指定している。第3引数に "true"を指定すると非同期通信を行なうことができるが、このサンプルでは不要なので使用していない。次のsetRequestHeaderメソッドは、取得したいイメージの最終更新時間を指定している。最後にsendメソッドを呼び出してリクエストを送信する。

LIST6③で行なっているのは、戻り値のチェックである。HTTPのステータスコードが200であれば、processResponse関数を呼び出してイメージを表示する処理を実行する。200以外が返ってきた場合は、エラーダイアログを表示して何もしない。

LIST6④では、Webブラウザに表示されているHTMLページから、documentというDOM(Document Object Model)オブジェクトのgetElementByIdメソッドでidが "xml"というテキストボックスを取得し、そこへFlickrAPIから返されるレスポンスメッセージ(XMLで記述されている)をそのまま表示させている。このDHTMLの仕組みで、Ajaxでは表示済みのHTMLページを変化させ、リッチなユーザーインターフェイスを実現する。レスポンスメッセージは、XMLHttpRequestオブジェクトのresponseTextプロパティを参照することで取得している。

Flickr APIからのレスポンス(LIST8)はLIST6⑤で解析して、表示する写真をリクエストするためのURLを組み立てている。写真のURLは次のような形をしており、レスポンスXMLから必要な要素を取り出してはめ込んでURLを作成する。

http://static.flickr.com/{serverid}/{id}_{secret}.jpg

サンプルの説明は以上だが、このようにAjaxを使えばHTMLページのリロードなしに、Webからデータを取得し、それを使ってHTMLページの一部分だけを書き換えられる。また、今回は利用しなかったが、現在ではYahoo UI Libraryなど、リッチなユーザーインターフェイスを実装するためのフレームワークも多数提供されている。

一方、Ajaxにも欠点がある。XMLHttpRequestオブジェクトのところでも簡単に触れたが、JavaScriptを使うということで、Webブラウザ間の互換性に問題が生じる。ただし、これに関しては、現在出てきているさまざまなフレームワークを利用することでフレームワーク内に隠蔽可能である。また、Ajaxはかなり注目度の高い技術なので、Webブラウザの開発チームによってそのうち解決されるだろう(と期待している)。そのほか、JavaScriptに関してエンジニアがまだ少ない、デバッグが難しいといった問題がある。これらも開発ツールの充実や、Ajaxを利用するプロジェクトの増加などで今後解決されていくであろう。

LIST6 Flickrから1枚だけ写真を取得し表示するAjaxアプリケーション

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Ajaxサンプル</title>
<script type="text/javascript">
<!--
var req;
var last_modified = "Thu, 01 Jun 1970 00:00:00 GMT";
function getRecentFlickrImage() {
  // ②
req.open("GET",
    "http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=API_KEY
      &per_page=1", false);
  req.setRequestHeader("If-Modified-Since", last_modified);
  req.send(null);
  // ③
if (req.status == 200) {
    last_modified = new Date();
    processResponse();
  } else {
    alert("写真の取得に失敗しました。");
  }
}
function processResponse() {
  // ④
var xml = document.getElementById("xml");
  xml.value = req.responseText;
  var timestamp = document.getElementById("timestamp");
  timestamp.innerHTML = new Date();
  // ⑥
var response = req.responseXML;
  var photo = response.getElementsByTagName("photo");
  var serverID = photo[0].getAttribute("server");
  var id = photo[0].getAttribute("id");
  var secret = photo[0].getAttribute("secret");
  var displayArea = document.getElementById("showImage");
  displayArea.innerHTML = "<img src='" +
    "http://static.flickr.com/" + serverID + "/" + id + "_" + secret + ".jpg" + "'/>";
}
// ①
function onLoad() {
  req = new ActiveXObject("Msxml2.XMLHTTP");
  getRecentFlickrImage();
  setInterval("getRecentFlickrImage()", 60000);
}
// -->
</script>
</head>
<body onLoad="onLoad()">
Flickrからのレスポンス
<form>
<textarea id="xml" cols="70" rows="10"></textarea>
</form>
<div id="timestamp"></div>
<div id="showImage"></div>
</body>
</html>

LIST7 XMLHttpRequestオブジェクト生成をクロスブラウザ対応にする関数

function createXMLHttpRequest() {
  if(window.XMLHttpRequest) {
  // Firefox用の生成方法
return new XMLHttpRequest();
  }
  try {
    // バージョン6以降のIE用の生成方法
return new ActiveXObject("MSXML2.XMLHTTP");
  } catch(e) {
    try {
      // バージョン6以前のIE用の生成方法
return new ActiveXObject("Microsoft.XMLHTTP");
    } catch(ex) {
      return null;
    }
  }
}

LIST8 Flickr APIからのレスポンス

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="1000" perpage="1" total="1000">
<photo  owner="foo" secret="5aab6fd280" server="116"
  title="misc 2000-07-20 Image35" ispublic="1" isfriend="0" isfamily="0" />
</photos>
</rsp>

コラム : Flashベースのリッチクライアント開発環境「Flex2」

「Flex2」は、Flash技術を使い、Ajaxでさえも実現が難しいリッチなWebアプリケーションを開発可能なツールである。Flex登場以前のFlashの開発環境は、デザイナー向けに用意されているものしかなく、開発ツールではなくオーサリングツールという位置付けだった。Flashコンテンツ用のプログラミング言語ActionScriptも使えたが、デザイナー向けに作られたオーサリングツールを使いこなせるプログラマは非常に限られていた。かといって、ActionScriptを自由に扱うことができるデザイナーも非常に少なく、Flashのリッチクライアント開発を困難にしていた。

それに対し、Flex2ではプログラマ向けの開発環境(Flex Builder 2)を提供している。操作感がVisual Basicに似ており、習得も難しくないだろう。Flex2の製品ラインナップは次のようになっている。

  • Flex2 Software Development Kit(無償)
  • UI部品、コンパイラ、デバッガ、クラスライブラリが含まれている。GUIビルダは含まれていないが、これだけでFlashコンテンツを開発することも不可能ではない。
  • Flex Builder 2(有償)
  • Eclipseベースの統合開発環境で、GUIビルダも含まれている。現実的には、この製品を使って開発することになるだろう。
  • Flex Data Service 2(無償/有償)

非HTTPデータ通信やDBアクセスをサポートするサーバー製品。使用できる機能により、有償版と無償版がある。Flex2アプリケーションの構成は図Bのとおり だ。画面を定義するMXML(MacromediaMarkup Language)ファイルとビジネスロジックを記述するActionScriptからなる。これらを、コンパイラに渡すことでSWF(Flash形式)ファイルが作成される。アプリケーションの構成はJSFに非常に似ており、JSFの タグ内に記述する情報がMXMLに、Backing Beanなどで記述するロジック部分がActionScriptに相当する。Flashアプリケーションには、Ajaxアプリケーションと比較して、次のようなメリット/デメリットがある。

メリット

  • Ajaxよりもさらにリッチな操作感を持ったアプリケーションを開発できる
  • Flash Player上で動作するので、クロスプラットフォームでありながら、Ajaxよりは互換性の問題が発生しづらい
  • Flex Builder2は、Visual Basic感覚でアプリケーションの開発ができる

デメリット

  • WebブラウザにFlashプラグインが必要。ただし、最近ではFlashプラグインのインストール率が90%を超えているようなので、デメリットにはならないかもしれない
  • Ajaxに比べて利用実績が少ない(と思われる)ので、エンジニアの確保が難しい
  • SWFファイルが含まれているページはAjaxのページよりもサイズが大きくなる傾向があり、動き出すまでに多少時間がかかるデメリットもあるが、Flashアプリケーションが提供するリッチなユーザーインタフェースには魅力がある。今後、採用実績が増えていけば、リッチなWebアプリケーションの有力な選択肢になっていくだろう
図B Flex2 アプリケーションの構成

図B Flex2 アプリケーションの構成

コラム : Ajaxで使用される「JSON」とは

JSON(JavaScript Object Notation)とは、構造化されたデータをテキストで表現するためのフォーマットである。JavaScriptでの使用が想定されているが、基本的には言語から独立したフォーマットである。JSONの記法は、JavaScriptではオブジェクト作成の文法そのものである。そのため、JavaScriptではJSONを評価する(実行する)ことでオブジェクトに変換できる。クライアントの処理がJavaScriptで書かれているAjaxアプリケーションでは、XMLなどでデータをやり取りするよりもJSONを使ったほうが効率が良いのである。JSONのデータ記述例は次のとおりである。

var data =[
{"prop": "value1"},
{"prop": "value2"},
{"prop": "value3"}
];

JSONのデータは、{"キー1": "値1", "キー2": "値2″, ......} と["値1", "値2", ......]の2種類(それぞれJavaScriptのオブジェクトと配列に相当する)を組み合わせて構成する。JavaScriptでは、これを関数evalで評価するとオブジェクトに変換できる。先の例では、data[0].propで"value1"という値を取り出せる。

ただし、JSONにも問題がある。受け取った文字列(実行可能な文など)をそのまま評価してしまうと、悪意のあるデータから被害を受ける場合もある。信用できないサーバーとの通信結果の解析には使用するべきではないだろう。Ajaxとは言っても、データのやり取りに必ずしもXMLを使う必要はないし、それが常に最適とも限らない。

図Cをご覧いただきたい。JavaScriptで処理するという点だけをみれば、XMLよりもJSONのほうがはるかに扱いやすいだろう。サーバーサイドの処理をAjaxアプリケーションのみ使うようであれば、JSONを採用しても問題ないと思う。ただ、サーバーサイドの諸処理をWebサービスという形で公開するなど、Ajaxアプリケーション以外での利用も想定されるのであれば、XMLの採用を勧めたい。

図C JSONとXMLの使い分け

図C JSONとXMLの使い分け

複雑なUI構築を容易にするJSF

JSFとは、Webアプリケーションのユーザーインターフェイスを構築するためのフレームワークである。JSF登場以前は、JSPがこの役割を担っていた。JSFはJSPを置き換えるものではなく、JSPをベースにして、標準的なユーザーインターフェイスコンポーネントや、イベントハンドリング、データバリデーションなどの仕組みを載せたものと考えられるだろう。

JSPでは、ユーザーインターフェイスを構成する部品の記述をHTMLで行なう必要があった。これに対してJSFでは、標準でいくつかのコンポーネントが用意されている。カスタムタグを使うことで、これらのコンポーネントを利用できる。また、カスタムコンポーネントを定義するための仕組みも提供されている。

JSFのアーキテクチャ

JSFのアーキテクチャ概要を図7に示す。JSF環境では、WebブラウザからのリクエストはすべてFacesServletが受け取る。このServletはリクエストを解析して、表示するべきJSPを決定する。JSPはカスタムタグを使って画面を作成したり、Backing Bean (注17) と呼ばれるJavaBeansを利用して必要なデータを入手(ビジネスロジックを実行)する。DBアクセスに関しては、Session Bean経由にするか、Backing Beanが直接JPAを使って行なうかは要件次第で使い分けることになる。

それでは、JSFのサンプルコードを見てみよう。テキストボックスに入力された内容をそのまま画面に表示するというシンプルなものだ。画面遷移も図8のようにごく単純である。LIST9はデータを入力するためのJSPページ「input.jsp」である。最初のパートはタグライブラリの利用宣言だ。このサンプルでは、JSFのHTMLコンポーネントとCoreコンポーネントを利用している。

次にタグを使って、JSFのViewを定義している。JSFでは、すべてのJSFコンポーネントはこのView内に入れるのが決まりだ。最後は入力フォームを定義している部分だ。でHTMLフォームを、でテキストボックスを、でサブミットボタンをそれぞれ定義している。

テキストボックスのvalue属性に指定されている#{Echo.echoString}は、テキストボックスに入力された値をBacking BeanであるEchoクラス(LIST10)のプロパティechoStringに設定することを意味する。のvalueに指定された場合はsetterメソッドが、のvalueに設定された 場合はgetterメソッドがそれぞれ呼び出されることになる。

次に、入力された文字列をそのまま表示するJSPページ「output.jsp」を見てみよう(LIST11)。内容はほとんどinput.jspと同じだ。違うのはformの中身で、こちらはの代わりにが使われている。このページは出力専用であるため、inputTextである必要がないからだ。はラベルを"戻る"としている。

さて、最後に画面遷移とBacking Beanに関する設定を見てみよう。これらは、facesconfig. xmlというファイルに定義する(LIST12)。

前半部分のnavigation-rule要素では画 面遷移を定義している。from-view-id要素に記述したJSPページから送られてきた値(サンプルではinput.jspおよびoutput.jspにあるh:commandButtonのactionプロパティ)がfrom-outcomeの値と等しいとき、to-view-id要素のページへ遷移するという内容である。

また、input.jspとoutput.jspではh:commandButtonのactionプロパティは"success"で固定されているが、この部分を"#{Echo.doBusinessLogic}"のようにすれば、doBusinessLogicメソッドの戻り値によって遷移先を変えられる。

後半のBacking Beanに関する設定では、Echoという名前でsample.Echoクラスにアクセスできるようにすること、Beanのライフサイクルスコープがセッションである(セッションが有効な間、Beanも破棄されない)ことが指定されている。

以上、簡単にJSFの実装を紹介した。GUIを構成するパーツがカスタムタグとして標準で定義されている点は、これまでのJSPとの大きな違いだが、JSFが真の力を発揮するのは、開発ツールと組み合わせたときだろう。GUI部品やイベントハンドリング、データバリデーションなどが標準として定義されているので、開発ツールのサポートにより、Webページのデザインもずっと簡単になるはずだ。

また、Webページのデザイナーが利用する一般的なWebオーサリングツールがJSFをサポートしてくれれば、図9のような環境で開発を進められるようになり、プログラマとデザイナーとの役割分担で頭を悩ませることも少なくなるのではないだろうか。

LIST9 input.jsp

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<%@ page contentType="text/html;charset=Shift_JIS" %>
<%-- JSFのHTMLコンポーネントタグライブラリとCoreライブラリを利用する --%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<head><title>echo(input)</title></head>
<body>
<%-- viewの定義。JSFのコンポーネントタグはすべてこの中になければならない --%>
<f:view>
<%-- JSFのform、inputText、commandButtonコンポーネントを使って画面を作成 --%>
<h:form>
    文字列を入力してください。
    <h:inputText id="number" value="#{Echo.echoString}"/>
    <h:commandButton id="submit" action="success" value="送信"/>
  </h:form>
</f:view>
</body>
</html>

LIST10 Backing BeanのEchoクラス

package sample;
import java.io.*;
public class Echo implements Serializable {
  String echoString;
  public Echo() {
  }
  public String getEchoString() {
    return echoString;
  }
  public void setEchoString(String echoString){
    this.echoString =echoString;
  }
}

LIST11 output.jsp

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<%@ page contentType="text/html;charset=Shift_JIS" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<head><title>echo(output)</title></head>
<body>
<f:view>
  <h:form>
    <%-- JSFのform、outputText、commandButtonコンポーネントを使って画面を作成 --%>
入力された文字列は<h:outputText id="output" value="#{Echo.echoString}"/>です。
    <h:commandButton id="back" value="戻る" action="success"/>
  </h:form>
</f:view>
</body>
</html>

LIST12 faces-config.xml

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<navigation-rule>
    <description></description>
    <from-view-id>/input.jsp</from-view-id>
    <navigation-case>
      <description></description>
       <!--         (画面遷移の定義)
         Input.jspの<h:commandButton>だけ抜粋
         <h:commandButton  action="success" value="送信"/>
         この部分が一致した場合に/output.jspに遷移することを意味する       -->
       <from-outcome>success</from-outcome>
       <to-view-id>/output.jsp</to-view-id>
     </navigation-case>
   </navigation-rule>
   <navigation-rule>
     <description></description>
     <from-view-id>/output.jsp</from-view-id>
     <navigation-case>
       <description></description>
       <from-outcome>success</from-outcome>
       <to-view-id>/input.jsp</to-view-id>
     </navigation-case>
   </navigation-rule>
   <!-- Backing Beanの定義 -->
<managed-bean>
    <managed-bean-name>Echo</managed-bean-name>
    <managed-bean-class>sample.Echo</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>
</faces-config>
図7 JSFのアーキテクチャ概要

図7 JSFのアーキテクチャ概要

図8 JSFサンプルの画面遷移

図8 JSFサンプルの画面遷移

図9 デザイナーとプログラマのJSFを介した作業分担

図9 デザイナーとプログラマのJSFを介した作業分担

コラム : 変更に強いDIコンテナ

昨年より、SpringやSeaser2といった「DIコンテナ」と呼ばれているJava環境のフレームワークが注目を集めている。DIとは「Dependency Injection」の略で、依存性の注入と訳されている。具体的に言えば、インターフェイスと実装を分離し、ソフトウェアコンポーネント間の依存性を最小化しようという発想のもとに開発された技術だ。

LIST Aは、java.utilパッケージのListインターフェイスを利用するコードである。Listの具体的な実装としてはArrayListが使用されている。このようにしておけば、aListを使う限り、Listインターフェイスにのみ依存するが、ArrayListという実装には依存しなくて済むので、インターフェイスと実装がきちんと分離されているように見える。

しかし、ArrayListの実装をLinkedListに変更しようとしたらどうだろうか。ArrayListをnewしている部分のコードをLinkedListに変更し、リコンパイルが必要になるだろう。

LIST A java.utilパッケージのListインターフェイスを利用

java.util.List aList = new java.util.ArrayList();
aList.add("・・・・");
public void processList(java.util.List aList) {
// java.util.List内の要素に特定の処理を施す
}

そこで、リコンパイルなしに実装を変更するための技術として考え出されたのがDIコンテナである。DIコンテナはJ2EE準拠の複雑なアプリケーションサーバーに比べて比較的簡単に使える点も特徴だ。実際のところ、J2EE(特にEJB)のような大げさな仕組みを必要とするシステムは限られており、大多数のシステムはDIコンテナで十分開発ができてしまう。

また、DIコンテナがしばしば「軽量コンテナ」と呼ばれるのは、複雑なJ2EE環境にくらべて軽量、という意味である。このような流れを受けて、Java EE 5ではDIコンテナの考え方が取り入れられた。例えば、本文のJPAのサンプルコードでも紹介したEntityManagerだが、次のように記述することで、実行時に実装を注入できる。

@PersistenceContext private ⇒ EntityManager entityManager;

しかし、DIコンテナにも欠点がある。実行時に注入するべき実装クラスは外部のXMLファイルなどで定義することになる。そのため、あまりにもDIを濫用しすぎると、コードを読む際、コード本体と設定ファイルの間を何度も往復せざるを得ず、見通しが悪くなってしまう。SpringやSeaser2は自由にDIが使えるので、特にこの傾向が強い。

Java EE 5はDIで設定できるクラスが限られているので、使いすぎを抑止できる。J2EEのこのアプローチはなかなか興味深い。いずれにしても、正しく使えばコンポーネント間の依存性が低い、柔軟性のあるシステムを構築できる。ぜひ試してほしい技術の1つである。

おわりに

本パートでは、最近注目を集めているWebアプリケーション技術を駆け足で紹介した。冒頭でも述べたが、少し前までJ2EE一辺倒だったWebアプリケーション開発に、現在いろいろな選択肢が出てきていることがお分かりいただけたと思う。

最近の進化の方向性は、EoD(Ease of Development)であると感じている。Ruby onRailsやDIコンテナなどはその典型例だろう。技術の入れ替わりが非常に激しい現在において、この進化の方向性は正しいと思う。技術は簡単に使えるべきなのである。

誌面の都合上、あまり詳細に触れることはできなかったが、本稿が現時点での技術動向を把握する一助になれば幸いである。

  • 注:C#アプリケーションは、Eclipseで提供されている環境で開発することもできた。
  • 注1:Flickrは、参加者が写真をアップし、共有するWebサイト(http://www.flickr.com/)。タギングとは参加者が写真に「言葉(タグ)」付けることを言い、検索キーとして使える。
  • 注2:はてなは、ブログやRSSリーダーといったサービスを提供するコンテンツプロバイダ(http://www.hatena.ne.jp/)。ソーシャルブックマークとは、参加者が気に入ったWebサイトを登録し共有するサービス。
  • 注3:EJBを使わず、JSP/Servletなどの組み合わせで済ませるようなシステムも含む。
  • 注4:EJBの実行環境。アプリケーションサーバーという形態で製品化されている。
  • 注5:業務アプリケーションで扱うデータをDB に格納するためのフレームワーク。
  • 注6:最近ではStruts+Spring もしくはSeaser2+Hibernateという組み合わせも多いと思われる。
  • 注7:マーチン・ファウラー氏による造語で、名前のとおり「昔からある普通のJavaオブジェクト」といったような意味である。EJBコンポーネントのような、ある決まったインターフェイス実装や継承を求められたり、特別な環境でしか実行できないようなJavaオブジェクトとの対比で使われる。
  • 注8:Entity BeanはJavaオブジェクトとRDBとのマッピングを定義するだけで、永続化処理は行なわないことになる。
  • 注9:規約自体を変更することも可能ではある。
  • 注10:このWebサーバーはすべてRubyで記述されている。
  • 注11:既存のWebサービスをうまく組み合わせて新たなアプリケーションを開発するという考え方。グルメサイトで店舗の詳細情報を見るとGoogle Maps上に場所が表示されるアプリケーションなどは、マッシュアップの例と言えよう。
  • 注12:アーキテクチャの形のこと。
  • 注13:RESTについての詳しい説明は、山本陽平氏のブログ記事「REST 入門」(http://yohei-y.blogspot.com/2005/04/rest_23.html)に分かりやすくまとめられているので、そちらを参照してほしい。
  • 注14:両技術を連携するブリッジのようなものを使えば通信も可能ではあった。
  • 注15:Web Services Description Languageで記述された、Webサービスのリクエスト方法などを示すファイル。
  • 注16:メソッドの宣言だけでなく、実際の処理まで記述されたクラス。
  • 注17:インスタンス化や破棄のタイミングがJSFによって管理されている以外は、ごく普通のJavaBeansである。JSFの各UIコンポーネントは、Backing Beanを経由してビジネスロジックの実行結果などを受け取る。

中村正弘(なかむらまさひろ)

ウルシステムズ株式会社に所属。シニアコンサルタント。ここ1 年くらいはWeb 2.0 的な短い期間でアップデートを繰り返す開発プロジェクトのリーダーをやっている。最近の技術では、Ruby on Rails がお気に入り。

アーカイブス一覧へ