twitter APIに接続するためのjavaコード

twitter APIに接続し、エントリーを投稿するJavaソースコードです。

ソースコード

以下、ソースコードの全文です。

import java.security.*;
import java.io.*;
import java.util.*;
import java.text.*;
import java.net.*;
import java.util.zip.*;

/**
 * Twitter APIに接続するためのjavaコード
 * @author nattou_curry
 */
public class TwitterAPIAccess {

	// Twitter APIのエンコーディング
	private static final String ENCODING = "UTF-8";

	/**
	 * statuses/updateでエントリーを投稿する。
	 * @param username ユーザ名
	 * @param password パスワード
	 * @param status ステータス
	 */
	public static void postStatusesUpdate( String username, String password, String status ) {

		String html;
		HttpURLConnection conn;

		//////////////////////////////////////////////
		// 認証情報を生成する。
		//////////////////////////////////////////////
		
		String authorization = createAuthorization( username, password );

		//////////////////////////////////////////////
		// エントリー投稿用のクエリを作成する。
		//////////////////////////////////////////////
		
		String query;
		try {
			query = "status=" + URLEncoder.encode( status, ENCODING );
		} catch ( java.io.UnsupportedEncodingException e ) {
			throw new RuntimeException( e );
		}

		//////////////////////////////////////////////
		// statuses/updateでエントリーを投稿する。
		//////////////////////////////////////////////
		
		conn = null;
		try {
			// 接続を開く。
			conn = openConnection( "http://twitter.com/statuses/update.xml" );

			// リクエストプロパティを設定する。
			conn.setRequestProperty( "Authorization", "Basic " + authorization );

			// POSTリクエストを送信する。
			requestPost( conn, query );

			// ステータスコードが正常であることを確認する。
			if ( conn.getResponseCode() != 200 ) {
				// 正常でない:
				
				int code = conn.getResponseCode();
				String message = conn.getResponseMessage();
				throw new RuntimeException( code + " " + message );
			}

			// HTMLを取得する。
			html = getHTML( conn );

		} catch ( IOException e ) {
			// 通信エラー:
			throw new RuntimeException( e );

		} finally {
			// 接続を閉じる。
			closeConnection( conn );
		}
	}

	/**
	 * BASIC認証用のヘッダ文字列を作成する。
	 * @param in_username ユーザ名
	 * @param in_password パスワード
	 * @return BASIC認証用のヘッダ文字列
	 */
	public static String createAuthorization( String in_username, String in_password ) {

		String string = in_username + ":" + in_password;

		byte[] tmp = getAsciiBytes( string );

		String encoded = base64Encode( tmp );

		return encoded;
	}

	/**
	 * 文字列をASCIIのバイト配列に変換します。
	 * @param text 対象の文字列
	 * @return 変換後のバイト配列
	 */
	private static byte[] getAsciiBytes( String text ) {

		byte[] ascii;
		try {
			ascii = text.getBytes( "ASCII" );
		} catch ( UnsupportedEncodingException e ) {
			throw new RuntimeException( e );
		}

		return ascii;
	}

	/**
	 * バイト配列をBASE64エンコードします。
	 * @param ascii 対象のバイト配列
	 * @return エンコード後の文字列
	 */
	private static String base64Encode( byte[] ascii ) {

		// ASCIIをビットパターンに変換します。
		StringBuffer bitPattern = new StringBuffer();
		for ( int i = 0; i < ascii.length; ++i ) {
			int i_tmp = ascii[i] & 0xff;
			String bin_tmp = Integer.toBinaryString( i_tmp );
			while ( bin_tmp.length() < 8 ) {
				bin_tmp = "0" + bin_tmp;
			}
			bitPattern.append( bin_tmp );
		}

		// ビットパターンのビット数が6の倍数にするため、末尾に0を追加します。
		while ( bitPattern.length() % 6 != 0 ) {
			bitPattern.append( "0" );
		}

		// 変換表
		final String[] table = {
			 "A", "B", "C", "D", "E", "F", "G", "H",
			 "I", "J", "K", "L", "M", "N", "O", "P",
			 "Q", "R", "S", "T", "U", "V", "W", "X",
			 "Y", "Z", "a", "b", "c", "d", "e", "f",
			 "g", "h", "i", "j", "k", "l", "m", "n",
			 "o", "p", "q", "r", "s", "t", "u", "v",
			 "w", "x", "y", "z", "0", "1", "2", "3",
			 "4", "5", "6", "7", "8", "9", "+", "/"
		};

		// 変換表を利用して、ビットパターンを4ビットずつ文字に変換します。
		StringBuffer encoded = new StringBuffer();
		for ( int i = 0; i < bitPattern.length(); i += 6 ) {
			String tmp = bitPattern.substring( i, i + 6 );
			int index = Integer.parseInt( tmp, 2 );
			encoded.append( table[index] );
		}

		// 変換後の文字数を4の倍数にするため、末尾に=を追加します。
		while ( encoded.length() % 4 != 0 ) {
			encoded.append( "=" );
		}

		return encoded.toString();
	}

	/**
	 * レスポンスヘッダよりクッキーを取得し、編集用のマップに設定する。
	 * @param conn HTTP接続
	 * @param cookieMap クッキー編集用のマップ
	 */
	private static void putCookiesToMap( HttpURLConnection conn, Map<String, String> cookiesMap ) {

		List<String> cookies = null;

		// レスポンスヘッダより、クッキーを取得する。
		Map<String, List<String>> header = conn.getHeaderFields();
		for ( String key : header.keySet() ) {
			if ( key != null && key.compareToIgnoreCase( "set-cookie" ) == 0 ) {
				cookies = header.get( key );
				break;
			}
		}
		
		if ( cookies == null ) {
			// クッキーが取得できない場合:
			return;
		}
		
		// クッキーを分解し、編集用のマップに設定する。
		for ( int i = 0; i < cookies.size(); ++i ) {
			String cookieLine = cookies.get( i );
			String[] keyValuePairs = cookieLine.split( "; *" );
			
			for ( int j = 0; j < keyValuePairs.length; ++j ) {
				String keyValuePair = keyValuePairs[j];
				String[] keyValue = keyValuePair.split( "=", 2 );
				String key = keyValue[0];
				String value = null;
				
				if ( keyValue.length >= 2 ) {
					value = keyValue[1];
				}
				
				if ( "Domain".equalsIgnoreCase( key ) ) continue;
				if ( "HttpOnly".equalsIgnoreCase( key ) ) continue;
				if ( "Expires".equalsIgnoreCase( key ) ) continue;
				if ( "Secure".equalsIgnoreCase( key ) ) continue;
				if ( "Path".equalsIgnoreCase( key ) ) continue;

				if ( "EXPIRED".equalsIgnoreCase( value ) )continue;
				
				cookiesMap.put( key, value );
			}
		}
	}
	
	/**
	 * 編集用のマップからクッキー文字列を作成する。
	 * @param cookieMap クッキー編集用のマップ
	 * @return クッキー文字列
	 */
	private static String cookiesMapToString( Map<String, String> cookiesMap ) {
		
		StringBuffer cookie = new StringBuffer();
		for ( String key: cookiesMap.keySet() ) {
			String value = cookiesMap.get( key );
			
			if ( value != null ) {
				cookie.append( key + "=" + value + "; " );
			} else {
				cookie.append( key + "; " );
			}
		}
		
		return cookie.toString();
	}

	/**
	 * HTTP接続を開く。
	 * @param requestURL リクエストURL
	 * @return HTTP接続
	 */
	private static HttpURLConnection openConnection( String requestURL ) throws IOException {
		return openConnection( requestURL, null );
	}
	
	/**
	 * HTTP接続を開く。
	 * @param requestURL リクエストURL
	 * @param cookie クッキー
	 * @return HTTP接続
	 */
	private static HttpURLConnection openConnection( String requestURL, String cookie ) throws IOException {

		URL url = new URL( requestURL );
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setInstanceFollowRedirects( false );
		conn.setRequestProperty( "User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6" );
		conn.setRequestProperty( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" );
		conn.setRequestProperty( "Accept-Language", "ja,en-us;q=0.7,en;q=0.3" );
		conn.setRequestProperty( "Accept-Encoding", "gzip,deflate" );
		conn.setRequestProperty( "Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7" );
		conn.setRequestProperty( "Keep-Alive", "300" );
		conn.setRequestProperty( "Connection", "keep-alive" );
		if ( cookie != null ) {
			conn.setRequestProperty( "Cookie", cookie );
		}
		
		return conn;
	}
	
	/**
	 * HTTP接続を閉じる。
	 * @param conn HTTP接続
	 */
	private static void closeConnection( HttpURLConnection conn ) {

		try {
			OutputStream out = conn.getOutputStream();
			out.close();
		} catch ( Exception e ) {}

		try {
			InputStream in = conn.getInputStream();
			in.close();
		} catch ( Exception e ) {}
	}

	/**
	 * 接続先のHTMLを取得する。
	 * @param conn 接続
	 * @return HTML
	 */
	private static String getHTML( HttpURLConnection conn ) throws IOException {
		
		//////////////////////////////////////////////////////////////////
		// レスポンスヘッダより、GZIPを使用しているか判定する。
		//////////////////////////////////////////////////////////////////

		boolean usingGZIP = false;
		
		List<String> contentEncodings = conn.getHeaderFields().get( "Content-Encoding" );
		if ( contentEncodings != null ) {
			for ( int i = 0; i < contentEncodings.size(); ++i ) {
				String contentEncoding = contentEncodings.get( i );
				if ( contentEncoding.equals( "gzip" ) ) {
					usingGZIP = true;
					break;
				}
			}
		}
			
		//////////////////////////////////////////////////////////////////
		// レスポンスデータを取得する。
		//////////////////////////////////////////////////////////////////

		StringBuffer buf = new StringBuffer();

		BufferedReader in = null;
		try {
			// GZIPを使用しているかどうかにより、レスポンスの入力方法を変える。
			if ( usingGZIP ) {
				// GZIPを使用している:
				in = new BufferedReader(
					new InputStreamReader(
						new GZIPInputStream( conn.getInputStream() )
						, ENCODING ) );
			} else {
				// GZIP を使用していない。
				in = new BufferedReader(
					new InputStreamReader( conn.getInputStream(), ENCODING ) );
			}
				
			int c;
			while ( ( c = in.read() ) != -1 ) {
				buf.append( (char) c );
			}
			
		} finally { 
			if ( in != null ) {
				in.close();
			}
		}

		String html = buf.toString();
		
		return html;
	}
	
	/**
 	 * GETリクエストを行います。
 	 * @param conn HTTP接続
 	 * @param query GETするクエリ
 	 */
	private static void requestGet( HttpURLConnection conn ) throws IOException {
		conn.setRequestMethod( "GET" );
		conn.connect();
	}

	/**
 	 * POSTリクエストを行います。
 	 * @param conn HTTP接続
 	 * @param query POSTするクエリ
 	 */
	private static void requestPost( HttpURLConnection conn, String query ) throws IOException {
		conn.setRequestMethod( "POST" );
		conn.setDoOutput( true );
		conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" );
		conn.setRequestProperty( "Content-Length", query.length() + "" );

		conn.connect();

		OutputStreamWriter out = new OutputStreamWriter( conn.getOutputStream(), ENCODING );
		out.write( query );
		out.flush();
		out.close();
	}

	/**
 	 * PUTリクエストを行います。
 	 * @param conn HTTP接続
 	 * @param query PUTするクエリ
 	 */
	private static void requestPut( HttpURLConnection conn, String query ) throws IOException {
		conn.setRequestMethod( "PUT" );
		conn.setDoOutput( true );
		conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" );
		conn.setRequestProperty( "Content-Length", query.length() + "" );

		conn.connect();

		OutputStreamWriter out = new OutputStreamWriter( conn.getOutputStream(), ENCODING );
		out.write( query );
		out.flush();
		out.close();
	}

	/**
 	 * DELETEリクエストを行います。
 	 * @param conn HTTP接続
 	 * @param query DELETEするクエリ
 	 */
	private static void requestDelete( HttpURLConnection conn ) throws IOException {
		conn.setRequestMethod( "DELETE" );
		conn.connect();
	}

	/**
	 * 【デバッグ用】レスポンスヘッダを表示する。
	 * @param conn HTTP接続
	 */
	private static void printHeader( HttpURLConnection conn ) {
		Map<String, List<String>> header = conn.getHeaderFields();
		for ( String key : header.keySet() ) {
			List<String> list = header.get( key );
			System.out.println( "[" + key + "]" );
			for ( int i = 0; i < list.size(); ++i ) {
				System.out.println( list.get( i ) );
			}
		}
	}
}