/* * "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.concurrent.Executors; import java.util.logging.Logger; import java.util.logging.Level; import net.sf.json.*; import com.sun.net.httpserver.*; import is4.*; import is4.exceptions.*; import local.html.tags.*; import local.json.validator.*; import local.db.*; import local.metadata.MetadataMngr; public class JoinHandler extends Filter implements HttpHandler { private Vector<String> errorVec = new Vector<String>(); private Registrar registrar = Registrar.registrarInstance(); protected static Logger logger = Logger.getLogger(JoinHandler.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 JoinHandler(String uri){ URI = uri; } public void doFilter(HttpExchange exchange, Filter.Chain chain) throws IOException { logger.info("here"); 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; } private boolean filterCheck(HttpExchange exchange){ logger.info("here"); 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); return true; } } catch (IOException e){ logger.log(Level.WARNING, "Could not carry out the Filter operation", e); return false; } return false; } public String description(){ return "JoinHandler " + URI + " filter"; } public void handle(HttpExchange exchange) throws IOException{ logger.info("handler:exchange handler: " + exchange.getLocalAddress().getHostName() + ":" + exchange.getLocalAddress().getPort() + "->" + exchange.getRemoteAddress()); //check if the filter was hit up if(filterCheck(exchange)) return; String requestMethod = exchange.getRequestMethod(); if (requestMethod.equalsIgnoreCase("GET")) { // TODO: page should be fetched and served from a file on the local host. OutputStream responseBody = exchange.getResponseBody(); HTMLSimpleTags response = new HTMLSimpleTags(); response.setTitle("Join Resource"); //compose body for response String body = "Join resource<br>"; String joinSchemaUrl="http://www.eecs.berkeley.edu/~jortiz/"; joinSchemaUrl = joinSchemaUrl + "gridos/site/schemas/protocols/join_schema.json"; body = body + "Schema: <a href=\"" + joinSchemaUrl + "\">Join Schema</a><br>"; body = body + "Instructions: <a href=\"http://www.eecs.berkeley.edu/~jortiz/gridos/site\">"; body = body + "here</a><br>"; //construct response and send System.out.println("Join: GET heard something and responded"); Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Content-Type", "text/html"); exchange.sendResponseHeaders(200, 0); responseBody.write(response.toString().getBytes()); responseBody.close(); return; } else if (requestMethod.equalsIgnoreCase("POST") || requestMethod.equalsIgnoreCase("PUT")){ OutputStream responseBody = exchange.getResponseBody(); //Print out the request body BufferedReader is = new BufferedReader(new InputStreamReader(exchange.getRequestBody())); String line=""; StringBuffer bodyBuf = new StringBuffer(); while((line=is.readLine())!=null){ bodyBuf.append(line).append(" "); } //Parse the json request Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Content-Type", "text/plain"); JSONObject jsonObj= getJSON(bodyBuf.toString()); String regId=processJoin(exchange, jsonObj); if(jsonObj!=null) { if(regId!=null && !regId.equals("0")){ logger.info("Join Success"); sendJoinSuccessReply(exchange,regId); } else{ logger.info("Join Fail"); sendJoinErrorReply(exchange,"0",200); } return; } else { //error parsing json request exchange.sendResponseHeaders(400, 0); //response should be a JSON object that describes the error responseBody.write((new String("JSON Syntex Error")).getBytes()); } //responseBody.close(); } else { //System.out.println("heard something"); logger.warning("JoinHandler: Heard invalid request type"); } } public JSONObject getJSON(String jsonPiece) { try { JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(jsonPiece); return jsonObj; } catch (JSONException e) { e.printStackTrace(); return null; } } private String easyReg(){ String regId = null; try { Random r = new Random(); String deviceName = "smap_" + r.nextInt(323234); regId=registrar.registerDevice(deviceName); logger.info("Registering device with name " + deviceName + "; registration identifier=" + regId); } catch(Exception e){ String thisError = ""; if(e instanceof NameRegisteredException){ thisError = "Name already registered; try a new device name"; errorVec.addElement(thisError); //System.out.println(thisError); logger.warning(thisError); } else if (e instanceof NoMoreRegistrantsException){ thisError="Maximum Joins reached; try again later"; errorVec.addElement(thisError); logger.warning(thisError); } else logger.log(Level.WARNING, "Join processing error", e); return regId; } return regId; } private String processJoin(HttpExchange exchange, JSONObject joinReq) { logger.info("processing join"); String newPubParam = (String) exchange.getAttribute("new"); if(newPubParam != null && newPubParam.equalsIgnoreCase("true")){ return easyReg(); } else { try { String regId=null; //get the associated streams JSONObject objectStream = joinReq.getJSONObject("object_stream"); JSONObject contextStream = joinReq.getJSONObject("context_stream"); JSONObject logicStream = joinReq.getJSONObject("logic_stream"); //fetch join schema and validate join request (joinReq) if(objectStream ==null || contextStream == null || logicStream ==null) return regId; //JSONSchemaValidator validator = new JSONSchemaValidator(); //JSONObject joinSchema = JSONSchemaValidator.fetchJSONObj("http://www.eecs.berkeley.edu/~jortiz/gridos/site/schemas/protocols/join_schema.json"); //validate and insert streams into repository try { String deviceName = objectStream.getString("device_name"); regId=registrar.registerDevice(deviceName); logger.info("Registering device with name " + deviceName + "; registration identifier=" + regId); //if(validator.validate(joinReq, joinSchema) && regId !=null && !regId.equals("0")) { if(regId !=null && !regId.equals("0") && !regId.equals("")) { System.out.println("device_name: " + deviceName); //store in database Is4Database dbLayer = (Is4Database) new DBAbstractionLayer(); //timestamp before entering objectStream.put("PubId", regId); contextStream.put("PubId", regId); logicStream.put("PubId", regId); Date date = new Date(); long timestamp = date.getTime()/1000; objectStream.put("timestamp", timestamp); contextStream.put("timestamp", timestamp); logicStream.put("timestamp", timestamp); //place into database dbLayer.putEntry(objectStream); dbLayer.putEntry(contextStream); dbLayer.putEntry(logicStream); logger.log(Level.FINER, "Adding object stream:\n", objectStream); logger.log(Level.FINER, "Adding context stream:\n", contextStream); logger.log(Level.FINER, "Adding logic stream:\n", logicStream); //create metadata binding JSONObject metadata = new JSONObject(); metadata.put("object_stream", objectStream); metadata.put("context_stream", contextStream); metadata.put("logic_stream", logicStream); MetadataMngr.getInstance().bind(regId, metadata); return regId; } } catch(Exception e){ String thisError = ""; if(e instanceof NameRegisteredException){ thisError = "Name already registered; try a new device name"; errorVec.addElement(thisError); //System.out.println(thisError); logger.warning(thisError); } else if (e instanceof NoMoreRegistrantsException){ thisError="Maximum Joins reached; try again later"; errorVec.addElement(thisError); logger.warning(thisError); } else logger.log(Level.WARNING, "Join processing error", e); return regId; } return regId; } catch (Exception e){ logger.log(Level.WARNING, "Join processing error 2", e); return null; } } } private boolean processObjectStream(JSONObject objStream) { return true; } private boolean processConextStream(JSONObject contextStream) { return true; } private boolean processLogicStream(JSONObject logicStream){ return true; } private void sendJoinSuccessReply(HttpExchange exchange, String joinId){ logger.info("sendJoinSuccessReply"); try { OutputStream responseBody = exchange.getResponseBody(); //compose body for response JSONObject sendSuccessDoc = new JSONObject(); sendSuccessDoc.put("operation", "join"); sendSuccessDoc.put("status", "success"); sendSuccessDoc.put("ident",joinId); 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){ e.printStackTrace(); } } private void sendJoinErrorReply(HttpExchange exchange, String joinId, int errorCode){ logger.info("sendJoinErrorReply"); try { OutputStream responseBody = exchange.getResponseBody(); //compose body for response JSONObject sendErrorDoc = new JSONObject(); JSONArray errorArray = new JSONArray(); sendErrorDoc.put("operation", "join"); sendErrorDoc.put("status", "fail"); sendErrorDoc.put("ident",joinId); //add all the errors to the response message for (int i=0; i<errorVec.size(); i++){ errorArray.add(i, (String)errorVec.elementAt(i)); } sendErrorDoc.put("errors", errorArray); errorVec.clear(); String body = sendErrorDoc.toString(); //construct response and send Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Content-Type", "text/plain"); if(errorCode>0) exchange.sendResponseHeaders(errorCode, 0); else exchange.sendResponseHeaders(200, 0); responseBody.write(body.getBytes()); responseBody.close(); } catch (Exception e){ logger.log(Level.WARNING, "Error sending join error reply", e); } } protected void sendResponse(HttpExchange exchange, int errorCode, String response){ logger.info("sendResponse"); 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); } } }