WebSphere Application Server Feature Pack for Web 2.0 開発者ガイド
by user
Comments
Transcript
WebSphere Application Server Feature Pack for Web 2.0 開発者ガイド
WebSphere Application Server Feature Pack for Web 2.0 開発者ガイド 第 2 回 「Web Remoting と Dojo」 日本アイ・ビー・エム株式会社 ソフトウェア事業 2008 年 4 月 1 ■■WebSphere Application Sever Feature Pack for Web 2.0 開発者ガイド 第 2 回 ■■.....................................................3 ■■はじめに .....................................................................................................................................................................................3 ■前回のおさらいと準備...............................................................................................................................................................3 ■開発するアプリケーションの概要 ...........................................................................................................................................3 ■アプリケーションの構造...........................................................................................................................................................3 ■■開発環境の準備..........................................................................................................................................................................5 ■WAS のプロファイル新規作成.................................................................................................................................................5 ■AST でのプロジェクト新規作成..............................................................................................................................................9 ■■サーバーサイド処理の実装.....................................................................................................................................................11 ■データベース初期化サーブレットの作成..............................................................................................................................11 ■パラメータクラスの作成.........................................................................................................................................................12 ■データベースアクセスクラスの作成......................................................................................................................................15 ■サービスクラスの作成.............................................................................................................................................................20 ■■RPCAdapter の設定................................................................................................................................................................22 ■RPCAdapter とは?................................................................................................................................................................22 ■RPCAdapter の登録................................................................................................................................................................22 ■サービスクラスの公開.............................................................................................................................................................23 ■■Dojo による JSON-RPC サービスの利用 ............................................................................................................................24 ■JSON-RPC と SMD(Simple Method Description).............................................................................................................24 ■Dojo JSON-RPC クライアント..............................................................................................................................................24 ■dojo.rpc.JsonService による RPCAdapter クライアントの作成........................................................................................25 ■■まとめ.......................................................................................................................................................................................32 ■■参考資料 ...................................................................................................................................................................................32 ■AST の入手 ..............................................................................................................................................................................32 ■WAS Feature Pack for Web 2.0 に関する情報源.................................................................................................................32 ■関連する技術情報....................................................................................................................................................................32 2 ■■WebSphere Application Sever Feature Pack for Web 2.0 開発者ガイド 第 2 回 ■■ ■■はじめに ■前回のおさらいと準備 前回は、Feature Pack for Web 2.0 のインストールとサンプルアプリケーションの実行手順、および Dojo Toolkit を利用 した簡単なアプリケーションの開発方法についてご紹介しました。 今回から、Feature Pack for Web 2.0 を利用した本格的なアプリケーションの開発に着手します。本記事では、Feature Pack 適用済みの WebSphere Application Server 6.1、および Application Server Toolkit 6.1 を利用したアプリケーション 開発手順をご紹介していきますので、もし準備が整っていないようであれば前回の記事をご参照の上、あらかじめ環境構築 を実施しておいてください。 http://www-06.ibm.com/jp/software/websphere/developer/was/wv61/feature_pack/web20/guide/ また、本記事では開発環境として WindowsXP(SP2)を利用しています。 ■開発するアプリケーションの概要 これから開発していくアプリケーションは、インターネットオークションを題材としたものです。今回は、以下の機能を 実装します。 ・ 出品者が、オークションへ商品を出品する機能 ・ 入札者が、出品された商品に入札する機能 ・ 出品者および入札者が、商品情報および入札状況を参照する機能 今回は、データベース処理やサーバーサイドのビジネスロジックといった基本部分を実装し、それを Ajax クライアント から呼び出せるようにします。次回以降、機能は随時拡張していく予定です。 ■アプリケーションの構造 オークションの情報はすべてリレーショナルデータベースに格納します。データモデルは次の通りです。 ITEM 論理名 物理名 データ型 データ型 出品ID itemid int(自動採番),PK 商品ID productid varchar(30) 商品名 productname varchar(100) BID 論理名 物理名 データ型 データ型 入札ID bidid int(自動採番),PK 出品ID itemid int 入札者 buyer varchar(20) 0..* 画像URL imageurl varchar(100) 商品ページURL itempageurl varchar(100) 入札価格 price bigint 出品者 seller varchar(20) 入札日時 date timestamp 終了日時 enddate timestamp 登録日時 registdate timestamp 出品者がオークションに商品を出品すると、ITEM テーブルにレコードが 1 つ追加されます。出品された商品に対して入 札者が入札を行うたびに、BID テーブルにレコードが追加されていきます。 データベースには、WAS に同梱されている Derby を利用します。デフォルトデータソースとして Derby が設定済みであ るため、特に設定作業などは必要ありません。 もし、デフォルト以外のデータソースを利用したい場合は、ソースコード中でデータソースを JNDI から参照している箇 所を適宜修正してください。また、SQL 文には Derby 固有のステートメントが含まれていますので、他のデータベースを 3 利用したい場合は、利用する製品に応じて SQL 文の修正が必要です。 アプリケーションコンポーネントの構成は次の通りです。 POJO JSON-RPC RPCAdapter Webブラウザ Web2.0 FeaturePackが 提供 DbUtil Item ItemDao Auction BidDao Bid 特筆すべきことは、サーバーサイドのコンポーネントはすべて POJO(Plain Old Java Object)で実装可能な点です。 Feature Pack for Web 2.0 が提供する RPCAdapter(サーブレット)に対してサービスとして公開する POJO を登録するだけ で、クライアントからのサービス呼び出し(JSON-RPC および HTTP RPC)を、POJO のメソッド呼び出しにマップするこ とが可能です。 今回は全ての処理を POJO で実装していますが、サービスとして公開するクラスは POJO であれば良いので、もちろん そこからバックエンドの EJB や WebService を呼び出すことも可能です。 また、POJO のメソッドに対する引数や、メソッド実行結果のシリアライズ・デシリアライズも RPCAdapter が自動的 に行います。シリアライズ可能な形式は JSON(JavaScript Object Notation)および XML です。そのため、専用のサーブレ ットを新たに開発したり、煩雑なフォーマット変換に煩わされたりすることなく、Ajax クライアントに対して容易にサービ スを公開することができます。 このように、RPCAdapter は、既存の Java EE 資産を Web 2.0 の領域で活用したいというニーズに対して、必要最小限 の労力で対応することを可能にしています。実際のコードサンプルでそれを確認してみましょう。 4 ■■開発環境の準備 ■WAS のプロファイル新規作成 1. Windows のスタートメニュー「プログラム」-「IBM WebSphere」-「Application Server Network Deployment V6.1」 -「プロファイル管理ツール」から、プロファイル管理ツールを起動します 2. アプリケーション・サーバー・プロファイルを作成します。 * WAS ND 環境を構築する場合は、以下のサイトをご参照ください。 http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.ejbfep.multiplatform.doc/inf o/ae/ae/tins_scenario_ejb3.html 5 3. プロファイル作成オプション画面で「拡張プロファイル」を選択し、 「次へ」をクリックします。 4. 管理コンソールのデプロイとデフォルト・アプリケーションのデプロイをチェックし、 「次へ」をクリックします。 6. プロファイル名およびロケーションを指定し、 「次へ」をクリックします。(例 プロファイル名 AppSrv01) 6 7. ノード名とホスト名を指定し、 「次へ」をクリックします。 8. 「管理セキュリティを有効にする」のチェックをはずし、 「次へ」をクリックします。 9. ポート値の割り当て(デフォルトのまま)を指定し、 「次へ」をクリックします。 7 10. 「アプリケーション・サーバー・プロセスを Windows サービスとして実行する」のチェックをはずし、 「次へ」をクリ ックします。 11. 「Web サーバー定義の作成」はチェックせずに、 「次へ」をクリックします。 12. 「プロファイル作成サマリー」画面を確認し、 「作成」をクリックすると作成が開始されます。 8 13. 「プロファイル作成の完了」画面が表示されます。 「正常に作成」されていることを確認し、 「終了」をクリックします。 ■AST でのプロジェクト新規作成 1. Windows のスタートメニュー「プログラム」 「IBM WebSphere」 「Application Server Toolkit V6.1.1」 -「Application Server Toolkit」を起動します 2. 「ワークスペースの選択」画面では、適当なディレクトリを選択します。 3. 「ようこそ」画面では、右端の矢印アイコンをクリックしてワークベンチに移動します。 4. メニューから「ファイル」-「新規」-「プロジェクト」を選択し、 「Web」-「動的 Web プロジェクト」を選択して「次 へ」をクリックします。 5. 「プロジェクト名」に"Auction"と入力し、ターゲットランタイムが WAS6.1 スタブ となっていることを確認して「終 了」をクリックします。 6. J2EE パースペクティブを開くかどうかの確認メッセージが表示されるので、 「常にこの設定を利用する」にチェック を入れ、 「はい」をクリックする。 9 7. メニューから「ファイル」-「新規」-「その他」を選択し、 「サーバー」-「サーバー」を選択して「次へ」をクリック します 8. 「新規サーバーの定義」画面では、デフォルト設定のまま「次へ」をクリックします。 9. 「WebSphere ランタイムの選択」画面では、WAS のインストールディレクトリを指定します。 10. 「WebSphere サーバーの設定」画面では、先の手順で作成したプロファイルを選択し、 「次へ」をクリックします。 11. 「プロジェクトの追加および除去」画面では、使用可能なプロジェクトにある"AuctionEAR"を選択して「追加」ボタ ンをクリックし、プロジェクトが移動したのを確認してから「終了」をクリックします。 12. 「サーバー」ビューで、作成したサーバーを選択し、始動ボタンでサーバーを起動します。 10 ■■サーバーサイド処理の実装 ■データベース初期化サーブレットの作成 デフォルトデータベース(Derby)にテーブルを構築するサーブレットを作成します。 1. Auction プロジェクトを右クリックし、 「新規」-「サーブレット」を選択します。 2. パッケージを"util"、クラス名を"InitServlet"として、 「終了」をクリックします。 3. doGet()メソッドを以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); try { InitialContext ic = new InitialContext(); DataSource ds = (DataSource)ic.lookup("DefaultDatasource"); Connection con = ds.getConnection(); Statement st = con.createStatement(); try { st.execute("drop table BID"); } catch (Exception e) {} try { st.execute("drop table ITEM"); } catch (Exception e) {} st.execute("create table ITEM ( " + "itemid INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY," + "productid varchar(30)," + "productname varchar(100)," + "imageurl varchar(100)," + "itempageurl varchar(100)," + 11 "seller varchar(20)," + "enddate timestamp," + "registdate timestamp" + ")" ); st.execute("alter table ITEM ADD CONSTRAINT ITEM_PK PRIMARY KEY (itemid)"); st.execute("create table BID ( " + "bidid INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY," + "itemid integer," + "buyer varchar(20)," + "price bigint," + "date timestamp" + ")" ); st.execute("alter table BID ADD CONSTRAINT BID_PK PRIMARY KEY (bidid)"); st.close(); con.close(); pw.println("<h1>Database initialized.</h1>"); } catch (Exception e) { e.printStackTrace(); pw.println("<h1>Database initialization failed.</h1>"); } } ----------------------------------------------------------------------------------------------------------------------------------------4. Import 文として以下を追加します。 ----------------------------------------------------------------------------------------------------------------------------------------import java.sql.Connection; import java.sql.Statement; import javax.naming.InitialContext; import javax.sql.DataSource; ----------------------------------------------------------------------------------------------------------------------------------------5. ファイルを保存し、右クリックから「実行」-「サーバーで実行」を選択します。 6. 「サーバーをプロジェクトのデフォルトに設定」にチェックを入れ、 「終了」をクリックします。 7. "Database initilalized"と表示されたら、初期化は完了です。Eclipse 内蔵ブラウザを閉じて下さい。 (注意)ここでは、手順を簡単にするために例外処理などを省略していますが、実運用アプリケーションではこのようなこ とは避けるべきです。 ■パラメータクラスの作成 アイテム情報および入札情報を格納するクラス(JavaBean)を作成します。 Item クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"domain"、名前を"Item"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 12 ----------------------------------------------------------------------------------------------------------------------------------------package domain; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Item { private int itemid; private String productid; private String productname; private String imageurl; private String itempageurl; private String seller; private Date enddate; private Date registdate; private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public Date getRegistdate() { return registdate; } public String getRegistdateString() { return sdf.format(registdate); } public void setRegistdate(Date registdate) { this.registdate = registdate; } public Date getEnddate() { return enddate; } public String getEnddateString() { return sdf.format(enddate); } public void setEnddate(Date enddate) { this.enddate = enddate; } public void setEnddateString(String senddate) { try { this.enddate = sdf.parse(senddate); } catch (ParseException e) { throw new RuntimeException(e); } } public String getImageurl() { return imageurl; } public void setImageurl(String imageurl) { this.imageurl = imageurl; } public int getItemid() { return itemid; 13 } public void setItemid(int itemid) { this.itemid = itemid; } public String getItempageurl() { return itempageurl; } public void setItempageurl(String itempageurl) { this.itempageurl = itempageurl; } public String getProductid() { return productid; } public void setProductid(String productid) { this.productid = productid; } public String getProductname() { return productname; } public void setProductname(String productname) { this.productname = productname; } public String getSeller() { return seller; } public void setSeller(String seller) { this.seller = seller; } } ----------------------------------------------------------------------------------------------------------------------------------------Bid クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"domain"、名前を"Bid"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------package domain; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Bid { private int bidid; private int itemid; private String buyer; private long price; private Date date; private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 14 public int getBidid() { return bidid; } public void setBidid(int bidid) { this.bidid = bidid; } public String getBuyer() { return buyer; } public void setBuyer(String buyer) { this.buyer = buyer; } public Date getDate() { return date; } public String getDateString() { return sdf.format(date); } public void setDate(Date date) { this.date = date; } public void setDateString(String sdate) { try { this.date = sdf.parse(sdate); } catch (ParseException e) { throw new RuntimeException(e); } } public int getItemid() { return itemid; } public void setItemid(int itemid) { this.itemid = itemid; } public long getPrice() { return price; } public void setPrice(long price) { this.price = price; } } ----------------------------------------------------------------------------------------------------------------------------------------- ■データベースアクセスクラスの作成 Item および Bid をデータベースに永続化するためのクラス(DAO)と、データベースアクセスのヘルパークラスを作成しま す。データベースアクセスを簡素化するために Apache Commons の dbutils を利用するので、必要な jar の追加も実施しま す。 15 Apache Commons dbutils ライブラリの追加 1. http://commons.apache.org/dbutils/ の"download"リンクをクリックします。 2. Binary のセクションから、1.1.zip をクリックしてダウンロードします。 3. ダウンロードした zip を展開し、commons-dbutils-1.1.jar を取り出します。 4. AST のメニューから、 「ウィンドウ」-「ビューの表示」-「ナビゲーター」を選択し、ナビゲータービューを開きます。 5. Auction プロジェクトを展開し、WebContent/WEB-INF/lib に commons-dbutils-1.1.jar をドラッグアンドドロップし ます。 6. プロジェクト・エクスプローラービューに戻ります。 DbUtil クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"util"、名前を"DbUtil"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------package util; import javax.naming.InitialContext; import javax.sql.DataSource; public class DbUtil { private static DataSource ds; public static DataSource getDataSource(){ if(null==ds){ try { InitialContext ic = new InitialContext(); ds = (DataSource)ic.lookup("DefaultDatasource"); } catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); } } return ds; } } 16 ----------------------------------------------------------------------------------------------------------------------------------------ItemDao クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"dao"、名前を"ItemDao"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------package dao; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import util.DbUtil; import domain.Item; public class ItemDao { public static int addItem(Item item){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); int cnt; try { cnt = qr.update( "INSERT INTO ITEM (productid, productname, imageurl, itempageurl, seller, enddate, registdate) " + "VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)", new Object[] { item.getProductid(), item.getProductname(), item.getImageurl(), item.getItempageurl(), item.getSeller(), item.getEnddateString() } ); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return cnt; } public static List getAllItem(){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new BeanListHandler(Item.class); List items = null; try { items = (List)qr.query("SELECT * from ITEM", h); } catch (SQLException e) { e.printStackTrace(); 17 throw new RuntimeException(e); } return items; } public static List getLiveItem(){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new BeanListHandler(Item.class); List items = null; try { items = (List)qr.query("SELECT enddate>CURRENT_TIMESTAMP " + "ORDER BY enddate", h); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return items; } public static List getClosedItem(){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new BeanListHandler(Item.class); List items = null; try { items = (List)qr.query("SELECT enddate<=CURRENT_TIMESTAMP " + "ORDER BY enddate", h); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return items; } * from ITEM WHERE * from ITEM WHERE public static Item getItem(int id){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new BeanHandler(Item.class); Item item = null; try { item = (Item)qr.query("SELECT * from ITEM WHERE itemid=?", new Object[]{id}, h); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return item; } } 18 ----------------------------------------------------------------------------------------------------------------------------------------BidDao クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"dao"、名前を"BidDao"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------package dao; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.ArrayHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import util.DbUtil; import domain.Bid; public class BidDao { public static int addBid(Bid bid){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); int cnt; try { cnt = qr.update( "INSERT INTO BID (itemid, buyer, price, date) " + "VALUES (?, ?, ?, CURRENT_TIMESTAMP)", new Object[] { bid.getItemid(), bid.getBuyer(), bid.getPrice() } ); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return cnt; } public static List getAllBidByItem(int itemid){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new BeanListHandler(Bid.class); List bids = null; try { bids = (List)qr.query("SELECT * from BID WHERE itemid=? ORDER BY date DESC", new Object[]{ itemid }, h); } catch (SQLException e) { e.printStackTrace(); 19 throw new RuntimeException(e); } return bids; } public static long getMaxBidByItem(int itemid){ DataSource ds = DbUtil.getDataSource(); QueryRunner qr = new QueryRunner(ds); ResultSetHandler h = new ArrayHandler(); Object[] bid; try { bid = (Object[])qr.query("SELECT MAX(price) from BID WHERE itemid=?", new Object[]{ itemid }, h); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } long result = 0; System.out.println("bid[0]="+bid[0]); if(null != bid[0]) result = (Long)bid[0]; return result; } } ----------------------------------------------------------------------------------------------------------------------------------------- ■サービスクラスの作成 ビジネスロジックを実装し、サービス提供の窓口となるクラス(Auction)を作成します。 Auction クラスの作成 1. Auction プロジェクトを右クリックし、 「新規」-「クラス」を選択します。 2. パッケージを"service"、名前を"Auction"として、 「終了」をクリックします。 3. クラスの定義を以下のようにします。 ----------------------------------------------------------------------------------------------------------------------------------------package service; import java.util.Date; import java.util.List; import dao.BidDao; import dao.ItemDao; import domain.Bid; import domain.Item; public class Auction { //Item public boolean putItem(String productid, String productname, String imageurl, String itempageurl, String seller, String senddate){ Item item = new Item(); item.setProductid(productid); 20 item.setProductname(productname); item.setImageurl(imageurl); item.setItempageurl(itempageurl); item.setSeller(seller); item.setEnddateString(senddate); Date now = new Date(); if(item.getEnddate().before(now)){ return false; } else { int cnt = ItemDao.addItem(item); return cnt>0 ? true : false; } } public Item getItem(int id){ return ItemDao.getItem(id); } public List getLiveItem(){ return ItemDao.getLiveItem(); } public List getClosedItem(){ return ItemDao.getClosedItem(); } //Bid public boolean placeBid(int itemid, String buyer, long price){ long maxbid = BidDao.getMaxBidByItem(itemid); if(price > maxbid){ Bid bid = new Bid(); bid.setItemid(itemid); bid.setBuyer(buyer); bid.setPrice(price); int cnt = BidDao.addBid(bid); return cnt>0 ? true : false; } else { return false; } } public List getBidByItem(int itemid){ return BidDao.getAllBidByItem(itemid); } } ----------------------------------------------------------------------------------------------------------------------------------------- 21 ■■RPCAdapter の設定 ■RPCAdapter とは? Web Remoting とは、proxy を配置することでサーバーサイドの JavaBean をクライアントサイドの JavaScript から透過 的に呼び出せるようする手法のことです。RPCAdapter は、IBM による proxy の実装です。 RPCAdapter の詳細については、 <WAS 導入ディレクトリ> ¥web2fep¥documentation¥RPCAdapter¥index.html を参照してください。 ■RPCAdapter の登録 RPCAdapter は、Servlet として実装されています。また、利用するためには依存ライブラリをプロジェクトにインポート する必要があります。 RPCAdapter および依存ライブラリの追加 1. AST のメニューから、 「ウィンドウ」-「ビューの表示」-「ナビゲーター」を選択し、ナビゲータービューを開きます。 2. 次の jar ファイルを WebContent/WEB-INF/lib にドラッグアンドドロップします。 <WAS 導入ディレクトリ> ¥web2fep¥optionalLibraries¥RPCAdapter¥ RPCAdapter.jar retroweaver-rt-2.0.jar commons-logging-1.0.4.jar <WAS 導入ディレクトリ> ¥web2fep¥optionalLibraries¥JSON4J¥ JSON4J.jar RPCAdapter サーブレットの登録 1. WebContent/WEB-INF/web.xml を開き、ソースビューに移動します。 2. <servlet>セクションに以下を追加します。 ----------------------------------------------------------------------------------------------------------------------------------------<servlet> <display-name>RPCAdapter</display-name> <servlet-name>RPCAdapter</servlet-name> <servlet-class>com.ibm.websphere.rpcadapter.RPCAdapter</servlet-class> </servlet> ----------------------------------------------------------------------------------------------------------------------------------------3. <servlet-mapping>セクションに以下を追加します。 ----------------------------------------------------------------------------------------------------------------------------------------<servlet-mapping> <servlet-name>RPCAdapter</servlet-name> <url-pattern>/RPCAdapter</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>RPCAdapter</servlet-name> <url-pattern>/RPCAdapter/*</url-pattern> </servlet-mapping> ----------------------------------------------------------------------------------------------------------------------------------------- 22 ■サービスクラスの公開 RPCAdapter は、独自の設定ファイル(XML)によって、公開するサービスクラスを定義します。 RPCAdapter 定義(RpcAdapterConfig.xml)の作成 1. ナビゲータービューで /WebContent/WEB-INF を右クリックし、 「新規」-「ファイル」を選択します。 2. ファイル名を"RpcAdapterConfig.xml"とし、 「終了」をクリックします。 3. RpcAdapterConfig.xml のソースビューに移動し、以下を記入します。 ----------------------------------------------------------------------------------------------------------------------------------------<rpcAdapter xmlns="http://www.ibm.com/xmlns/prod/websphere/featurepack/v6.1/RpcAdapterConfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <default-format>xml</default-format> <services> <pojo> <name>AuctionService</name> <implementation>service.Auction</implementation> <description>Auction Service</description> </pojo> </services> </rpcAdapter> ----------------------------------------------------------------------------------------------------------------------------------------これだけで、Auction サービスの公開は完了です。サービス呼び出しの URL は次のようになります。 HTTP RPC http://localhost:9080/Auction/RPCAdapter/httprpc/<サービス名>/<メソッド名> JSON-RPC http://localhost:9080/Auction/RPCAdapter/jsonrpc/<サービス名>/<メソッド名> 例えば、http://localhost:9080/Auction/RPCAdapter/httprpc/AuctionService/getClosedItem にリクエストを送信すると、 RPCAdapter が正常に動作していれば、<results/> という空の結果が取得できるはずです。 23 ■■Dojo による JSON-RPC サービスの利用 ■JSON-RPC と SMD(Simple Method Description) JSON-RPC とは、 JSON 形式のデータを交換することによってHTTP 上でのRPC を実現する手法です。 Feature Pack for Web 2.0 の RPCAdapter も JSON-RPC に対応しています。 JSON-RPC では、サービスの仕様定義に Simple Method Description (SMD)という JSON ドキュメントを利用します。 SMD とは、SOAP における WSDL のようなものといえば理解しやすいでしょうか。RPC の仕様定義を JavaScript で行っ たもので、メソッド名とパラメータが取得できるようになっています。 RPCAdapter の場合、JSON-RPC サービスの URL からメソッドを除いたものにリクエストを送信すると、サービスの SMD が取得できます。例えば、http://localhost:9080/Auction/RPCAdapter/jsonrpc/AuctionService/ にリクエストを送信 すると、次のような SMD が取得できます。 ----------------------------------------------------------------------------------------------------------------------------------------{"SMDVersion":"0.1", "serviceType":"JSON-RPC", "objectName":"AuctionService", "serviceURL":"¥/Auction¥/RPCAdapter¥/jsonrpc¥/AuctionService¥/", "methods":[ {"parameters":[{"name":"p0"},{"name":"p1"},{"name":"p2"},{"name":"p3"},{"name":"p4"},{"name":"p5"}],"name":"putItem"}, {"parameters":[{"name":"p0"}],"name":"getItem"}, {"parameters":[],"name":"getLiveItem"}, {"parameters":[],"name":"getClosedItem"}, {"parameters":[{"name":"p0"},{"name":"p1"},{"name":"p2"}],"name":"placeBid"}, {"parameters":[{"name":"p0"}],"name":"getBidByItem"}, ・・・・・・ ]} ----------------------------------------------------------------------------------------------------------------------------------------JSON-RPC に関する詳細情報は、http://json-rpc.org/ をご参照下さい。日本語での情報としては、少し古いものですがこ ちらも参考になります。 「Dojo/JavaScript Toolkit のメモ」RPC 呼び出し http://ymdmstk.cocolog-nifty.com/blog/2007/04/rpc_50c6.html ■Dojo JSON-RPC クライアント Dojo は、dojo.rpc.JsonService によって JSON-RPC をサポートしています。次のように、JsonService のコンストラクタ の引数に SMD を渡してやると、このオブジェクトが proxy として動作するようになり、オブジェクトに対するメソッド呼 び出しが JSON-RPC として実行されます。 var auctionService = new dojo.rpc.JsonService("/Auction/RPCAdapter/jsonrpc/AuctionService"); var f = document.itemForm; auctionService.putItem(f.productid.value, f.productname.value, f.imageurl.value, auctionService f.itempageurl.value, f.seller.value, f.enddate.value+" 00:00:00"); これを利用して、簡単なクライアントアプリケーションを作成してみましょう。 24 ■dojo.rpc.JsonService による RPCAdapter クライアントの作成 Dojo Toolkit のインポート 1. 次のディレクトリを WebContent/ 直下にドラッグアンドドロップします。 <WAS 導入ディレクトリ> ¥web2fep¥ajax-rt_1.X Item 登録クライアントの作成 1. WebContent を右クリックし、 「新規」-「ファイル」を選択します。 2. ファイル名を"item.html"として「終了」をクリックします。 3. ファイルの内容を以下の通りとします。 ----------------------------------------------------------------------------------------------------------------------------------------<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Item</title> <style type="text/css"> @import "./ajax-rt_1.X/dijit/themes/tundra/tundra.css"; @import "./ajax-rt_1.X/dojo/resources/dojo.css" </style> <script type="text/javascript" src="./ajax-rt_1.X/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script> dojo.require("dojo.parser") dojo.require("dojo.io.script") dojo.require("dojo.rpc.RpcService") dojo.require("dojo.rpc.JsonService") dojo.require("dojo.rpc.JsonpService") dojo.require("dijit.form.TextBox") dojo.require("dijit.form.DateTextBox") var auctionService = new dojo.rpc.JsonService("/Auction/RPCAdapter/jsonrpc/AuctionService"); function putItem(){ var f = document.itemForm; auctionService.putItem(f.productid.value, f.productname.value, f.imageurl.value, f.itempageurl.value, f.seller.value, f.enddate.value+" 00:00:00"); } function showItem(){ auctionService.getLiveItem().addCallback(displayItem); } function displayItem(result){ var list = document.getElementById("list"); list.textContent = dojo.toJson(result, true); } </script> </head> <body class="tundra"> <form name="itemForm"> <table> <tr> 25 <td>ProductID:</td> <td><input type="text" length="30" name="productid" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>ProductName:</td> <td><input type="text" length="30" name="productname" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>ImageUrl:</td> <td><input type="text" length="30" name="imageurl" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>ItemPageUrl:</td> <td><input type="text" length="30" name="itempageurl" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>Seller:</td> <td><input type="text" length="10" name="seller" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>EndDate:</td> <td><input type="text" length="10" name="enddate" dojoType="dijit.form.DateTextBox" constraints="{datePattern:'yyyy-MM-dd'}" /></td> </tr> </table> <input id="putItemBtn" type="button" value="Put Item" onClick="putItem()"><br/> </form> <input id="showItemBtn" type="button" value="Show Item" onClick="showItem()"><br/> <hr/> <div id="list"/> </body> </html> ----------------------------------------------------------------------------------------------------------------------------------------- 26 4. 「Put Item」でアイテムの登録、 「Show Item」で登録済みアイテムを JSON 形式で参照できます。 Bid 登録クライアントの作成 1. WebContent を右クリックし、 「新規」-「ファイル」を選択します。 2. ファイル名を"bid.html"として「終了」をクリックします。 3. ファイルの内容を以下の通りとします。 ----------------------------------------------------------------------------------------------------------------------------------------<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Bid</title> <style type="text/css"> @import "./ajax-rt_1.X/dijit/themes/tundra/tundra.css"; @import "./ajax-rt_1.X/dojo/resources/dojo.css" </style> <script type="text/javascript" src="./ajax-rt_1.X/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script> dojo.require("dojo.parser") dojo.require("dojo.io.script") dojo.require("dojo.rpc.RpcService") dojo.require("dojo.rpc.JsonService") dojo.require("dojo.rpc.JsonpService") dojo.require("dijit.form.TextBox") var auctionService = new dojo.rpc.JsonService("/Auction/RPCAdapter/jsonrpc/AuctionService"); 27 function placeBid(){ var f = document.bidForm; auctionService.placeBid(parseInt(f.itemid.value), f.buyer.value, parseInt(f.price.value) ); } function showBid(){ var f = document.bidForm; auctionService.getBidByItem(parseInt(f.itemid.value)).addCallback(displayBid); } function displayBid(result){ var list = dojo.byId("list"); list.textContent = dojo.toJson(result, true); } </script> </head> <body class="tundra"> <form name="bidForm"> <table> <tr> <td>ItemID:</td> <td><input type="text" length="30" name="itemid" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>Buyer:</td> <td><input type="text" length="10" name="buyer" dojoType="dijit.form.TextBox"/></td> </tr> <tr> <td>Price:</td> <td><input type="text" length="30" name="price" dojoType="dijit.form.TextBox"/></td> </tr> </table> <input id="placeBidBtn" type="button" value="Place Bid" onClick="placeBid()"><br/> </form> <input id="showBidBtn" type="button" value="Show Bid" onClick="showBid()"><br/> <hr/> <div id="list"/> </body> </html> ----------------------------------------------------------------------------------------------------------------------------------------- 28 4. 「Place Bid」で入札、 「Show Bid」で入札状況を JSON 形式で参照できます。 Bid 詳細表示クライアントの作成 1. WebContent を右クリックし、 「新規」-「ファイル」を選択します。 2. ファイル名を"biddingstatus.html"として「終了」をクリックします。 3. ファイルの内容を以下の通りとします。 ----------------------------------------------------------------------------------------------------------------------------------------<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Bidding Status</title> <style type="text/css"> @import "./ajax-rt_1.X/dojox/grid/_grid/tundraGrid.css"; @import "./ajax-rt_1.X/dijit/themes/tundra/tundra.css"; @import "./ajax-rt_1.X/dojo/resources/dojo.css" </style> <script type="text/javascript" src="./ajax-rt_1.X/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script> dojo.require("dojo.parser"); dojo.require("dojo.io.script"); dojo.require("dojo.rpc.RpcService"); dojo.require("dojo.rpc.JsonService"); dojo.require("dojo.rpc.JsonpService"); dojo.require("dijit.form.TextBox"); dojo.require("dojox.grid.Grid"); dojo.require("dojox.grid._data.model"); 29 dojo.require("dojo.data.ItemFileReadStore"); var auctionService = new dojo.rpc.JsonService("/Auction/RPCAdapter/jsonrpc/AuctionService"); var dataItems = { id:'bidid', items:[], label:'bid' }; var view1 = { cells: [[ {name:'Buyer', field:"buyer"}, {name:'Price', field:"price"}, {name:'Date', field:"dateString", width:'auto'} ]] }; var layout = [ view1 ]; function refresh(){ var f = document.dummyForm; var id = parseInt(f.itemid.value); auctionService.getItem(id).addCallback(displayItem); auctionService.getBidByItem(id).addCallback(displayBid); } function displayItem(result){ dojo.byId("itemPane_itemid").textContent = result.itemid; dojo.byId("itemPane_itemid").textContent = result.itemid; dojo.byId("itemPane_itemid").textContent = result.itemid; dojo.byId("itemPane_productid").textContent = result.productid; dojo.byId("itemPane_productname").textContent = result.productname; dojo.byId("itemPane_seller").textContent = result.seller; dojo.byId("itemPane_registdate").textContent = result.registdateString; dojo.byId("itemPane_enddate").textContent = result.enddateString; dojo.byId("itemPane_imageurl").src = result.imageurl; dojo.byId("itemPane_itempageurl").href = result.itempageurl; dojo.byId("itemPane_itempageurl_text").textContent = result.itempageurl; } function displayBid(result){ dataItems.items = result; console.debug(dataItems.items); var bidstore = new dojo.data.ItemFileReadStore({ data:dataItems }); var bidmodel = new dojox.grid.data.DojoData(); bidmodel.store = bidstore; bidmodel.query = {buyer:'*'}; var bidGrid = dijit.byId('bidGrid'); bidGrid.setModel(bidmodel); } </script> </head> <body class="tundra"> <form name="dummyForm"> <table> <tr> <td>ItemID:</td> <td><input type="text" length="30" name="itemid" dojoType="dijit.form.TextBox"/></td> <td><input id="dummyBtn" type="button" value="Change Item" onClick="refresh()"></td> 30 </tr> </table> </form> <hr/> <div id="itemPane"> <table> <tr><td>ItemID</td><td><div id="itemPane_itemid"></div></td></tr> <tr><td>商品 ID</td><td><div id="itemPane_productid"></div></td></tr> <tr><td>商品名</td><td><div id="itemPane_productname"></div></td></tr> <tr><td>出品者</td><td><div id="itemPane_seller"></div></td></tr> <tr><td>登録日</td><td><div id="itemPane_registdate"></div></td></tr> <tr><td>終了日</td><td><div id="itemPane_enddate"></div></td></tr> </table> <img id="itemPane_imageurl" src=""/> <a id="itemPane_itempageurl" href=""><span id="itemPane_itempageurl_text"></span></a> </div> <hr/> <div id="bidGrid" dojotype="dojox.Grid" structure="layout"></div> </body> </html> ----------------------------------------------------------------------------------------------------------------------------------------4. ItemID を指定し、 「Change Item」で入札状況の詳細がグリッド形式で確認できます。 31 ■■まとめ 今回は、WebSphere Feature Pack for Web 2.0 の Web Remoting 機能である RPCAdapter、および Dojo Toolkit の JSON-RPC クライアントからの利用方法についてご紹介しました。サーバーサイドの POJO を、手間をかけずに Ajax ク ライアントから利用できることが実感いただけたのではないかと思います。 また、今回も随所で Dojo Toolkit を利用していますが、詳細についてはご説明できませんでした。次回以降で、本格的な GUI の構築と並行してご紹介していく予定です。 ■■参考資料 ■AST の入手 この資料では AST を開発ツールとして推奨しています。製品版を既にインストールされている方はそちらをご使用くだ さい。製品版をお持ちでない方は、評価版をご利用いただくことが可能です。 ・AST 6.1.1 ダウンロード http://www-6.ibm.com/jp/domino01/mkt/websphere.nsf/doc/001D642E ■WAS Feature Pack for Web 2.0 に関する情報源 (1)WebSphere Application Server Feature Pack for Web 2.0 公式サイト(英語) http://www-306.ibm.com/software/webservers/appserv/was/featurepacks/web20/index.html (2)WebSphere Application Server 関連 ① WSDD 技術文書 http://www-6.ibm.com/jp/software/websphere/developer/ WebSphere 関連の技術文書がそろっています。 ・Application Server Toolkit (AST)V6.1 基本操作ガイド http://www-6.ibm.com/jp/software/websphere/developer/was/wv6/ast/ ・Web Sphere Application Server V6.1 管理ガイド http://www-6.ibm.com/jp/software/websphere/developer/was/wv61/guide/ ・Web Sphere Application Server V6.1 新機能紹介 http://www-6.ibm.com/jp/software/websphere/developer/was/wv6/enhance/ ・Web Sphere Application Server 最新動向ワークショップ(2007 年 4 月版) http://www-6.ibm.com/jp/software/websphere/developer/was/wv61/workshop/ ② WAS Info Center http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.ejbfep.multiplatform.doc/inf o/welcome_nd.html オンラインヘルプです。個別の項目でわからないところがあれば、まずはここにアクセスしてください。 ■関連する技術情報 (1)Dojo Toolkit http://dojotoolkit.org/ オープンソースの JavaSctipt ツールキットです。Feature Pack には Dojo-1.0 が含まれます。 (2)Firebug http://getfirebug.com/jp.html Ajax 開発におけるデファクトスタンダードのデバッグツールです。Firefox のプラグインです。 (3)Apache Commons dbutils http://commons.apache.org/dbutils/ JDBC まわりの煩雑な処理を軽減してくれるライブラリです。非常にシンプルで、O/R マッピングツールよりも気軽に使え ます。 32