Apache Ant의 내장 메일 태스크를 사용하면 제공된 목록의 사용자에게 이메일을 전송하여 빌드 프로세스의 완료를 통보할 수 있다. 하지만 시간이 지나면서 사람들이 이메일 주소를 변경하거나 프로젝트를 그만 두는 등의 여러 이유로 인해 이 기능의 유용성이 떨어지고 있다.
Twitter.com에서는 사용자가 휴대전화, TV 및 게임 콘솔과 같은 다양한 소스를 사용하여 계정을 업데이트할 수 있도록 지원하는 공용 API를 제공한다. 빌드 완료와 관련된 업데이트를 Twitter 계정에 업데이트하는 방법을 사용하면 프로젝트 개발자 및 테스트에게 사용 준비가 완료된 새 빌드의 상태를 즉시 통보할 수 있다. 더불어 빌드 엔지니어가 관여하지 않더라도 관련 사용자가 피드 구독 여부를 결정할 수 있다는 장점도 있다.
이 기사에서는 연관된 Twitter 계정에 빌드 상태를 업데이트하는 Twitter 클라이언트 Ant 태스크를 작성하는 방법에 대해 설명하며, 이 작업에는 Twitter와의 상호 작용을 지원하는 오픈 소스 Java™ 라이브러리가 사용된다. 이 기사의 샘플 코드는 다운로드를 통해 얻을 수 있다.
빌드 통보 시스템에 Twitter를 사용하려면 Twitter 계정을 작성한 다음 클라이언트 애플리케이션을 등록해야 한다.
첫 번째 단계는 가장 간단하다. twitter.com에서 계정을 작성하면 된다. 필자가 데모 목적으로 tweet_task라는 계정을 작성해 두었으므로 http://twitter.com/tweet_task에서 최신 상태 업데이트를 볼 수 있다.
Twitter 계정의 상태를 업데이트하는 데 사용되는 모든 클라이언트 애플리케이션과 마찬가지로 이 기사에서 빌드할 애플리케이션도 먼저 Twitter에 등록해야만 사용할 수 있다. Twitter OAuth 클라이언트 등록 페이지(http://twitter.com/oauth_clients/new)를 열고 양식을 완료한다(그림 1 참조).
그림 1. Twitter에 애플리케이션 등록하기
양식의 Application Icon 필드를 사용하여 클라이언트 애플리케이션의 아이콘으로 사용할 이미지를 입력하거나 찾아서 선택할 수 있으며, 이 이미지는 700k 이하의 GIF, JPG 또는 PNG 파일이어야 한다. Application Name에는 twitter라는 단어가 포함되지 않은 이름이라면 자유롭게 사용할 수 있다. (이 클라이언트를 사용하는 업데이트에 클라이언트 이름이 하위 제목으로 포함될 것이라는 점에 유의하자. 필자가 이 기사의 데모를 위해 tweet_task_client라는 이름을 선택했기 때문에 모든 상태에 via tweet_task_client라는 하위 제목이 표시된다.) Description 필드에 애플리케이션에 대한 간략한 설명을 입력한다. Application Website 필드는 비워둘 수 없으므로 애플리케이션의 URL을 입력한다. (작동하지 않는 URL이라도 입력해야 한다.) Organization 필드 및 이와 연관된 Website 필드는 선택사항이다. Application Type으로 Client를 선택하고 Read & Write를 Default Access Type으로 선택한다. 그런 다음 Use Twitter for login: 항목에서 Yes, use Twitter for login을 선택한다.
애플리케이션이 등록되면 컨슈머 키 및 컨슈머 시크릿 토큰이 포함된 화면이 표시된다. 이러한 정보를 기록해 두고 안전하게 보관한다.
Twitter4J는 내장 OAuth 지원을 제공하는 비공식 오픈 소스 Java 라이브러리이다. Twitter4J 웹 사이트(참고자료 참조)에서 최신 릴리스를 다운로드한 후 클래스 경로에 추가한다.
클라이언트가 계정의 상태를 업데이트할 수 있으려면 해당 계정에서 먼저 클라이언트에게 업데이트 권한을 부여해야 한다. 목록 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라는 두 개의 파일로 직렬화된다. 이러한 오브젝트는 이후 모든 트랜잭션에서 클라이언트가 계정에 대한 인증을 받을 때 사용된다. 이러한 파일의 백업을 저장해 둔다. 파일이 삭제된 경우에는 새 URL을 생성하는 프로그램을 다시 실행하여 파일을 다시 작성해야 한다. 계정의 사용자 이름 및 비밀번호는 코드에서 전혀 사용되지 않는다는 점에 유의한다. 토큰 및 토큰 시크릿은 데이터베이스나 레지스트리를 비롯한 원하는 위치에 저장할 수 있으며, 파일로 직렬화하는 방법은 이 기사에서 추천하는 하나의 제안이다.
이제 사용자에게 제공할 토큰이 마련되었으므로 토큰의 사용을 테스트하고 계정의 상태를 업데이트하는 클라이언트
애플리케이션을 작성할 수 있다. 목록 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의 컨슈머 키 및 컨슈머 시크릿을 사용자의
컨슈머 키 및 컨슈머 시크릿으로 바꾼다. 토큰 및 토큰 시크릿 오브젝트를 제안된 파일 이외의 위치에
저장해 둔 경우에는 해당 오브젝트를 검색하는 loadAccessToken() 메소드를
다시 작성해야 한다.
Twitter4JUpdate.java를 컴파일한다. 계정의 상태가 올바르게 업데이트되는지 확인하기 위해 표시하려는 상태 업데이트를 사용하여 다음 명령을 실행한다.
java Twitter4JUpdate update |
twitter.com에서 입력한 업데이트가 올바르게 표시되는지 확인한다.
계정 상태를 업데이트하는 사용자 정의 Ant 태스크 작성하기
사용자 정의 Ant 태스크는 org.apache.tools.ant.Task 태스크를 확장한 다음 execute()
메소드를 대체하는 간단한 방법을 통해 작성할 수 있다(참고자료 참조). 모든 런타임
변수는 적절한 set 및 get 메소드가 포함된 private 클래스 속성으로 정의된다. 명령행 매개변수를 사용하여
계정의 상태를 설정하는 대신 빌드 파일에 문자열 값을 설정하면 태스크에서 이 문자열 값을 사용하여 상태를
업데이트하게 된다.
목록 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에서는 목록 2의 main() 메소드를
태스크의 execute() 메소드로 리팩토링했으며, loadAccessToken() 메소드의
경우에는 static 한정자를 제거하여 클래스 메소드에서 인스턴스 메소드로 변경했다. (토큰 및 토큰 시크릿
오브젝트를 제안된 파일 이외의 위치에 저장해 둔 경우에는 목록 2에서 사용한 동일한 메소드를 다시
사용한다.) TweetTask.java를 컴파일한다.
이제 목록 4와 같은 Ant build.xml 파일을 작성하여 사용자 정의 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 웹 사이트에서 다운로드한 동일한 JAR 파일이 사용자 정의 태스크의 클래스 경로에
추가되었다. classpath 속성의 값을 다운로드한 파일의 이름으로
바꾼다. TweetTask.java 파일을 패키지(예: mypackage.customtasks)에
배치한 경우에는 classname 속성에 이 사항이 반영되어야 한다. 이
기사에서 제안한 방법에 따라서 토큰 및 토큰 시크릿 오브젝트를 로컬 파일에 직렬화한 경우에는
token.txt 및 tokenSecret.txt 파일이 이 build.xml 파일과 같은 디렉토리에 있어야만 빌드를 완료할
수 있다.
Ant를 사용하여 build.xml 파일을 실행한다. 실행이 완료되면 Twitter 계정을 검사하여 사용자 정의 태스크가 계정의 상태를 build completed at 시간 날짜 형식으로 올바르게 업데이트했는지 확인한다(그림 2 참조).
그림 2. Twitter에 게시된 빌드 완료 업데이트
이제 프로젝트의 모든 관계자가 Twitter 피드를 팔로우하여 빌드 완료 시기를 확인할 수 있다.
이 기사에서는 Twitter의 OAuth 메커니즘을 사용하여 클라이언트 Java 프로그램에서 계정의 상태를 업데이트하는 방법을 살펴보았다. 오픈 소스 프로젝트의 빌드 엔지니어가 이 기술을 활용하면 빌드와 관련된 메일링 목록을 관리 및 업데이트하는 부차적인 업무에 시간을 낭비하지 않아도 된다. 개발자, 테스터를 포함하여 프로젝트에 관심이 있는 모든 사람이 Twitter 계정을 구독(또는 팔로우)하여 빌드 완료 즉시 통보를 받을 수 있다. twitter.com 또는 프로젝트 계정이 정상적으로 작동하지 않을 경우에는 메일 태스크를 대체 방법으로 사용하여 사용자에게 빌드 상태를 알려줄 수 있다.
지난 4년 동안 Twitter의 사용량은 급속도로 성장했으며, 그 뒤를 이어 status.net, Jaiku, NotePub 등의 여러 마이크로블로깅 대안도 등장하고 있다. 이 기사의 업데이트 태스크를 확장하면 이러한 서비스를 활용할 수 있을 뿐만 아니라 프로젝트의 Facebook 상태를 업데이트할 수도 있다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| Sample code for this article | j-tweettask.zip | 7KB | HTTP |
교육
-
Apache Ant는 사실상의 표준 Java 빌드 도구이다.
-
Ant tasks: Ant 매뉴얼에서
Writing Your Own Task를
포함한 Ant 태스크 관련 섹션을 살펴보자.
-
Twitter: Twitter를 시작하자.
-
Twitter API Wiki: 프로그래밍 방식으로 Twitter를 사용해 보자.
-
Twitter OAuth Client Registration: Twitter 계정을 열었다면 애플리케이션을 등록할 수 있다.
-
AOuth: 보안 인증을 위한 이 오픈 프로토콜에 대해 알아보자.
-
Twitter4J는 Twitter API를 위한 비공식 Java 라이브러리이다.
-
developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.
제품 및 기술 얻기
-
Twitter4J: Twitter4J를 다운로드할 수 있다.
토론
- My developerWorks 커뮤니티에 참여하자.
개발자가 이끌고 있는 블로그, 포럼, 그룹 및 Wiki를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다.
