Twitter.java

/*
 * Twitter.java
 *
 * Author: Markku Rossi <mtr@iki.fi>
 *
 * Copyright (c) 2011-2012, Markku Rossi
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *     * Redistributions of source code must retain the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *     * Neither the name of the Markku Rossi nor the names of its
 *       contributors may be used to endorse or promote products
 *       derived from this software without specific prior written
 *       permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

import java.io.*;
import java.net.*;
import java.security.SignatureException;
import java.security.SecureRandom;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Twitter
{
  private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

  private static final String BASE64
  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

  public static String base64Encode(byte[] data)
  {
    StringBuilder sb = new StringBuilder();
    int i, len;

    for (i = 0, len = data.length; len > 0; i += 3, len -= 3)
      {
        int val;

        val = (data[i] & 0xff) << 16;
        if (len > 1)
          val |= (data[i + 1] & 0xff) << 8;
        if (len > 2)
          val |= (data[i + 2] & 0xff);

        sb.append(BASE64.charAt(val >> 18));
        sb.append(BASE64.charAt((val >> 12) & 0x3f));
        sb.append(BASE64.charAt((val >> 6) & 0x3f));
        sb.append(BASE64.charAt(val & 0x3f));
      }

    for (; len < 0; len++)
      sb.setCharAt(sb.length() + len, '=');

    return sb.toString();
  }

  private static String urlEncode(String s)
  {
    StringBuilder sb = new StringBuilder();
    int i;

    for (i = 0;i < s.length(); i++)
      {
        char ch = s.charAt(i);

        if ('0' <= ch && ch <= '9'
            || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z'
            || ch == '-' || ch == '.' || ch == '_' || ch == '~')
          {
            sb.append(ch);
          }
        else
          {
            int val = (int) ch & 0xff;

            sb.append('%');

            if (val <= 0xf)
              sb.append('0');

            sb.append(Integer.toHexString(val).toUpperCase());
          }
      }

    return sb.toString();
  }

  private static final String CONSUMER_KEY
  = "*** consumer key ***";

  private static final String CONSUMER_SECRET
  = "*** consumer secret ***********************";

  private static final String TOKEN
  = "*** access token *********************************";

  private static final String TOKEN_SECRET
  = "*** token secret *************************";

  private static final String MAC_NAME = "HmacSHA1";

  /** Random nonce. */
  private static String nonce;

  /** Current unix time in seconds. */
  private static long timestamp;

  private static void addParam(StringBuilder sb, boolean first,
                               String key, String value)
  {
    if (!first)
      sb.append("%26");

    sb.append(urlEncode(key));
    sb.append("%3D");
    sb.append(urlEncode(value));
  }

  private static String computeAuthorization(String message,
                                             String url,
                                             String method,
                                             String consumerKey,
                                             String consumerSecret,
                                             String token,
                                             String tokenSecret)
  {
    try
      {
        String keyString = (urlEncode(consumerSecret)
                            + "&" + urlEncode(tokenSecret));

        byte[] keyBytes = keyString.getBytes("UTF-8");
        SecretKeySpec key = new SecretKeySpec(keyBytes, MAC_NAME);
        Mac mac = Mac.getInstance(MAC_NAME);

        mac.init(key);

        StringBuilder sbs = new StringBuilder();

        sbs.append(method);
        sbs.append("&");
        sbs.append(urlEncode(url));
        sbs.append("&");

        addParam(sbs, true, "oauth_consumer_key", consumerKey);
        addParam(sbs, false, "oauth_nonce", nonce);
        addParam(sbs, false, "oauth_signature_method", "HMAC-SHA1");
        addParam(sbs, false, "oauth_timestamp", String.valueOf(timestamp));
        addParam(sbs, false, "oauth_token", token);
        addParam(sbs, false, "oauth_version", "1.0");
        addParam(sbs, false, "status", urlEncode(message));

        System.out.println("SBS: " + sbs.toString());

        byte[] text = sbs.toString().getBytes("UTF-8");

        return base64Encode(mac.doFinal(text));
      }
    catch (Throwable t)
      {
        t.printStackTrace();
        return null;
      }
  }

  private static void twitterPost(String message, String baseUrl, String method,
                                  String consumerKey, String consumerSecret,
                                  String token, String tokenSecret)
  {
    int i;

    /* Create nonce. */

    StringBuilder nb = new StringBuilder();
    SecureRandom random = new SecureRandom();

    for (i = 0; i < 20; i++)
      nb.append(Integer.toHexString(random.nextInt(256)));

    nonce = nb.toString();

    /* Time in seconds. */
    timestamp = System.currentTimeMillis() / 1000;

    String signature = computeAuthorization(message, baseUrl, method,
                                            consumerKey, consumerSecret,
                                            token, tokenSecret);
    StringBuilder sb = new StringBuilder();

    sb.append("OAuth");
    sb.append(" oauth_consumer_key=\"");
    sb.append(urlEncode(consumerKey));
    sb.append("\",oauth_signature_method=\"");
    sb.append("HMAC-SHA1");
    sb.append("\",oauth_timestamp=\"");
    sb.append(String.valueOf(timestamp));
    sb.append("\",oauth_nonce=\"");
    sb.append(urlEncode(nonce));
    sb.append("\",oauth_version=\"");
    sb.append(urlEncode("1.0"));
    sb.append("\",oauth_token=\"");
    sb.append(urlEncode(token));
    sb.append("\",oauth_signature=\"");
    sb.append(urlEncode(signature));
    sb.append("\"");

    System.out.println("Authorization: " + sb.toString());

    HttpURLConnection conn = null;
    try
      {
        URL url = new URL(baseUrl);

        conn = (HttpURLConnection) url.openConnection();

        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setRequestMethod(method);

        StringBuilder cb = new StringBuilder();

        cb.append(urlEncode("status"));
        cb.append("=");
        cb.append(urlEncode(message));

        String contentString = cb.toString();
        System.out.println("content: " + contentString);
        byte[] content = contentString.getBytes("UTF-8");

        conn.setRequestProperty("Authorization", sb.toString());
        conn.setRequestProperty("Content-Type",
                                "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length",
                                Integer.toString(content.length));

        OutputStream os = conn.getOutputStream();

        os.write(content);
        os.close();

        int responseCode = conn.getResponseCode();

        System.out.println("code=" + responseCode);

        InputStream is;

        try
          {
            is = conn.getInputStream();
          }
        catch (IOException e)
          {
            is = conn.getErrorStream();
          }

        InputStreamReader isr = new InputStreamReader(is);

        int ch;
        while ((ch = isr.read()) >= 0)
          System.out.write((char) ch);

        isr.close();
        System.out.println();
      }
    catch (Throwable t)
      {
        t.printStackTrace();
      }
    finally
      {
        if (conn != null)
          conn.disconnect();
      }
  }

  public static void main(String argv[])
  {
    twitterPost(argv[0],
                "http://api.twitter.com/1/statuses/update.json",
                "POST",
                CONSUMER_KEY, CONSUMER_SECRET, TOKEN, TOKEN_SECRET);
  }
}

Generated by GNU enscript 1.6.4.