/**
* Global Sensor Networks (GSN) Source Code
* Copyright (c) 2006-2016, Ecole Polytechnique Federale de Lausanne (EPFL)
*
* This file is part of GSN.
*
* GSN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GSN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GSN. If not, see <http://www.gnu.org/licenses/>.
*
* File: src/ch/epfl/gsn/vsensor/DataCleanVirtualSensor.java
*
* @author Sofiane Sarni
*
*/
package ch.epfl.gsn.vsensor;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.slf4j.LoggerFactory;
import ch.epfl.gsn.beans.DataTypes;
import ch.epfl.gsn.beans.StreamElement;
import ch.epfl.gsn.utils.Helpers;
import ch.epfl.gsn.utils.models.ModelFitting;
import ch.epfl.gsn.vsensor.AbstractVirtualSensor;
import ch.epfl.gsn.vsensor.BridgeVirtualSensor;
import org.slf4j.Logger;
import static ch.epfl.gsn.utils.models.ModelFitting.getModelIdFromString;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.TreeMap;
public class DataCleanVirtualSensor extends AbstractVirtualSensor {
private static final transient Logger logger = LoggerFactory.getLogger(BridgeVirtualSensor.class);
private static final String OPERATOR = "_operator";
private static final String DEPLOYMENT = "_deployment";
private static final String STATION = "_station";
private static final String SENSOR = "_sensor";
private static final String FROM = "_from";
private static final String TO = "_to";
private static final String DIRTINESS = "_dirtiness";
private static final String xml_template = "<metadata>\n" +
"\t<deployement>" + DEPLOYMENT + "</deployment>\n" +
"\t<operator>" + OPERATOR + "</operator>\n" +
"\t<station>" + STATION + "</station>\n" +
"\t<sensor>" + SENSOR + "</sensor>\n" +
"\t<from>" + FROM + "</from>\n" +
"\t<to>" + TO + "</to>\n" +
"\t<dirtiness>" + DIRTINESS + "</dirtiness>\n" +
"</metadata>";
private static final String PARAM_MODEL = "model";
private static final String PARAM_ERROR_BOUND = "error_bound";
private static final String PARAM_WINDOW_SIZE = "window_size";
// optional parameters
private static final String PARAM_METADATA_SERVER = "metadata_server_url"; // metadata server for posting metadata, e.g. http://www.example.com/dataclean.php
private static final String PARAM_METADATA_USERNAME = "user"; // username for metadata server
private static final String PARAM_METADATA_PASSWORD = "password"; // password for metadata server
private static final String PARAM_METADATA_OPERATOR = "operator"; // operator for metadata server, typically e-mail
private static final String PARAM_METADATA_DEPLOYEMENT = "deployment"; // name of deployemnt for metadata server
private static final String PARAM_METADATA_STATION = "station"; // name of station for metadata server
private static final String PARAM_METADATA_SENSOR = "sensor"; // name of station for metadata server
private static final String PARAM_LOGGING_INTERVAL = "logging-interval";
private static final int NORMAL_RESULT = 200; // normal result after http post
private int model = -1;
private int window_size = 0;
private double error_bound = 0;
private double[] stream;
private long[] timestamps;
private double[] processed;
private double[] dirtiness;
private double[] quality;
private String metadata_server_url;
private String username;
private String password;
private String operator;
private String deployement;
private String station;
private String sensor;
private String prepared_xml_request;
private boolean publish_to_metadata_server = false;
private boolean metadata_server_requieres_password = false;
private int bufferCount = 0;
private boolean logging_timestamps = false;
private long logging_interval = 1;
private long logging_counter = 0;
public boolean initialize() {
TreeMap<String, String> params = getVirtualSensorConfiguration().getMainClassInitialParams();
String model_str = params.get(PARAM_MODEL);
if (model_str == null) {
logger.warn("Parameter \"" + PARAM_MODEL + "\" not provided in Virtual Sensor file");
return false;
} else {
model = getModelIdFromString(model_str.trim());
if (model == -1) {
logger.warn("Parameter \"" + PARAM_MODEL + "\" incorrect in Virtual Sensor file");
return false;
}
}
String window_size_str = params.get(PARAM_WINDOW_SIZE);
if (window_size_str == null) {
logger.warn("Parameter \"" + PARAM_WINDOW_SIZE + "\" not provided in Virtual Sensor file");
return false;
} else try {
window_size = Integer.parseInt(window_size_str.trim());
} catch (NumberFormatException e) {
logger.warn("Parameter \"" + PARAM_WINDOW_SIZE + "\" incorrect in Virtual Sensor file");
return false;
}
if (window_size < 0) {
logger.warn("Window size should always be positive.");
return false;
}
String error_bound_str = params.get(PARAM_ERROR_BOUND);
if (error_bound_str == null) {
logger.warn("Parameter \"" + PARAM_ERROR_BOUND + "\" not provided in Virtual Sensor file");
return false;
} else try {
error_bound = Double.parseDouble(error_bound_str.trim());
} catch (NumberFormatException e) {
logger.warn("Parameter \"" + PARAM_ERROR_BOUND + "\" incorrect in Virtual Sensor file");
return false;
}
metadata_server_url = params.get(PARAM_METADATA_SERVER);
if (metadata_server_url != null) {
publish_to_metadata_server = true;
username = params.get(PARAM_METADATA_USERNAME);
password = params.get(PARAM_METADATA_PASSWORD);
if (username != null && password != null)
metadata_server_requieres_password = true;
operator = params.get(PARAM_METADATA_OPERATOR);
deployement = params.get(PARAM_METADATA_DEPLOYEMENT);
station = params.get(PARAM_METADATA_STATION);
sensor = params.get(PARAM_METADATA_SENSOR);
if ((operator == null) || (deployement == null) || (station == null) || (sensor == null)) {
logger.warn("A parameter required for publishing metadata is missing. Couldn't publish to metadata server.");
publish_to_metadata_server = false;
} else {
prepared_xml_request = xml_template.replaceAll(OPERATOR, operator);
prepared_xml_request = prepared_xml_request.replaceAll(DEPLOYMENT, deployement);
prepared_xml_request = prepared_xml_request.replaceAll(STATION, station);
prepared_xml_request = prepared_xml_request.replaceAll(SENSOR, sensor);
}
}
stream = new double[window_size];
timestamps = new long[window_size];
processed = new double[window_size];
dirtiness = new double[window_size];
quality = new double[window_size];
String logging_interval_str = params.get(PARAM_LOGGING_INTERVAL);
if (logging_interval_str != null) {
logging_timestamps = true;
try {
logging_interval = Integer.parseInt(logging_interval_str.trim());
} catch (NumberFormatException e) {
logger.warn("Parameter \"" + PARAM_LOGGING_INTERVAL + "\" incorrect in Virtual Sensor file");
logging_timestamps = false;
}
}
return true;
}
public void dataAvailable(String inputStreamName, StreamElement data) {
if (logging_timestamps && logging_counter % logging_interval == 0) {
logger.warn(getVirtualSensorConfiguration().getName() + " , " + logging_counter + " , " + System.currentTimeMillis());
}
logging_counter++;
if (bufferCount < window_size) {
timestamps[bufferCount] = data.getTimeStamp();
stream[bufferCount] = (Double) data.getData()[0];
bufferCount++;
} else {
ModelFitting.FitAndMarkDirty(model, error_bound, window_size, stream, timestamps, processed, dirtiness, quality);
for (int j = 0; j < processed.length; j++) {
StreamElement se = new StreamElement(new String[]{"stream", "processed", "dirtiness", "distance", "quality"},
new Byte[]{DataTypes.DOUBLE, DataTypes.DOUBLE, DataTypes.DOUBLE, DataTypes.DOUBLE, DataTypes.DOUBLE},
new Serializable[]{stream[j], processed[j], dirtiness[j], processed[j] - stream[j], quality[j]},
timestamps[j]);
dataProduced(se);
if ((dirtiness[j] > 0) && publish_to_metadata_server) {
try {
String request = outputAsXML(stream[j], processed[j], dirtiness[j], timestamps[j], timestamps[j]);
boolean result = httpPost(metadata_server_url, request);
if (!result) {
logger.warn("Couldn't post request => " + request);
} else {
logger.warn("Posted => " + request);
}
} catch (Exception e) {
logger.warn("Error while trying to post to metadata server. " + e.getMessage() + e);
}
}
}
bufferCount = 0;
}
}
public boolean httpPost(String url, String xmlString) {
boolean success = true;
PostMethod post = new PostMethod(url);
RequestEntity entity;
HttpClient httpclient = new HttpClient();
if (metadata_server_requieres_password) {
httpclient.getState().setCredentials(
new AuthScope(metadata_server_url, 80),
new UsernamePasswordCredentials(username, password)
);
}
try {
entity = new StringRequestEntity(xmlString, "text/xml", "ISO-8859-1");
post.setRequestEntity(entity);
int result = httpclient.executeMethod(post);
if (result != NORMAL_RESULT) {
logger.warn("Response status code: " + result);
// Display response
logger.warn("Response body: ");
logger.warn(post.getResponseBodyAsString());
success = false;
}
}
catch (UnsupportedEncodingException e) {
logger.warn(new StringBuilder("Unsupported encoding for: ").append(url).toString());
success = false;
}
catch (HttpException e) {
logger.warn(new StringBuilder("Error for: ")
.append(url).append(e).toString());
success = false;
}
catch (IOException e) {
logger.warn(new StringBuilder("Error for: ")
.append(url).append(e).toString());
success = false;
}
finally {
post.releaseConnection();
}
return success;
}
/*
* Returns an xml string from the given parameters
* */
public String outputAsXML(double stream, double processed, double dirtiness, long from_date, long to_date) throws Exception {
String output = prepared_xml_request.replaceAll(DIRTINESS, Double.toString(dirtiness));
output = output.replaceAll(FROM, Helpers.convertTimeFromLongToIso(from_date, "yyyy-MM-dd'T'HH:mm:ss.SSSZZ"));
output = output.replaceAll(TO, Helpers.convertTimeFromLongToIso(to_date, "yyyy-MM-dd'T'HH:mm:ss.SSSZZ"));
return output;
}
public void dispose() {
}
}