package org.oliot.epcis.service.admin; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Level; import org.bson.BsonDocument; import org.bson.BsonInt32; import org.bson.BsonString; import org.json.JSONArray; import org.json.JSONObject; import org.oliot.epcis.configuration.Configuration; import org.oliot.epcis.converter.mongodb.MongoWriterUtil; import org.oliot.epcis.security.OAuthUtil; import org.oliot.epcis.service.query.mongodb.MongoQueryService; import org.oliot.model.epcis.PollParameters; import org.oliot.model.epcis.QueryParameterException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.ServletContextAware; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.model.IndexOptions; import com.restfb.Connection; import com.restfb.FacebookClient; import com.restfb.types.User; /** * Copyright (C) 2014-2016 Jaewook Byun * * This project is part of Oliot open source (http://oliot.org). Oliot EPCIS * v1.2.x is Java Web Service complying with Electronic Product Code Information * Service (EPCIS) v1.2. * * @author Jaewook Byun, Ph.D student * * Korea Advanced Institute of Science and Technology (KAIST) * * Real-time Embedded System Laboratory(RESL) * * bjw0829@kaist.ac.kr, bjw0829@gmail.com */ @Controller public class NamedQueryRegistration implements ServletContextAware { @Autowired ServletContext servletContext; @SuppressWarnings("unused") @Autowired private HttpServletRequest request; @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } /** * Provide existing Named Event Queries */ @RequestMapping(value = "/Admin/NamedEventQuery", method = RequestMethod.GET) @ResponseBody public ResponseEntity<?> getNamedEventQueries() { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Content-Type", "application/json; charset=utf-8"); MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("NamedEventQuery", BsonDocument.class); MongoCursor<BsonDocument> cursor = collection.find().iterator(); JSONArray jarray = new JSONArray(); while (cursor.hasNext()) { BsonDocument doc = cursor.next(); JSONObject json = new JSONObject(doc.toJson()); jarray.put(json); } return new ResponseEntity<>(jarray.toString(1), responseHeaders, HttpStatus.OK); } /** * Provide existing Named Event Queries */ @RequestMapping(value = "/Admin/NamedEventQuery/{name}", method = RequestMethod.GET) @ResponseBody public ResponseEntity<?> putNamedEventQuery(@PathVariable String name, @RequestParam String description, @RequestParam(required = false) String eventType, @RequestParam(required = false) String GE_eventTime, @RequestParam(required = false) String LT_eventTime, @RequestParam(required = false) String GE_recordTime, @RequestParam(required = false) String LT_recordTime, @RequestParam(required = false) String EQ_action, @RequestParam(required = false) String EQ_bizStep, @RequestParam(required = false) String EQ_disposition, @RequestParam(required = false) String EQ_readPoint, @RequestParam(required = false) String WD_readPoint, @RequestParam(required = false) String EQ_bizLocation, @RequestParam(required = false) String WD_bizLocation, @RequestParam(required = false) String EQ_transformationID, @RequestParam(required = false) String MATCH_epc, @RequestParam(required = false) String MATCH_parentID, @RequestParam(required = false) String MATCH_inputEPC, @RequestParam(required = false) String MATCH_outputEPC, @RequestParam(required = false) String MATCH_anyEPC, @RequestParam(required = false) String MATCH_epcClass, @RequestParam(required = false) String MATCH_inputEPCClass, @RequestParam(required = false) String MATCH_outputEPCClass, @RequestParam(required = false) String MATCH_anyEPCClass, @RequestParam(required = false) Integer EQ_quantity, @RequestParam(required = false) Integer GT_quantity, @RequestParam(required = false) Integer GE_quantity, @RequestParam(required = false) Integer LT_quantity, @RequestParam(required = false) Integer LE_quantity, @RequestParam(required = false) String EQ_eventID, @RequestParam(required = false) Boolean EXISTS_errorDeclaration, @RequestParam(required = false) String GE_errorDeclarationTime, @RequestParam(required = false) String LT_errorDeclarationTime, @RequestParam(required = false) String EQ_errorReason, @RequestParam(required = false) String EQ_correctiveEventID, @RequestParam(required = false) String orderBy, @RequestParam(required = false) String orderDirection, @RequestParam(required = false) Integer eventCountLimit, @RequestParam(required = false) Integer maxEventCount, @RequestParam(required = false) String vocabularyName, @RequestParam(required = false) Boolean includeAttributes, @RequestParam(required = false) Boolean includeChildren, @RequestParam(required = false) String attributeNames, @RequestParam(required = false) String EQ_name, @RequestParam(required = false) String WD_name, @RequestParam(required = false) String HASATTR, @RequestParam(required = false) Integer maxElementCount, @RequestParam(required = false) String format, @RequestParam String userID, @RequestParam String accessToken, @RequestParam Map<String, String> params) { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Content-Type", "text/html; charset=utf-8"); // Access Control is not mandatory // However, if fid and accessToken provided, more information provided FacebookClient fc = null; List<String> friendList = null; if (userID != null) { // Check accessToken fc = OAuthUtil.isValidatedFacebookClient(accessToken, userID); if (fc == null) { return new ResponseEntity<>(new String("Unauthorized Token"), responseHeaders, HttpStatus.UNAUTHORIZED); } friendList = new ArrayList<String>(); Connection<User> friendConnection = fc.fetchConnection("me/friends", User.class); for (User friend : friendConnection.getData()) { friendList.add(friend.getId()); } } // OAuth Fails if (!OAuthUtil.isAdministratable(userID, friendList)) { Configuration.logger.log(Level.INFO, " No right to administration "); return new ResponseEntity<>(new String("No right to administration"), responseHeaders, HttpStatus.BAD_REQUEST); } try { PollParameters p = new PollParameters("SimpleEventQuery", eventType, GE_eventTime, LT_eventTime, GE_recordTime, LT_recordTime, EQ_action, EQ_bizStep, EQ_disposition, EQ_readPoint, WD_readPoint, EQ_bizLocation, WD_bizLocation, EQ_transformationID, MATCH_epc, MATCH_parentID, MATCH_inputEPC, MATCH_outputEPC, MATCH_anyEPC, MATCH_epcClass, MATCH_inputEPCClass, MATCH_outputEPCClass, MATCH_anyEPCClass, EQ_quantity, GT_quantity, GE_quantity, LT_quantity, LE_quantity, EQ_eventID, EXISTS_errorDeclaration, GE_errorDeclarationTime, LT_errorDeclarationTime, EQ_errorReason, EQ_correctiveEventID, orderBy, orderDirection, eventCountLimit, maxEventCount, vocabularyName, includeAttributes, includeChildren, attributeNames, EQ_name, WD_name, HASATTR, maxElementCount, format, params); MongoQueryService mqs = new MongoQueryService(); // null means no error String reason = mqs.checkConstraintSimpleEventQuery(p); if (reason != null) return new ResponseEntity<>(reason, responseHeaders, HttpStatus.BAD_REQUEST); boolean isSuccess = addNamedEventQueryToDB(name, description, p); if (isSuccess == false) { return new ResponseEntity<>(new String("Existing NamedEventQuery, Use another name"), responseHeaders, HttpStatus.BAD_REQUEST); } } catch (QueryParameterException e) { return new ResponseEntity<>(e.toString(), responseHeaders, HttpStatus.BAD_REQUEST); } Configuration.logger.log(Level.INFO, "NamedEventQuery: " + name + " is registered"); return new ResponseEntity<>(new String("NamedEventQuery " + name + " is registered"), responseHeaders, HttpStatus.OK); } /** * Provide existing Named Event Queries */ @RequestMapping(value = "/Admin/NamedEventQuery/{name}", method = RequestMethod.DELETE) @ResponseBody public ResponseEntity<?> deleteNamedEventQuery(@PathVariable String name, @RequestParam String userID, @RequestParam String accessToken) { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Content-Type", "text/html; charset=utf-8"); // Access Control is not mandatory // However, if fid and accessToken provided, more information provided FacebookClient fc = null; List<String> friendList = null; if (userID != null) { // Check accessToken fc = OAuthUtil.isValidatedFacebookClient(accessToken, userID); if (fc == null) { return new ResponseEntity<>(new String("Unauthorized Token"), responseHeaders, HttpStatus.UNAUTHORIZED); } friendList = new ArrayList<String>(); Connection<User> friendConnection = fc.fetchConnection("me/friends", User.class); for (User friend : friendConnection.getData()) { friendList.add(friend.getId()); } } // OAuth Fails if (!OAuthUtil.isAdministratable(userID, friendList)) { Configuration.logger.log(Level.INFO, " No right to administration "); return new ResponseEntity<>(new String("No right to administration"), responseHeaders, HttpStatus.BAD_REQUEST); } if (deleteNamedEventQueryFromDB(name)) { Configuration.logger.log(Level.INFO, "NamedEventQuery: " + name + " is removed"); return new ResponseEntity<>(new String("NamedEventQuery: " + name + " is removed"), responseHeaders, HttpStatus.OK); } else { Configuration.logger.log(Level.INFO, "NamedEventQuery: " + name + " does not exist"); return new ResponseEntity<>(new String("NamedEventQuery: " + name + " does not exist"), responseHeaders, HttpStatus.OK); } } private boolean deleteNamedEventQueryFromDB(String name) { MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("NamedEventQuery", BsonDocument.class); BsonDocument s = collection.findOneAndDelete(new BsonDocument("name", new BsonString(name))); if (s == null) { return false; } else { MongoCollection<BsonDocument> eventDataCollection = Configuration.mongoDatabase.getCollection("EventData", BsonDocument.class); eventDataCollection.dropIndex(name); return true; } } private boolean addNamedEventQueryToDB(String name, String description, PollParameters p) { MongoCollection<BsonDocument> namedEventQueryCollection = Configuration.mongoDatabase.getCollection("NamedEventQuery", BsonDocument.class); MongoCollection<BsonDocument> eventDataCollection = Configuration.mongoDatabase.getCollection("EventData", BsonDocument.class); BsonDocument existingDoc = namedEventQueryCollection.find(new BsonDocument("name", new BsonString(name))).first(); if (existingDoc == null) { BsonDocument bson = PollParameters.asBsonDocument(p); bson.put("name", new BsonString(name)); bson.put("description", new BsonString(description)); namedEventQueryCollection.insertOne(bson); } else { return false; } // Create Index with the given NamedEventQuery name and background option IndexOptions indexOptions = new IndexOptions().name(name).background(true); BsonDocument indexDocument = makeIndexObject(p); eventDataCollection.createIndex(indexDocument, indexOptions); Configuration.logger.log(Level.INFO, "NamedEventQuery: " + name + " is added to DB. "); return true; } private BsonDocument makeIndexObject(PollParameters p) { BsonDocument indexDocument = new BsonDocument(); if (p.getEventType() != null) { indexDocument.put("eventType", new BsonInt32(1)); } if (p.getGE_eventTime() != null) { indexDocument.put("eventTime", new BsonInt32(1)); } if (p.getLT_eventTime() != null) { indexDocument.put("eventTime", new BsonInt32(1)); } if (p.getGE_recordTime() != null) { indexDocument.put("recordTime", new BsonInt32(1)); } if (p.getLT_recordTime() != null) { indexDocument.put("recordTime", new BsonInt32(1)); } if (p.getGE_errorDeclarationTime() != null) { indexDocument.put("errorDeclaration.declarationTime", new BsonInt32(1)); } if (p.getLT_errorDeclarationTime() != null) { indexDocument.put("errorDeclaration.declarationTime", new BsonInt32(1)); } if (p.getEQ_action() != null) { indexDocument.put("action", new BsonInt32(1)); } if (p.getEQ_bizStep() != null) { indexDocument.put("bizStep", new BsonInt32(1)); } if (p.getEQ_disposition() != null) { indexDocument.put("disposition", new BsonInt32(1)); } if (p.getEQ_readPoint() != null) { indexDocument.put("readPoint.id", new BsonInt32(1)); } if (p.getWD_readPoint() != null) { indexDocument.put("readPoint.id", new BsonInt32(1)); } if (p.getEQ_bizLocation() != null) { indexDocument.put("bizLocation.id", new BsonInt32(1)); } if (p.getWD_bizLocation() != null) { indexDocument.put("bizLocation.id", new BsonInt32(1)); } if (p.getEQ_transformationID() != null) { indexDocument.put("transformationID", new BsonInt32(1)); } if (p.getMATCH_epc() != null) { indexDocument.put("epcList.epc", new BsonInt32(1)); indexDocument.put("childEPCs.epc", new BsonInt32(1)); } if (p.getMATCH_parentID() != null) { indexDocument.put("parentID", new BsonInt32(1)); } if (p.getMATCH_inputEPC() != null) { indexDocument.put("inputEPCList.epc", new BsonInt32(1)); } if (p.getMATCH_outputEPC() != null) { indexDocument.put("outputEPCList.epc", new BsonInt32(1)); } if (p.getMATCH_anyEPC() != null) { indexDocument.put("epcList.epc", new BsonInt32(1)); indexDocument.put("childEPCs.epc", new BsonInt32(1)); indexDocument.put("inputEPCList.epc", new BsonInt32(1)); indexDocument.put("outputEPCList.epc", new BsonInt32(1)); indexDocument.put("parentID", new BsonInt32(1)); } if (p.getMATCH_epcClass() != null) { indexDocument.put("extension.quantityList.epcClass", new BsonInt32(1)); indexDocument.put("extension.childQuantityList.epcClass", new BsonInt32(1)); } if (p.getMATCH_inputEPCClass() != null) { indexDocument.put("inputQuantityList.epcClass", new BsonInt32(1)); } if (p.getMATCH_outputEPCClass() != null) { indexDocument.put("outputQuantityList.epcClass", new BsonInt32(1)); } if (p.getMATCH_anyEPCClass() != null) { indexDocument.put("extension.quantityList.epcClass", new BsonInt32(1)); indexDocument.put("extension.childQuantityList.epcClass", new BsonInt32(1)); indexDocument.put("inputQuantityList.epcClass", new BsonInt32(1)); indexDocument.put("outputQuantityList.epcClass", new BsonInt32(1)); } if (p.getEQ_eventID() != null) { indexDocument.put("eventID", new BsonInt32(1)); } if (p.getEQ_errorReason() != null) { indexDocument.put("errorDeclaration.reason", new BsonInt32(1)); } if (p.getEQ_correctiveEventID() != null) { indexDocument.put("errorDeclaration.correctiveEventIDs", new BsonInt32(1)); } if (p.getEXISTS_errorDeclaration() != null) { indexDocument.put("errorDeclaration", new BsonInt32(1)); } if (p.getParams() != null) { Iterator<String> paramIter = p.getParams().keySet().iterator(); while (paramIter.hasNext()) { String paramName = paramIter.next(); if (paramName.contains("EQ_bizTransaction_")) { indexDocument.put("bizTransactionList", new BsonInt32(1)); } if (paramName.contains("EQ_source_")) { indexDocument.put("extension.sourceList", new BsonInt32(1)); indexDocument.put("sourceList", new BsonInt32(1)); } if (paramName.contains("EQ_destination_")) { indexDocument.put("extension.destinationList", new BsonInt32(1)); indexDocument.put("destinationList", new BsonInt32(1)); } if (paramName.startsWith("EQ_ILMD_")) { String type = paramName.substring(8, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("extension.ilmd.any." + type, new BsonInt32(1)); indexDocument.put("ilmd.any." + type, new BsonInt32(1)); } if (paramName.startsWith("GT_ILMD_") || paramName.startsWith("GE_ILMD_") || paramName.startsWith("LT_ILMD_") || paramName.startsWith("LE_ILMD_")) { String type = paramName.substring(8, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("extension.ilmd.any." + type, new BsonInt32(1)); indexDocument.put("ilmd.any." + type, new BsonInt32(1)); } if (paramName.startsWith("EXISTS_ILMD_")) { String field = paramName.substring(12, paramName.length()); field = MongoWriterUtil.encodeMongoObjectKey(field); indexDocument.put("extension.ilmd.any." + field, new BsonInt32(1)); indexDocument.put("ilmd.any." + field, new BsonInt32(1)); } if (paramName.startsWith("EQ_ERROR_DECLARATION_")) { String type = paramName.substring(21, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("errorDeclaration.any." + type , new BsonInt32(1)); } if (paramName.startsWith("GT_ERROR_DECLARATION_") || paramName.startsWith("GE_ERROR_DECLARATION_") || paramName.startsWith("LT_ERROR_DECLARATION_") || paramName.startsWith("LE_ERROR_DECLARATION_")) { String type = paramName.substring(21, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("errorDeclaration.any." + type , new BsonInt32(1)); } boolean isExtraParam = isExtraParameter(paramName); if (isExtraParam == true) { if (paramName.startsWith("EQ_")) { String type = paramName.substring(3, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("any." + type , new BsonInt32(1)); } if (paramName.startsWith("GT_") || paramName.startsWith("GE_") || paramName.startsWith("LT_") || paramName.startsWith("LE_")) { String type = paramName.substring(3, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("any." + type , new BsonInt32(1)); } if (paramName.startsWith("EXISTS_")) { String type = paramName.substring(3, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); indexDocument.put("any." + type , new BsonInt32(1)); } } } } // Update Query with ORDER and LIMIT if (p.getOrderBy() != null) { String orderBy = MongoWriterUtil.encodeMongoObjectKey(p.getOrderBy()); // Currently only eventTime, recordTime can be used if (orderBy.trim().equals("eventTime")) { indexDocument.put("eventTime" , new BsonInt32(1)); } else if (orderBy.trim().equals("recordTime")) { indexDocument.put("recordTime" , new BsonInt32(1)); } else { indexDocument.put("any." + orderBy , new BsonInt32(1)); } } return indexDocument; } boolean isExtraParameter(String paramName) { if (paramName.contains("eventTime")) return false; if (paramName.contains("recordTime")) return false; if (paramName.contains("errorDeclarationTime")) return false; if (paramName.contains("action")) return false; if (paramName.contains("bizStep")) return false; if (paramName.contains("disposition")) return false; if (paramName.contains("readPoint")) return false; if (paramName.contains("bizLocation")) return false; if (paramName.contains("bizTransaction")) return false; if (paramName.contains("source")) return false; if (paramName.contains("destination")) return false; if (paramName.contains("transformationID")) return false; if (paramName.contains("ILMD")) return false; if (paramName.contains("eventID")) return false; if (paramName.contains("errorReason")) return false; if (paramName.contains("correctiveEventID")) return false; if (paramName.contains("errorDeclaration")) return false; if (paramName.contains("ERROR_DECLARATION")) return false; if (paramName.contains("INNER")) return false; return true; } }