/**
* Global Sensor Networks (GSN) Source Code
* Copyright (c) 2006-2014, Ecole Polytechnique Federale de Lausanne (EPFL)
* <p/>
* This file is part of GSN.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* You should have received a copy of the GNU General Public License
* along with GSN. If not, see <http://www.gnu.org/licenses/>.
* <p/>
* File: gsn-tiny/src/tinygsn/model/vsensor/AbstractVirtualSensor.java
*
* @author Do Ngoc Hoan
*/
package tinygsn.model.vsensor;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.Pair;
import com.google.android.gms.maps.model.LatLng;
import org.epfl.locationprivacy.adaptiveprotection.AdaptiveProtectionInterface;
import org.epfl.locationprivacy.util.Utils;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import tinygsn.beans.DataField;
import tinygsn.beans.InputStream;
import tinygsn.beans.StaticData;
import tinygsn.beans.StreamElement;
import tinygsn.beans.StreamSource;
import tinygsn.beans.VSensorConfig;
import tinygsn.model.utils.ParameterType;
import tinygsn.model.utils.Parameter;
import tinygsn.model.wrappers.AndroidGPSWrapper;
import tinygsn.storage.db.SqliteStorageManager;
import tinygsn.utils.Logging;
public abstract class AbstractVirtualSensor implements Serializable {
/**
*
*/
private static final long serialVersionUID = -94046553047097162L;
/*public static final String[] VIRTUAL_SENSOR_LIST = {"bridge", "notification", "activity", "MET compute", "O3 calibrate", "Exposure"};
public static final String[] VIRTUAL_SENSOR_CLASSES = {"tinygsn.model.vsensor.BridgeVirtualSensor", "tinygsn.model.vsensor.NotificationVirtualSensor",
"tinygsn.model.vsensor.ActivityVirtualSensor", "tinygsn.model.vsensor.METVirtualSensor", "tinygsn.model.vsensor.CalibrateOzoneVirtualSensor",
"tinygsn.model.vsensor.ExposureVirtualSensor"};
*/
public static final String[] VIRTUAL_SENSOR_LIST = {"bridge", "notification"};
public static final String[] VIRTUAL_SENSOR_CLASSES = {"tinygsn.model.vsensor.BridgeVirtualSensor", "tinygsn.model.vsensor.NotificationVirtualSensor"};
private transient SqliteStorageManager storage = new SqliteStorageManager();
private VSensorConfig config;
public InputStream is;
private String LOGTAG = "AbstractVirtualSensor";
private String loggingSubFolder = "";
private long logTime = 0;
public boolean initialize_wrapper() {
initLog(config.getName());
HashMap<String, String> param = storage.getSetting("vsensor:" + config.getName() + ":");
for (Entry<String, String> e : param.entrySet()) {
initParameter(e.getKey(), e.getValue());
}
return initialize();
}
public ArrayList<Parameter> getParameters() {
return new ArrayList<>();
}
public ArrayList<Parameter> getParameters(ArrayList<String> params) {
return getPrivacyParameters();
}
/**
* Add parameters for privacy
*
* @return
*/
public ArrayList<Parameter> getPrivacyParameters() {
ArrayList<Parameter> parameters = getParameters();
// TODO : show it only when GPS is selected
// GPS
parameters.add(0, new Parameter("GPS Privacy", ParameterType.CHECKBOX));
return parameters;
}
public abstract boolean initialize();
protected void initParameter(String key, String value) {
}
// synchronized
protected void dataProduced(StreamElement streamElement, boolean adjust) {
log("dataProduced_" + config.getName(), "===========================================");
log("dataProduced_" + config.getName(), "Data produced (saved in db) for stream element : " + streamElement.toString());
long startTime = System.currentTimeMillis();
try {
storage.executeInsert("vs_" + config.getName(), null, streamElement);
} catch (SQLException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
log("dataProduced_" + config.getName(), "End of produced data for stream element in " + (endTime - startTime) + " ms.");
}
/**
* Calls the dataProduced with adjust = false.
*
* @param streamElement
*/
protected synchronized void dataProduced(StreamElement streamElement) {
dataProduced(streamElement, true);
}
/*
* First checks compatibility of the data type of each output data item in the
* stream element with the defined output in the VSD file. (this check is done
* regardless of the value for adjust flag).
* <p/>
* If the adjust flag is set to true, the method checks the newly generated
* stream element and returns true if and only if the number of data items is
* equal to the number of output data structure defined for this virtual
* sensor. If the adjust=true, then this test is not performed.
*
* @param se
* @param outputStructure
* @param adjust default is false.
* @return
*/
/*private static boolean compatibleStructure(StreamElement se,
DataField[] outputStructure, boolean adjust) {
// if (!adjust && outputStructure.length != se.getFieldNames().length ) {
// logger.warn(
// "Validation problem, the number of field doesn't match the number of output data strcture of the virtual sensor"
// );
// return false;
// }
// int i =-1;
// for (DataField field: outputStructure) {
// Serializable value = se.getData(field.getName());
// i++;
// if (value==null)
// continue;
// if ( ( ( field.getDataTypeID() == DataTypes.BIGINT ||
// field.getDataTypeID() == DataTypes.DOUBLE ||
// field.getDataTypeID() == DataTypes.INTEGER||
// field.getDataTypeID() == DataTypes.SMALLINT||
// field.getDataTypeID() == DataTypes.TINYINT ) &&!(value instanceof
// Number))
// ||
// ( (field.getDataTypeID() == DataTypes.VARCHAR || field.getDataTypeID() ==
// DataTypes.CHAR) && !(value instanceof String)) ||
// ( (field.getDataTypeID() == DataTypes.BINARY) && !(value instanceof
// byte[]))
// ){
// logger.warn( "Validation problem for output field >" + field.getName( ) +
// ", The field type declared as >" +
// field.getType()+"< while in VSD it is defined as >"+DataTypes.TYPE_NAMES[outputStructure[
// i ].getDataTypeID( )]);
// return false;
// }
// }
return true;
}*/
public DataField[] getOutputStructure(DataField[] in) {
return in;
}
/**
* Called when the container want to stop the pool and remove it's resources.
* The container will call this method once on each install of the virtual
* sensor in the pool. The progrmmer should release all the resouce used by
* this virtual sensor instance in this method specially those resouces
* aquired during the <code>initialize</code> call.
* <p/>
* Called once while finalizing an instance of the virtual sensor
*/
public abstract void dispose();
/**
* @return the virtualSensorConfiguration
*/
public VSensorConfig getVirtualSensorConfiguration() {
if (config == null) {
throw new RuntimeException("The VirtualSensorParameter is not set !!!");
}
return config;
}
/**
* @param virtualSensorConfiguration the virtualSensorConfiguration to set
*/
public void setVirtualSensorConfiguration(VSensorConfig virtualSensorConfiguration) {
this.config = virtualSensorConfiguration;
}
/**
* This method is going to be called by the container when one of the input
* streams has a data to be delivered to this virtual sensor. After receiving
* the data, the virtual sensor can do the processing on it and this
* processing could possibly result in producing a new stream element in this
* virtual sensor in which case the virtual sensor will notify the container
* by simply adding itself to the list of the virtual sensors which have
* produced data. (calling <code>container.publishData(this)</code>. For more
* information please check the <code>AbstractVirtalSensor</code>
*
* @param inputStreamName is the name of the input stream as specified in the configuration
* file of the virtual sensor.
* @param streamElement is actually the real data which is produced by the input stream
* and should be delivered to the virtual sensor for possible
* processing.
*/
public abstract void dataAvailable(String inputStreamName, StreamElement streamElement);
public void dataAvailable(String inputStreamName,
ArrayList<StreamElement> data) {
if (!data.isEmpty()) dataAvailable(inputStreamName, data.get(data.size() - 1));
}
/**
* Transform a precise GPS position into an area depending
* on privacy settings
* @param streamElement
* @return a streamElement containing the obfuscated area
*/
private StreamElement anonymizeGPS(StreamElement streamElement) {
String prefix = "vsensor:" + getVirtualSensorConfiguration().getName();
HashMap settings = storage.getSetting(prefix);
boolean gpsPrivacy;
if (settings.get(prefix + ":" + "GPS Privacy") != null && (settings.get(prefix + ":" + "GPS Privacy")).equals("true")) {
gpsPrivacy = true;
} else {
gpsPrivacy = false;
}
if (gpsPrivacy) {
AdaptiveProtectionInterface prot = StaticData.getAdaptiveProtectionInterface();
// get data from streamElement for obfuscate them
double latitude = (double) streamElement.getData("latitudeTopLeft");
double longitude = (double) streamElement.getData("longitudeTopLeft");
Pair<LatLng, LatLng> obfuscatedPosition = prot.getObfuscationLocation(new LatLng(latitude, longitude), streamElement.getTimeStamp());
streamElement = new StreamElement(streamElement.getFieldNames(), streamElement.getFieldTypes(),
new Serializable[]{obfuscatedPosition.first.latitude, obfuscatedPosition.first.longitude,
obfuscatedPosition.second.latitude, obfuscatedPosition.second.longitude});
}
return streamElement;
}
/**
* Anonymize data
* @param inputStreamName
* @param streamElement
* @return data anonymized
*/
public StreamElement anonymizeData(String inputStreamName, StreamElement streamElement) {
StreamElement anonymizedStreamElement;
if (inputStreamName.equals(tinygsn.model.wrappers.AndroidGPSWrapper.class.getCanonicalName()) ||
inputStreamName.equals(tinygsn.model.wrappers.GPSFileWrapper.class.getCanonicalName())) {
anonymizedStreamElement = anonymizeGPS(streamElement);
} else {
anonymizedStreamElement = streamElement;
}
return anonymizedStreamElement;
}
synchronized public void start() {
config = StaticData.findConfig(config.getId());
if (!config.getRunning()) {
config.setRunning(true);
}
}
synchronized public void stop() {
config = StaticData.findConfig(config.getId());
if (config.getRunning()) {
config.setRunning(false);
}
}
public VSensorConfig getConfig() {
return config;
}
public void delete() {
stop();
for (StreamSource streamSource : config.getInputStream().getSources()) {
streamSource.dispose();
}
dispose();
}
protected void initLog(String logtag) {
/*if ((boolean) Utils.getBuildConfigValue(StaticData.globalContext, "LOGGING")) {
loggingSubFolder = Logging.createNewLoggingFolder(StaticData.globalContext, logtag);
}*/
}
protected void log(String logtag, String s) {
/*if ((boolean) Utils.getBuildConfigValue(StaticData.globalContext, "LOGGING")) {
long startlogging = System.currentTimeMillis();
Log.d(logtag, System.currentTimeMillis() + " : " + s);
Logging.appendLog(loggingSubFolder, logtag + ".txt", s, StaticData.globalContext);
logTime = (System.currentTimeMillis() - startlogging);
}*/
}
}