プロジェクトのビルド・ステータスをツイートで知らせる

Twitter アカウントの近況アップデートを通じてビルド完了のステータスを知らせられるように、OAuth を使用するカスタムの Ant タスクを作成する

長年使用されてきて、その能力を実証済みのツールである Apache Ant と、流行のサービスである Twitter とを組み合わせ、Ant の mail タスクを使わないビルド通知システムを作成しましょう。Ant での自動ビルド完了後に Twitter でステータスの更新を受信できると、プロジェクトの開発者やテスターは新しいビルドが利用できるようになったことを即座に知ることができます。また開発者やテスターは、その通知を受け取ることも受け取らないことも自由に決めることができます。

Mr Joseph P. McCarthy, Developer, IBM

Photo of Joseph McCarthyJoseph McCarthy は Dublin Software Lab の Java 開発者です。彼はコンピューター・システムの学士号、コンピューター・エンジニアリングの準修士号で University of Limerick を卒業後、2002年7月に IBM に入社しました。彼は Java 技術に幅広い経験があり、カスタム Ant タスクを開発し、また Twitter を含むさまざまな公開 API を扱ってきました。


developerWorks 貢献著者レベル

2010年 10月 05日

Apache Ant に組み込みの mail タスクを使用すると、提供されたユーザー・リストに基づいて E メールを送信し、ビルド・プロセスの完了を通知することができます。しかし時間が経過すると、ユーザーの E メール・アドレスが変更されたり、プロジェクトから外れるユーザーが出てきたりするなどして、mail タスクはあまり便利な機能ではなくなります。

Twitter.com が提供する API は公開されており、ユーザーはこの API を使用することで、さまざまなソース (携帯電話、テレビ、ゲーム・コンソールなど) から Twitter アカウントの近況アップデートをすることができます。ビルド完了のアップデートを Twitter アカウントに投稿することで、プロジェクト・チームの開発者やテスターに対し、新しいビルドが利用できるようになったことを即座に通知することができます。これにより、対象となるユーザーは、通知を受け取るか受け取らないかを自由に選択することができ、そこにビルド・エンジニアが関与する必要がないというメリットがもたらされます。

この記事では Twitter クライアントの役割を持つ Ant タスクを作成する方法について説明します。この Ant タスクでは、オープンソースの Java™ ライブラリーを使用して Twitter とやり取りし、このタスクに関連付けられた Twitter アカウントの近況アップデートを通じて、ビルド・ステータスを通知します。この記事のサンプル・コードは「ダウンロード」セクションからダウンロードすることができます。

Twitter を使えるようにする

ビルド通知システムに Twitter を使用するためには、Twitter アカウントを作成してクライアント・アプリケーションを登録する必要があります。

Twitter アカウントを作成する

OAuthcalypse

2010年 9月以前には、HTTP の BASIC 認証を使ってサードパーティーのアプリケーションから Twitter アカウントにログインすることができました。しかし現在では、OAuth (Open Authorization) を使用するアプリケーション以外は Twitter サーバーに認識されません。(Twitter ユーザーは、この出来事に OAuthcalypse という名前を付けました)。OAuth を使用する場合には、Twitter アカウントのユーザー名とパスワードがクライアント・アプリケーションとサーバーとの間で送信されることは決してありません。

最初のステップは至って簡単です。Twitter.com にナビゲートし、アカウントを作成します。私は説明用に tweet_task という名前のアカウントを作成しました。http://twitter.com/tweet_task にアクセスすると、現在までの近況アップデートを見ることができます。

クライアント・アプリケーションを登録する

Twitter アカウントの近況アップデートに使用されるすべてのクライアント・アプリケーションと同様、この記事で作成するクライアント・アプリケーションを使用する前に、まずこのアプリケーションを Twitter に登録する必要があります。OAuth クライアントを登録するための Twitter のページ (http://twitter.com/oauth_clients/new) を開き、表示されるフォームに入力します (図 1)。

図 1. Twitter にアプリケーションを登録する
アプリケーションを登録するための Twitter のフォームを表示した画面のスクリーンショット

クリックして大きなイメージを見る

図 1. Twitter にアプリケーションを登録する

アプリケーションを登録するための Twitter のフォームを表示した画面のスクリーンショット

このフォームの「Application Icon (アプリケーションのアイコン)」フィールドには、クライアント・アプリケーションのアイコンとして使用する画像のファイル名を入力するか、あるいは「Browse (参照)」をクリックしてその画像ファイルを指定します。画像は GIF、JPG、PNG のいずれかのファイルであり、700KB 以下でなければなりません。「Application Name (アプリケーション名)」には、twitter という単語が含まれなければ、どんな名前でも付けることができます (このクライアントを使用して近況アップデートをする場合には必ず、クライアントの名前をサブタイトルとして含める必要があることを忘れないでください。この記事の説明用として、私は tweet_task_client という名前を選びました。これは、すべての近況アップデートに tweet_task_client というサブタイトルが付いていることでわかると思います)。「Description (アプリケーションの説明)」フィールドには、このアプリケーションの簡単な説明を入力します。「Application Website (アプリケーションのウェブサイトURL)」フィールドが空白であってはならないことに注意してください。そこで、アプリケーションの URL を入力します (この URL は無効なものでも構いません)。「Organization (所属会社/団体)」フィールドと、それに関連する「Website (サイト)」フィールドはオプションです。「Application Type (アプリケーションの種類)」として「Client (クライアントアプリケーション)」を選択し、「Default Access type (デフォルトのアクセス・タイプ)」として「Read & Write (読み書き)」を選択します。「Use Twitter for login (Twitterでログインする)」では、隣の「Yes, use Twitter for login (はい、Twitterをログインに使用します。)」を選択します。

アプリケーションが登録されると、「Consumer key (コンシューマー・キー)」と「Consumer secret (コンシューマー・シークレット)」のトークンを含む画面が表示されます。これらをメモし、安全なところに保管します。


AccessToken オブジェクトを作成する

Twitter4J は、OAuth のサポートが組み込まれたオープンソースの非公式の Java ライブラリーです。Twitter4J の Web サイト (「参考文献」を参照) から最新リリースをダウンロードし、クラスパスに追加します。

クライアントから Twitter アカウントの近況アップデートをできるようにするためには、そのための権限をクライアントに与える必要があります。リスト 1 は、アプリケーションからアカウントへのアクセスを承認するための URL を生成する簡単なプログラムです。

リスト 1. Twitter4JRegister.java
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;

import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.http.AccessToken;
import twitter4j.http.RequestToken;

public class Twitter4JRegister {


  public static void main(String args[]) throws Exception {

    Twitter twitter = new TwitterFactory().getInstance();
    twitter.setOAuthConsumer("consumer key", "consumer secret");
    RequestToken requestToken = twitter.getOAuthRequestToken();
    AccessToken accessToken = null;
    BufferedReader bufferedReader = new BufferedReader(
        new InputStreamReader(System.in));
    while (null == accessToken) {
      System.out
          .println("Open the following URL and grant access to your account:");
      System.out.println(requestToken.getAuthorizationURL());
      System.out
          .print("Enter the generated PIN:");
      String pin = bufferedReader.readLine();
      try {
        if (pin.length() > 0) {
          accessToken = twitter
              .getOAuthAccessToken(requestToken, pin);
        } else {
          accessToken = twitter.getOAuthAccessToken();
        }

      } catch (TwitterException e) {
        if (401 == e.getStatusCode()) {
          System.out.println("Unable to get the access token.");
        } else {
          e.printStackTrace();
        }
      }
    }
    storeAccessToken(accessToken);
    Status status = twitter.updateStatus("Client installed");
    System.out.println("Successfully updated the status to ["
        + status.getText() + "].");
    System.exit(0);
  }

  private static void storeAccessToken(AccessToken accessToken) {

    try {
      FileOutputStream fileOutputStream = new FileOutputStream(
          "token.txt");
      ObjectOutputStream objectOutputStream = new ObjectOutputStream(
          fileOutputStream);
      objectOutputStream.writeObject(accessToken.getToken());
      objectOutputStream.flush();
      fileOutputStream = new FileOutputStream("tokenSecret.txt");
      objectOutputStream = new ObjectOutputStream(fileOutputStream);
      objectOutputStream.writeObject(accessToken.getTokenSecret());

      objectOutputStream.flush();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }

}

リスト 1 のコードを Twitter4JRegister.java というファイルに入力し、コンシューマー・キーとコンシューマー・シークレットのプレースホルダーを皆さんのキーとシークレットで置き換えたら、そのコードをコンパイルします。コンパイルされたコードを実行し、生成された URL をブラウザーのアドレス・バーに入力します。ログインには、先ほど作成した Twitter アカウントのユーザー名とパスワードを使います。PIN が生成されて表示されたら、その PIN をコンソールに入力します。

トークン・オブジェクトとトークン・シークレット・オブジェクトは、それぞれ token.txt、tokenSecret.txt という別のファイルにシリアライズされます。クライアントはこの 2 つのオブジェクトを使用し、今後のすべてのトランザクションでアカウントを認証します。この 2 つのファイルは、バックアップを取っておいてください。削除してしまうと、再度プログラムを実行して新しい URL を生成し、この 2 つのオブジェクトを作成しなければなりません。アカウントのユーザー名とパスワードを決してコードの中で使わないように注意してください。トークンとトークン・シークレットは、(データベースやレジストリなど) 任意の場所に永続化することができますが、この記事ではファイルにシリアライズする方法のみを示します。


トークンを使って近況アップデートを行う

これでユーザーがトークンを利用できるようになったので、クライアント・アプリケーションを作成してトークンを使ったテストを行い、Twitter アカウントの近況アップデートをすることができます。リスト 2 は、Twitter4JUpdate というクライアント・アプリケーションのコードを示しています。

リスト 2. Twitter4JUpdate.java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.http.AccessToken;

public class Twitter4JUpdate {

  public static void main(String args[]) throws Exception {

    TwitterFactory factory = new TwitterFactory();
    AccessToken accessToken = loadAccessToken();
    Twitter twitter = factory.getOAuthAuthorizedInstance("consumer key",
        "consumer secret", accessToken);
    Status status = twitter.updateStatus("Client registered");
    System.out.println("Successfully updated the status to ["
        + status.getText() + "].");
    System.exit(0);
  }

  private static AccessToken loadAccessToken() {
    String token = null;
    String tokenSecret = null;
    try {
      FileInputStream fileInputStream = new FileInputStream("token.txt");
      ObjectInputStream objectInputStream = new ObjectInputStream(
          fileInputStream);
      token = (String) objectInputStream.readObject();
      fileInputStream = new FileInputStream("tokenSecret.txt");
      objectInputStream = new ObjectInputStream(fileInputStream);
      tokenSecret = (String) objectInputStream.readObject();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return new AccessToken(token, tokenSecret);

  }

}

先ほどと同様、リスト 2 のコンシューマー・キーとコンシューマー・シークレットを皆さんのものに置き換えます。先ほど示したファイル以外のどこかにトークン・オブジェクトとトークン・シークレット・オブジェクトを永続化した場合には、その 2 つのオブジェクトを取得できるように loadAccessToken() メソッドを作成し直す必要があります。

Twitter4JUpdate.java をコンパイルします。Twitter アカウントの近況アップデートが適切に行われることを確認するためには、下記のコマンドを使用し、表示させたい近況アップデートを update に指定します。

java Twitter4JUpdate update

入力した近況アップデートが適切に表示されるかどうかを twitter.com で確認します。


カスタムの Ant タスクを作成して Twitter アカウントの近況アップデートを行う

カスタムの Ant タスクを作成するには、org.apache.tools.ant.Task タスクを継承して execute() メソッドをオーバーライドするだけのことです (「参考文献」を参照)。ランタイム変数はすべて、適切な set メソッドと get メソッドを持つプライベートなクラス属性として定義されます。コマンドライン・パラメーターを使って Twitter アカウントの近況を設定する代わりに、ビルド・ファイルの中でストリング値を設定します。すると、Ant タスクはそのストリング値を使って近況アップデートを行います。

リスト 3 のコードを TweetTask.java というファイルに入力し、先ほどと同様にコンシューマー・キーとコンシューマー・シークレットを置き換えます。

リスト 3. TweetTask.java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

import org.apache.tools.ant.Task;

import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.http.AccessToken;

public class TweetTask extends Task {

  private String status;

  public void execute() {

    try {

      TwitterFactory factory = new TwitterFactory();
      AccessToken accessToken = loadAccessToken();
      Twitter twitter = factory.getOAuthAuthorizedInstance(
          "consumer key", "consumer secret", accessToken);
      Status updatedStatus = twitter.updateStatus(status);
      System.out.println("Updated status to: "
          + updatedStatus.getText());

    } catch (TwitterException e) {

      e.printStackTrace();

    }

  }

  private AccessToken loadAccessToken() {

    String token = null;
    String tokenSecret = null;
    try {
      FileInputStream fileInputStream = new FileInputStream(
          "accessToken.txt");
      ObjectInputStream objectInputStream = new ObjectInputStream(
          fileInputStream);
      token = (String) objectInputStream.readObject();
      fileInputStream = new FileInputStream("accessTokenSecret.txt");
      objectInputStream = new ObjectInputStream(fileInputStream);
      tokenSecret = (String) objectInputStream.readObject();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return new AccessToken(token, tokenSecret);

  }

  public String getStatus() {
    return status;
  }

  public void setStatus(String status) {
    this.status = status;
  }

}

リスト 3 ではリスト 2main() メソッドを Ant タスクの execute() メソッドにリファクタリングしていることに注意してください。またリスト 3 では loadAccessToken() メソッドをリファクタリングし、単純に static 修飾子を削除して loadAccessToken() メソッドをクラス・メソッドからインスタンス・メソッドに変更しています (先ほど示したファイル以外のどこかにトークン・オブジェクトとトークン・シークレット・オブジェクトを永続化した場合には、リスト 2 で使用したメソッドと同じメソッドを再利用します)。TweetTask.java をコンパイルします。

今度は Ant の build.xml ファイルを作成し (リスト 4)、カスタムの TweetTask タスクをテストします。

リスト 4. build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project default="default" basedir=".">

  <taskdef name="tweet"
     classname="TweetTask"
     classpath="Twitter4J Jar file" />

  <target name="default">
  
    <tstamp>
      <format property="build.completed" 
        pattern="HH:mm:ss z dd-MM-yyyy" />
    </tstamp>
    <tweet status="build completed at ${build.completed}" />
    
  </target>
  
</project>

Twitter4J の Web サイトからダウンロードしたものと同じ JAR ファイルが、このカスタム・タスクのクラスパスに追加されていることに注意してください。classpath 属性の値を、ダウンロードしたファイルの名前で置き換えます。mypackage.customtasks などのパッケージの中に TweetTask.java ファイルを配置した場合には、そのパッケージ名を classname 属性に反映する必要があります。この記事で示した例に従ってトークン・オブジェクトとトークン・シークレット・オブジェクトをローカル・ファイルにシリアライズした場合には、token.txt ファイルと tokenSecret.txt ファイルは、この build.xml ファイルと同じディレクトリーの中に配置されている必要があります。そうでないとビルドが適切に完了しません。

Ant で build.xml ファイルを実行します。実行が終了したら、Twitter アカウントをチェックし、カスタム・タスクによって適切に近況アップデートが行われ、「build completed at [時刻 タイムゾーン 日付]」という内容が表示されることを確認します (図 2)。

図 2. ビルド完了の近況アップデートが Twitter に表示された様子
Twitter アカウントに、ビルド完了を示す近況アップデートが表示された状態のスクリーンショット

これで、プロジェクトの関係者全員が Twitter のツイートをフォローすることで、ビルド完了時に通知を受けられるようになりました。


まとめ

この記事では、Twitter の OAuth メカニズムを使用して、クライアント Java プログラムから Twitter アカウントの近況アップデートを行う方法を説明しました。この手法により、オープンソース・プロジェクトのビルド・エンジニアはビルドのメーリング・リストの保守および更新作業から解放されます (こうした作業は彼らが行うべき作業ではありません)。プロジェクトに関心を持つ開発者、テスター、その他誰でも、Twitter アカウントを購読 (つまり「フォロー」) することで、ビルドが完了したときに瞬時に通知を受けることができます。万が一 twitter.com を利用できない場合、あるいはプロジェクトのアカウントがセキュリティー侵害を受けた場合には、代替手段として mail タスクを使用して、ビルド・ステータスをユーザーに知らせることができます。

Twitter はこの 4 年間で飛躍的にその利用が増大してきました。その結果 status.net、Jaiku、NotePub などのミニブログが生まれています。この記事で紹介した近況アップデートのタスクを拡張することで、それらのサービスを利用したり、Facebook でプロジェクトの近況アップデートを行ったりすることができるようになります。


ダウンロード

内容ファイル名サイズ
Sample code for this articlej-tweettask.zip7KB

参考文献

学ぶために

製品や技術を入手するために

  • Twitter4J をダウンロードしてください。

議論するために

  • My developerWorks コミュニティーに加わってください。開発者向けのブログ、フォーラム、グループ、ウィキなど利用しながら、他の developerWorks ユーザーとやり取りしてください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=559877
ArticleTitle=プロジェクトのビルド・ステータスをツイートで知らせる
publish-date=10052010