【Twitter】JavaでのXauth 投稿サンプル

投稿サンプル、と題していますが、ご覧の通り、コンストラクタに渡すmethod,api,parameterMapの内容を変更すれば他のAPIも実行できます。ベースにどうぞ。
thx @aki_null, @kiri_feather

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


public class TwitterCommand {
	private static final String CONSUMER_KEY = "xxxxxxxxxxxxxx";
	private static final String CONSUMER_SECRET = "xxxxxxxxxxxxxxxxxxxxxx";
	private static final String OAUTH_TOKEN = "xxxxx accessTokenで取得した oauth_token xxxxx";
	private static final String OAUTH_SECRET = "xxxxx accessTokenで取得した oauth_secret_token xxxxx";

	private static final String SIGNATURE_METHOD = "HMAC-SHA1";
	private static final String OAUTH_VERSION = "1.0";
	private static final String ALGOTITHM = "HmacSHA1";
	private Map<String, String> parameterMap;
	private SortedMap<String, String> oauthParametersMap;
	private boolean useProxy = false;
	private String method = null;
	private String api = null;

	public TwitterCommand(String method, String api, Map<String, String> parameterMap) {
		this.method = method;
		this.api = api;
		this.parameterMap = parameterMap;
	}

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		try {
			map.put("status", SignatureEncode.encode("何故なら私は、アメリカ合衆国大統領だからだ!"));
		} catch (UnsupportedEncodingException ignore) {
		}
//		try {
//			map.put("status", SignatureEncode.encode("@lynmock Let's party!!"));
//		} catch (UnsupportedEncodingException ignore) {
//		}
//		map.put("in_reply_to_status_id", String.valueOf(13775833805l));

		TwitterCommand update = new TwitterCommand(
				"POST",
				"http://api.twitter.com/1/statuses/update.xml",
				map);
		update.request();
	}

	public void request() {
		setProperty();
		oauthParametersMap = createParametersMap();
		HttpURLConnection urlconn = null;
		BufferedReader reader = null;
		try {
			String apiParamter = createParameters();
			URL url = new URL(api +
								(apiParamter.length() > 0 ? "?" + apiParamter : ""));
			urlconn = (HttpURLConnection) url.openConnection();
			urlconn.setRequestMethod(method);
			urlconn.addRequestProperty("Authorization", createAuthorizationValue());
			urlconn.connect();

    		System.out.println(urlconn.getResponseCode());

	    	if (urlconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
	    		reader = new BufferedReader(new InputStreamReader(urlconn.getInputStream()));
	    		while (true){
	    			String line = reader.readLine();
	    			if (line == null){
	    				break;
	    			}
	    			System.out.println(line);
	    		}
	    	} else {
	    		urlconn.disconnect();
//	    		String message = null;
//	    		switch (urlconn.getResponseCode()) {
//	    		case HttpURLConnection.HTTP_BAD_REQUEST:
//	    			message = "API limit over.";
//	    			break;
//	    		case HttpURLConnection.HTTP_FORBIDDEN:
//	    			message = "Tweet overlaps. ";
//	    			break;
//	    		default:
//	    			message = urlconn.getResponseMessage();
//	    		}
	    	}
		} catch (SocketTimeoutException ignore) {
			// "Request Timeout.";
		} catch (IOException ignore) {
		} catch (InvalidKeyException ignore) {
		} catch (NoSuchAlgorithmException ignore) {
		}finally{
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException ignore) {
				}
			}
			if (urlconn != null) {
				urlconn.disconnect();
			}
		}
	}

	private void setProperty() {
	    System.setProperty("sun.net.client.defaultReadTimeout", "15000");
	    System.setProperty("sun.net.client.defaultConnectTimeout", "15000");
	    if(useProxy){
	    	System.setProperty("http.proxyHost", "proxyServerName");
	    	System.setProperty("http.proxyPort", "proxyPortNo");
	    }else{
	    	System.setProperty("http.nonProxyHosts", "localhost");
	    }
	}

	private SortedMap<String, String> createParametersMap() {
		SortedMap<String, String> map = new TreeMap<String, String>();
		map.put("oauth_consumer_key", CONSUMER_KEY);
		map.put("oauth_nonce", UUID.randomUUID().toString());
		map.put("oauth_signature_method", SIGNATURE_METHOD);
		map.put("oauth_timestamp", getTimeStamp());
		map.put("oauth_version", OAUTH_VERSION);
		map.put("oauth_token", OAUTH_TOKEN);
		return map;
	}

	private String createParameters() {
		if (parameterMap == null || parameterMap.size() == 0) {
			return "";
		}
		StringBuilder builder = new StringBuilder();
		for (Map.Entry<String, String> param : parameterMap.entrySet()) {
			builder.append(param.getKey() + "=");
			builder.append(param.getValue());
			builder.append("&");
		}
		return builder.toString().substring(0, builder.length() -1);
	}

	private String createAuthorizationValue() throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
		StringBuilder builder = new StringBuilder();
		builder.append("OAuth ");
		for (Map.Entry<String, String> param : oauthParametersMap.entrySet()) {
			builder.append(param.getKey() + "=");
			builder.append("\"" + param.getValue() + "\",");
		}
		builder.append("oauth_signature" + "=");
		builder.append("\"" +
						getSignature(getSignatureBaseString(), getKey())
						+ "\"");
		return builder.toString();
	}

	private String getKey() {
		StringBuilder builder = new StringBuilder();
		builder.append(CONSUMER_SECRET);
		builder.append("&");
		builder.append(OAUTH_SECRET);
		return builder.toString();
	}

	private String getRequestParameters() {
		if (parameterMap != null && parameterMap.size() > 0) {
			for (Map.Entry<String, String> param : parameterMap.entrySet()) {
				oauthParametersMap.put(param.getKey(), param.getValue());
			}
		}
		StringBuilder builder = new StringBuilder();
		for (Map.Entry<String, String> param : oauthParametersMap.entrySet()) {
			builder.append(param.getKey());
			builder.append("=");
			builder.append(param.getValue());
			builder.append("&");
		}
		return builder.toString().substring(0, builder.length() -1);
	}

	private String getSignatureBaseString() throws UnsupportedEncodingException {
		return method + "&" + encodeURL(api) + "&" + SignatureEncode.encode(getRequestParameters());
	}

	private String getSignature(String signatureBaseString, String keyString)
		throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException{
		Mac mac = Mac.getInstance(ALGOTITHM);
		Key key= new SecretKeySpec(keyString.getBytes(), ALGOTITHM);
		mac.init(key);
		byte[] digest = mac.doFinal(signatureBaseString.getBytes());
		return encodeURL(Base64.encodeBytes(digest));
	}

	private String encodeURL(String str) {
		String encord = null;
		try {
			encord = URLEncoder.encode(str, "UTF-8");
		} catch (UnsupportedEncodingException ignore) {
		}
		return encord;
	}

	private String getTimeStamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}
}
import java.io.UnsupportedEncodingException;


public class SignatureEncode {
	private static final String UNRESERVEDCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

	public static final String encode(String s) throws UnsupportedEncodingException {
        byte[] bytes = s.getBytes("utf-8");
        StringBuffer builder = new StringBuffer();
        for (byte b: bytes){
        	char c = (char) b;
        	if (UNRESERVEDCHARS.indexOf(String.valueOf(c)) >= 0) {
        		builder.append(String.valueOf(c));
        	} else {
        		builder.append("%" +
        				String.valueOf(Integer.toHexString(b > 0 ? b : b + 256)).toUpperCase());
        	}
        }
        return builder.toString();
	}
}