Web APIの次世代標準プロトコル「Atom Publishing Protocol」

第4回 Atom Publishing Protocolを試す

この記事を読むのに必要な時間:およそ 7 分

AtomPubクライアント実装

前述のとおり,RESTはステートフルなHTTP通信という簡単な仕組みでできています。そのために多数のプログラミング言語において標準ライブラリだけでAtomPubのクライアントを簡単に実装することが可能です。とはいうものの,そうでない言語も幾つかあります。本節では実装にあたり,まずAtomPubの実装要件からはじめたいと思います。

AtomPubの実装要件

AtomPubはHTTPメソッドのGET,POST,PUT,DELETEを利用して,データのCRUDを実現しています。また,認証等の付加情報はHTTPのヘッダーに埋め込みます。このような点からAtomPubが実装要件は以下の3つと考えられます。

  1. HTTP(HTTPS)に対応していること
  2. HTTP(HTTPS)のヘッダーを編集できること
  3. HTTP(HTTPS)メソッドのうち,GET,POST,PUT,DELETEに対応していること

これらを満たすものはPerl,Ruby,ASP.NET,JavaScript and DHTML,Java(J2SE, J2EE),…とあげればキリがありません。RESTはそれほど汎用的な仕組みと言えます。逆に満たさないものは,Java(J2ME),FlashLiteとモバイルソフトウェアエンジニアにお馴染みの言語が多いようです。これらに共通しているのは3番目の要件のうちPUTとDELETEが使えないことです。これは携帯電話の限られたスペックを考慮して,環境を軽量に最適化(例えばJ2MEではJVMではなくキロバイトのメモリで動くKVMを使っている)しているため,当時あまり使われていなかった機能は極力削られているという経緯があります。

モバイルアプリ開発環境におけるAtomPub対応状況

前述のとおり,ほとんどのモバイルアプリ開発環境おいてはPUTとDELETEに対応していません。また,J2ME(DoJa)では厳重なセキュリティを考え,HTTPヘッダーの編集を許可しません。これはAtomPubだけでなくCookieが使えない原因ともなっています。これらを表3にまとめます。モバイルアプリとしてAtomPubを実装するためには,Socketクラスから自分で書くなどの工夫と労力が必要になります。

表3 携帯アプリ開発環境におけるAtom要件対応状況

環境説明標準ライブラリ利用によるヘッダーの編集標準ライブラリ利用によるPUT,DELETEの実行
J2ME(DoJa5.0)Sunmicrosystems提供の携帯端末用Javaプラットフォーム,DoCoMoが採用××
J2ME(MIDP2.0)Sunmicrosystems提供の携帯端末用Javaプラットフォーム,au,SoftBank,WILLCOMが採用×
FlashLite2.0Adobe提供の携帯端末用のFlashプラットフォーム,au,SoftBankが採用×
FlashLite3.0Adobe提供の携帯端末用のFlashプラットフォーム,DoCoMoが採用×
BREW3.1Qualcommが提供している携帯端末用C++プラットフォーム,auが採用×
AndroidGoogle提供の携帯端末用Javaプラットフォーム
.NET Compact Framework2.0Microsoft提供の携帯端末用フレームワーク,Windows Mobile5.0,6.0で採用

このように残念ながら携帯端末とAtomPubは相性がいいとは言えません。しかし携帯端末の性能は緩やかながらも向上していますし,Androidのような新しい開発環境も出現していますので,今後は携帯端末との親和性も高くなることが予想されます。

次は,実際にクライアントを作ってみましょう。今回は,AtomPubの実装要件を満たす言語の1つであるJava(J2SE)を使った実装を簡単に説明したいと思います。

J2SEによる実装

J2SEにおいてHTTP通信を行うための手段はSocketクラスをはじめ,たくさんありますが,その中でも簡単にHTTP独自の機能を使うためにはjava.net.HttpURLConnectionクラスを使います(ちなみにHTTPSにはjavax.net.ssl.HttpURLConnectionが用意されています⁠⁠。今回はこれを利用して,以下にAtomPubの通信手順を説明していきます。

  • ①.URI(URL)の設定
  • ②.コネクションのオープン
  • ③.HTTPリクエストヘッダーの設定
  • ④.POST,PUTの場合はアウトプットストリームの作成
  • ⑤.URI(URL)へ接続
  • ⑥.HTTPレスポンスコードを得る
  • ⑦.HTTPレスポンスヘッダーを得る
  • ⑧.HTTPレスポンスボディを得る(ある場合に限る)
  • ⑨.XMLのDOM化,DOMの処理
  • ⑩.①へ戻る

と見ていただいてわかるように,AtomPubはRESTベースなのでHTTP通信手順とほぼ同じです。

①.URI(URL)の設定,②.コネクションのオープン(リスト1)

まず,URLオブジェクトを得て,HttpURLConnectionオブジェクトを作ります。この時点ではURLが示すリソースに接続されていません。AtomPubでは,多くの場合URIを使うので,厳密にはリスト2のようになりますが,どちらでも構いません。

//リスト1
URL url =new URL(String);
HttpURLConnection con=(HttpURLConnection)url.openConnection();
/*リスト2
URI uri =new URI(String);
HttpURLConnection con=(HttpURLConnection)uri.toURL().openConnection();
*/
③.HTTPリクエストヘッダーの設定(リスト3)

リクエストヘッダーの設定を行います。POSTやPUTであれば,属性「Content-Type」「Content-Length」を明示する必要があります。また,仕様でOPTIONに定められているWSSEやBASIC認証に対応するには,属性「X-WSSE」「Authorization」リスト4のように追加します。

//リスト3
con.setRequestProperty("Content-Type", "image/jpeg");
/*ベーシック認証を使う場合
con.setRequestProperty("Authorization",makeBasic(ID,PASSWD);
*/
//中略
//リスト4 ベーシック認証
private String makeBasic(String id, String pass){
  String basic=id+":"+pass;
  basic = "Basic "+new String(Base64.encode(basic.getBytes())); 
  return basic;
}
④.POST,PUTの場合はアウトプットストリームの作成(リスト5)

POSTやPUTの場合,リソースに接続する前にPOSTまたはPUTするデータをHTTPリクエストボディに書き込むことでこれを実現します。具体的にはまず,コネクションにおいてPOST,PUTができるようにHTTPURLConnection.setDoOutput(boolean)で設定し,その後OutputStreamを作成します。

//リスト5
//POST(PUT)可能にします
con.setDoOutput(true);
///POST(PUT)用のOutputStreamを取得
os = con.getOutputStream();

次に,OutputstreamにPOST,PUTしたいファイルを書き込めば接続前の準備完了です。リスト6では,入力がFileの場合とStringの場合の2パターンを示しています。

//リスト6
//Fileの場合
InputStream fdata = new FileInputStream(File);
byte[] buffer = new byte[8192];
int rsize;
while ((rsize = fdata.read(buffer)) != -1) {
os.write(buffer, 0, rsize);
}

/*Stringの場合
os.write(String.getBytes());
*/
⑤.URI(URL)へ接続,⑥.HTTPレスポンスコードを得る,⑦.HTTPレスポンスヘッダーを得る(リスト7)

指定したURLへリクエストを送るためにHttpURLConnection.connect()を使います。この時点からHttpレスポンスが取得可能になります。続けてHttpレスポンスコード,Httpレスポンスヘッダーを取得します。

//リスト7
//接続
con.connect();
//レスポンスコードを得る
System.out.print("Response Code["+con.getResponseCode()+"]");
System.out.println(":"+"Response Message["+con.getResponseMessage()+"]");
//レスポンスヘッダー
Map headers = con.getHeaderFields();
Iterator it = headers.keySet().iterator();
System.out.println("Response Header");
while(it.hasNext()){
  String key=(String)it.next();
  System.out.println(" "+key+" : "+headers.get(key));
}

※AtomPubで使われている主なレスポンスコードを示します。これ以外はRFC2616を参照してください。

表4 レスポンスコード

レスポンスコード意味メソッド:補足
200OkGET,PUT,DELETE:成功時
201CreatedPOST:成功時
304Not modifiedGET:修正できないメンバー
415Unsupported Media TypePOST:サポート外のメディアタイプ

著者プロフィール

坂野大作(さかのだいさく)

NTTコミュニケーションズに入社後,先端IPアーキテクチャセンタにてモバイル,Webテクノロジ領域でアプリ開発・技術開発に取り組む。