/* * "Copyright (c) 2010-11 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * * Author: Jorge Ortiz (jortiz@cs.berkeley.edu) * IS4 release version 2.0 */ package local.rest.resources; import is4.*; import local.db.*; import local.rest.*; import local.rest.resources.util.*; import local.metadata.context.*; import com.mongodb.*; import net.sf.json.*; import java.util.*; import java.util.logging.Logger; import java.util.logging.Level; import java.lang.StringBuffer; import com.sun.net.httpserver.*; import javax.naming.InvalidNameException; import java.io.*; /** * Resource object for a device. */ public class GenericPublisherResource extends Resource{ protected static transient Logger logger = Logger.getLogger(GenericPublisherResource.class.getPackage().getName()); protected static MySqlDriver database = (MySqlDriver)DBAbstractionLayer.database; public UUID publisherId =null; protected static final int headCount = 5; //public static int TYPE = ResourceUtils.GENERIC_PUBLISHER_RSRC; protected long last_data_ts = 0; public GenericPublisherResource(String uri, UUID pubId) throws Exception, InvalidNameException{ super(uri); if (pubId != null) publisherId = pubId; else throw new Exception("Null pointer to pubId"); //set type to generic_publisher TYPE=ResourceUtils.GENERIC_PUBLISHER_RSRC; database.setRRType(URI, ResourceUtils.translateType(TYPE).toLowerCase()); } public synchronized void get(HttpExchange exchange, boolean internalCall, JSONObject internalResp){ if(exchange.getAttribute("query") != null && ((String) exchange.getAttribute("query")).equalsIgnoreCase("true")){ if(!internalCall) exchange.setAttribute("query", "false"); query(exchange, null, internalCall, internalResp); return; } logger.info("GET " + this.URI); JSONObject response = new JSONObject(); try { JSONObject properties = database.rrGetProperties(this.URI); if(properties == null){ properties = new JSONObject(); } properties.put("type", "properties"); response.put("status", "success"); UUID assocPubid = database.isRRPublisher2(this.URI); if(assocPubid != null){ response.put("pubid", assocPubid.toString()); logger.info("POPULATING"); properties.put("PubId", assocPubid.toString()); properties.put("URI", this.URI); String dataStr = "URI: " + this.URI + "\n\nPubId: " + assocPubid.toString(); properties.put("data", dataStr); //get last few values received //db.is4_main_coll.find().sort({timestamp:1}).limit(5); JSONObject queryJSON = new JSONObject(); queryJSON.put("PubId", publisherId.toString()); queryJSON.put("timestamp", new Long(last_data_ts)); JSONObject sortByJSON = new JSONObject(); sortByJSON.put("timestamp",1); MongoDBDriver mongoDriver = new MongoDBDriver(); JSONObject lastValuesReceived = mongoDriver.queryWithLimit( queryJSON.toString(), sortByJSON.toString(), headCount); properties.put("head", lastValuesReceived.toString()); } response.put("properties", properties); sendResponse(exchange, 200, response.toString(), internalCall, internalResp); return; } catch (Exception e){ logger.log(Level.WARNING, "", e); } sendResponse(exchange, 200, null, internalCall, internalResp); } public synchronized void put(HttpExchange exchange, String data, boolean internalCall, JSONObject internalResp){ post(exchange, data, internalCall, internalResp); } public synchronized void post(HttpExchange exchange, String data, boolean internalCall, JSONObject internalResp){ logger.info("Publisher handling PUT/POST data request"); if(exchange.getAttribute("query") != null && ((String) exchange.getAttribute("query")).equalsIgnoreCase("true")){ if(!internalCall) exchange.setAttribute("query", "false"); query(exchange, data, internalCall, internalResp); } else { JSONObject resp = new JSONObject(); JSONArray errors = new JSONArray(); try{ JSONObject dataObject = (JSONObject) JSONSerializer.toJSON(data); logger.info("data: " + dataObject.toString()); String operation = dataObject.optString("operation"); if(operation!= null && !operation.equals("")){ if(operation.equalsIgnoreCase("create_symlink")){ super.put(exchange, data, internalCall, internalResp); } else { super.handlePropsReq(exchange, data, internalCall, internalResp); } }else { String type = (String) exchange.getAttribute("type"); UUID pubid = UUID.fromString((String) exchange.getAttribute("pubid")); logger.info("type: " + type +"; pubid: " + pubid.toString()); if(!internalCall){ exchange.setAttribute("pubid", ""); exchange.setAttribute("type", ""); } if(type != null && pubid != null && !type.equals("") && !pubid.equals("") && type.equalsIgnoreCase("generic") && pubid.compareTo(publisherId)==0){ //store and send success handleIncomingData(dataObject); resp.put("status", "success"); sendResponse(exchange, 200, resp.toString(), internalCall, internalResp); } else { resp.put("status", "fail"); if(type == null || type.equalsIgnoreCase("")) errors.add("type parameter missing"); if(pubid == null || pubid.equals("")) errors.add("pubid parameter missing"); if(type != null) errors.add("Unknown type"); if(pubid.compareTo(publisherId) != 0) errors.add("pubid does not match that of this generic publisher"); resp.put("errors", errors); sendResponse(exchange, 200, resp.toString(), internalCall, internalResp); } } } catch(Exception e){ if(e instanceof JSONException){ errors.add("Invalid JSON"); } resp.put("status", "fail"); resp.put("errors", errors); sendResponse(exchange, 200, resp.toString(), internalCall, internalResp); } } } public void delete(HttpExchange exchange,boolean internalCall, JSONObject internalResp){ logger.info("Handling DELETE PUBLISHER command for " + this.URI); //reset properties JSONObject emptyProps = new JSONObject(); super.updateProperties(emptyProps); //remove association with device database.removeDeviceEntry(this.URI); //delete entry from publishers table database.removePublisher(this.publisherId); //delete rest_resource entry database.removeRestResource(this.URI); RESTServer.removeResource(this); //remove subscriptions to this publisher SubMngr submngr = SubMngr.getSubMngrInstance(); submngr.pubRemoved(exchange, internalCall, internalResp, publisherId.toString()); //remove from internal graph this.metadataGraph.removeNode(this.URI); sendResponse(exchange, 200, null, internalCall, internalResp); } protected void handleIncomingData(JSONObject data){ Registrar registrar = Registrar.registrarInstance(); //add timestamp Date date = new Date(); long timestamp = date.getTime()/1000; data.put("timestamp", timestamp); //Forward to subscribers String dataStr = data.toString(); dataStr = dataStr.replace("$","d_"); JSONObject dataCopy = (JSONObject)JSONSerializer.toJSON(dataStr); dataCopy.put("PubId", publisherId.toString()); dataCopy.put("is4_uri", this.URI.toString()); SubMngr submngr = SubMngr.getSubMngrInstance(); logger.info("SubMngr Copy: " + dataCopy.toString()); submngr.dataReceived(dataCopy); //get the alias associated with this publisher String alias = null; if(URI.endsWith(publisherId.toString() + "/") || URI.endsWith(publisherId.toString())){ alias = publisherId.toString(); } else { String thisuri = URI; if(thisuri.endsWith("/")) thisuri = thisuri.substring(0, thisuri.length()-1); alias = thisuri.substring(thisuri.lastIndexOf("/"), thisuri.length()); } logger.info("Publsher PUTTING in data repository"); //put the data entry in the database //database.putInDataRepository(data, publisherId, alias); database.updateLastRecvTs(URI, timestamp); //store in the mongodb repos MongoDBDriver mongod = new MongoDBDriver(); mongod.putEntry(dataCopy); last_data_ts = timestamp; } public JSONObject queryTimeseriesRepos(JSONObject queryJson){ JSONObject queryResults = new JSONObject(); try{ MongoDBDriver mongoDriver = new MongoDBDriver(); //only run the query for this publisher queryJson.put("PubId", publisherId.toString()); //remove the PubId key from the results JSONObject keys = new JSONObject(); keys.put("PubId",0); logger.info("QUERY: " + queryJson.toString() + "\nKEYS: " + keys.toString()); JSONObject queryR = mongoDriver.query(queryJson.toString(), keys.toString()); if(queryR != null) queryResults.putAll(queryR); } catch(Exception e){ logger.log(Level.WARNING, "", e); } return queryResults; } public void query(HttpExchange exchange, String data, boolean internalCall, JSONObject internalResp){ JSONObject resp = new JSONObject(); JSONArray errors = new JSONArray(); resp.put("path", URI); try{ JSONObject tsQueryObj = new JSONObject(); //get query object from input data if(data != null && !data.equals("")){ JSONObject dataJsonObj = (JSONObject) JSONSerializer.toJSON(data); JSONObject dataTsQuery = dataJsonObj.optJSONObject("ts_query"); tsQueryObj.putAll(dataTsQuery); } Iterator keys = exchangeJSON.keys(); Vector<String> attributes = new Vector<String>(); Vector<String> values = new Vector<String>(); while(keys.hasNext()){ String thisKey = (String) keys.next(); logger.fine("Keys found!; thisKey=" + thisKey); if(thisKey.startsWith("ts_")){ String str = "ts_"; String queryKey = thisKey.substring(thisKey.indexOf(str)+str.length(), thisKey.length()); String queryValue = exchangeJSON.optString(thisKey); logger.info("Query Value: " + queryValue); JSONObject conditions = Resource.genJSONClause(queryValue); logger.info("Conditions: " + conditions); if(conditions!=null){ tsQueryObj.put(queryKey, conditions); } else{ if(isNumber(queryValue)){ long val = Long.parseLong(queryValue); tsQueryObj.put(queryKey, val); } else { tsQueryObj.put(queryKey, queryValue); } } } else if(thisKey.startsWith("ts")){ String queryValue = exchangeJSON.optString(thisKey); JSONObject conditions = Resource.genJSONClause(queryValue); if(conditions!=null){ tsQueryObj.putAll(conditions); } else{ if(isNumber(queryValue)){ long val = Long.parseLong(queryValue); tsQueryObj.put(thisKey, val); } else { logger.warning("Invalid conditions set for generic props query"); } } } } logger.fine("Timeseries Query: " + tsQueryObj.toString()); if(!tsQueryObj.toString().equals("{}")){ tsQueryObj.put("is4_uri", URI); /*if(last_props_ts>0) tsQueryObj.put("timestamp", last_props_ts);*/ JSONObject mqResp = queryTimeseriesRepos(tsQueryObj); logger.fine("mqResp: " + mqResp.toString()); resp.put("ts_query_results", mqResp); } else { errors.add("TS Query Error: Empty or invalid query"); logger.warning(errors.toString()); resp.put("errors", errors); } } catch (Exception e){ logger.log(Level.WARNING, "", e); if(e instanceof JSONException){ errors.add("Invalid JSON for POST data; url params ignored"); resp.put(errors, errors); sendResponse(exchange, 200, resp.toString(), internalCall, internalResp); return; } } JSONObject propsQueryResultsBuffer = new JSONObject(); super.query(exchange, data, true, propsQueryResultsBuffer); resp.put("props_query_results", propsQueryResultsBuffer); exchangeJSON.clear(); sendResponse(exchange, 200, resp.toString(), internalCall, internalResp); } }