/** * Copyright (c) 2011-2014, OpenIoT * * This file is part of OpenIoT. * * OpenIoT is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3 of the License. * * OpenIoT 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenIoT. If not, see <http://www.gnu.org/licenses/>. * * Contact: OpenIoT mailto: info@openiot.eu * @author Sofiane Sarni * @author Ivo Dimitrov * @author Milos Stojanovic * @author Jean-Paul Calbimonte */ package org.openiot.gsn.http.restapi; import org.openiot.gsn.Main; import org.openiot.gsn.Mappings; import org.openiot.gsn.beans.DataField; import org.openiot.gsn.beans.VSensorConfig; import java.sql.*; import java.text.ParseException; import java.util.*; import org.apache.log4j.Logger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.openiot.gsn.utils.geo.GridTools; import org.apache.commons.collections.KeyValue; public class GetRequestHandler { private static transient Logger logger = Logger.getLogger(GetRequestHandler.class); private static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private static final long DEFAULT_PREVIEW_SIZE = 1000; public RestResponse getSensors() { RestResponse restResponse = new RestResponse(); restResponse.setHttpStatus(RestResponse.HTTP_STATUS_OK); restResponse.setResponse(getSensorsInfoAsJSON()); restResponse.setType(RestResponse.JSON_CONTENT_TYPE); return restResponse; } public String getSensorsInfoAsJSON() { JSONArray sensorsInfo = new JSONArray(); Iterator<VSensorConfig> vsIterator = Mappings.getAllVSensorConfigs(); while (vsIterator.hasNext()) { JSONObject aSensor = new JSONObject(); VSensorConfig sensorConfig = vsIterator.next(); String vs_name = sensorConfig.getName(); aSensor.put("name", vs_name); JSONArray listOfFields = new JSONArray(); for (DataField df : sensorConfig.getOutputStructure()) { String field_name = df.getName().toLowerCase(); String field_type = df.getType().toLowerCase(); if (field_type.indexOf("double") >= 0) { listOfFields.add(field_name); } } aSensor.put("fields", listOfFields); Double alt = 0.0; Double lat = 0.0; Double lon = 0.0; for (KeyValue df : sensorConfig.getAddressing()) { String adressing_key = df.getKey().toString().toLowerCase().trim(); String adressing_value = df.getValue().toString().toLowerCase().trim(); if (adressing_key.indexOf("altitude") >= 0) alt = Double.parseDouble(adressing_value); if (adressing_key.indexOf("longitude") >= 0) lon = Double.parseDouble(adressing_value); if (adressing_key.indexOf("latitude") >= 0) lat = Double.parseDouble(adressing_value); } aSensor.put("lat", lat); aSensor.put("lon", lon); aSensor.put("alt", alt); sensorsInfo.add(aSensor); } return sensorsInfo.toJSONString(); } public RestResponse getGeoDataForSensor() { RestResponse restResponse = new RestResponse(); return restResponse; } public RestResponse getMeasurementsForSensor() { RestResponse restResponse = new RestResponse(); return restResponse; } public RestResponse getGridData(String sensor, String date) { logger.warn(sensor); logger.warn(date); RestResponse restResponse = new RestResponse(); long timestamp = -1; try { timestamp = new java.text.SimpleDateFormat(ISO_FORMAT).parse(date).getTime(); } catch (ParseException e) { logger.warn("Timestamp is badly formatted: " + date); } if (timestamp == -1) { restResponse = RestResponse.CreateErrorResponse(RestResponse.HTTP_STATUS_BAD_REQUEST, "Malformed date for 'date' field."); logger.warn(restResponse.toString()); return restResponse; } restResponse.setHttpStatus(RestResponse.HTTP_STATUS_OK); restResponse.setType(RestResponse.JSON_CONTENT_TYPE); restResponse.setResponse(GridTools.executeQueryForGridAsJSON(sensor, timestamp)); logger.warn(restResponse.toString()); return restResponse; } public RestResponse getPreviewMeasurementsForSensorField(String sensor, String field, String from, String to, String size) { RestResponse restResponse = new RestResponse(); Vector<Double> stream = new Vector<Double>(); Vector<Long> timestamps = new Vector<Long>(); boolean errorFlag = false; long n = -1; long fromAsLong = -1; long toAsLong = -1; if (size == null) n = DEFAULT_PREVIEW_SIZE; else try { n = Long.parseLong(size); } catch (NumberFormatException e) { logger.error(e.getMessage(), e); } if (n < 1) n = DEFAULT_PREVIEW_SIZE; // size should be strictly larger than 0 if (from == null) { // no lower bound provided fromAsLong = getMinTimestampForSensorField(sensor, field); } else try { fromAsLong = new java.text.SimpleDateFormat(ISO_FORMAT).parse(from).getTime(); } catch (Exception e) { logger.error(e.getMessage(), e); errorFlag = true; } if (to == null) { // no lower bound provided toAsLong = getMaxTimestampForSensorField(sensor, field); } else try { toAsLong = new java.text.SimpleDateFormat(ISO_FORMAT).parse(to).getTime(); } catch (Exception e) { logger.error(e.getMessage(), e); errorFlag = true; } if (errorFlag) { restResponse = RestResponse.CreateErrorResponse(RestResponse.HTTP_STATUS_BAD_REQUEST, "Malformed date for from or to field."); return (restResponse); } errorFlag = !getDataPreview(sensor, field, fromAsLong, toAsLong, stream, timestamps, n); if (errorFlag) { restResponse = RestResponse.CreateErrorResponse(RestResponse.HTTP_STATUS_BAD_REQUEST, "Error in request."); return (restResponse); } JSONObject jsonResponse = new JSONObject(); jsonResponse.put("sensor", sensor); jsonResponse.put("field", field); jsonResponse.put("from", from); jsonResponse.put("to", to); JSONArray streamArray = new JSONArray(); JSONArray timestampsArray = new JSONArray(); JSONArray epochsArray = new JSONArray(); for (int i = 0; i < stream.size(); i++) { streamArray.add(stream.get(i)); timestampsArray.add(new java.text.SimpleDateFormat(ISO_FORMAT).format(new java.util.Date(timestamps.get(i)))); epochsArray.add(timestamps.get(i)); } jsonResponse.put("timestamps", timestampsArray); jsonResponse.put("values", streamArray); jsonResponse.put("epochs", epochsArray); restResponse.setHttpStatus(RestResponse.HTTP_STATUS_OK); restResponse.setType(RestResponse.JSON_CONTENT_TYPE); restResponse.setResponse(jsonResponse.toJSONString()); return restResponse; } private long getMinTimestampForSensorField(String sensor, String field) { return getTimestampBoundForSensorField(sensor, field, "min"); } private long getMaxTimestampForSensorField(String sensor, String field) { return getTimestampBoundForSensorField(sensor, field, "max"); } private long getTimestampBoundForSensorField(String sensor, String field, String boundType) { Connection conn = null; ResultSet resultSet = null; boolean result = true; long timestamp = -1; try { conn = Main.getDefaultStorage().getConnection(); StringBuilder query = new StringBuilder("select ").append(boundType).append("(timed) from ").append(sensor); resultSet = Main.getStorage(sensor).executeQueryWithResultSet(query, conn); if (resultSet.next()) { timestamp = resultSet.getLong(1); } } catch (SQLException e) { logger.error(e.getMessage(), e); result = false; } finally { Main.getStorage(sensor).close(resultSet); Main.getStorage(sensor).close(conn); } return timestamp; } private long getTableSize(String sensor) { Connection conn = null; ResultSet resultSet = null; boolean result = true; long timestamp = -1; try { conn = Main.getDefaultStorage().getConnection(); StringBuilder query = new StringBuilder("select count(*) from ").append(sensor); resultSet = Main.getStorage(sensor).executeQueryWithResultSet(query, conn); if (resultSet.next()) { timestamp = resultSet.getLong(1); } } catch (SQLException e) { logger.error(e.getMessage(), e); result = false; } finally { Main.getStorage(sensor).close(resultSet); Main.getStorage(sensor).close(conn); } return timestamp; } public RestResponse getMeasurementsForSensorField(String sensor, String field, String from, String to) { RestResponse restResponse = new RestResponse(); Vector<Double> stream = new Vector<Double>(); Vector<Long> timestamps = new Vector<Long>(); boolean errorFlag = false; long fromAsLong = 0; long toAsLong = 0; try { fromAsLong = new java.text.SimpleDateFormat(ISO_FORMAT).parse(from).getTime(); toAsLong = new java.text.SimpleDateFormat(ISO_FORMAT).parse(to).getTime(); } catch (Exception e) { logger.error(e.getMessage(), e); errorFlag = true; } if (errorFlag) { restResponse = RestResponse.CreateErrorResponse(RestResponse.HTTP_STATUS_BAD_REQUEST, "Malformed date for from or to field."); return (restResponse); } errorFlag = !getData(sensor, field, fromAsLong, toAsLong, stream, timestamps); if (errorFlag) { restResponse = RestResponse.CreateErrorResponse(RestResponse.HTTP_STATUS_BAD_REQUEST, "Error in request."); return (restResponse); } JSONObject jsonResponse = new JSONObject(); jsonResponse.put("sensor", sensor); jsonResponse.put("field", field); jsonResponse.put("from", from); jsonResponse.put("to", to); JSONArray streamArray = new JSONArray(); JSONArray timestampsArray = new JSONArray(); JSONArray epochsArray = new JSONArray(); for (int i = 0; i < stream.size(); i++) { streamArray.add(stream.get(i)); epochsArray.add(timestamps.get(i)); timestampsArray.add(new java.text.SimpleDateFormat(ISO_FORMAT).format(new java.util.Date(timestamps.get(i)))); } jsonResponse.put("timestamps", timestampsArray); jsonResponse.put("epochs", epochsArray); jsonResponse.put("values", streamArray); restResponse.setHttpStatus(RestResponse.HTTP_STATUS_OK); restResponse.setType(RestResponse.JSON_CONTENT_TYPE); restResponse.setResponse(jsonResponse.toJSONString()); return restResponse; } public boolean getData(String sensor, String field, long from, long to, Vector<Double> stream, Vector<Long> timestamps) { Connection conn = null; ResultSet resultSet = null; boolean result = true; try { conn = Main.getDefaultStorage().getConnection(); StringBuilder query = new StringBuilder("select timed, ") .append(field) .append(" from ") .append(sensor) .append(" where timed >= ") .append(from) .append(" and timed<=") .append(to); resultSet = Main.getStorage(sensor).executeQueryWithResultSet(query, conn); while (resultSet.next()) { //int ncols = resultSet.getMetaData().getColumnCount(); long timestamp = resultSet.getLong(1); double value = resultSet.getDouble(2); //logger.warn(ncols + " cols, value: " + value + " ts: " + timestamp); stream.add(value); timestamps.add(timestamp); } } catch (SQLException e) { logger.error(e.getMessage(), e); result = false; } finally { Main.getStorage(sensor).close(resultSet); Main.getStorage(sensor).close(conn); } return result; } public boolean getDataPreview(String sensor, String field, long from, long to, Vector<Double> stream, Vector<Long> timestamps, long size) { Connection conn = null; ResultSet resultSet = null; boolean result = true; long skip = getTableSize(sensor) / size; /* logger.warn("skip = " + skip); logger.warn("size = " + size); logger.warn("getTableSize(sensor) = " + getTableSize(sensor)); */ try { conn = Main.getDefaultStorage().getConnection(); StringBuilder query = new StringBuilder("select timed, ") .append(field) .append(" from ") .append(sensor); if (skip > 1) query.append(" where mod(pk,") .append(skip) .append(")=1"); resultSet = Main.getStorage(sensor).executeQueryWithResultSet(query, conn); while (resultSet.next()) { //int ncols = resultSet.getMetaData().getColumnCount(); long timestamp = resultSet.getLong(1); double value = resultSet.getDouble(2); //logger.warn(ncols + " cols, value: " + value + " ts: " + timestamp); stream.add(value); timestamps.add(timestamp); } } catch (SQLException e) { logger.error(e.getMessage(), e); result = false; } finally { Main.getStorage(sensor).close(resultSet); Main.getStorage(sensor).close(conn); } return result; } }