/**
* @version $Id: TweetConvert.java 1839 2014-04-16 02:33:51Z yukihiro-kinjyo $
*
* 2012/09/19 19:53:59
* @author yukihiro-kinjo
*
* Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved.
*/
package com.tida_okinawa.corona.webentry.twitter;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.ResourcesPlugin;
import twitter4j.Status;
import twitter4j.URLEntity;
import com.tida_okinawa.corona.common.Encoding;
/**
* Twitter投稿をCoronaで読み込める形式に変換するクラス
*
* @author yukihiro-kinjo
*
*/
public class TweetConvert {
private static final String THIS_PLUGIN_TEMP_DIR = "/.webEntry/temp/"; //$NON-NLS-1$
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; //$NON-NLS-1$
private String dataName;
private String productName;
private boolean screanNameVisible;
private boolean nameVisible;
private boolean dateVisible;
private boolean useRetweet;
private boolean tcoExpand;
private boolean followVisible;
private boolean followerVisible;
private boolean profileVisible;
/**
* コンストラクター
*
* @param dataName
* 問い合わせデータ名
* @param productName
* ターゲット名
* @param screanNameVisible
* ユーザー表示名を取得する場合true
* @param nameVisible
* ユーザーIDを取得する場合true
* @param dateVisible
* 投稿日時を取得する場合true
* @param useRetweet
* リツイート数を取得する場合はtrue
* @param followVisible
* ユーザーのフォロー数を取得する場合はtrue
* @param followerVisible
* ユーザーのフォロワー数を取得する場合はtrue
* @param profileVisible
* ユーザーのプロフィールを取得する場合はtrue
* @param tcoExpand
* t.co短縮URLを展開する場合はtrue
*/
public TweetConvert(String dataName, String productName, boolean screanNameVisible, boolean nameVisible, boolean dateVisible, boolean useRetweet,
boolean followVisible, boolean followerVisible, boolean profileVisible, boolean tcoExpand) {
super();
this.dataName = dataName;
this.productName = convertStringToCsvSafe(productName);
this.screanNameVisible = screanNameVisible;
this.nameVisible = nameVisible;
this.dateVisible = dateVisible;
this.useRetweet = useRetweet;
this.followVisible = followVisible;
this.followerVisible = followerVisible;
this.profileVisible = profileVisible;
this.tcoExpand = tcoExpand;
}
/**
* 文字列をCSVに取り込める状態に変換する
*
* @param source
* 変換する文字列
* @return 変換済み文字列
*/
private static String convertStringToCsvSafe(String source) {
if ((source == null) || source.isEmpty()) {
return ""; //$NON-NLS-1$
}
String converted = source;
/* 半角カンマとダブルクォーテーションと円記号を安全な文字に置き換える */
converted = converted.replace(',', ',').replace('\"', '”').replace('\\', '¥');
if (converted.contains("\n")) { //$NON-NLS-1$
return new StringBuilder(converted.length() + 2).append('"').append(converted).append('"').toString();
}
return converted;
}
/**
* ツイート群からリツイートを除去します
*
* @param tweets
* Twitter投稿
*/
public void filterRT(List<Status> tweets) {
Iterator<Status> it = tweets.iterator();
while (it.hasNext()) {
Status item = it.next();
if (item.isRetweet()) {
it.remove();
}
}
}
/**
* ツイート群からリプライを除去します
*
* @param tweets
* Twitter投稿
*/
public void filterReply(List<Status> tweets) {
Iterator<Status> it = tweets.iterator();
while (it.hasNext()) {
Status item = it.next();
long userid = item.getInReplyToUserId();
if (userid > 1) {
it.remove();
}
}
}
/**
* Twitter投稿をCSVファイルに変換し出力する
*
* @param tweets
* Twitter投稿
* @param path
* 保存ファイルパス
* @return 何らかの問題が発生した場合にfalseを返却
*/
public boolean convertTweetToCsvFile(List<Status> tweets, String path) {
File tempCsv = new File(path);
BufferedWriter writer = null;
try {
if (tempCsv.exists()) {
return false;
}
if (!(tempCsv.createNewFile())) {
return false;
}
if (!(tempCsv.canWrite())) {
return false;
}
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempCsv), Encoding.UTF_8.toString()));
/* Tweet 140 + any */
StringBuilder outputBuffer = new StringBuilder(256);
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
for (Status item : tweets) {
/* Memo getUser()がnullを返却する場合、Exceptionとなるのでnullチェック */
if (item.getUser() != null) {
if (screanNameVisible) {
/* Memo getNameに表示名が入っている。APIのバグか? */
outputBuffer.append(convertStringToCsvSafe(item.getUser().getName())).append(',');
}
if (nameVisible) {
/* Memo getScreenNameにユーザ名が入っている。APIのバグか? */
outputBuffer.append(convertStringToCsvSafe(item.getUser().getScreenName())).append(',');
}
} else {
outputBuffer.append(",,");
}
String tempBody = item.getText();
if (tcoExpand) {
tempBody = tcoExpand(tempBody, item);
}
outputBuffer.append(convertStringToCsvSafe(tempBody)).append(',');
if (dateVisible) {
outputBuffer.append(dateFormat.format(item.getCreatedAt())).append(',');
}
if (useRetweet) {
outputBuffer.append(item.getRetweetCount()).append(',');
}
if (followerVisible) {
outputBuffer.append(item.getUser().getFollowersCount()).append(',');
}
if (followVisible) {
outputBuffer.append(item.getUser().getFriendsCount()).append(',');
}
if (profileVisible) {
outputBuffer.append(convertStringToCsvSafe(item.getUser().getDescription())).append(',');
}
outputBuffer.append(productName);
writer.write(outputBuffer.toString());
writer.write('\n');
outputBuffer.setLength(0);
}
} catch (IOException e) {
return false;
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
return false;
}
}
}
return true;
}
private static String tcoExpand(String body, Status status) {
URLEntity[] entities = status.getURLEntities();//entity取得
for (URLEntity entity : entities) {
String ex_url = entity.getExpandedURL();//展開後のURL
String tco = entity.getURL();//t.co
Pattern p = Pattern.compile(tco);
Matcher m = p.matcher(body);
body = m.replaceAll(ex_url);//置換
}
return body;
}
/**
* Twitter投稿をデーターベースに取り込むための定義SQLを作成する
*
* @param path
* 保存ファイルパス
* @return 何らかの問題が発生した場合にfalseを返却
*/
public boolean createDefineSqlFile(String path) {
File tempSql = new File(path);
BufferedWriter writer = null;
try {
if (tempSql.exists()) {
return false;
}
if (!(tempSql.createNewFile())) {
return false;
}
if (!(tempSql.canWrite())) {
return false;
}
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempSql), Encoding.UTF_8.toString()));
StringBuilder outputBuffer = new StringBuilder(250);
outputBuffer.append("CREATE TABLE "); //$NON-NLS-1$
outputBuffer.append(dataName);
outputBuffer.append("\n(\n\tID INT NOT NULL AUTO_INCREMENT,\n"); //$NON-NLS-1$
if (screanNameVisible) {
outputBuffer.append("\tUSERNAME VARCHAR(64),\n"); //$NON-NLS-1$
}
if (nameVisible) {
outputBuffer.append("\tUSER VARCHAR(64),\n"); //$NON-NLS-1$
}
if (tcoExpand) {
outputBuffer.append("\tBODY TEXT,\n"); //$NON-NLS-1$
} else {
outputBuffer.append("\tBODY VARCHAR(256),\n"); //$NON-NLS-1$
}
if (dateVisible) {
outputBuffer.append("\tDATETIME DATETIME,\n"); //$NON-NLS-1$
}
if (useRetweet) {
outputBuffer.append("\tRETWEET MEDIUMINT,\n");
}
if (followerVisible) {
outputBuffer.append("\tFOLLOW MEDIUMINT,\n");
}
if (followVisible) {
outputBuffer.append("\tFOLLOWER MEDIUMINT,\n");
}
if (profileVisible) {
outputBuffer.append("\tPROFILE TEXT,\n");
}
outputBuffer.append("\tTARGET VARCHAR(128),\n\tPRIMARY KEY (ID)\n);"); //$NON-NLS-1$
writer.write(outputBuffer.toString());
} catch (IOException e) {
return false;
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
return false;
}
}
}
return true;
}
/**
* 変換テンポラリディレクトリ内のファイルを削除する。<br />
* 削除に失敗したファイルは、Java仮想マシン終了時に削除されるようスケジュールされる。
*/
public void deleteConvertTempFiles() {
/* Memo 複数保存できるようにするのでなければ、staticでかまわない */
String tempDirPath = getTempStoreDirPath();
if (tempDirPath == null) {
return;
}
File tempDir = new File(tempDirPath);
if (tempDir.exists()) {
File[] files = tempDir.listFiles();
for (File item : files) {
if (item.exists() && item.isFile()) {
if (!(item.delete())) {
item.deleteOnExit();
}
}
}
}
}
private static String stateLocation;
/**
* 自動実行用
* 通常、<code>ResourcesPlugin.getPlugin().getStateLocation()</code>
* で取れるパスを渡し、スタンドアロン起動時でもTwitterAccessTokenやテンポラリファイルの保存位置を取得できるようにする
*
* @param path
* アクセストークンの格納場所
*/
public static void setStateLocation(String path) {
stateLocation = path;
}
/**
* テンポラリファイルを保存するディレクトリへのパスを取得する
*
* @return テンポラリファイルを保存するパスを示す文字列
*/
public static String getTempStoreDirPath() {
String tempStoreDirPath;
if (ResourcesPlugin.getPlugin() != null) {
tempStoreDirPath = ResourcesPlugin.getPlugin().getStateLocation() + THIS_PLUGIN_TEMP_DIR;
} else {
/* スタンドアロン(自動実行)用の対策 */
tempStoreDirPath = stateLocation + THIS_PLUGIN_TEMP_DIR;
}
File directory = new File(tempStoreDirPath);
if (!(directory.exists())) {
if (!(directory.mkdirs())) {
return null;
}
}
return tempStoreDirPath;
}
}