はてなブックマークAtomAPI
必要なライブラリ
AndroidSDKだけでは足りないので、以下のライブラリをビルドパスにつっこみます。
- commons-codec-1.4.jar
バージョンは現時点で最新の1.4を使用します。
ソース
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.TimeZone; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.protocol.HTTP; public class HatenaAPI { public static final String URI_HATENA_B_ROOT_ATOM_END_POINT = "http://b.hatena.ne.jp/atom"; public static final String URI_HATENA_B_POST = "http://b.hatena.ne.jp/atom/post"; public static final String URI_HATENA_B_FEED = "http://b.hatena.ne.jp/atom/feed"; private static final String XML_HATENA_B_POST = "<entry xmlns=\"http://purl.org/atom/ns#\"><title>dummy</title><link rel=\"related\" type=\"text/html\" href=\"%s\" /><summary type=\"text/plain\">%s</summary></entry>\n"; private static final String XML_HATENA_B_EDIT = "<entry xmlns=\"http://purl.org/atom/ns#\"><title>%s</title><summary type=\"text/plain\">%s</summary></entry>"; private static final String CONTENT_TYPE_APPLICATION_ATOM = "application/x.atom+xml"; private static final String USER_AGENT_JAVA = "Sun Java/5.0"; private HttpClient mClient; public String mUser; public String mPassword; public HatenaAPI() { mClient = new DefaultHttpClient(); mClient.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); } public HatenaAPI(String user, String password) { this(); mUser = user; mPassword = password; } public boolean isAvailableUser() throws NoSuchAlgorithmException, HttpException, IOException { HttpUriRequest request = new HttpGet(URI_HATENA_B_ROOT_ATOM_END_POINT); request.addHeader("X-WSSE", getWSSEHeaderValue(mUser, mPassword)); return mClient.execute(request).getStatusLine().getStatusCode() == HttpStatus.SC_OK; } public int postBookmark(String url, String comment) throws NoSuchAlgorithmException, HttpException, IOException { HttpPost post = new HttpPost(URI_HATENA_B_POST); post.setHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_ATOM); post.addHeader("X-WSSE", getWSSEHeaderValue(mUser, mPassword)); post.addHeader(HTTP.USER_AGENT, USER_AGENT_JAVA); StringEntity entity = new StringEntity(String.format(XML_HATENA_B_POST, url, comment), HTTP.UTF_8); entity.setContentType(CONTENT_TYPE_APPLICATION_ATOM); post.setEntity(entity); return mClient.execute(post).getStatusLine().getStatusCode(); } public int editBookmark(String editUrl, String title, String comment) throws NoSuchAlgorithmException, ClientProtocolException, IOException { HttpPut put = new HttpPut(editUrl); put.setHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_ATOM); put.addHeader("X-WSSE", getWSSEHeaderValue(mUser, mPassword)); put.addHeader(HTTP.USER_AGENT, USER_AGENT_JAVA); StringEntity entity = new StringEntity(String.format(XML_HATENA_B_EDIT, title, comment), HTTP.UTF_8); entity.setContentType(CONTENT_TYPE_APPLICATION_ATOM); entity.setChunked(false); put.setEntity(entity); return mClient.execute(put).getStatusLine().getStatusCode(); } public int deleteBookmark(String editUrl) throws NoSuchAlgorithmException, ClientProtocolException, IOException { HttpDelete delete = new HttpDelete(editUrl); delete.setHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_ATOM); delete.addHeader("X-WSSE", getWSSEHeaderValue(mUser, mPassword)); return mClient.execute(delete).getStatusLine().getStatusCode(); } public String getBookmarks(int of) throws NoSuchAlgorithmException, ClientProtocolException, IOException { HttpGet get = new HttpGet(URI_HATENA_B_FEED + "?of=" + of); get.setHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_ATOM); get.addHeader("X-WSSE", getWSSEHeaderValue(mUser, mPassword)); HttpResponse response = mClient.execute(get); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { return null; } BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 256 * 1024); String line = null; StringBuffer buffer = new StringBuffer(); do { line = reader.readLine(); if (line != null) { buffer.append(line).append("\n"); } } while (line != null); return buffer.toString(); } protected final 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(); } }
使い方
読んで、感じ取ってください。
質問あれば、コメントにて