package logbook.gui.logic;
import static javax.json.stream.JsonParser.Event.VALUE_STRING;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import logbook.config.AppConfig;
import logbook.constants.AppConstants;
import logbook.internal.LoggerHolder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/**
* Push通知
*
*/
public final class PushNotify {
/** 通知処理のキュー*/
private static Queue<String[]> notifyQueue = new ArrayBlockingQueue<String[]>(10);
/** ロガー */
private static final LoggerHolder LOG = new LoggerHolder(PushNotify.class);
/**
* 通知メッセージを処理待ちキューに入れます
*
* @param String メッセージ
* @param Sgring イベント名
* @param int priority
*/
public static void add(String notifymsg, String eventname, int priority) {
notifyQueue.offer(new String[] { notifymsg, eventname, String.valueOf(priority) });
}
/**
* 通知を実行します
*
* @param String 通知メッセージ
*/
public static void push(String[] msg) {
if (AppConfig.get().getNotifyProwl()) {
pushProwl(msg);
}
if (AppConfig.get().getNotifyNMA()) {
pushNMA(msg);
}
if (AppConfig.get().getNotifyImKayac()) {
pushImKayac(msg);
}
}
/**
* Prowlによる通知
*
* @param String 通知メッセージ
*/
private static void pushProwl(String[] msg) {
StringBuilder postdata = new StringBuilder();
String result = null;
addPOSTData(postdata, "apikey", AppConfig.get().getProwlAPIKey());
addPOSTData(postdata, "application", AppConstants.PUSH_NOTIFY_APPNAME);
addPOSTData(postdata, "description", msg[0]);
addPOSTData(postdata, "event", msg[1]);
addPOSTData(postdata, "priority", msg[2]);
try {
result = HttpPOSTRequest(AppConstants.PUSH_NOTIFY_PROWL_URI, postdata);
if (result != "") {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inStream = new InputSource();
inStream.setCharacterStream(new StringReader(result));
Document doc = db.parse(inStream);
Element root = doc.getDocumentElement();
if (root.getTagName().equals("prowl")) {
Node item = root.getFirstChild();
String childName = item.getNodeName();
if (!childName.equals("success")) {
LOG.get().warn("Prowl による Push 通知に失敗しました。", result);
}
}
}
} catch (Exception e) {
LOG.get().warn("Prowl による Push 通知に失敗しました。", e);
}
}
/**
* NMAによる通知
*
* @param String 通知メッセージ
*/
private static void pushNMA(String msg[]) {
StringBuilder postdata = new StringBuilder();
String result = null;
addPOSTData(postdata, "apikey", AppConfig.get().getNMAAPIKey());
addPOSTData(postdata, "application", AppConstants.PUSH_NOTIFY_APPNAME);
addPOSTData(postdata, "description", msg[0]);
addPOSTData(postdata, "event", msg[1]);
addPOSTData(postdata, "priority", msg[2]);
try {
result = HttpPOSTRequest(AppConstants.PUSH_NOTIFY_NMA_URI, postdata);
if (result != "") {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inStream = new InputSource();
inStream.setCharacterStream(new StringReader(result));
Document doc = db.parse(inStream);
Element root = doc.getDocumentElement();
if (root.getTagName().equals("nma")) {
Node item = root.getFirstChild();
String childName = item.getNodeName();
if (!childName.equals("success")) {
LOG.get().warn("NMA による Push 通知に失敗しました。", result);
}
}
}
} catch (Exception e) {
LOG.get().warn("NMA による Push 通知に失敗しました。", e);
}
}
/**
* ImKayacによる通知
*
* @param String 通知メッセージ
*/
private static void pushImKayac(String msg[]) {
StringBuilder postdata = new StringBuilder();
String result = null;
try {
if (AppConfig.get().getImKayacPrivateKey() != "") {
MessageDigest md = MessageDigest.getInstance("SHA-1");
String sigstr = msg[0] + AppConfig.get().getImKayacPrivateKey();
StringBuffer buffer = new StringBuffer();
md.update(sigstr.getBytes("UTF-8"));
byte[] digest = md.digest();
for (int i = 0; i < digest.length; i++) {
String tmpStr = Integer.toHexString(digest[i] & 0xff);
if (tmpStr.length() == 1) {
buffer.append('0').append(tmpStr);
} else {
buffer.append(tmpStr);
}
}
String sig = buffer.toString();
addPOSTData(postdata, "sig", sig);
addPOSTData(postdata, "message", msg[0]);
result = HttpPOSTRequest(AppConstants.PUSH_NOTIFY_IMKAYAC_URI + AppConfig.get().getImKayacUserName(),
postdata);
} else {
addPOSTData(postdata, "message", msg[0]);
addPOSTData(postdata, "password", AppConfig.get().getImKayacPasswd());
result = HttpPOSTRequest(AppConstants.PUSH_NOTIFY_IMKAYAC_URI + AppConfig.get().getImKayacUserName(),
postdata);
}
JsonParser parser = Json.createParser(new StringReader(result));
boolean postflag = false;
while (parser.hasNext()) {
JsonParser.Event event = parser.next();
if (event == VALUE_STRING) {
if (parser.getString() == "posted") {
postflag = true;
}
}
}
if (postflag = false) {
LOG.get().warn("ImKayac による Push 通知に失敗しました", result);
}
} catch (Exception e) {
LOG.get().warn("ImKayac による Push 通知に失敗しました", e);
}
}
/**
* HTTP POSTリクエストの送信
*
* @param String URL
* @param StringBuilder POSTデータ
*
*/
private static String HttpPOSTRequest(String posturi, StringBuilder postsb) {
HttpURLConnection connection = null;
URL url = null;
String postdata = postsb.toString();
try {
url = new URL(posturi);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(postdata);
writer.flush();
writer.close();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
StringBuffer response = new StringBuffer();
String line = null;
while ((line = in.readLine()) != null) {
response.append(line);
}
String resultStr = response.toString();
return resultStr;
} else {
LOG.get().warn("Push 通知に失敗しました。HTTPレスポンスコード:" + connection.getResponseCode());
return "";
}
} catch (Exception e) {
LOG.get().warn("Push 通知に失敗しました", e);
return "";
}
}
/**
* POSTデータの生成
* @param sb StringBuilder url-form-encoded data
* @param name Key name
* @param value Value
*/
private static void addPOSTData(StringBuilder sb, String name, String value)
{
if (sb.length() > 0) {
sb.append("&");
}
try {
sb.append(URLEncoder.encode(name, "UTF-8"));
sb.append("=");
sb.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
LOG.get().warn("POSTデータの生成に失敗しました。", e);
}
}
/**
* Push通知用スレッド
*
*/
public static class PushNotifyThread extends Thread {
/** ロガー */
private static final LoggerHolder LOG = new LoggerHolder(PushNotifyThread.class);
/**
* 通知スレッド
*/
public PushNotifyThread() {
this.setName("logbook_pushnotify.push_thread");
}
@Override
public void run() {
try {
while (true) {
String msg[] = notifyQueue.poll();
if (msg != null) {
push(msg);
}
Thread.sleep(500);
}
} catch (Exception e) {
LOG.get().fatal("スレッドが異常終了しました", e);
throw new RuntimeException(e);
}
}
}
}