GDataAPIを使って はてなのAtomPubを操作する方法
AppEngineからはてなのAtomPubAPIにアクセスしたくて実装方法を検討しました。
Abdera Client に嵌る
最初、Apache Abdera Project というのを見つけてこいつは便利そうだ、WSSE認証もついてる、と本命視。
しかし、commons httpclientを使っていてAppEngine上では動かない。
commons httpclientがAppEngine上で動いたという記事もあり惑わされつついろいろやってみるも結局断念。
嵌り期間、約2週間 orz..
GData API を拡張して WSSE認証に対応させる
次に、Google GData API。Googleサービス向けのAtomPub実装なので筋はよさそう。しかしWSSE認証がついていないのでその部分をフックできればいけるのではないか・・・
WSSE認証については、id:tomorrowkey さんのエントリ はてなブックマークAtomAPI - 明日の鍵 を参考にしました。(Thx)
GDataのRequestに WSSEヘッダを追加してやるために com.google.gdata.client.Service を拡張して createRequestメソッドをoverrideします。
public class HatenaAtomService extends Service { private String wsseHeader = null; public void setWSSEHeader(String username, String password) { try { this.wsseHeader = this.getWSSEHeaderValue(username, password); } catch (NoSuchAlgorithmException e) { } catch (UnsupportedEncodingException e) { } } @Override public GDataRequest createRequest(GDataRequest.RequestType type, URL requestUrl, ContentType inputType) throws IOException, ServiceException { GDataRequest request = super.createRequest(type, requestUrl, inputType); request.setHeader("X-WSSE", wsseHeader); return request; } private String getWSSEHeaderValue(String user, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException { byte[] nonceB = new byte[8]; SecureRandom.getInstance("SHA1PRNG").nextBytes(nonceB); SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); zulu.setTimeZone(TimeZone.getTimeZone("GMT")); Calendar now = Calendar.getInstance(); now.setTimeInMillis(System.currentTimeMillis()); String created = zulu.format(now.getTime()); byte[] createdB = created.getBytes("utf-8"); byte[] passwordB = password.getBytes("utf-8"); byte[] v = new byte[nonceB.length + createdB.length + passwordB.length]; System.arraycopy(nonceB, 0, v, 0, nonceB.length); System.arraycopy(createdB, 0, v, nonceB.length, createdB.length); System.arraycopy( passwordB, 0, v, nonceB.length + createdB.length, passwordB.length); MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(v); byte[] digest = md.digest(); StringBuffer buf = new StringBuffer(); buf.append("UsernameToken Username=\""); buf.append(user); buf.append("\", PasswordDigest=\""); buf.append(new String(Base64.encodeBase64(digest))); buf.append("\", Nonce=\""); buf.append(new String(Base64.encodeBase64(nonceB))); buf.append("\", Created=\""); buf.append(created); buf.append('"'); return buf.toString(); } }
たったこれだけでFeedの取得からEntryの投稿まで簡単にできるようになりました。(Abderaで嵌った時間はなんだったのだ^^;)
使い方
上記 HatenaAtomService を適当にどっかに作成してください。
- Feed取得
HatenaAtomService service = new HatenaAtomService(); service.setWSSEHeader("ユーザ名", "パスワード"); Feed f = service.getFeed(new URL(url), Feed.class);
- エントリ投稿
HatenaAtomService service = new HatenaAtomService(); service.setWSSEHeader("ユーザ名", "パスワード"); BlogEntry e = new BlogEntry(); e.setTitle(new PlainTextConstruct("GData API から投稿してみるテスト")); e.setContent(new TextContent(new PlainTextConstruct("はてな記法で。\n- はてな\n- 記法"))); service.insert(new URL(url), e);