/*
* "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 1.0
*/
package local.rest.handlers;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.InetAddress;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import is4.*;
import local.rest.resources.*;
import local.db.*;
import local.metadata.*;
import net.sf.json.*;
import com.sun.net.httpserver.*;
import javax.naming.InvalidNameException;
//public class PubHandler extends Filter implements HttpHandler {
public class PubHandler extends Resource {
protected static Logger logger = Logger.getLogger(PubHandler.class.getPackage().getName());
//This addresses the HttpContext switch bug
//For every call to create a context in the httpServer after the root, the HttpContext object changes, and the filter
//is no longer used in the new object.
//protected HttpContext thisContext = null;
//protected static String URI = null;
public PubHandler(String uri) throws Exception, InvalidNameException{
super(uri);
//URI = uri;
}
public String description(){
return "PubHandler filter";
}
public void put(HttpExchange exchange, String data, boolean internalCall, JSONObject internalResp){
logger.info("put");
post(exchange, data, internalCall, internalResp);
}
public void post(HttpExchange exchange, String data, boolean internalCall, JSONObject internalResp){
logger.info("Handling post to " + URI);
//check that the id is registered
Registrar registrar = Registrar.registrarInstance();
//Parse the json request
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(data);
if(jsonObj!=null) {
//if pubid provided as url paramter, override the pubid in the jsonobject request
String pubidParam = (String) exchange.getAttribute("pubid");
if(pubidParam != null){
try {
UUID u = UUID.fromString(pubidParam);
exchange.setAttribute("pubid", null);
jsonObj.put("PubId", pubidParam);
} catch(IllegalArgumentException e){}
}
////////////////////////////////////////////////////////////////////////
String regId = jsonObj.getString("PubId");
boolean bound = true;
boolean registered = true;
if((registered=registrar.isRegisteredId(regId))){ //&& (bound=MetadataMngr.getInstance().isBound(regId))){
logger.info("PubHandler: Valid PubId: " + regId);
//add timestamp and store in database
Date date = new Date();
long timestamp = date.getTime()/1000;
jsonObj.put("timestamp", timestamp);
//update Metadata lease
MetadataMngr.getInstance().touch(regId);
//Forward to subscribers
SubMngr submngr = SubMngr.getSubMngrInstance();
submngr.dataReceived(jsonObj);
//put in database
Is4Database dbLayer = (Is4Database) new DBAbstractionLayer();
if(DBAbstractionLayer.DBTYPE == DBAbstractionLayer.MYSQL && !tagEntry(exchange, jsonObj)){
JSONArray errors = new JSONArray();
errors.add("Unknown request data type");
//sendPubFailReply(exchange, regId, errors);
JSONObject sendFail = new JSONObject();
sendFail.put("operation", "pub");
sendFail.put("status", "failed");
sendFail.put("ident",regId);
sendFail.put("errors", errors);
sendResponse(exchange, 202, sendFail.toString(), internalCall, internalResp);
return;
} else {
dbLayer.putEntry(jsonObj);
}
//send ack success
//sendPubSuccessReply(exchange,regId);
JSONObject sendSuccessDoc = new JSONObject();
sendSuccessDoc.put("operation", "pub");
sendSuccessDoc.put("status", "success");
sendSuccessDoc.put("ident",regId);
sendResponse(exchange, 202, sendSuccessDoc.toString(), internalCall, internalResp);
return;
} else{
//System.out.println("pub FAILED");
JSONArray errors = new JSONArray();
if(!registered) {
String msg = "Publisher id " + regId + " is not registered; dropping data packet";
logger.warning(msg);
errors.add(msg);
}
if(!bound){
String msg = "Publisher id " + regId + " is not bound; dropping data packet";
logger.warning(msg);
errors.add(msg);
}
//sendPubFailReply(exchange,regId, errors);
JSONObject sendFail = new JSONObject();
sendFail.put("operation", "pub");
sendFail.put("status", "failed");
sendFail.put("ident",regId);
sendFail.put("errors", errors);
sendResponse(exchange, 202, sendFail.toString(), internalCall, internalResp);
}
//exchange.sendResponseHeaders(202, 0);
}
else {
/*OutputStream responseBody = exchange.getResponseBody();
exchange.sendResponseHeaders(400, 0);
responseBody.write((new String("JSON Syntax Error")).getBytes());
responseBody.close();*/
sendResponse(exchange, 200, "JSON Syntac Error", internalCall, internalResp);
}
}
//public void delete(HttpExchange exchange, boolean internalCall, JSONObject internalResp);
/*public void doFilter(HttpExchange exchange, Filter.Chain chain) throws IOException {
boolean paramsOk = false;
if((paramsOk = parseParams(exchange)) && chain==null)
this.handle(exchange);
else if (!paramsOk)
sendResponse(exchange, 404, null);
else
chain.doFilter(exchange);
}
protected boolean parseParams(HttpExchange exchange) {
logger.info("Request URI: " + exchange.getRequestURI().toString());
StringTokenizer tokenizer = new StringTokenizer(exchange.getRequestURI().toString(), "?");
if(tokenizer != null && tokenizer.hasMoreTokens()){
String thisResourcePath = tokenizer.nextToken();
if(URI == null && !thisResourcePath.equals(URI) && !thisResourcePath.equals(URI + "/"))
return false;
if(tokenizer.countTokens()>0) {
StringTokenizer paramStrTokenizer = new StringTokenizer(tokenizer.nextToken(), "&");
if(paramStrTokenizer !=null && paramStrTokenizer.hasMoreTokens()){
while (paramStrTokenizer.hasMoreTokens()){
StringTokenizer paramPairsTokenizer = new StringTokenizer(paramStrTokenizer.nextToken(),"=");
if(paramPairsTokenizer != null && paramPairsTokenizer.hasMoreTokens()){
String attr = paramPairsTokenizer.nextToken();
String val = paramPairsTokenizer.nextToken();
exchange.setAttribute(attr, val);
logger.info("Added (" + attr + ", " + val + ") pair to exchange session");
}
}
}
} else{
logger.fine("Not enough tokens");
}
}
return true;
}
public void handle(HttpExchange exchange) throws IOException{
try {
//This addresses the HttpContext switch bug in the library
//The filter must be called BEFORE the handler
if (exchange.getHttpContext() != thisContext && exchange.getHttpContext().getFilters().size()==0) {
thisContext = exchange.getHttpContext();
thisContext.getFilters().add(this);
this.doFilter(exchange, null);
}
} catch (IOException e){
logger.log(Level.WARNING, "Could not carry out the Filter operation", e);
}
String requestMethod = exchange.getRequestMethod();
if (requestMethod.equalsIgnoreCase("GET")) {
//System.out.println("Pub: GET heard; Nothing to get from Pub resource");
logger.finer("GET Request received");
}
else if (requestMethod.equalsIgnoreCase("POST")
|| requestMethod.equalsIgnoreCase("PUT")){
logger.info("Handling post to " + URI);
//check that the id is registered
Registrar registrar = Registrar.registrarInstance();
//Print out the request body
BufferedReader is = new BufferedReader(new InputStreamReader(exchange.getRequestBody()));
String line="";
StringBuffer bodyBuf = new StringBuffer();
while((line=is.readLine())!=null){
System.out.println(line);
bodyBuf.append(line).append(" ");
}
//Parse the json request
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(bodyBuf.toString());
if(jsonObj!=null) {
//if pubid provided as url paramter, override the pubid in the jsonobject request
String pubidParam = (String) exchange.getAttribute("pubid");
if(pubidParam != null){
try {
UUID u = UUID.fromString(pubidParam);
exchange.setAttribute("pubid", null);
jsonObj.put("PubId", pubidParam);
} catch(IllegalArgumentException e){}
}
////////////////////////////////////////////////////////////////////////
String regId = jsonObj.getString("PubId");
boolean bound = true;
boolean registered = true;
if((registered=registrar.isRegisteredId(regId))){ //&& (bound=MetadataMngr.getInstance().isBound(regId))){
logger.info("PubHandler: Valid PubId: " + regId);
//add timestamp and store in database
Date date = new Date();
long timestamp = date.getTime()/1000;
jsonObj.put("timestamp", timestamp);
//update Metadata lease
MetadataMngr.getInstance().touch(regId);
//Forward to subscribers
SubMngr submngr = SubMngr.getSubMngrInstance();
submngr.dataReceived(jsonObj);
//put in database
Is4Database dbLayer = (Is4Database) new DBAbstractionLayer();
if(DBAbstractionLayer.DBTYPE == DBAbstractionLayer.MYSQL && !tagEntry(exchange, jsonObj)){
JSONArray errors = new JSONArray();
errors.add("Unknown request data type");
sendPubFailReply(exchange, regId, errors);
return;
} else {
dbLayer.putEntry(jsonObj);
}
//send ack success
sendPubSuccessReply(exchange,regId);
return;
} else{
//System.out.println("pub FAILED");
JSONArray errors = new JSONArray();
if(!registered) {
String msg = "Publisher id " + regId + " is not registered; dropping data packet";
logger.warning(msg);
errors.add(msg);
}
if(!bound){
String msg = "Publisher id " + regId + " is not bound; dropping data packet";
logger.warning(msg);
errors.add(msg);
}
sendPubFailReply(exchange,regId, errors);
}
//exchange.sendResponseHeaders(202, 0);
}
else {
OutputStream responseBody = exchange.getResponseBody();
//error parsing json request
exchange.sendResponseHeaders(400, 0);
//response should be a JSON object that describes the error
responseBody.write((new String("JSON Syntax Error")).getBytes());
responseBody.close();
}
}
}*/
private boolean tagEntry(HttpExchange exchange, JSONObject jsonObj){
logger.info("Tagging the entry");
String schemaName = (String) exchange.getAttribute("schema");
if(schemaName != null && MySqlDriver.isValidSchema(schemaName)){
logger.info("Schema-name: " + schemaName);
if(schemaName.equalsIgnoreCase("context")){
jsonObj.put("name", "context_stream");
return true;
} else if(schemaName.equalsIgnoreCase("logic")){
jsonObj.put("name", "logic_stream");
return true;
} else if(schemaName.equalsIgnoreCase("device")){
jsonObj.put("name", "device_entry");
return true;
} else if(schemaName.equalsIgnoreCase("location")) {
jsonObj.put("name", "location_entry");
return true;
} else if(schemaName.equalsIgnoreCase("meta")) {
jsonObj.put("name", "meta_entry");
return true;
} else if(schemaName.equalsIgnoreCase("reading")) {
jsonObj.put("name", "meter_reading_entry");
return true;
} else if(schemaName.equalsIgnoreCase("report")) {
jsonObj.put("name", "meter_reading_entry");
return true;
} else if(schemaName.equalsIgnoreCase("profile")){
jsonObj.put("name", "profile_entry");
return true;
} else if(schemaName.equalsIgnoreCase("resource")){
jsonObj.put("name", "resource_listing_entry");
return true;
} else if(schemaName.equalsIgnoreCase("unit")){
jsonObj.put("name", "unit_labels_entry");
return true;
} else if(schemaName.equalsIgnoreCase("formatting")){
jsonObj.put("name", "formatting_entry");
return true;
} else if(schemaName.equalsIgnoreCase("parameter")){
jsonObj.put("name", "parameter_entry");
return true;
}
}
return false;
}
protected void sendResponse(HttpExchange exchange, int errorCode, String response){
try{
logger.info("Sending Response");
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "application/json");
exchange.sendResponseHeaders(errorCode, 0);
OutputStream responseBody = exchange.getResponseBody();
if(response!=null)
responseBody.write(response.getBytes());
responseBody.close();
}catch(Exception e){
logger.log(Level.WARNING, "Exception thrown while sending response",e);
}
}
private void sendPubSuccessReply(HttpExchange exchange, String regId){
logger.info("Sending publish success reply");
try {
OutputStream responseBody = exchange.getResponseBody();
//compose body for response
JSONObject sendSuccessDoc = new JSONObject();
sendSuccessDoc.put("operation", "pub");
sendSuccessDoc.put("status", "success");
sendSuccessDoc.put("ident",regId);
String body = sendSuccessDoc.toString();
//construct response and send
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(202, 0);
responseBody.write(body.getBytes());
responseBody.close();
} catch (Exception e){
logger.log(Level.WARNING, "Error while sending publish-success reply", e);
}
}
private void sendPubFailReply(HttpExchange exchange, String regId, JSONArray errors){
logger.info("Sending publish fail reply");
try {
OutputStream responseBody = exchange.getResponseBody();
//compose body for response
JSONObject sendFail = new JSONObject();
sendFail.put("operation", "pub");
sendFail.put("status", "failed");
sendFail.put("ident",regId);
sendFail.put("errors", errors);
String body = sendFail.toString();
//construct response and send
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(202, 0);
responseBody.write(body.getBytes());
responseBody.close();
} catch (Exception e){
logger.log(Level.WARNING, "Error while sending publish-fail reply", e);
}
}
}