なお、本稿で紹介する作例は記事にサンプルコードを添付しているため、そちらも併せて参照して欲しい。
1. Webアプリケーションに特化した軽量版WebSphere「Liberty Core」
IBMが提供するアプリケーションサーバ「WebSphere Application Server」(以下、WAS)に、v8.5.5より新しいエディションとして「Liberty Core」が追加された。Liberty Coreは、フルスタックのJava EEを必要としない、 Webアプリケーション向けに設計された軽量なアプリケーションサーバである。Webアプリケーションの開発や実行に特化しているため、WASの他のエディションに比べて少ないリソースで高速な動作を実現している点が特徴だ。
Liberty CoreはWAS v8.5から追加されたLibertyプロファイルをベースに構成されている。LibertyプロファイルはJava EEに定義されたWebプロファイルをサポートしたアプリケーションランタイムで、当初はWASの一機能として、主に開発やテストの用途向けに提供されていたもの。そのLibertyプロファイルをベースに、実運用を想定した独立したエディションとして完成させたのがLiberty Coreということだ。
Liberty Coreの最大の利点は、Webアプリケーションの開発および運用に特化した軽量さにあるが、その他にもEclipseの拡張機能として利用できる開発環境の導入の手軽さ、デプロイメントに向けたパッケージ化の容易さ、拡張性の高さなども特徴として挙げることができる。一方で、WASの他のエディションで利用可能なLibertyプロファイルの一部の機能が、Liberty Coreではサポートされていないという注意点もある。例えばJMSやJAXB、JAX-WSなどといったJava EE Webプロファイルに含まれない一部のAPIは、Libertyプロファイルではサポートされているが、Liberty Coreには含まれていない。Liberty Coreを含むWASの各エディションでサポートされる機能の一覧は、Libertyフィーチャーのページにまとめられている。
2. なぜLiberty Coreが必要なのか
Libertyプロファイルが生まれた背景には、WASでの開発をもっと高速でストレスなく行いたいという開発現場の声があるという。Webアプリケーションの開発では、アプリケーションサーバの再起動を頻繁に繰り返しながらデバッグやチューニングを行うことが多い。迅速な開発スピードを求められる現場では、このアプリケーションサーバの再起動にかかる時間を縮小することには大きな意味がある。Tomcatをはじめとするオープンソースのアプリケーションサーバが人気を誇っているのは、簡単に使える手軽さもさることながら、軽量で起動が速く開発時のストレスが少ないという理由も大きい。
その一方で、それらのオープンソース系のアプリケーションサーバには、大規模なアプリケーションの開発では機能が十分でないという問題もある。エンタープライズ規模のアプリケーションを安定して動作させるためには、クラスタリングや統合管理機能などフル活用して大量のトランザクションに耐えるシステム基盤を用意しなければならない。オープンソースのプロダクトを組み合わせてそのようなシステムを組むことも不可能ではないが、幅広いノウハウが必要であり、敷居は決して低くない。
その点、WASであればあらゆる規模のアプリケーションにおいて信頼性の高いシステム基盤を構築することができる。しかしながら、これまでのWASは機能拡張を続けた結果、導入にディスクを何枚も使って1時間以上かかるほどに拡大化しており、素早い開発というニーズに対応することが難しくなっていた。
そこで登場したのがWASのLibertyプロファイルというわけだ。Libertyプロファイルは、WASの安定性や信頼性の高さを維持しながら、軽量で起動が速いという開発フェーズでのニーズを満たす、言わば「いいところ取り」をした製品と言える。従って、Libertyプロファイルの利用シーンとしては、その軽量さを活かしてアプリケーション開発の効率を上げつつ、完成したアプリケーションを信頼性の高いWAS環境で実行するというシナリオが想定されている。
とはいえ、最近のWebアプリケーションではJava EEのフル機能までは必要ないというケースも少なくないだろう。そこで、WASからLibertyプロファイルを稼働させるのに必要十分な機能を抽出し、単独のアプリケーションサーバとして利用できるようにしたのが新エディション「Liberty Core」である。Liberty Coreは、他のWASエディションのようにJava EEのフルスタックを利用できるわけではなく、あくまでもWebアプリケーションの実行基盤に特化されたものだ。その代わりに、極めて安価で提供されているので手軽に利用できるほか、上位エディションにも容易に移行することができるという強みがある。初期コストを押さえつつ、事業の成長に応じてシームレスに規模を拡大していくことが可能なため、リーンスタートアップにも向いた製品ということができる。
3. Liberty Core用アプリケーション開発ツールの導入
前述のとおり、Liberty Coreの第一のフォーカスは開発時のストレス軽減にある。そこで本稿では、実際にLiberty Coreを使って簡単なWebアプリケーションを作成、実行してみたい。
Liberty Coreを導入する方法には、次の3種類がある。
- IBM Installation Managerを使ってインストールする
- 自己展開圧縮JARファイルをダウンロードして展開する
- Eclipse用プラグイン「WebSphere Application Server Developer Tools(WDT)」を利用する
開発用途であれば3番目のWDTを使う方法が一番手軽とのことなので、今回はそれを利用してみる。Eclipseのパッケージは4.3(Kepler)のJava EE Developers(Pleiadesで日本語化済み)で、プラグインは「IBM WebSphere Application Server V8.5.5 Liberty Profile Developer Tools for Eclipse Juno & Kepler V8.5.5.1」を使用する。
Liberty Profile Developer ToolsはEclipseのマーケットプレースからインストールできるので、まずは[ヘルプ]-[Eclipse マーケットプレース]を選択してマーケットプレースを立ち上げる。「WebSphere Liberty」で検索をかければ、図3.1のように対象のプラグインが見つかるはずなので、[インストール]をクリックしてインストールを開始する。
フィーチャーの選択画面では4つの機能が表示されるが、すべて選択しておけば問題ないだろう。
ライセンスが表示されるので、同意してインストールを実行する。途中で「署名なしコンテンツを含む」という旨のセキュリティー警告が表示されるが、特に理由がなければ続行しても問題ない。インストールが完了したら、画面の指示に従ってEclipseを再起動すれば、Libertyプロファイルが利用できるようになる。
続いてLibertyプロファイルのサーバー定義を作成しよう。ワークベンチのサーバー・ビュー上(図3.3)で右クリックして[New]-[Server]を選択し、新規サーバーウィザードを立ち上げ、図3.4のようにサーバータイプは[IBM]-[WebSphere Application Server V8.5 Liberty Profile]を選択し、任意のホスト名とサーバー名を記入して[次へ]をクリックする。
図3.5のようにLiberty Profileのランタイム環境を設定する画面になるので、[download or install]のリンクをクリックする。ただし、もしすでに他の方法でPCにランタイムがインストールされている場合には、[参照]をクリックしてそのパスを指定してもよい。
ランタイムのインストール画面では、図3.6のように[Download and install a new environment from:]にチェックを入れ、使用するランタイムの種類を選択する。今回は、現行バージョンである「V8.5.5.1 Liberty Profile」を使用した。なお、「8.5.5.Next Alpha Liberty Profile」というのは、次期バージョンに搭載される予定の最新機能を試すことができるパッケージだ。また、もしローカルにLibertyプロファイルのアーカイブをダウンロードしてある場合には、そのパスを指定してインストールすることもできる。
[次へ]をクリックするとアドオンの選択画面になり、追加で導入する機能などがインストールできる。各種サンプルアプリケーションなどもここでインストールすることが可能だ。
最後に、Libertyプロファイルをインストールするディレクトリを指定する。これは任意の空ディレクトリのパスを指定すればよい。
[完了]をクリックすればインストールが実施され、成功すると図3.9のように再度ランタイム環境の設定画面に戻ってくるので、[次へ]で先に進む。ただし、もし複数のJREがインストールされている場合には、ここで使用するJREを指定しておく必要がある。
最後に、サーバー名に任意の名前を記入し、[完了]をクリックすればLibertyプロファイルの初期設定は完了だ。
すべてEclipseのウィザード上で設定できるので、Eclipseに慣れたユーザーであれば特に迷うことなく導入できるのではないだろうか。
4. Servletアプリケーションの作成と実行
環境の準備ができたので、まずは基本的なServletのプログラムを作って動かしてみよう。通常通りプロジェクトマネージャーから「動的Webプロジェクト」を作成し、ランタイムおよび構成にLiberty Profileを選択する。本稿では、郵便番号から住所を取得するアプリケーションを、「PostalCodeServlet」という名称で作成した(図4.1)。
まず、郵便番号を指定して住所を取得するためのクラスとして「com.example.postcode.PostalCode.java」を用意した。郵便番号データは、日本郵便が公開しているCSVデータから郵便番号と住所の部分を抜粋したファイルを用意し、クラスの初期化時にMapに読み込むようにしている。実際に検索を行うのはget()メソッドである。
public class PostalCode { private Map<String, String> postalCodeMap = new HashMap<>(); public PostalCode() { try (BufferedReader reader = new BufferedReader(new InputStreamReader (this.getClass().getResourceAsStream("postalcode.csv"), "UTF-8"))) { String line; StringTokenizer token; while ((line = reader.readLine()) != null) { token = new StringTokenizer(line, ","); String code = token.nextToken(); String address = token.nextToken(); this.postalCodeMap.put(code, address); } } catch(IOException ex) { ex.printStackTrace(); } } public String get(String postalcode) { String address = this.postalCodeMap.get(postalcode); if (address == null) { address = "NoData"; } return address; } }
Servletクラスは次のようにした。init()でPostalCodeの初期化を行い、doGet()ではパラメータとして郵便番号を受け取り、PostalCode.get()メソッドで住所を検索して画面に結果を返す。
@WebServlet("/PostalCodeServlet") public class PostalCodeServlet extends HttpServlet { private static final long serialVersionUID = 1L; private PostalCode postalCode; public PostalCodeServlet() { super(); } public void init() throws ServletException { this.postalCode = new PostalCode(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String postalcode = request.getParameter("postalcode"); String address = this.postalCode.get(postalcode); String result; if (!address.equals("NoData")) { result = "<p style='font-size:large'>〒" + postalcode + " の住所は</p>" + "<p style='font-size:x-large'>" + address + "</p>" + "<p style='font-size:large'>です。</p>"; } else { result = "<p style='font-size:x-large'>〒" + postalcode + " は存在しません。"; } response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Sample Servlet</title>"); out.println("</head>"); out.println("<body>"); out.println(result); out.println("</body>"); out.println("</html>"); out.flush(); out.close(); } }
Webページ側は次のようになる。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Sample Servlet</title> </head> <body> <p style='font-size:large'>郵便番号を入力してください。</p> <form action="PostalCodeServlet"> <input type="text" name="postalcode" size="50"/> <input type="submit" value="送信"/> </form> </body> </html>
アプリケーションが準備できたら、サーバー上で実行してみる。単純なServletであれば特別な設定は必要ない。プロジェクトマネージャーから[実行]-[サーバーで実行]を選び、使用するサーバーとしてLiberty Profileを選択すればよい。
起動に成功すれば、EclipseのWebプレビューでServletの動作を確認できる。
注目すべきはサーバーの起動時間だ。初回でも、ものの数秒で起動およびアプリケーションのデプロイが完了する。また、ホットデプロイの仕組みが組み込まれているため、ソースコードや設定を書き換えた場合でも、サーバーを再起動することなく自動で変更が反映される。反映にかかる時間も、ものの1~2秒といったところだ。
軽量という謡い文句のとおり、極めてスムーズな動作が実現されており、コーディングとプレビューの繰り返しをストレスなく行うことができる。
5. JSF+Facelets+CDIを利用する
続いて、JavaServer Faces(JSF)を使ったアプリケーションを動かしてみよう。プロジェクト名は「PostalCodeJSF」とした。開発に必要なライブラリはLiberty Profileに含まれているので、プロジェクトとしての追加の設定は特に必要ないが、サーバー側の設定には少し手を加える必要がある。サーバーマネージャーにおいて「サーバー構成」をダブルクリックしてserver.xmlを開き、図5.1のように「フィーチャーマネージャー」を表示する。
ここで右側の[追加]ボタンをクリックして、使用したいフィーチャーを選択すれば、サーバー上でその機能が有効になる。今回はJSFを使いたいので、jsf-2.0を選択すればよい。また、せっかくなので、CDI(Context and Dependency Injection)も使えるようにしておこう。なお、ここには表示されていないが、Servlet 3.0やJSON、Bean Validationはデフォルトで有効になっている(下部のShow implicitly enabled featuresをチェックすると表示される)。
PostalCodeクラスは先ほどの例のものが流用できるが、CDIを使うので、@Namedや@PostConstruct、スコープを決める@ApplicationScopedといったアノテーションを追加する。
@Named @ApplicationScoped public class PostalCode { private Map<String, String> postalCodeMap = new HashMap<>(); @PostConstruct public void init() { // 省略 } public String get(String postalcode) { // 省略 } }
ManagedBeanでは、@InjectアノテーションでPostalCodeオブジェクトをInjectする。プロパティは郵便番号と住所に対応したcodeとaddressの2つ。住所の取得はgetAddressFromCode()メソッドで行う。
@Named @SessionScoped public class PostalCodeController implements Serializable { private static final long serialVersionUID = 1L; String code; String address; @Inject PostalCode postalCode; public void getAddressFromCode() { this.address = postalCode.get(this.code); } // Getter/Setter省略 }
Webページは、Faceletsを利用すればHTMLに近いタグ構成で作ることができる。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Sample JSF</title> </head> <body ui:id="body"> <p style='font-size:large'>郵便番号を入力してください。</p> <form jsfc="h:form" ui:id="form"> <input jsfc="h:inputText" type="text" ui:value="#{postalCodeController.code}" size="50" /> <input jsfc="h:commandButton" type="submit" value="送信" ui:action="#{postalCodeController.getAddressFromCode()}" /> <p style='font-size:x-large'>住所: #{postalCodeController.address}</p> </form> </body> </html>
その他、beans.xmlやweb.xml、faces-config.xmlがWebContentsのWEB-INF以下に必要。準備ができたら、先ほどと同じようにサーバー上で実行すればプレビューできる。server.xmlの設定を変更したが、これも保存時に自動で反映されるので、サーバーを再起動する必要はない。
6. JAX-RSを利用する
せっかくJava EE Webプロファイルが完全にサポートされているので、RESTful Webサービス用のAPIであるJAX-RS(The Java API for RESTful Web Services)も使ってみよう。JAX-RSを使うには、JSFのときと動揺に、フィーチャーマネージャーを使って「jaxrs-1.1」を有効にすればよい。なお、JAX-RSの実装としてはApache Winkが採用されている。
CDIを使う場合、PostalCode.javaはJSFのサンプルのものがそのまま使える。リクエストを受け取るためのクラスは、GetAddressという名前で次のように実装した。
@Named @ApplicationScoped @Path("/address") public class GetAddress { @Inject private PostalCode postalCode; @Path("get") @GET @Produces({MediaType.APPLICATION_JSON}) public Result get( @QueryParam("code") String code) { String address = postalCode.get(code); return new Result(code, address); } }
住所を取得するためのメソッドをget()とし、リクエストパスは@Pathアノテーションを用いて「/address/get」となるように設定している。郵便番号をパラメータとして受け取るように@QueryParamアノテーションをセットしているので、実際にリクエストする際URLは「?/address/get?code=郵便番号」のようになる。
結果を返すためのクラスも用意する。今回の例ではリクエストされた郵便番号と、それに対応した住所を返したいので、この2つをフィールドとして持つResultクラスを定義した。
public class Result { private String code; private String address; public Result(String code, String address) { this.code = code; this.address = address; } // Getter/Setter省略 }
JAR-RSの設定を行うのに必要なApplidationConfigクラスは次のようになった。ルートパスを「ws」とし、リクエストを受け取るGetAddressクラスを登録している。その他、CDIのためにbeans.xmlも必要になる。
@javax.ws.rs.ApplicationPath("ws") public class ApplicationConfig extends Application{ public Set<Class<?>> getClasses(){ HashSet<Class<?>> set = new HashSet<Class<?>>(); set.add(GetAddress.class); return set; } }
準備ができたら、プロジェクトをサーバーで実行してみる。なお、プロジェクト名はPostalCodeServiceとした。Webブラウザからリクエスト用のURL(この例では「http://localhost:9080/PostalCodeService/ws/address/get?code=郵便番号」)にアクセスすると、次のようなResultオブジェクトのJSONデータが返ってくるはずだ(Firefoxではブラウザ上に表示されるが、EclipseのWebプレビューの場合はファイルがダウンロードされる)。
{"address":"東京都千代田区千代田","code":"1000001"}
7. Liberty CoreへのWebアプリケーションのデプロイ
さて、ここまではEclipse向けのWDT上でLibertyプロファイルを使っていたが、せっかくなのでLiberty Core単体でのWebアプリケーションの動作も確認してみたい。IBMのサイトからはLiberty Coreの無償評価版がダウンロードできるので、まずはこれを使ってみよう。
JARアーカイブ版とInstall Manager版が用意されており、今回はJARアーカイブ版を利用する。ファイル名は「wlp-core-trial-runtime-8.5.5.0.jar」となっている。このファイルそのものがインストーラになっているので、ダウンロードしたらコマンドプロンプトを立ち上げて、javaコマンドで次のように実行する。
C:\>java -jar wlp-core-trial-runtime-8.5.5.0.jar
途中で表示されるライセンスに同意し、インストール先を指定すれば、指定した場所にwlpというディレクトリが作られて必要なファイルが展開される。本稿の例では、「C:\workspace\liberty-core」にインストールした。
インストールが完了したら、続いてサーバーを作成しよう。サーバーの作成や起動、停止などの操作は、binディレクトリにあるserverコマンドで行うことができる。serverコマンドはWindows版とUNIXシェル版が用意されている。新規サーバーの作成は、次のようにserver createコマンドを使って行う(Windows上で、「sampleServer」という名前のサーバーを作成する例)。
C:\> cd C:\workspace\liberty-core\wlp\bin C:\workspace\liberty-core\wlp\bin> .\server create sampleServer サーバー sampleServer が作成されました。
サーバーが作成されたら、次のようにserver startコマンドを使って起動しよう。
C:\workspace\liberty-core\wlp\bin>.\server start sampleServer サーバー sampleServer を始動中です。 サーバー sampleServer が始動しました。
Liberty Coreはホットデプロイ機能を持っているので、アプリケーションのデプロイは指定のディレクトリにWARアーカイブを配置するだけでできてしまう。ホットデプロイ用のディレクトリは「\user\servers\サーバー名\dropins」。先ほどEclipseで作ったPostalCodeServletをWAR形式にエクスポートして、このディレクトリにコピーしてみよう。必要な操作はこれだけで、Webブラウザからアクセスできるようになっているはずだ。
PostalCodeJSFやPostalCodeServiceの場合はフィーチャーの設定が必要になる。「\user\servers\サーバー名」のディレクトリにserver.xmlがあるので、ここに使用しているフィーチャーを追加する。記述方法は、Eclipseで設定したserver.xmlのソースを参考にすればいいだろう。例えば、JSFとCDIを使う場合は以下のようになる。
<server description="new server"> <!-- Enable features --> <featureManager> <feature>jsp-2.2</feature> <feature>jsf-2.0</feature> <feature>cdi-1.0</feature> </featureManager> <httpEndpoint id="defaultHttpEndpoint" host="localhost" httpPort="9080" httpsPort="9443" /> </server>
最後に、サーバーの停止はserver stopコマンドで行う。
C:\workspace\liberty-core\wlp\bin>.\server stop sampleServer サーバー sampleServer を停止中です。 サーバー sampleServer は停止しました。
8. まとめ
今回はJava EEのWebプロファイルを使って簡単なWebアプリケーションを作ってみたが、特に細かな設定をすることもなく、実にスムーズにプレビューまで進むことができた。率直な感想を言ってしまえば、予想を上回る手軽さだった。その手軽さはTomcatやJBossをはじめとするオープンソースのアプリケーションサーバとまったく遜色のないレベルであり、WASを使ったことのないユーザーにとっても導入の敷居は極めて低いと言えるだろう。
起動やデプロイの速度はもちろんのこと、フィーチャーマネージャーで必要な機能だけを簡単に付けたり外したりできる管理の手軽さも大きな魅力である。自分で選択するほかに、使われているフィーチャーだけを自動検出する機能もあるため、軽量化のための最小構成を容易に実現することができるはずだ。
その他、本稿の例では紹介し切れなかったが、他のオープンソースのフレームワークやAPIと組み合わせる使い方も可能で、各種サンプルアプリケーションも公開されている。TomcatからLiberty Profileへのマイグレーションでは移行ツールも用意されている。軽量Webアプリケーションサーバを使用している場合、機能拡張したい場合などでも商用製品への移行が容易ではないという問題があるが、少なくともLiberty Coreではその心配はいらないそうだ。規模の拡大を見据えた開発環境および本番環境の充実化に向けて、Liberty Coreは有力な候補だと言えるだろう。