/** * 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() { } }