Movable Type の XML-RPC API による記事投稿メモ
Movable Type の XML-RPC API を調べていて、metaWeblog.newPost や metaWeblog.editPost に渡すパラメータについて気になったのでメモ。
記事の投稿内容を content 構造体パラメーターで指定するのだが、このパラメーターには Movable Type の独自実装として、たとえば「コメントを許可するかどうか」などを含めることができる。
しかし、これらのうち、いわゆるフラグ系(真偽値)の指定の仕方がちょっと変わっている。
- mt_allow_comments (int) 0 なら false、1 なら true
- mt_allow_pings (int) 0 なら false、1 なら true
- mt_convert_breaks (string) "0" または "none" で false、"1" または "convert_breaks" で true
mt_convert_breaks が string なのは、mt.supportedTextFilters で返ってきた値を使えるようにするためなんだろうな。たぶん。
Redstone XML-RPC Library への不満
どうやら Java の XML-RPC ライブラリとは、あまり縁がないらしい。またもや、XML-RPC ライブラリへの愚痴エントリである。
Apache XML-RPC ライブラリの複雑さとドキュメントのすくなさ(いつまでホームページのロゴ画像がリンク切れなのだろう?)に辟易して、今度は Redstone というライブラリを試してみた。
Redstone の前身である Marquee というライブラリは developerWorks に紹介記事だって載っている由緒正しい(?)XML-RPC ライブラリだ。
最初は何も問題ないかのように思えた。すべてが順調で平和だった。API はシンプルで、ホームページの簡潔なチュートリアルも必要十分に思えた。
だが、決して小さくはない欠陥がいくつもあることがわかってきた(バージョンは 1.0.1)。
- contentType の指定が無視される。
- エラー処理がいいかげん
- <methodResponse> の faultCode がハードコーディングされている。
- そのエンコーディングも ISO-8859-1 でハードコーディング。日本語書けない。せめて UTF-8 にしてよ...
- Base64 のコードがバグっていて、複数行にエンコードされていると対応できない。
- カスタマイズが困難。
- API がシンプルで一見、拡張しやすく見えるが、実際には重要なポイントが private だったりしてサブクラス化しづらい。
- たとえば、XmlRpcDispatcher を拡張しても、それを使っている XmlRpcServer に独自の XmlRpcDispatcher を設定する API がない(ので、結局、こいつもサブクラス化して、さらに、サブクラス化した XmlRpcServer を使う XmlRpcServlet を書いて ...)。
- XmlRpcParser は XML-RPC の xml を解析できるが、肝心の結果は private になっているため、これ単体で使えない。
実は 3. までの問題を修正するためのラッパーライブラリを、テストコード含めて 800 行ほど書いていた。しかし、それも 4. の理由により挫折しかけている。まあ、ad-hoc な修正の塊なので、コード自体はもったいなくないのだが。
誰も XML-RPC なんて使ってないのかな...。
XML-RPC で "Premature end of file."
Java で XML-RPC の開発をしている。
動作確認は UNIX コマンドの curl で手軽にすませているのだが、突然、すべての curl コマンドで Premature end of file. というエラーが出るようになった。
[Fatal Error] :-1:-1: Premature end of file.
このエラーには見覚えがある。たしか、XML の絡んだ通信で接続状態が悪くなり、通信が途絶えた場合などに ぼろぼろ出ていたやつだ。つまり、XML が不完全なのだろう。
しかし、curl の POST で送っているデータをいくら調べてもおかしい部分が見つからない。 問題になりがちな改行を取り除いても、コンソールのエンコーディングを変更しても同じ。
しかたがないので、デバッガでブレークポイントを設定し、動作を追ってみた。
その結果、リクエストオブジェクトの入力ストリームから読み出す時点でデータが空なことが判明。つまり、curl で POST したデータを読みだせていないわけだ。
では、何が原因でデータを読みだせていないんだろう? curl の -v オプションの出力を眺めているうちに気がついた。
POST /api/xmlrpc HTTP/1.1
User-Agent: curl/7.13.1 (powerpc-apple-darwin8.0) libcurl/7.13.1 OpenSSL/0.9.7l zlib/1.2.3
Host: example.com
Pragma: no-cache
Accept: */*
Content-Length: 123
Content-Type: application/x-www-form-urlencoded
application/x-www-form-urlencoded で POST しているせいだ。
Content-Type が application/x-www-form-urlencoded だと、HttpServletRequest がパラメータとして解析するために先に入力を読みだしてしまうので、HttpServletRequest#getInputStream() から読みだすときは空なわけだ。
次のように POST すれば、正常に動作した(--data-ascii の XML は省略)。
% curl -v -H "Content-Type: text/xml" --data-ascii "..." "http://example.com/api/xmlrpc"
どうやら、昨日まではちゃんと -H オプションで Content-Type を指定していたのだが、一日寝ると忘れてしまったようだ。
だから、ブログに書いている。
Apache XML-RPC への不満
Apache Web Services Project の一環として開発されている Apache XML-RPC は Web に紹介記事も多く、もっとも利用されている印象を受ける。
実際、これまで仕事でも XML-RPC クライアントとして Apache XML-RPC を使用していた。他の選択肢を知らなかった、というのもあるが、Apache というブランドの影響も大きいと思う。
しかし、不満がないわけではない。
特に、クラス階層が複雑なのには手こずった。動作をカスタマイズしたいときなど、あるクラスがどのインターフェースを実装し、どのファクトリで生成されるかを調べるだけでも大変だ(RequestProcessorFactoryFactory インターフェースまでくると、もう冗談のように思えてくる)。
実例をあげよう。
RPC の結果として不正な XML が返ってきた場合のエラー処理。 たとえば、XML 宣言の前に PHP のエラーが出力されている、なんてことはざらにある(現実とはそういう世界なのだ)。こういうときでも、XML 宣言以降は正当な XML なので、できるだけ XML をパースして処理の結果を拾いたい。
そして、このリカバリ処理自体は難しくない。例外をキャッチして、結果の文字列を XML 宣言までスキップして、再度パースしてみるだけだ。
だが、結局、その処理をするためには、ダウンロードした Apache XML-RPC のソースコードから既存のクラスをコピーして別のクラスを作成する必要があった。どうしてだろう? もしかすると、他にエレガントな解決方法があったのかもしれない。だが、発見できなかった。
そして、いま、サーバサイドの XML-RPC サービスを実装しているのだが、今度は出力エンコーディングを設定する方法が分からない。きっとどこかで、エレガントな解決方法が、発見されるのを待っているのだろう。
ブログの XML-RPC サポート
個人的メモとして、各ブログの XML-RPC サポート状況をまとめてみた。
Movable Type は Blogger の API と、米 UserLand Software 社の MetaWeblog API に準拠しているようだ。また、WordPress も Movable Type に準ずるかたちになっている。
面白いのは Blogger。 現在は XML-RPC ではなく、 Google Data APIs (GData) による Blogger Data API を使用している。
Web ページのサイドバーには他にも "Calendar Data API" や "Spreadsheets Data API" など、Google の他サービスの名前が並んでいるので、GData はこれらのサービスでも実装されているのだろう。GData によるサービス同士の連携もあるのかもしれない。