/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.action.nma.internal;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.openhab.core.scriptengine.action.ActionDoc;
import org.openhab.core.scriptengine.action.ParamDoc;
import org.openhab.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* This class contains the methods that are made available in scripts and rules
* for NotifyMyAndroid.
*
* @author Till Klocke
* @since 1.3.0
*/
public class NotifyMyAndroid {
private static final Logger logger = LoggerFactory.getLogger(NotifyMyAndroid.class);
private final static String API_URL = "https://www.notifymyandroid.com/publicapi/notify";
private final static String CONTENT_TYPE = "application/x-www-form-urlencoded";
private final static String UTF_8_ENCODING = "UTF-8";
public static final String MESSAGE_KEY_API_KEY = "apikey";
public static final String MESSAGE_KEY_APP = "application";
public static final String MESSAGE_KEY_EVENT = "event";
public static final String MESSAGE_KEY_DESC = "description";
public static final String MESSAGE_KEY_PRIORITY = "priority";
public static final String MESSAGE_KEY_DEV_KEY = "developerkey";
public static final String MESSAGE_KEY_URL = "url";
public static final String MESSAGE_KEY_CONTENT_TYPE = "content-type";
static String appName = "openHAB";
static String apiKey;
static String url;
static String developerKey;
static int timeout = 10000;
static int defaultPriotiy = 0;
static String defaultUrl;
@ActionDoc(text = "Send a notification to your Android device using the default api key", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description) {
return notifyMyAndroid(apiKey, event, description);
}
@ActionDoc(text = "Send a notification to your Android device using the default api key", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description,
@ParamDoc(name = "priority", text = "The priority of the notification") int priority) {
return notifyMyAndroid(apiKey, event, description, priority);
}
@ActionDoc(text = "Send a notification to your Android device", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(
@ParamDoc(name = "apiKey", text = "apiKey to use for the notification") String apiKey,
@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description) {
return notifyMyAndroid(apiKey, event, description, defaultPriotiy);
}
@ActionDoc(text = "Send a notification to your Android device", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(
@ParamDoc(name = "apiKey", text = "apiKey to use for the notification") String apiKey,
@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description,
@ParamDoc(name = "priority", text = "The priority of the notification") int priority) {
return notifyMyAndroid(apiKey, event, description, priority, null);
}
@ActionDoc(text = "Send a notification to your Android device", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(
@ParamDoc(name = "apiKey", text = "apiKey to use for the notification") String apiKey,
@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description,
@ParamDoc(name = "priority", text = "The priority of the notification") int priority,
@ParamDoc(name = "url", text = "An URL representing this event") String url) {
return notifyMyAndroid(apiKey, event, description, priority, url, false);
}
// Example
@ActionDoc(text = "Send a notification to your Android device", returns = "<code>true</code>, if successful and <code>false</code> otherwise.")
public static boolean notifyMyAndroid(
@ParamDoc(name = "apiKey", text = "apiKey to use for the notification") String apiKey,
@ParamDoc(name = "event", text = "The event to notify") String event,
@ParamDoc(name = "description", text = "A description of the event to notify") String description,
@ParamDoc(name = "priority", text = "The priority of the notification") int priority,
@ParamDoc(name = "url", text = "An URL representing this event") String url,
@ParamDoc(name = "html", text = "Should the description of the event be interpreted as html") boolean html) {
StringBuilder data = new StringBuilder();
try {
if (!StringUtils.isEmpty(apiKey)) {
addEncodedParameter(data, MESSAGE_KEY_API_KEY, apiKey);
} else if (!StringUtils.isEmpty(NotifyMyAndroid.apiKey)) {
addEncodedParameter(data, MESSAGE_KEY_API_KEY, NotifyMyAndroid.apiKey);
} else {
logger.error("No api key specified");
return false;
}
addEncodedParameter(data, MESSAGE_KEY_APP, appName);
if (!StringUtils.isEmpty(description)) {
addEncodedParameter(data, MESSAGE_KEY_DESC, description);
} else {
logger.error("Description of event is missing");
return false;
}
addEncodedParameter(data, MESSAGE_KEY_DEV_KEY, developerKey);
if (!StringUtils.isEmpty(event)) {
addEncodedParameter(data, MESSAGE_KEY_EVENT, event);
} else {
logger.error("Event is empty");
return false;
}
addEncodedParameter(data, MESSAGE_KEY_PRIORITY, String.valueOf(priority));
if (!StringUtils.isEmpty(url)) {
addEncodedParameter(data, MESSAGE_KEY_URL, url);
} else if (!StringUtils.isEmpty(defaultUrl)) {
addEncodedParameter(data, MESSAGE_KEY_URL, defaultUrl);
}
if (html) {
addEncodedParameter(data, MESSAGE_KEY_CONTENT_TYPE, "text/html");
}
String content = data.toString();
logger.debug("Executing post to " + API_URL + " with the following content: " + content);
String response = HttpUtil.executeUrl("POST", API_URL, IOUtils.toInputStream(content), CONTENT_TYPE,
timeout);
logger.debug("Raw response: " + response);
try {
String responseMessage = parseResponse(response);
if (StringUtils.isEmpty(responseMessage)) {
return true;
} else {
logger.error("Received error message from NMA: " + responseMessage);
return false;
}
} catch (Exception e) {
logger.warn("Can't parse response from NMA: " + response, e);
return false;
}
} catch (Exception e) {
logger.error("An error occured while notifying your android", e);
return false;
}
}
private static String parseResponse(String response)
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inStream = new InputSource();
inStream.setCharacterStream(new StringReader(response));
Document doc = db.parse(inStream);
Element root = doc.getDocumentElement();
String lastError = null;
if (root.getTagName().equals("nma")) {
Node item = root.getFirstChild();
String childName = item.getNodeName();
if (!childName.equals("success")) {
lastError = item.getFirstChild().getNodeValue();
}
}
return lastError;
}
private static void addEncodedParameter(StringBuilder sb, String name, String value)
throws UnsupportedEncodingException {
if (StringUtils.isEmpty(value)) {
return;
}
if (sb.length() > 0) {
sb.append("&");
}
sb.append(URLEncoder.encode(name, UTF_8_ENCODING));
sb.append("=");
sb.append(URLEncoder.encode(value, UTF_8_ENCODING));
}
}