/** * 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 */ package org.openiot.gsn.http; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.index.strtree.STRtree; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; import org.openiot.gsn.Main; import org.openiot.gsn.Mappings; import org.openiot.gsn.beans.VSensorConfig; import org.openiot.gsn.http.ac.UserUtils; import org.apache.log4j.Logger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.*; import java.util.*; public class DynamicGeoDataServlet extends HttpServlet { private static GeometryFactory geometryFactory; private static STRtree geoIndex; private static transient Logger logger = Logger.getLogger(DynamicGeoDataServlet.class); private static final String SEPARATOR = ","; private static final String NEWLINE = "\n"; private List<SensorGeoReading> sensorReadingsList = new Vector<SensorGeoReading>(); private HashMap<String, SensorGeoReading> sensorReadingsHash = new HashMap<String, SensorGeoReading>(); private List<String> sensorsWithinEnvelope = new ArrayList<String>(); private boolean debugMode = false; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String env = HttpRequestUtils.getStringParameter("env", null, request); // e.g. "POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"; String field = HttpRequestUtils.getStringParameter("field", null, request); String timed = HttpRequestUtils.getStringParameter("timed", null, request); String query = HttpRequestUtils.getStringParameter("query", "value", request); String username = HttpRequestUtils.getStringParameter("username", null, request); String password = HttpRequestUtils.getStringParameter("password", null, request); String debugModeStr = HttpRequestUtils.getStringParameter("debug", "false", request); String format = HttpRequestUtils.getStringParameter("format", "csv", request); if (debugModeStr.equalsIgnoreCase("true")) debugMode = true; else debugMode = false; List<String> allowedSensors = new Vector<String>(); if (Main.getContainerConfig().isAcEnabled()) { if (username != null && password != null) { if (UserUtils.allowUserToLogin(username, password) == null) { response.getWriter().write("ERROR: incorrect login for user '" + username + "'. Check your credentials."); return; } else { // user authenticated correctly allowedSensors = UserUtils.getAllowedVirtualSensorsForUser(username, password, getAllSensors()); } } else { // username or password is null response.getWriter().write("ERROR: username and password required."); return; } } else { // No access control allowedSensors = getAllSensors(); } StringBuilder sb = new StringBuilder(); StringBuilder sqlQueryStr = new StringBuilder(); if (timed.equalsIgnoreCase("latest")) { for (int i = 0; i < allowedSensors.size(); i++) { sqlQueryStr.append("select '" + allowedSensors.get(i) + "'") .append(" as name, timed, ") .append(field) .append(", latitude, longitude, altitude ") .append(" from ") .append(allowedSensors.get(i)) .append(" where timed = ( select max(timed) from ") .append(allowedSensors.get(i)) .append(" )"); if (i < allowedSensors.size() - 1) sqlQueryStr.append("\n union \n"); } } else { // timed explicitly specified for (int i = 0; i < allowedSensors.size(); i++) { sqlQueryStr.append("select '" + allowedSensors.get(i) + "'") .append(" as name, timed, ") .append(field) .append(", latitude, longitude, altitude ") .append(" from ") .append(allowedSensors.get(i)) .append(" where timed = ") .append(timed); if (i < allowedSensors.size() - 1) sqlQueryStr.append("\n union \n"); } } sb.append("env = " + env) .append("\ndebug = " + debugMode) .append("\n") .append("field = " + field) .append("\n") .append("timed = " + timed) .append("\n") .append("query = " + query) .append("\n") .append("all_sensors = " + sensorsToString(allowedSensors)) .append("\n") .append(sqlQueryStr) .append("\n# -------\n") .append(executeQuery(sqlQueryStr.toString(), field)); if (debugMode) response.getWriter().write(sb.toString()); logger.warn(sb.toString()); buildGeoIndex(); try { sensorsWithinEnvelope = getListOfSensorsWithinEnvelope(env); } catch (ParseException e) { logger.warn(e.getMessage(), e); response.getWriter().write("ERROR: cannot create geographic index"); return; } if (debugMode) { response.getWriter().write("\nSensors within envelope: "); response.getWriter().write(sensorsToString(sensorsWithinEnvelope)); response.getWriter().write("\n"); } //response.getWriter().write(formatter("default", field)); response.getWriter().write(formatter(format, field)); } public String formatter(String format, String field) { StringBuilder sb = new StringBuilder(); if (format.equalsIgnoreCase("json")) { JSONArray sensorsReadings = new JSONArray(); for (String aSensor : sensorsWithinEnvelope) { JSONObject aSensorReading = new JSONObject(); aSensorReading.put("name", sensorReadingsHash.get(aSensor).sensorName); aSensorReading.put("latitude", sensorReadingsHash.get(aSensor).coordinates.getY()); aSensorReading.put("longitude", sensorReadingsHash.get(aSensor).coordinates.getX()); aSensorReading.put("timed", sensorReadingsHash.get(aSensor).timestamp); aSensorReading.put(field, sensorReadingsHash.get(aSensor).value); sensorsReadings.add(aSensorReading); } return sensorsReadings.toJSONString(); } else if (format.equalsIgnoreCase("xml")) { sb.append("<geodata>\n"); for (String aSensor : sensorsWithinEnvelope) { sb.append("\t<sensor name=\"") .append(sensorReadingsHash.get(aSensor).sensorName) .append("\" latitude=\"") .append(sensorReadingsHash.get(aSensor).coordinates.getY()) .append("\" longitude=\"") .append(sensorReadingsHash.get(aSensor).coordinates.getX()) .append("\" timed=\"") .append(sensorReadingsHash.get(aSensor).timestamp) .append("\" field=\"") .append(field) .append("\">") .append(sensorReadingsHash.get(aSensor).value) .append("</sensor>\n"); } sb.append("</geodata>"); return sb.toString(); } else if (format.equalsIgnoreCase("native")) { for (String aSensor : sensorsWithinEnvelope) { sb.append(sensorReadingsHash.get(aSensor).toString() + "\n"); } return sb.toString(); } else if (format.equalsIgnoreCase("csv")) { sb.append("# name, latitude, longitude, timed, " + field + "\n"); for (String aSensor : sensorsWithinEnvelope) { sb.append(sensorReadingsHash.get(aSensor).sensorName + ", " + sensorReadingsHash.get(aSensor).coordinates.getY() + ", " + sensorReadingsHash.get(aSensor).coordinates.getX() + ", " + sensorReadingsHash.get(aSensor).timestamp + ", " + +sensorReadingsHash.get(aSensor).value + "\n"); } return sb.toString(); } else { //default is CSV sb.append("# name, latitude, longitude, timed, " + field + "\n"); for (String aSensor : sensorsWithinEnvelope) { sb.append(sensorReadingsHash.get(aSensor).sensorName + ", " + sensorReadingsHash.get(aSensor).coordinates.getY() + ", " + sensorReadingsHash.get(aSensor).coordinates.getX() + ", " + sensorReadingsHash.get(aSensor).timestamp + ", " + +sensorReadingsHash.get(aSensor).value + "\n"); } return sb.toString(); } } public List<String> getAllSensors() { Iterator iter = Mappings.getAllVSensorConfigs(); List<String> sensors = new Vector<String>(); while (iter.hasNext()) { VSensorConfig sensorConfig = (VSensorConfig) iter.next(); //Double longitude = sensorConfig.getLongitude(); //Double latitude = sensorConfig.getLatitude(); //Double altitude = sensorConfig.getAltitude(); String sensor = sensorConfig.getName(); sensors.add(sensor); } return sensors; } public String sensorsToString(List<String> sensors) { StringBuilder sensorsAsString = new StringBuilder(); for (String sensor : sensors) { sensorsAsString.append(sensor); sensorsAsString.append(SEPARATOR); } if (sensorsAsString.length() > 0) sensorsAsString.setLength(sensorsAsString.length() - 1); // remove the last SEPARATOR return sensorsAsString.toString(); } public String executeQuery(String query, String fieldName) { sensorReadingsList.clear(); // reset global sensor readings geometryFactory = new GeometryFactory(); StringBuilder sb = new StringBuilder(); Connection connection = null; try { connection = Main.getDefaultStorage().getConnection(); Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet results = statement.executeQuery(query); ResultSetMetaData metaData; // Additional information about the results int numCols, numRows; // How many rows and columns in the table metaData = results.getMetaData(); // Get metadata on them numCols = metaData.getColumnCount(); // How many columns? results.last(); // Move to last row numRows = results.getRow(); // How many rows? String s; sb.append("# "); for (int col = 0; col < numCols; col++) { sb.append(metaData.getColumnLabel(col + 1)); if (col < numCols - 1) sb.append(SEPARATOR); } sb.append(NEWLINE); for (int row = 0; row < numRows; row++) { results.absolute(row + 1); // Go to the specified row Double latitude = results.getDouble("latitude"); Double longitude = results.getDouble("longitude"); Double altitude = results.getDouble("altitude"); Double value = results.getDouble(fieldName); String sensorName = results.getString("name"); Long timeStamp = results.getLong("timed"); logger.warn("longitude = " + longitude + " , latitude = " + latitude); Point coordinates = geometryFactory.createPoint(new Coordinate(longitude, latitude)); SensorGeoReading sensorReadings = new SensorGeoReading(sensorName, coordinates, timeStamp, value, fieldName); sensorReadingsList.add(sensorReadings); sensorReadingsHash.put(sensorName, sensorReadings); //String logger.warn(sensorReadings); for (int col = 0; col < numCols; col++) { Object o = results.getObject(col + 1); // Get value of the column //logger.warn(row + " , "+col+" : "+ o.toString()); if (o == null) s = "null"; else s = o.toString(); if (col < numCols - 1) sb.append(s).append(SEPARATOR); else sb.append(s); } sb.append(NEWLINE); } } catch (SQLException e) { sb.append("ERROR in execution of query: " + e.getMessage()); } finally { Main.getDefaultStorage().close(connection); } return sb.toString(); } /* * Builds geographic geoIndex from list of sensors currently loaded in the system * */ public void buildGeoIndex() { geoIndex = new STRtree(); //geometryFactory = new GeometryFactory(); for (int i = 0; i < sensorReadingsList.size(); i++) { geoIndex.insert(sensorReadingsList.get(i).coordinates.getEnvelopeInternal(), sensorReadingsList.get(i).coordinates); //logger.warn(sensors.get(i) + " : " + coordinates.get(i) + " : " + searchForSensors_String(coordinates.get(i))); } geoIndex.build(); } public List<String> getListOfSensorsWithinEnvelope(String envelope) throws ParseException { Geometry geom = new WKTReader().read(envelope); List listEnvelope = geoIndex.query(geom.getEnvelopeInternal()); List<String> sensors = new ArrayList<String>(); for (int i = 0; i < listEnvelope.size(); i++) { sensors.add(searchForSensors_String((Point) listEnvelope.get(i))); } return sensors; } /* * Searches for the list of sensors which are located at the given point (comma separated) * */ public String searchForSensors_String(Point p) { StringBuilder s = new StringBuilder(""); for (int i = 0; i < sensorReadingsList.size(); i++) { if (sensorReadingsList.get(i).coordinates == p) { return sensorReadingsList.get(i).sensorName; } } return ""; } public class SensorGeoReading { public SensorGeoReading(String name, Point coords, Long ts, double v, String field) { sensorName = name; coordinates = coords; timestamp = ts; value = v; fieldName = field; } String sensorName; Point coordinates; Long timestamp; Double value; String fieldName; public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[") .append(sensorName) .append("] (lat:") .append(coordinates.getY()) .append(",lon:") .append(coordinates.getX()) .append(") @ ") .append(timestamp) .append(" => ") .append(fieldName) .append(" = ") .append(value); return sb.toString(); } } }