/* * SMART FP7 - Search engine for MultimediA enviRonment generated contenT * Webpage: http://smartfp7.eu * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The Original Code is Copyright (c) 2012-2013 Athens Information Technology * All Rights Reserved * * Contributor: * Nikolaos Katsarakis nkat@ait.edu.gr */ package eu.smartfp7.EdgeNode; import java.io.IOException; import java.io.PrintWriter; import java.util.Hashtable; import java.util.List; import java.util.Properties; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.lightcouch.CouchDbClient; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import eu.smartfp7.utils.Json; /** * Servlet implementation class RetrieveXML */ @WebServlet("/retrieveXML") public class RetrieveXML extends HttpServlet { private static final long serialVersionUID = 1L; private Hashtable<String, CouchDbClient> allClients; // CouchDB access parameters private int port; private String server, user, pass; /** * @see HttpServlet#HttpServlet() */ public RetrieveXML() { super(); } /** * @see Servlet#init(ServletConfig) */ public void init(ServletConfig config) throws ServletException { super.init(config); try { super.init(config); } catch (ServletException e) { System.err.println("Can not initialize servlet"); return; } // Read couchdb properties from file and initialise the client for feeds Properties dbProps = new Properties(); try { dbProps.load(getServletContext().getResourceAsStream("/WEB-INF/couchdb.properties")); } catch (IOException e1) { System.err.println("Can not open couchdb properties file"); return; } server = dbProps.getProperty("server"); port = Integer.parseInt(dbProps.getProperty("port")); user = dbProps.getProperty("user"); pass = dbProps.getProperty("pass"); // List of connections to databases (one client per) allClients = new Hashtable<String, CouchDbClient>(); // Create one connection by default (to the database of feeds) allClients.put("feeds", new CouchDbClient("feeds", false, "http", server, port, user, pass)); } /** * @see Servlet#destroy() */ public void destroy() { // Close all connections to CouchDb for (CouchDbClient client : allClients.values()) client.shutdown(); // Clear client list allClients.clear(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/xml;charset=UTF-8"); PrintWriter out = response.getWriter(); // Get the requested database String feedName = request.getParameter("feed"); if (feedName != null) { feedName = feedName.toLowerCase(); System.out.println("feed=" + feedName); } else { try { response.sendRedirect("retrieveXML.html"); } catch (IOException e1) { System.out.println("doGet IOException: Can not redirect"); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); out.println("<?xml version=\"1.0\"?><error>feed parameter not specified</error>"); } return; } // Check if the database (corresponding feed) already exists if (!allClients.get("feeds").context().getAllDbs().contains(feedName)) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); out.println("<?xml version=\"1.0\"?><error>Feed " + feedName + " does not exist!</error>"); return; } // Client for current request CouchDbClient curClient; if (!allClients.containsKey(feedName)) { // No request for this feed has arrived so far, add a new client to // the list curClient = new CouchDbClient(feedName, true, "http", server, port, user, pass); allClients.put(feedName, curClient); } else { // We've had requests for this feed before, set the corresponding // client as active curClient = allClients.get(feedName); } System.out.println("Connected to DB: " + curClient.context().info().getDbName()); // Check if a maximum number of results has been specified String limitStr = request.getParameter("limit"); Integer limit = 100; if (limitStr != null) { try { limit = Integer.parseInt(limitStr); } catch (NumberFormatException e) { // Ignore if improperly formatted } } if (!curClient.contains("_design/get_data")) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); out.println("<?xml version=\"1.0\"?><error>Design document for feed " + feedName + " does not exist!</error>"); return; } Long startMillis = null, endMillis = null; String startDate = request.getParameter("start_date"); if (startDate != null) { try { startMillis = Long.parseLong(startDate); } catch (NumberFormatException e) { try { startMillis = javax.xml.bind.DatatypeConverter.parseDateTime(startDate).getTimeInMillis(); } catch (IllegalArgumentException e1) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); out.println("<?xml version=\"1.0\"?><error>Could not parse start date</error>"); return; } } } String endDate = request.getParameter("end_date"); if (endDate != null) { try { endMillis = Long.parseLong(endDate); } catch (NumberFormatException e) { try { endMillis = javax.xml.bind.DatatypeConverter.parseDateTime(endDate).getTimeInMillis(); } catch (IllegalArgumentException e1) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); out.println("<?xml version=\"1.0\"?><error>Could not parse end date</error>"); return; } } } List<JsonObject> resList = null; String low_level = request.getParameter("low_level_events"); if (low_level!=null) { try { curClient.view("get_data/with_low_level_event").limit(1).query(JsonObject.class); } catch (org.lightcouch.NoDocumentException e) { response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); out.println("<?xml version=\"1.0\"?><error>Can not search feed '" + feedName + "' for low level events, ensure that the '_design/get_data' document contains a view named 'with_low_level_event'</error>"); return; } } String viewStr; if (low_level!=null) viewStr="get_data/with_low_level_event"; else viewStr="get_data/by_date"; if (startMillis != null && endMillis != null) resList = curClient.view(viewStr).startKey(startMillis).endKey(endMillis) .query(JsonObject.class); else if (startMillis == null && endMillis == null) resList = curClient.view(viewStr).limit(limit).descending(true).query(JsonObject.class); if (resList == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); out.println("<?xml version=\"1.0\"?><error>no data could be found</error>"); return; } // Convert the response to an XML-RDF document StringBuilder result = new StringBuilder(); for (int i = 0; i < resList.size(); i++) { JsonObject item = resList.get(i); JsonElement el = item.get("value"); String data = el.toString(); if (low_level!=null) { String time = Common.millis2String(item.get("key").getAsLong()); // Add time and a low_level_event element before each data data = "{\"time\":\"" + time + "\",\"low_level_event\": " + data + "}"; if (i > 0) data = "," + data; } else { // Add a measurement element before each data if (i == 0) data = "\"measurement\": " + data; else data = ",\"measurement\": " + data; } result.append(data); } if (low_level!=null) { // Surround the results with the rdf and measurement tags result.insert(0, "{\"rdf\": { \"measurement\": ["); result.append("]}}"); } else { // Surround the result with the rdf tag result.insert(0, "{\"rdf\": {"); result.append("}}"); } String finalres = Json.convertToXml(result.toString()); out.print(finalres); } }