package org.oliot.epcis.service.query.mongodb; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Pattern; import javax.xml.bind.JAXB; import javax.xml.bind.JAXBElement; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import org.apache.log4j.Level; import org.bson.BsonArray; import org.bson.BsonBoolean; import org.bson.BsonDateTime; import org.bson.BsonDocument; import org.bson.BsonInt32; import org.bson.BsonObjectId; import org.bson.BsonString; import org.bson.BsonType; import org.bson.BsonValue; import org.bson.types.ObjectId; import org.json.JSONArray; import org.json.JSONObject; import org.oliot.epcis.configuration.Configuration; import org.oliot.epcis.converter.mongodb.AggregationEventReadConverter; import org.oliot.epcis.converter.mongodb.MasterDataReadConverter; import org.oliot.epcis.converter.mongodb.MongoWriterUtil; import org.oliot.epcis.converter.mongodb.ObjectEventReadConverter; import org.oliot.epcis.converter.mongodb.QuantityEventReadConverter; import org.oliot.epcis.converter.mongodb.TransactionEventReadConverter; import org.oliot.epcis.converter.mongodb.TransformationEventReadConverter; import org.oliot.epcis.security.OAuthUtil; import org.oliot.epcis.service.subscription.MongoSubscription; import org.oliot.epcis.service.subscription.MongoSubscriptionTask; import org.oliot.epcis.service.subscription.TriggerEngine; import org.oliot.model.epcis.AggregationEventType; import org.oliot.model.epcis.AttributeType; import org.oliot.model.epcis.EPCISEventListExtensionType; import org.oliot.model.epcis.EPCISQueryBodyType; import org.oliot.model.epcis.EPCISQueryDocumentType; import org.oliot.model.epcis.EventListType; import org.oliot.model.epcis.InvalidURIException; import org.oliot.model.epcis.ObjectEventType; import org.oliot.model.epcis.PollParameters; import org.oliot.model.epcis.QuantityEventType; import org.oliot.model.epcis.QueryParameterException; import org.oliot.model.epcis.QueryParams; import org.oliot.model.epcis.QueryResults; import org.oliot.model.epcis.QueryResultsBody; import org.oliot.model.epcis.QuerySchedule; import org.oliot.model.epcis.QueryTooLargeException; import org.oliot.model.epcis.SubscribeNotPermittedException; import org.oliot.model.epcis.SubscriptionControls; import org.oliot.model.epcis.SubscriptionControlsException; import org.oliot.model.epcis.SubscriptionType; import org.oliot.model.epcis.TransactionEventType; import org.oliot.model.epcis.TransformationEventType; import org.oliot.model.epcis.VocabularyElementType; import org.oliot.model.epcis.VocabularyListType; import org.oliot.model.epcis.VocabularyType; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.springframework.web.bind.annotation.PathVariable; import com.mongodb.client.FindIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import static org.oliot.epcis.service.query.mongodb.MongoQueryUtil.*; import static org.quartz.CronScheduleBuilder.cronSchedule; import static org.quartz.JobBuilder.newJob; import static org.quartz.JobKey.jobKey; import static org.quartz.TriggerBuilder.newTrigger; import static org.quartz.TriggerKey.triggerKey; /** * 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 */ public class MongoQueryService { public String subscribeEventQuery(SubscriptionType s, String userID, List<String> friendList) throws QueryParameterException, SubscriptionControlsException { // M27 - query params' constraint // M39 - query params' constraint String reason = checkConstraintSimpleEventQuery(s.getPollParameters()); if (reason != null) { throw new QueryParameterException(); // return makeErrorResult(reason, QueryParameterException.class); } // Existing subscription Check MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("Subscription", BsonDocument.class); BsonDocument exist = collection.find(new BsonDocument("subscriptionID", new BsonString(s.getSubscriptionID()))) .first(); if (exist != null) { return "SubscriptionID : " + s.getSubscriptionID() + " is already subscribed. "; } // cron Example // 0/10 * * * * ? : every 10 second if (s.getSchedule() != null && s.getTrigger() == null) { try { cronSchedule(s.getSchedule()); addScheduleToQuartz(s); } catch (RuntimeException e) { throw new SubscriptionControlsException(); // return makeErrorResult(e.toString(), // SubscriptionControlsException.class); } } else if (s.getSchedule() == null && s.getTrigger() != null) { // Add Trigger with Query TriggerEngine.addTriggerSubscription(s.getSubscriptionID(), s); } else { throw new SubscriptionControlsException(); // return makeErrorResult("One of schedule, trigger should be null", // SubscriptionControlsException.class); } // Manage Subscription Persistently addScheduleToDB(s, userID, friendList); String retString = "SubscriptionID : " + s.getSubscriptionID() + " is successfully triggered. "; return retString; } public String subscribe(SubscriptionType s, String userID, List<String> friendList) throws QueryParameterException, SubscriptionControlsException, InvalidURIException, SubscribeNotPermittedException { // M20 : Throw an InvalidURIException for an incorrect dest argument in // the subscribe method in EPCIS Query Control Interface try { new URL(s.getDest()); } catch (MalformedURLException e) { throw new InvalidURIException(); // return makeErrorResult(e.toString(), InvalidURIException.class); } // M24 : Virtual Error Handling // Automatically processed by URI param // v1.2 not work if (s.getDest() == null) { throw new QueryParameterException(); // return makeErrorResult("Fill the mandatory field in subscribe // method", QueryParameterException.class); } // M46 if (s.getPollParameters().getQueryName().equals("SimpleMasterDataQuery")) { throw new SubscribeNotPermittedException(); // return makeErrorResult("SimpleMasterDataQuery is not available in // subscription method", SubscribeNotPermittedException.class); } String retString = ""; if (s.getPollParameters().getQueryName().equals("SimpleEventQuery")) { retString = subscribeEventQuery(s, userID, friendList); } return retString; } // Soap Query Adaptor public void subscribe(String queryName, QueryParams params, URI dest, SubscriptionControls controls, String subscriptionID) throws QueryParameterException, SubscriptionControlsException, InvalidURIException, SubscribeNotPermittedException { PollParameters p = new PollParameters(queryName, params); // Subscription Control Processing /* * QuerySchedule: (Optional) Defines the periodic schedule on which the * query is to be executed. See Section 8.2.5.3. Exactly one of schedule * or trigger is required; if both are specified or both are omitted, * the implementation SHALL raise a SubscriptionControls- Exception.. */ QuerySchedule querySchedule = controls.getSchedule(); String schedule = null; if (querySchedule != null) { String sec = querySchedule.getSecond(); if (sec == null) sec = "*"; String min = querySchedule.getMinute(); if (min == null) min = "*"; String hour = querySchedule.getHour(); if (hour == null) hour = "*"; String dayOfMonth = querySchedule.getDayOfMonth(); if (dayOfMonth == null) dayOfMonth = "*"; String month = querySchedule.getMonth(); String dayOfWeek = querySchedule.getDayOfWeek(); // either month or dayOfWeek should be ? // two are not null -> dayOfWeek = ? // one of two exists -> non-exist = ? // two are null -> month=* , dayOfWeek=? if (month == null && dayOfWeek == null) { month = "*"; dayOfWeek = "?"; } else if (month != null && dayOfWeek == null) { dayOfWeek = "?"; } else if (month == null && dayOfWeek != null) { month = "?"; } else { dayOfWeek = "?"; } schedule = sec + " " + min + " " + hour + " " + dayOfMonth + " " + month + " " + dayOfWeek; } /* * InitialRecordTime: (Optional) Specifies a time used to constrain what * events are considered when processing the query when it is executed * for the first time. See Section 8.2.5.2. If omitted, defaults to the * time at which the subscription is created. */ XMLGregorianCalendar initialRecordTime = controls.getInitialRecordTime(); String initialRecordTimeStr = null; if (initialRecordTime != null) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); Date initialRecordDate = initialRecordTime.toGregorianCalendar().getTime(); initialRecordTimeStr = sdf.format(initialRecordDate); } /* * reportIfEmpty: If true, a QueryResults instance is always sent to the * subscriber when the query is executed. If false, a QueryResults * instance is sent to the subscriber only when the results are * non-empty. */ Boolean reportIfEmpty = controls.isReportIfEmpty(); SubscriptionType subscription = new SubscriptionType(subscriptionID, dest.toString(), schedule, controls.getTrigger(), initialRecordTimeStr, reportIfEmpty, p); subscribe(subscription, null, null); } public void unsubscribe(String subscriptionID) { MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("Subscription", BsonDocument.class); // Its size should be 0 or 1 BsonDocument s = collection .findOneAndDelete(new BsonDocument("subscriptionID", new BsonString(subscriptionID))); if (s != null) { SubscriptionType subscription = new SubscriptionType(s); if (subscription.getSchedule() != null && subscription.getTrigger() == null) { // Remove from current Quartz removeScheduleFromQuartz(subscription); } else { TriggerEngine.removeTriggerSubscription(subscription.getSubscriptionID()); } } } public String getSubscriptionIDsREST(@PathVariable String queryName) { JSONArray retArray = new JSONArray(); MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("Subscription", BsonDocument.class); Iterator<BsonDocument> subIterator = collection .find(new BsonDocument("pollParameters.queryName", new BsonString(queryName)), BsonDocument.class) .iterator(); while (subIterator.hasNext()) { BsonDocument subscription = subIterator.next(); retArray.put(subscription.getString("subscriptionID").getValue()); } return retArray.toString(1); } public List<String> getSubscriptionIDs(String queryName) { List<String> retList = new ArrayList<String>(); MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("Subscription", BsonDocument.class); Iterator<BsonDocument> subIterator = collection .find(new BsonDocument("pollParameters.queryName", new BsonString(queryName)), BsonDocument.class) .iterator(); while (subIterator.hasNext()) { BsonDocument subscription = subIterator.next(); retList.add(subscription.getString("subscriptionID").asString().getValue()); } return retList; } @SuppressWarnings({ "unchecked", "rawtypes" }) public String pollEventQuery(PollParameters p, String userID, List<String> friendList, String subscriptionID) throws QueryParameterException, QueryTooLargeException { // M27 - query params' constraint // M39 - query params' constraint String reason = checkConstraintSimpleEventQuery(p); if (reason != null) { throw new QueryParameterException(); // return makeErrorResult(reason, QueryParameterException.class); } // Make Base Result Document EPCISQueryDocumentType epcisQueryDocumentType = null; if (p.getFormat() == null || p.getFormat().equals("XML")) { epcisQueryDocumentType = makeBaseResultDocument(p.getQueryName(), subscriptionID); } else if (p.getFormat().equals("JSON")) { // Do Nothing } else { throw new QueryParameterException(); // return makeErrorResult("format param should be one of XML or // JSON", QueryParameterException.class); } // Prepare container which query results are included // eventObjects : Container which all the query results (events) will be // contained List<Object> eventObjects = null; if (p.getFormat() == null || p.getFormat().equals("XML")) { eventObjects = epcisQueryDocumentType.getEPCISBody().getQueryResults().getResultsBody().getEventList() .getObjectEventOrAggregationEventOrQuantityEvent(); } else { // foramt == JSON -> Do Nothing } // Event Collection MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("EventData", BsonDocument.class); // Queries BsonArray queryList = makeQueryObjects(p, userID, friendList); // Merge All the queries with $and BsonDocument baseQuery = new BsonDocument(); FindIterable<BsonDocument> cursor; if (queryList.isEmpty() == false) { BsonArray aggreQueryList = new BsonArray(); for (int i = 0; i < queryList.size(); i++) { aggreQueryList.add(queryList.get(i)); } baseQuery.put("$and", aggreQueryList); // Query cursor = collection.find(baseQuery); } else { cursor = collection.find(); } // Sort and Limit cursor = makeProjectSortedLimitedCursor(cursor, p.getParams(), p.getOrderBy(), p.getOrderDirection(), p.getEventCountLimit()); JSONArray retArray = new JSONArray(); MongoCursor<BsonDocument> slCursor = cursor.iterator(); while (slCursor.hasNext()) { BsonDocument dbObject = slCursor.next(); String eventTypeInDoc = dbObject.getString("eventType").getValue(); if (OAuthUtil.isAccessible(userID, friendList, dbObject) == false) { continue; } if (!isPostFilterPassed(eventTypeInDoc, dbObject, p.getParams())) continue; if (p.getFormat() == null || p.getFormat().equals("XML")) { if (eventTypeInDoc.equals("AggregationEvent")) { AggregationEventReadConverter con = new AggregationEventReadConverter(); JAXBElement element = new JAXBElement(new QName("AggregationEvent"), AggregationEventType.class, con.convert(dbObject)); eventObjects.add(element); } else if (eventTypeInDoc.equals("ObjectEvent")) { ObjectEventReadConverter con = new ObjectEventReadConverter(); JAXBElement element = new JAXBElement(new QName("ObjectEvent"), ObjectEventType.class, con.convert(dbObject)); eventObjects.add(element); } else if (eventTypeInDoc.equals("QuantityEvent")) { QuantityEventReadConverter con = new QuantityEventReadConverter(); JAXBElement element = new JAXBElement(new QName("QuantityEvent"), QuantityEventType.class, con.convert(dbObject)); eventObjects.add(element); } else if (eventTypeInDoc.equals("TransactionEvent")) { TransactionEventReadConverter con = new TransactionEventReadConverter(); JAXBElement element = new JAXBElement(new QName("TransactionEvent"), TransactionEventType.class, con.convert(dbObject)); eventObjects.add(element); } else if (eventTypeInDoc.equals("TransformationEvent")) { TransformationEventReadConverter con = new TransformationEventReadConverter(); TransformationEventType transformationEvent = con.convert(dbObject); EPCISEventListExtensionType extension = new EPCISEventListExtensionType(); extension.setTransformationEvent(transformationEvent); JAXBElement element = new JAXBElement(new QName("extension"), EPCISEventListExtensionType.class, extension); eventObjects.add(element); } } else { dbObject.remove("_id"); retArray.put(new JSONObject(dbObject.toJson())); } } // M44 if (p.getMaxEventCount() != null) { if (p.getFormat() == null || p.getFormat().equals("XML")) { if (eventObjects.size() > p.getMaxEventCount()) { throw new QueryTooLargeException(eventObjects.size(), p.getMaxEventCount(), "SimpleEventQuery", null); // return makeErrorResult("Violate maxEventCount", // QueryTooLargeException.class); } } else { if (retArray.length() > p.getMaxEventCount()) { throw new QueryTooLargeException(retArray.length(), p.getMaxEventCount(), "SimpleEventQuery", null); // return makeErrorResult("Violate maxEventCount", // QueryTooLargeException.class); } } } if (p.getFormat() == null || p.getFormat().equals("XML")) { StringWriter sw = new StringWriter(); JAXB.marshal(epcisQueryDocumentType, sw); return sw.toString(); } else { return retArray.toString(1); } } public String pollMasterDataQuery(PollParameters p, String userID, List<String> friendList) throws QueryTooLargeException, QueryParameterException { // Required Field Check if (p.getIncludeAttributes() == null || p.getIncludeChildren() == null) { throw new QueryParameterException(); // return makeErrorResult("SimpleMasterDataQuery's Required Field: // includeAttributes, includeChildren", // QueryTooLargeException.class); } // Make Base Result Document EPCISQueryDocumentType epcisQueryDocumentType = null; JSONArray retArray = new JSONArray(); if (p.getFormat() == null || p.getFormat().equals("XML")) { epcisQueryDocumentType = makeBaseResultDocument(p.getQueryName(), null); } else if (p.getFormat().equals("JSON")) { // Do Nothing } else { throw new QueryParameterException(); // return makeErrorResult("format param should be one of XML or // JSON", QueryParameterException.class); } MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("MasterData", BsonDocument.class); // Make Query BsonArray queryList = makeMasterQueryObjects(p); // Merge All the queries with $and BsonDocument baseQuery = new BsonDocument(); FindIterable<BsonDocument> cursor; if (queryList.isEmpty() == false) { BsonArray aggreQueryList = new BsonArray(); for (int i = 0; i < queryList.size(); i++) { aggreQueryList.add(queryList.get(i)); } baseQuery.put("$and", aggreQueryList); // Query cursor = collection.find(baseQuery); } else { cursor = collection.find(); } // Cursor needed to ordered List<VocabularyType> vList = new ArrayList<>(); MongoCursor<BsonDocument> slCursor = cursor.iterator(); while (slCursor.hasNext()) { BsonDocument dbObject = slCursor.next(); if (p.getFormat() == null || p.getFormat().equals("XML")) { MasterDataReadConverter con = new MasterDataReadConverter(); VocabularyType vt = con.convert(dbObject); if (vt.getVocabularyElementList() != null) { if (vt.getVocabularyElementList().getVocabularyElement() != null) { List<VocabularyElementType> vetList = vt.getVocabularyElementList().getVocabularyElement(); for (int i = 0; i < vetList.size(); i++) { VocabularyElementType vet = vetList.get(i); if (p.getIncludeAttributes() == false) { vet.setAttribute(null); } else if (p.getIncludeAttributes() == true && p.getAttributeNames() != null) { String[] attrArr = p.getAttributeNames().split(","); Set<String> attrSet = new HashSet<String>(); for (int j = 0; j < attrArr.length; j++) { attrSet.add(attrArr[j].trim()); } List<AttributeType> atList = vet.getAttribute(); List<AttributeType> filteredList = new ArrayList<AttributeType>(); for (int j = 0; j < atList.size(); j++) { if (attrSet.contains(atList.get(j).getId())) { filteredList.add(atList.get(j)); } } vet.setAttribute(filteredList); } if (p.getIncludeChildren() == false) { vet.setChildren(null); } } } } vList.add(vt); } else { dbObject.remove("_id"); if (p.getIncludeAttributes() == false) { dbObject.remove("attributes"); } else if (p.getIncludeAttributes() == true && p.getAttributeNames() != null) { String[] attrArr = p.getAttributeNames().split(","); Set<String> attrSet = new HashSet<String>(); for (int j = 0; j < attrArr.length; j++) { attrSet.add(attrArr[j].trim()); } BsonDocument attrObject = dbObject.get("attributes").asDocument(); BsonDocument newObject = new BsonDocument(); if (attrObject != null) { Iterator<String> attrKeys = attrObject.keySet().iterator(); while (attrKeys.hasNext()) { String attrKey = attrKeys.next(); if (attrSet.contains(attrKey)) { newObject.put(attrKey, attrObject.get(attrKey)); } } } dbObject.put("attributes", newObject); } if (p.getIncludeChildren() == false) { dbObject.remove("children"); } retArray.put(new JSONObject(dbObject.toJson())); } } if (p.getFormat() == null || p.getFormat().equals("XML")) { QueryResultsBody qbt = epcisQueryDocumentType.getEPCISBody().getQueryResults().getResultsBody(); VocabularyListType vlt = new VocabularyListType(); vlt.setVocabulary(vList); qbt.setVocabularyList(vlt); } // M47 if (p.getMaxElementCount() != null) { try { if (p.getFormat() == null || p.getFormat().equals("XML")) { if (vList.size() > p.getMaxElementCount()) { throw new QueryTooLargeException(vList.size(), p.getMaxElementCount(), "SimpleMasterDataQuery", null); // return makeErrorResult("Too Large Master Data // result", QueryTooLargeException.class); } } else { if (retArray.length() > p.getMaxElementCount()) { throw new QueryTooLargeException(retArray.length(), p.getMaxElementCount(), "SimpleMasterDataQuery", null); // return makeErrorResult("Too Large Master Data // result", QueryTooLargeException.class); } } } catch (NumberFormatException e) { } } if (p.getFormat() == null || p.getFormat().equals("XML")) { StringWriter sw = new StringWriter(); JAXB.marshal(epcisQueryDocumentType, sw); return sw.toString(); } else { return retArray.toString(1); } } // Soap Service Adaptor public String poll(String queryName, QueryParams queryParams) throws QueryParameterException, QueryTooLargeException { PollParameters p = new PollParameters(queryName, queryParams); return poll(p, null, null, null); } public String poll(PollParameters p, String userID, List<String> friendList, String subscriptionID) throws QueryParameterException, QueryTooLargeException { // M24 if (p.getQueryName() == null) { // It is not possible, automatically filtered by URI param throw new QueryParameterException(); // return makeErrorResult("queryName is mandatory field in poll // method", QueryParameterException.class); } if (p.getQueryName().equals("SimpleEventQuery")) return pollEventQuery(p, userID, friendList, subscriptionID); if (p.getQueryName().equals("SimpleMasterDataQuery")) return pollMasterDataQuery(p, userID, friendList); return ""; } static BsonDateTime getTimeMillis(String standardDateString) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); GregorianCalendar eventTimeCalendar = new GregorianCalendar(); eventTimeCalendar.setTime(sdf.parse(standardDateString)); return new BsonDateTime(eventTimeCalendar.getTimeInMillis()); } catch (ParseException e) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); GregorianCalendar eventTimeCalendar = new GregorianCalendar(); eventTimeCalendar.setTime(sdf.parse(standardDateString)); return new BsonDateTime(eventTimeCalendar.getTimeInMillis()); } catch (ParseException e1) { Configuration.logger.log(Level.ERROR, e1.toString()); } } // Never Happened return null; } 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; } public String checkConstraintSimpleEventQuery(PollParameters p) throws QueryParameterException { // M27 try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); if (p.getGE_eventTime() != null) sdf.parse(p.getGE_eventTime()); if (p.getLT_eventTime() != null) sdf.parse(p.getLT_eventTime()); if (p.getGE_recordTime() != null) sdf.parse(p.getGE_recordTime()); if (p.getLT_recordTime() != null) sdf.parse(p.getLT_recordTime()); } catch (ParseException e) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); if (p.getGE_eventTime() != null) sdf.parse(p.getGE_eventTime()); if (p.getLT_eventTime() != null) sdf.parse(p.getLT_eventTime()); if (p.getGE_recordTime() != null) sdf.parse(p.getGE_recordTime()); if (p.getLT_recordTime() != null) sdf.parse(p.getLT_recordTime()); } catch (ParseException e1) { throw new QueryParameterException(); // return makeErrorResult(e.toString(), // QueryParameterException.class); } } // M27 if (p.getOrderBy() != null) { /* * if (!orderBy.equals("eventTime") && * !orderBy.equals("recordTime")) { return makeErrorResult( * "orderBy should be eventTime or recordTime", * QueryParameterException.class); } */ if (p.getOrderDirection() != null) { if (!p.getOrderDirection().equals("ASC") && !p.getOrderDirection().equals("DESC")) { throw new QueryParameterException(); // return makeErrorResult("orderDirection should be ASC or // DESC", QueryParameterException.class); } } } // M27 if (p.getEventCountLimit() != null) { if (p.getEventCountLimit() <= 0) { throw new QueryParameterException(); // return makeErrorResult("eventCount should be natural number", // QueryParameterException.class); } } // M27 if (p.getMaxEventCount() != null) { if (p.getMaxEventCount() <= 0) { throw new QueryParameterException(); // return makeErrorResult("maxEventCount should be natural // number", QueryParameterException.class); } } // M39 if (p.getEQ_action() != null) { String[] actionArr = p.getEQ_action().split(","); for (String action : actionArr) { action = action.trim(); if (action.equals("")) continue; if (!action.equals("ADD") && !action.equals("OBSERVE") && !action.equals("DELETE")) { throw new QueryParameterException(); // return makeErrorResult("EQ_action: ADD | OBSERVE | // DELETE", QueryParameterException.class); } } } // M42 if (p.getEventCountLimit() != null && p.getMaxEventCount() != null) { throw new QueryParameterException(); // return makeErrorResult("One of eventCountLimit and maxEventCount // should be omitted", QueryParameterException.class); } return null; } public EPCISQueryDocumentType makeBaseResultDocument(String queryName, String subscriptionID) { // Make Base Result Document EPCISQueryDocumentType epcisQueryDocumentType = new EPCISQueryDocumentType(); EPCISQueryBodyType epcisBody = new EPCISQueryBodyType(); epcisQueryDocumentType.setEPCISBody(epcisBody); QueryResults queryResults = new QueryResults(); queryResults.setQueryName(queryName); epcisBody.setQueryResults(queryResults); QueryResultsBody queryResultsBody = new QueryResultsBody(); queryResults.setResultsBody(queryResultsBody); if (subscriptionID != null) queryResults.setSubscriptionID(subscriptionID); EventListType eventListType = new EventListType(); queryResultsBody.setEventList(eventListType); // Object instanceof JAXBElement List<Object> eventObjects = new ArrayList<Object>(); eventListType.setObjectEventOrAggregationEventOrQuantityEvent(eventObjects); return epcisQueryDocumentType; } @SuppressWarnings({ "rawtypes", "unused" }) private String makeErrorResult(String err, Class type) { if (type == InvalidURIException.class) { InvalidURIException e = new InvalidURIException(); e.setReason(err); EPCISQueryDocumentType retDoc = new EPCISQueryDocumentType(); EPCISQueryBodyType retBody = new EPCISQueryBodyType(); retBody.setInvalidURIException(e); retDoc.setEPCISBody(retBody); StringWriter sw = new StringWriter(); JAXB.marshal(retDoc, sw); return sw.toString(); } if (type == QueryParameterException.class) { QueryParameterException e = new QueryParameterException(); e.setReason(err); EPCISQueryDocumentType retDoc = new EPCISQueryDocumentType(); EPCISQueryBodyType retBody = new EPCISQueryBodyType(); retBody.setQueryParameterException(e); retDoc.setEPCISBody(retBody); StringWriter sw = new StringWriter(); JAXB.marshal(retDoc, sw); return sw.toString(); } if (type == SubscriptionControlsException.class) { SubscriptionControlsException e = new SubscriptionControlsException(); e.setReason(err); EPCISQueryDocumentType retDoc = new EPCISQueryDocumentType(); EPCISQueryBodyType retBody = new EPCISQueryBodyType(); retBody.setSubscriptionControlsException(e); retDoc.setEPCISBody(retBody); StringWriter sw = new StringWriter(); JAXB.marshal(retDoc, sw); return sw.toString(); } if (type == QueryTooLargeException.class) { QueryTooLargeException e = new QueryTooLargeException(); e.setReason(err); EPCISQueryDocumentType retDoc = new EPCISQueryDocumentType(); EPCISQueryBodyType retBody = new EPCISQueryBodyType(); retBody.setQueryTooLargeException(e); retDoc.setEPCISBody(retBody); StringWriter sw = new StringWriter(); JAXB.marshal(retDoc, sw); return sw.toString(); } if (type == SubscribeNotPermittedException.class) { SubscribeNotPermittedException e = new SubscribeNotPermittedException(); e.setReason(err); EPCISQueryDocumentType retDoc = new EPCISQueryDocumentType(); EPCISQueryBodyType retBody = new EPCISQueryBodyType(); retBody.setSubscribeNotPermittedException(e); retDoc.setEPCISBody(retBody); StringWriter sw = new StringWriter(); JAXB.marshal(retDoc, sw); return sw.toString(); } return null; } private FindIterable<BsonDocument> makeProjectSortedLimitedCursor(FindIterable<BsonDocument> cursor, Map<String, String> extParams, String orderBy, String orderDirection, Integer eventCountLimit) { Iterator<Entry<String, String>> extParamIter = extParams.entrySet().iterator(); BsonDocument projection = new BsonDocument(); BsonBoolean projValue = null; while (extParamIter.hasNext()) { Entry<String, String> entry = extParamIter.next(); String paramKey = entry.getKey(); String paramValue = entry.getValue(); if (paramKey.startsWith("PROJECTION_")) { if (projValue == null) { if (paramValue != null && (paramValue.equals("true") || paramValue.equals("true^boolean"))) { projValue = BsonBoolean.TRUE; } else { projValue = BsonBoolean.FALSE; } } String projKey = paramKey.substring(11, paramKey.length()); // eventType is prohibited for projection if (!projKey.equals("eventType")) projection.put(projKey, projValue); } } if (!projection.isEmpty()) { if (projValue.getValue() == true) projection.append("eventType", BsonBoolean.TRUE); cursor.projection(projection); } /** * orderBy : If specified, names a single field that will be used to * order the results. The orderDirection field specifies whether the * ordering is in ascending sequence or descending sequence. Events * included in the result that lack the specified field altogether may * occur in any position within the result event list. The value of this * parameter SHALL be one of: eventTime, recordTime, or the fully * qualified name of an extension field whose type is Int, Float, Time, * or String. A fully qualified fieldname is constructed as for the * EQ_fieldname parameter. In the case of a field of type String, the * ordering SHOULD be in lexicographic order based on the Unicode * encoding of the strings, or in some other collating sequence * appropriate to the locale. If omitted, no order is specified. The * implementation MAY order the results in any order it chooses, and * that order MAY differ even when the same query is executed twice on * the same data. (In EPCIS 1.0, the value quantity was also permitted, * but its use is deprecated in EPCIS 1.1.) * * orderDirection : If specified and orderBy is also specified, * specifies whether the results are ordered in ascending or descending * sequence according to the key specified by orderBy. The value of this * parameter must be one of ASC (for ascending order) or DESC (for * descending order); if not, the implementation SHALL raise a * QueryParameterException. If omitted, defaults to DESC. */ // Update Query with ORDER and LIMIT if (orderBy != null) { orderBy = MongoWriterUtil.encodeMongoObjectKey(orderBy); // Currently only eventTime, recordTime can be used if (orderBy.trim().equals("eventTime")) { if (orderDirection != null) { if (orderDirection.trim().equals("ASC")) { cursor = cursor.sort(new BsonDocument("eventTime", new BsonInt32(1))); } else if (orderDirection.trim().equals("DESC")) { cursor = cursor.sort(new BsonDocument("eventTime", new BsonInt32(-1))); } } else { cursor = cursor.sort(new BsonDocument("eventTime", new BsonInt32(-1))); } } else if (orderBy.trim().equals("recordTime")) { if (orderDirection != null) { if (orderDirection.trim().equals("ASC")) { cursor = cursor.sort(new BsonDocument("recordTime", new BsonInt32(1))); } else if (orderDirection.trim().equals("DESC")) { cursor = cursor.sort(new BsonDocument("recordTime", new BsonInt32(-1))); } } else { cursor = cursor.sort(new BsonDocument("recordTime", new BsonInt32(-1))); } } else { if (orderDirection != null) { if (orderDirection.trim().equals("ASC")) { cursor = cursor.sort(new BsonDocument("any." + orderBy, new BsonInt32(1))); } else if (orderDirection.trim().equals("DESC")) { cursor = cursor.sort(new BsonDocument("any." + orderBy, new BsonInt32(-1))); } } else { cursor = cursor.sort(new BsonDocument("any." + orderBy, new BsonInt32(-1))); } } } /** * eventCountLimit: If specified, the results will only include the * first N events that match the other criteria, where N is the value of * this parameter. The ordering specified by the orderBy and * orderDirection parameters determine the meaning of “first” for this * purpose. If omitted, all events matching the specified criteria will * be included in the results. This parameter and maxEventCount are * mutually exclusive; if both are specified, a QueryParameterException * SHALL be raised. This parameter may only be used when orderBy is * specified; if orderBy is omitted and eventCountLimit is specified, a * QueryParameterException SHALL be raised. This parameter differs from * maxEventCount in that this parameter limits the amount of data * returned, whereas maxEventCount causes an exception to be thrown if * the limit is exceeded. */ if (eventCountLimit != null) { try { cursor = cursor.limit(eventCountLimit); } catch (NumberFormatException nfe) { Configuration.logger.log(Level.ERROR, nfe.toString()); } } return cursor; } private BsonArray makeQueryObjects(PollParameters p, String userID, List<String> friendList) { BsonArray queryList = new BsonArray(); /** * eventType : If specified, the result will only include events whose * type matches one of the types specified in the parameter value. Each * element of the parameter value may be one of the following strings: * ObjectEvent, AggregationEvent, QuantityEvent, TransactionEvent, or * TransformationEvent. An element of the parameter value may also be * the name of an extension event type. If omitted, all event types will * be considered for inclusion in the result. * * List of String CSV REGEX */ if (p.getEventType() != null) { BsonArray paramArray = getParamBsonArray(p.getEventType()); BsonDocument queryObject = getQueryObject(new String[] { "eventType" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * GE_eventTime: If specified, only events with eventTime greater than * or equal to the specified value will be included in the result. If * omitted, events are included regardless of their eventTime (unless * constrained by the LT_ eventTime parameter). Example: * 2014-08-11T19:57:59.717+09:00 SimpleDateFormat sdf = new * SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); * eventTime.setTime(sdf.parse(timeString)); e.g. * 1988-07-04T12:08:56.235-07:00 * * Verified */ if (p.getGE_eventTime() != null) { BsonDateTime geBsonDateTime = getTimeMillis(p.getGE_eventTime()); BsonDocument query = new BsonDocument(); query.put("eventTime", new BsonDocument("$gte", geBsonDateTime)); queryList.add(query); } /** * LT_eventTime: If specified, only events with eventTime less than the * specified value will be included in the result. If omitted, events * are included regardless of their eventTime (unless constrained by the * GE_ eventTime parameter). * * Verified */ if (p.getLT_eventTime() != null) { BsonDateTime ltBsonDateTime = getTimeMillis(p.getLT_eventTime()); BsonDocument query = new BsonDocument(); query.put("eventTime", new BsonDocument("$lt", ltBsonDateTime)); queryList.add(query); } /** * GE_recordTime: If provided, only events with recordTime greater than * or equal to the specified value will be returned. The automatic * limitation based on event record time (Section 8.2.5.2) may * implicitly provide a constraint similar to this parameter. If * omitted, events are included regardless of their recordTime , other * than automatic limitation based on event record time (Section * 8.2.5.2). * * Verified */ if (p.getGE_recordTime() != null) { BsonDateTime geBsonDateTime = getTimeMillis(p.getGE_recordTime()); BsonDocument query = new BsonDocument(); query.put("recordTime", new BsonDocument("$gte", geBsonDateTime)); queryList.add(query); } /** * LE_recordTime: If provided, only events with recordTime less than the * specified value will be returned. If omitted, events are included * regardless of their recordTime (unless constrained by the GE_ * recordTime parameter or the automatic limitation based on event * record time). * * Verified */ if (p.getLT_recordTime() != null) { BsonDateTime ltBsonDateTime = getTimeMillis(p.getLT_recordTime()); BsonDocument query = new BsonDocument(); query.put("recordTime", new BsonDocument("$lt", ltBsonDateTime)); queryList.add(query); } /** * GE_errorDeclaration Time: If this parameter is specified, the result * will only include events that (a) contain an ErrorDeclaration ; and * where (b) the value of the errorDeclarationTime field is greater than * or equal to the specified value. If this parameter is omitted, events * are returned regardless of whether they contain an ErrorDeclaration * or what the value of the errorDeclarationTime field is. */ if (p.getGE_errorDeclarationTime() != null) { BsonDateTime geBsonDateTime = getTimeMillis(p.getGE_errorDeclarationTime()); BsonDocument query = new BsonDocument(); query.put("errorDeclaration.declarationTime", new BsonDocument("$gte", geBsonDateTime)); queryList.add(query); } /** * LT_errorDeclaration Time: contain an ErrorDeclaration ; and where (b) * the value of the errorDeclarationTime field is less than to the * specified value. If this parameter is omitted, events are returned * regardless of whether they contain an ErrorDeclaration or what the * value of the errorDeclarationTime field is. */ if (p.getLT_errorDeclarationTime() != null) { BsonDateTime ltBsonDateTime = getTimeMillis(p.getLT_errorDeclarationTime()); BsonDocument query = new BsonDocument(); query.put("errorDeclaration.declarationTime", new BsonDocument("$lt", ltBsonDateTime)); queryList.add(query); } /** * EQ_action: If specified, the result will only include events that (a) * have an action field; and where (b) the value of the action field * matches one of the specified values. The elements of the value of * this parameter each must be one of the strings ADD , OBSERVE , or * DELETE ; if not, the implementation SHALL raise a * QueryParameterException . If omitted, events are included regardless * of their action field. * * OR semantic * * Verified */ if (p.getEQ_action() != null) { // Constrained already checked BsonArray paramArray = getParamBsonArray(p.getEQ_action()); BsonDocument queryObject = getQueryObject(new String[] { "action" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_bizStep: If specified, the result will only include events that * (a) have a non-null bizStep field; and where (b) the value of the * bizStep field matches one of the specified values. If this parameter * is omitted, events are returned regardless of the value of the * bizStep field or whether the bizStep field exists at all. * * OR semantic Regex supported * * Verified */ if (p.getEQ_bizStep() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_bizStep()); BsonDocument queryObject = getQueryObject(new String[] { "bizStep" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * Like the EQ_ bizStep parameter, but for the disposition field. * * OR semantic Regex Supported * * Verified */ if (p.getEQ_disposition() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_disposition()); BsonDocument queryObject = getQueryObject(new String[] { "disposition" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_readPoint: If specified, the result will only include events that * (a) have a non-null readPoint field; and where (b) the value of the * readPoint field matches one of the specified values. If this * parameter and WD_ readPoint are both omitted, events are returned * regardless of the value of the readPoint field or whether the * readPoint field exists at all. * * OR semantic Regex supported * */ if (p.getEQ_readPoint() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_readPoint()); BsonDocument queryObject = getQueryObject(new String[] { "readPoint.id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * WD_readPoint: If specified, the result will only include events that * (a) have a non-null readPoint field; and where (b) the value of the * readPoint field matches one of the specified values, or is a direct * or indirect descendant of one of the specified values. The meaning of * “direct or indirect descendant” is specified by master data, as * described in Section 6.5. (WD is an abbreviation for “with * descendants.”) If this parameter and EQ_readPoint are both omitted, * events are returned regardless of the value of the readPoint field or * whether the readPoint field exists at all. * * OR semantic Regex Supported * */ if (p.getWD_readPoint() != null) { BsonArray paramArray = getWDParamBsonArray(p.getWD_readPoint()); BsonDocument queryObject = getQueryObject(new String[] { "readPoint.id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_bizLocation: Like the EQ_ readPoint parameter, but for the * bizLocation field. * * OR semantic Regex Supported * */ if (p.getEQ_bizLocation() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_bizLocation()); BsonDocument queryObject = getQueryObject(new String[] { "bizLocation.id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * WD_bizLocation: Like the WD_readPoint parameter, but for the * bizLocation field. * * OR semantic Regex Supported * */ if (p.getWD_bizLocation() != null) { BsonArray paramArray = getWDParamBsonArray(p.getWD_bizLocation()); BsonDocument queryObject = getQueryObject(new String[] { "bizLocation.id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_transformationID: If this parameter is specified, the result will * only include events that (a) have a transformationID field (that is, * TransformationEvents or extension event type that extend * TransformationEvent); and where (b) the transformationID field is * equal to one of the values specified in this parameter. * * OR semantic Regex Supported * */ if (p.getEQ_transformationID() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_transformationID()); BsonDocument queryObject = getQueryObject(new String[] { "transformationID" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_epc: If this parameter is specified, the result will only * include events that (a) have an epcList or a childEPCs field (that * is, ObjectEvent, AggregationEvent, TransactionEvent or extension * event types that extend one of those three); and where (b) one of the * EPCs listed in the epcList or childEPCs field (depending on event * type) matches one of the EPC patterns or URIs specified in this * parameter, where the meaning of “matches” is as specified in Section * 8.2.7.1.1. If this parameter is omitted, events are included * regardless of their epcList or childEPCs field or whether the epcList * or childEPCs field exists. * * */ if (p.getMATCH_epc() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_epc()); BsonDocument queryObject = getMatchQueryObject(new String[] { "epcList.epc", "childEPCs.epc" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_parentID: Like MATCH_epc, but matches the parentID field of * AggregationEvent, the parentID field of TransactionEvent, and * extension event types that extend either AggregationEvent or * TransactionEvent. The meaning of “matches” is as specified in Section * 8.2.7.1.1. */ if (p.getMATCH_parentID() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_parentID()); BsonDocument queryObject = getMatchQueryObject(new String[] { "parentID" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_inputEPC: If this parameter is specified, the result will only * include events that (a) have an inputEPCList (that is, * TransformationEvent or an extension event type that extends * TransformationEvent); and where (b) one of the EPCs listed in the * inputEPCList field matches one of the EPC patterns or URIs specified * in this parameter. The meaning of “matches” is as specified in * Section 8.2.7.1.1. If this parameter is omitted, events are included * regardless of their inputEPCList field or whether the inputEPCList * field exists. */ if (p.getMATCH_inputEPC() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_inputEPC()); BsonDocument queryObject = getMatchQueryObject(new String[] { "inputEPCList.epc" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_outputEPC: If this parameter is specified, the result will only * include events that (a) have an inputEPCList (that is, * TransformationEvent or an extension event type that extends * TransformationEvent); and where (b) one of the EPCs listed in the * inputEPCList field matches one of the EPC patterns or URIs specified * in this parameter. The meaning of “matches” is as specified in * Section 8.2.7.1.1. If this parameter is omitted, events are included * regardless of their inputEPCList field or whether the inputEPCList * field exists. */ if (p.getMATCH_outputEPC() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_outputEPC()); BsonDocument queryObject = getMatchQueryObject(new String[] { "outputEPCList.epc" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_anyEPC: If this parameter is specified, the result will only * include events that (a) have an epcList field, a childEPCs field, a * parentID field, an inputEPCList field, or an outputEPCList field * (that is, ObjectEvent, AggregationEvent, TransactionEvent, * TransformationEvent, or extension event types that extend one of * those four); and where (b) the parentID field or one of the EPCs * listed in the epcList, childEPCs, inputEPCList, or outputEPCList * field (depending on event type) matches one of the EPC patterns or * URIs specified in this parameter. The meaning of “matches” is as * specified in Section 8.2.7.1.1. */ if (p.getMATCH_anyEPC() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_anyEPC()); BsonDocument queryObject = getMatchQueryObject(new String[] { "epcList.epc", "childEPCs.epc", "inputEPCList.epc", "outputEPCList.epc", "parentID" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_epcClass: If this parameter is specified, the result will only * include events that (a) have a quantityList or a childQuantityList * field (that is, ObjectEvent, AggregationEvent, TransactionEvent or * extension event types that extend one of those three); and where (b) * one of the EPC classes listed in the quantityList or * childQuantityList field (depending on event type) matches one of the * EPC patterns or URIs specified in this parameter. The result will * also include QuantityEvents whose epcClass field matches one of the * EPC patterns or URIs specified in this parameter. The meaning of * “matches” is as specified in Section 8.2.7.1.1. */ if (p.getMATCH_epcClass() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_epcClass()); BsonDocument queryObject = getMatchQueryObject( new String[] { "extension.quantityList.epcClass", "extension.childQuantityList.epcClass" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_inputEPCClass: If this parameter is specified, the result will * only include events that (a) have an inputQuantityList field (that * is, TransformationEvent or extension event types that extend it); and * where (b) one of the EPC classes listed in the inputQuantityList * field (depending on event type) matches one of the EPC patterns or * URIs specified in this parameter. The meaning of “matches” is as * specified in Section 8.2.7.1.1. */ if (p.getMATCH_inputEPCClass() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_inputEPCClass()); BsonDocument queryObject = getMatchQueryObject(new String[] { "inputQuantityList.epcClass" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_outputEPCClass: If this parameter is specified, the result will * only include events that (a) have an outputQuantityList field (that * is, TransformationEvent or extension event types that extend it); and * where (b) one of the EPC classes listed in the outputQuantityList * field (depending on event type) matches one of the EPC patterns or * URIs specified in this parameter. The meaning of “matches” is as * specified in Section 8.2.7.1.1. */ if (p.getMATCH_outputEPCClass() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_outputEPCClass()); BsonDocument queryObject = getMatchQueryObject(new String[] { "outputQuantityList.epcClass" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * MATCH_anyEPCClass: If this parameter is specified, the result will * only include events that (a) have a quantityList, childQuantityList, * inputQuantityList, or outputQuantityList field (that is, ObjectEvent, * AggregationEvent, TransactionEvent, TransformationEvent, or extension * event types that extend one of those four); and where (b) one of the * EPC classes listed in any of those fields matches one of the EPC * patterns or URIs specified in this parameter. The result will also * include QuantityEvents whose epcClass field matches one of the EPC * patterns or URIs specified in this parameter. The meaning of * “matches” is as specified in Section 8.2.7.1.1. */ if (p.getMATCH_anyEPCClass() != null) { BsonArray paramArray = getParamBsonArray(p.getMATCH_anyEPCClass()); BsonDocument queryObject = getMatchQueryObject( new String[] { "extension.quantityList.epcClass", "extension.childQuantityList.epcClass", "inputQuantityList.epcClass", "outputQuantityList.epcClass" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * (DEPCRECATED in EPCIS 1.1) EQ_quantity; GT_quantity; GE_quantity; * LT_quantity; LE_quantity **/ /** * EQ_eventID : If this parameter is specified, the result will only * include events that (a) have a non-null eventID field; and where (b) * the eventID field is equal to one of the values specified in this * parameter. If this parameter is omitted, events are returned * regardless of the value of the eventID field or whether the eventID * field exists at all. * * List of String * */ if (p.getEQ_eventID() != null) { BsonArray orQueryArray = new BsonArray(); BsonArray paramArray = getParamBsonArray(p.getEQ_eventID()); BsonDocument queryObject = getQueryObject(new String[] { "eventID" }, paramArray); if (queryObject != null) { orQueryArray.add(queryObject); } BsonArray objectIDParamArray = new BsonArray(); for (int i = 0; i < paramArray.size(); i++) { BsonValue paramValue = paramArray.get(i); if (paramValue instanceof BsonString) { try { objectIDParamArray.add(new BsonObjectId(new ObjectId(paramValue.asString().getValue()))); } catch (IllegalArgumentException e) { Configuration.logger.debug("Non MongoDB ObjectID: " + e.toString()); } } } BsonDocument objectIDQueryObject = getQueryObject(new String[] { "_id" }, objectIDParamArray); if (objectIDQueryObject != null) { orQueryArray.add(objectIDQueryObject); } if (orQueryArray.size() != 0) { BsonDocument orQueryObject = new BsonDocument(); orQueryObject.put("$or", orQueryArray); queryList.add(orQueryObject); } } /** * EQ_errorReason: If this parameter is specified, the result will only * include events that (a) contain an ErrorDeclaration ; and where (b) * the error declaration contains a non-null reason field; and where (c) * the reason field is equal to one of the values specified in this * parameter. If this parameter is omitted, events are returned * regardless of the they contain an ErrorDeclaration or what the value * of the reason field is. */ if (p.getEQ_errorReason() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_errorReason()); BsonDocument queryObject = getQueryObject(new String[] { "errorDeclaration.reason" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_correctiveEventID: If this parameter is specified, the result will * only include events that (a) contain an ErrorDeclaration ; and where * (b) one of the elements of the correctiveEventIDs list is equal to * one of the values specified in this parameter. If this parameter is * omitted, events are returned regardless of the they contain an * ErrorDeclaration or the contents of the correctiveEventIDs list. */ if (p.getEQ_correctiveEventID() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_correctiveEventID()); BsonDocument queryObject = getQueryObject(new String[] { "errorDeclaration.correctiveEventIDs" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EXISTS_errorDeclaration: If this parameter is specified, the result * will only include events that contain an ErrorDeclaration . If this * parameter is omitted, events are returned regardless of whether they * contain an ErrorDeclaration . */ if (p.getEXISTS_errorDeclaration() != null) { Boolean isExist = Boolean.parseBoolean(p.getEXISTS_errorDeclaration().toString()); BsonBoolean isExistBson = new BsonBoolean(isExist); BsonDocument query = getExistsQueryObject("errorDeclaration", null, isExistBson); if (query != null) queryList.add(query); } if (p.getParams() != null) { Iterator<String> paramIter = p.getParams().keySet().iterator(); while (paramIter.hasNext()) { String paramName = paramIter.next(); String paramValues = p.getParams().get(paramName); // db.EventData.createIndex({"any.http://ns.example.com/epcis#point": "2dsphere" }); if (paramName.contains("NEAR_")) { String type = paramName.substring(5, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonDocument query = getNearQueryObject(type, paramValues); if (query != null) queryList.add(query); } /** * EQ_bizTransaction_type: This is not a single parameter, but a * family of parameters. If a parameter of this form is * specified, the result will only include events that (a) * include a bizTransactionList; (b) where the business * transaction list includes an entry whose type subfield is * equal to type extracted from the name of this parameter; and * (c) where the bizTransaction subfield of that entry is equal * to one of the values specified in this parameter. */ if (paramName.contains("EQ_bizTransaction_")) { String type = paramName.substring(18, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonDocument query = getFamilyQueryObject(type, new String[] { "bizTransactionList" }, paramValues); if (query != null) queryList.add(query); } /** * EQ_source_type: This is not a single parameter, but a family * of parameters. If a parameter of this form is specified, the * result will only include events that (a) include a * sourceList; (b) where the source list includes an entry whose * type subfield is equal to type extracted from the name of * this parameter; and (c) where the source subfield of that * entry is equal to one of the values specified in this * parameter. */ if (paramName.contains("EQ_source_")) { String type = paramName.substring(10, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); /* * if (eventType.equals("AggregationEvent") || * eventType.equals("ObjectEvent") || * eventType.equals("TransactionEvent")) { BsonDocument * query = getFamilyQueryObject(type, * "extension.sourceList", paramValues); if (query != null) * queryList.add(query); } if * (eventType.equals("TransformationEvent")) { BsonDocument * query = getFamilyQueryObject(type, "sourceList", * paramValues); if (query != null) queryList.add(query); } */ /* * if (eventType.equals("AggregationEvent") || * eventType.equals("ObjectEvent") || * eventType.equals("TransactionEvent")) { * * } if (eventType.equals("TransformationEvent")) { * BsonDocument query = getFamilyQueryObject(type, * "sourceList", paramValues); if (query != null) * queryList.add(query); } */ BsonDocument query = getFamilyQueryObject(type, new String[] { "extension.sourceList", "sourceList" }, paramValues); if (query != null) queryList.add(query); } /** * EQ_destination_type: This is not a single parameter, but a * family of parameters. If a parameter of this form is * specified, the result will only include events that (a) * include a destinationList; (b) where the destination list * includes an entry whose type subfield is equal to type * extracted from the name of this parameter; and (c) where the * destination subfield of that entry is equal to one of the * values specified in this parameter. */ if (paramName.contains("EQ_destination_")) { String type = paramName.substring(15, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); /* * if (eventType.equals("AggregationEvent") || * eventType.equals("ObjectEvent") || * eventType.equals("TransactionEvent")) { BsonDocument * query = getFamilyQueryObject(type, * "extension.destinationList", paramValues); if (query != * null) queryList.add(query); } if * (eventType.equals("TransformationEvent")) { BsonDocument * query = getFamilyQueryObject(type, "destinationList", * paramValues); if (query != null) queryList.add(query); } */ BsonDocument query = getFamilyQueryObject(type, new String[] { "extension.destinationList", "destinationList" }, paramValues); if (query != null) queryList.add(query); } /** * EQ_ILMD_field: Analogous to EQ_fieldname , but matches events * whose ILMD area (Section 7.3.6) contains a top-level field * having the specified fieldname whose value matches one of the * specified values. “Top level” means that the matching ILMD * element must be an immediate child of the <ilmd> element, not * an element nested within such an element. See * EQ_INNER_ILMD_fieldname for querying inner extension * elements. */ if (paramName.startsWith("EQ_ILMD_")) { String type = paramName.substring(8, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonArray paramArray = getParamBsonArray(paramValues); BsonDocument queryObject = getQueryObject( new String[] { "extension.ilmd.any." + type, "ilmd.any." + type }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * GT|GE|LT|LE_ILMD_field: Analogous to EQ_fieldname , * GT_fieldname , GE_fieldname , GE_fieldname , LT_fieldname , * and LE_fieldname , respectively, but matches events whose * ILMD area (Section 7.3.6) contains a field having the * specified fieldname whose integer, float, or time value * matches the specified value according to the specified * relational operator. */ 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); if (paramName.startsWith("GT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "extension.ilmd.any." + type, "ilmd.any." + type }, paramValues, "GT"); if (query != null) queryList.add(query); } if (paramName.startsWith("GE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "extension.ilmd.any." + type, "ilmd.any." + type }, paramValues, "GE"); if (query != null) queryList.add(query); } if (paramName.startsWith("LT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "extension.ilmd.any." + type, "ilmd.any." + type }, paramValues, "LT"); if (query != null) queryList.add(query); } if (paramName.startsWith("LE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "extension.ilmd.any." + type, "ilmd.any." + type }, paramValues, "LE"); if (query != null) queryList.add(query); } } /** * EXISTS_ILMD_fieldname: Like EXISTS_fieldname as described * above, but events that have a non-empty field named fieldname * in the ILMD area (Section 7.3.6). Fieldname is constructed as * for EQ_ILMD_fieldname . Note that the value for this query * parameter is ignored. */ if (paramName.startsWith("EXISTS_ILMD_")) { /* * if (p.getEventType().equals("ObjectEvent")) { String * field = paramName.substring(12, paramName.length()); * field = MongoWriterUtil.encodeMongoObjectKey(field); * Boolean isExist = Boolean.parseBoolean(paramValues); * BsonBoolean isExistBson = new BsonBoolean(isExist); * BsonDocument query = * getExistsQueryObject("extension.ilmd", field, * isExistBson); if (query != null) queryList.add(query); } * else if (p.getEventType().equals("TransformationEvent")) * { String field = paramName.substring(12, * paramName.length()); field = * MongoWriterUtil.encodeMongoObjectKey(field); Boolean * isExist = Boolean.parseBoolean(paramValues); BsonBoolean * isExistBson = new BsonBoolean(isExist); BsonDocument * query = getExistsQueryObject("ilmd", field, isExistBson); * if (query != null) queryList.add(query); } */ String field = paramName.substring(12, paramName.length()); field = MongoWriterUtil.encodeMongoObjectKey(field); Boolean isExist = Boolean.parseBoolean(paramValues); BsonBoolean isExistBson = new BsonBoolean(isExist); BsonDocument query = getExistsQueryObject(new String[] { "extension.ilmd.any", "ilmd.any" }, field, isExistBson); if (query != null) queryList.add(query); } /** * EQ_ERROR_DECLARATION_Fieldname : Analogous to EQ_fieldname , * but matches events containing an ErrorDeclaration and where * the ErrorDeclaration contains a field having the specified * fieldname whose value matches one of the specified values. * * List of String * */ if (paramName.startsWith("EQ_ERROR_DECLARATION_")) { String type = paramName.substring(21, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonArray paramArray = getParamBsonArray(paramValues); BsonDocument queryObject = getQueryObject(new String[] { "errorDeclaration.any." + type }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * Analogous to EQ_fieldname , GT_fieldname , GE_fieldname , * GE_fieldname , LT_fieldname , and LE_fieldname , * respectively, but matches events containing an * ErrorDeclaration and where the ErrorDeclaration contains a * field having the specified fieldname whose integer, float, or * time value matches the specified value according to the * specified relational operator. */ 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); if (paramName.startsWith("GT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "errorDeclaration.any." + type }, paramValues, "GT"); if (query != null) queryList.add(query); } if (paramName.startsWith("GE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "errorDeclaration.any." + type }, paramValues, "GE"); if (query != null) queryList.add(query); } if (paramName.startsWith("LT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "errorDeclaration.any." + type }, paramValues, "LT"); if (query != null) queryList.add(query); } if (paramName.startsWith("LE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "errorDeclaration.any." + type }, paramValues, "LE"); if (query != null) queryList.add(query); } } boolean isExtraParam = isExtraParameter(paramName); if (isExtraParam == true) { /** * EQ_fieldname: This is not a single parameter, but a * family of parameters. If a parameter of this form is * specified, the result will only include events that (a) * have a field named fieldname whose type is either String * or a vocabulary type; and where (b) the value of that * field matches one of the values specified in this * parameter. Fieldname is the fully qualified name of an * extension field. The name of an extension field is an XML * qname; that is, a pair consisting of an XML namespace URI * and a name. The name of the corresponding query parameter * is constructed by concatenating the following: the string * EQ_, the namespace URI for the extension field, a pound * sign (#), and the name of the extension field. */ if (paramName.startsWith("EQ_")) { String type = paramName.substring(3, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonArray paramArray = getParamBsonArray(paramValues); BsonDocument queryObject = getQueryObject( new String[] { "any." + type, "otherAttributes." + type }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * GT/GE/LT/LE_fieldname: Like EQ_fieldname as described * above, but may be applied to a field of type Int, Float, * or Time. The result will include events that (a) have a * field named fieldname; and where (b) the type of the * field matches the type of this parameter (Int, Float, or * Time); and where (c) the value of the field is greater * than the specified value. Fieldname is constructed as for * EQ_fieldname. */ if (paramName.startsWith("GT_") || paramName.startsWith("GE_") || paramName.startsWith("LT_") || paramName.startsWith("LE_")) { String type = paramName.substring(3, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); if (paramName.startsWith("GT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "any." + type, "otherAttributes." + type }, paramValues, "GT"); if (query != null) queryList.add(query); } if (paramName.startsWith("GE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "any." + type, "otherAttributes." + type }, paramValues, "GE"); if (query != null) queryList.add(query); } if (paramName.startsWith("LT_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "any." + type, "otherAttributes." + type }, paramValues, "LT"); if (query != null) queryList.add(query); } if (paramName.startsWith("LE_")) { BsonDocument query = getCompExtensionQueryObject(type, new String[] { "any." + type, "otherAttributes." + type }, paramValues, "LE"); if (query != null) queryList.add(query); } } /** * EXISTS_fieldname: Like EQ_fieldname as described above, * but may be applied to a field of any type (including * complex types). The result will include events that have * a non-empty field named fieldname . Fieldname is * constructed as for EQ_fieldname . EXISTS_ ILMD_fieldname * HASATTR_fieldname Void Note that the value for this query * parameter is ignored. * * Regex not supported * */ if (paramName.startsWith("EXISTS_")) { String field = paramName.substring(7, paramName.length()); field = MongoWriterUtil.encodeMongoObjectKey(field); paramValues = MongoWriterUtil.encodeMongoObjectKey(paramValues); Boolean isExist = Boolean.parseBoolean(paramValues); BsonBoolean isExistBson = new BsonBoolean(isExist); BsonDocument query = getExistsQueryObject("any", field, isExistBson); if (query != null) queryList.add(query); } } } } return queryList; } @SuppressWarnings("unused") private boolean isPostFilterPassed(String eventType, BsonDocument dbObject, Map<String, String> paramMap) { if (paramMap == null || paramMap.isEmpty()) return true; Iterator<String> paramIter = paramMap.keySet().iterator(); while (paramIter.hasNext()) { String paramName = paramIter.next(); String paramValues = paramMap.get(paramName); BsonDocument ilmd = null; BsonDocument error = null; BsonDocument ext = null; // Prepare BsonDocument if (eventType.equals("ObjectEvent")) { if (dbObject.containsKey("extension") && dbObject.getDocument("extension").containsKey("ilmd") && dbObject.getDocument("extension").getDocument("ilmd").containsKey("any")) { ilmd = dbObject.getDocument("extension").getDocument("ilmd").getDocument("any"); } } else if (eventType.equals("TransformationEvent")) { if (dbObject.containsKey("ilmd") && dbObject.getDocument("ilmd").containsKey("any")) { ilmd = dbObject.getDocument("ilmd").getDocument("any"); } } if (dbObject.containsKey("errorDeclaration")) { if (dbObject.getDocument("errorDeclaration").containsKey("any")) { error = dbObject.getDocument("errorDeclaration").getDocument("any"); } } if (dbObject.containsKey("any")) { ext = dbObject.getDocument("any"); } // TODO: HASATTR_fieldname /** * HASATTR_fieldname: This is not a single parameter, but a family * of parameters. If a parameter of this form is specified, the * result will only include events that (a) have a field named * fieldname whose type is a vocabulary type; and (b) where the * value of that field is a vocabulary element for which master data * is available; and (c) the master data has a non-null attribute * whose name matches one of the values specified in this parameter. * Fieldname is the fully qualified name of a field. For a standard * field, this is simply the field name; e.g., bizLocation . For an * extension EQATTR_fieldname _attrname List of String field, the * name of an extension field is an XML qname; that is, a pair * consisting of an XML namespace URI and a name. The name of the * corresponding query parameter is constructed by concatenating the * following: the string HASATTR_ , the namespace URI for the * extension field, a pound sign (#), and the name of the extension * field. */ if (paramName.startsWith("HASATTR_")) { String type = paramName.substring(8, paramName.length()); type = MongoWriterUtil.encodeMongoObjectKey(type); BsonArray paramArray = getParamBsonArray(paramValues); continue; } // TODO: EQATTR_fieldname_attrname /** * This is not a single parameter, but a family of parameters. If a * parameter of this form is specified, the result will only include * events that (a) have a field named fieldname whose type is a * vocabulary type; and (b) where the value of that field is a * vocabulary element for which master data is available; and (c) * the master data has a non-null attribute named attrname ; and (d) * where the value of that attribute matches one of the values * specified in this parameter. Fieldname is constructed as for * HASATTR_fieldname . The implementation MAY raise a * QueryParameterException if fieldname or attrname includes an * underscore character. EQ_eventID List of String EXISTS_ * errorDeclaration Void GE_errorDeclaration Time Time Explanation * (non-normative): because the presence of an underscore in * fieldname or attrname presents an ambiguity as to where the * division between fieldname and attrname lies, an implementation * is free to reject the query parameter if it cannot disambiguate. */ if (paramName.startsWith("EQATTR_")) { String type = paramName.substring(7, paramName.length()); String[] typeArr = type.trim().split("_"); if (typeArr.length != 2) continue; String fieldname = typeArr[0]; String attrname = typeArr[1]; BsonArray paramArray = getParamBsonArray(paramValues); continue; } /** * Analogous to EQ_ILMD_fieldname , but matches inner ILMD elements; * that is, any XML element nested within a top-level ILMD element. * Note that a matching inner element may exist within in more than * one top-level element or may occur more than once within a single * top-level element; this parameter matches if at least one * matching occurrence is found anywhere in the ILMD section (except * at top-level). */ if (paramName.startsWith("EQ_INNER_ILMD_")) { if (eventType.equals("AggregationEvent") || eventType.equals("QuantityEvent") || eventType.equals("TransactionEvent")) { return false; } if (ilmd == null) return false; String type = paramName.substring(14, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (isExtensionFilterPassed(type, paramArray, ilmd, true) == true) return true; else return false; } /** * Like EQ_INNER_ILMD_ fieldname as described above, but may be * applied to a field of type Int, Float, or Time. */ if (paramName.startsWith("GT_INNER_ILMD_") || paramName.startsWith("GE_INNER_ILMD_") || paramName.startsWith("LT_INNER_ILMD_") || paramName.startsWith("LE_INNER_ILMD_")) { if (eventType.equals("AggregationEvent") || eventType.equals("QuantityEvent") || eventType.equals("TransactionEvent")) { return false; } if (ilmd == null) return false; String type = paramName.substring(14, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (paramName.startsWith("GT_")) { if (isCompExtensionFilterPassed(type, "GT", paramArray, ilmd) == true) return true; else return false; } if (paramName.startsWith("GE_")) { if (isCompExtensionFilterPassed(type, "GE", paramArray, ilmd) == true) return true; else return false; } if (paramName.startsWith("LT_")) { if (isCompExtensionFilterPassed(type, "LT", paramArray, ilmd) == true) return true; else return false; } if (paramName.startsWith("LE_")) { if (isCompExtensionFilterPassed(type, "LE", paramArray, ilmd) == true) return true; else return false; } } /** * Analogous to EQ_ERROR_DECLARATION_fieldname , but matches inner * extension elements; that is, any XML element nested within a * top-level extension element. Note that a matching inner element * may exist within in more than one top-level element or may occur * more than once within a single top-level element; this parameter * matches if at least one matching occurrence is found anywhere in * the event (except at top-level).. */ if (paramName.startsWith("EQ_INNER_ERROR_DECLARATION_")) { if (error == null) return false; String type = paramName.substring(27, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (isExtensionFilterPassed(type, paramArray, error, true) == true) return true; else return false; } /** * Like EQ_INNER_ERROR_DECLARATION _ fieldname as described above, * but may be applied to a field of type Int, Float, or Time. */ if (paramName.startsWith("GT_INNER_ERROR_DECLARATION_") || paramName.startsWith("GE_INNER_ERROR_DECLARATION_") || paramName.startsWith("LT_INNER_ERROR_DECLARATION_") || paramName.startsWith("LE_INNER_ERROR_DECLARATION_")) { if (error == null) return false; String type = paramName.substring(27, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (paramName.startsWith("GT_")) { if (isCompExtensionFilterPassed(type, "GT", paramArray, error) == true) return true; else return false; } if (paramName.startsWith("GE_")) { if (isCompExtensionFilterPassed(type, "GE", paramArray, error) == true) return true; else return false; } if (paramName.startsWith("LT_")) { if (isCompExtensionFilterPassed(type, "LT", paramArray, error) == true) return true; else return false; } if (paramName.startsWith("LE_")) { if (isCompExtensionFilterPassed(type, "LE", paramArray, error) == true) return true; else return false; } } /** * Analogous to EQ_fieldname , but matches inner extension elements; * that is, any XML element nested within a top-level extension * element. Note that a matching inner element may exist within in * more than one top-level element or may occur more than once * within a single top-level element; this parameter matches if at * least one matching occurrence is found anywhere in the event * (except at top-level). */ if (paramName.startsWith("EQ_INNER_")) { if (ext == null) return false; String type = paramName.substring(9, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (isExtensionFilterPassed(type, paramArray, ext, true) == true) return true; else return false; } /** * Like EQ_INNER _ fieldname as described above, but may be applied * to a field of type Int, Float, or Time. */ if (paramName.startsWith("GT_INNER_") || paramName.startsWith("GE_INNER_") || paramName.startsWith("LT_INNER_") || paramName.startsWith("LE_INNER_")) { if (ext == null) return false; String type = paramName.substring(9, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); if (paramName.startsWith("GT_")) { if (isCompExtensionFilterPassed(type, "GT", paramArray, ext) == true) return true; else return false; } if (paramName.startsWith("GE_")) { if (isCompExtensionFilterPassed(type, "GE", paramArray, ext) == true) return true; else return false; } if (paramName.startsWith("LT_")) { if (isCompExtensionFilterPassed(type, "LT", paramArray, ext) == true) return true; else return false; } if (paramName.startsWith("LE_")) { if (isCompExtensionFilterPassed(type, "LE", paramArray, ext) == true) return true; else return false; } } } return true; } private boolean isExtensionFilterPassed(String type, BsonArray paramArray, BsonDocument ext, boolean isTopLevel) { type = MongoWriterUtil.encodeMongoObjectKey(type); Iterator<String> keyIterator = ext.keySet().iterator(); while (keyIterator.hasNext()) { String key = keyIterator.next(); BsonValue sub = ext.get(key); if (isTopLevel == false) { if (key.equals(type)) { for (int i = 0; i < paramArray.size(); i++) { BsonValue param = paramArray.get(i); if (sub.getBsonType() == param.getBsonType() && sub.toString().equals(param.toString())) { return true; } if (param.getBsonType() == BsonType.REGULAR_EXPRESSION && sub.getBsonType() == BsonType.STRING) { if (Pattern.matches(param.asRegularExpression().getPattern(), sub.asString().getValue())) return true; } } return false; } } if (sub.getBsonType() == BsonType.DOCUMENT) { if (isExtensionFilterPassed(type, paramArray, sub.asDocument(), false) == true) { return true; } } } return false; } private boolean isCompExtensionFilterPassed(String type, String comp, BsonArray paramArray, BsonDocument ext) { type = MongoWriterUtil.encodeMongoObjectKey(type); Iterator<String> keyIterator = ext.keySet().iterator(); while (keyIterator.hasNext()) { String key = keyIterator.next(); BsonValue sub = ext.get(key); if (key.equals(type)) { for (int i = 0; i < paramArray.size(); i++) { BsonValue param = paramArray.get(i); if (sub.getBsonType() == param.getBsonType()) { if (sub.getBsonType() == BsonType.INT32) { if (comp.equals("GT")) { if (sub.asInt32().getValue() > param.asInt32().getValue()) return true; } else if (comp.equals("GE")) { if (sub.asInt32().getValue() >= param.asInt32().getValue()) return true; } else if (comp.equals("LT")) { if (sub.asInt32().getValue() < param.asInt32().getValue()) return true; } else if (comp.equals("LE")) { if (sub.asInt32().getValue() <= param.asInt32().getValue()) return true; } } else if (sub.getBsonType() == BsonType.INT64) { if (comp.equals("GT")) { if (sub.asInt64().getValue() > param.asInt64().getValue()) return true; } else if (comp.equals("GE")) { if (sub.asInt64().getValue() >= param.asInt64().getValue()) return true; } else if (comp.equals("LT")) { if (sub.asInt64().getValue() < param.asInt64().getValue()) return true; } else if (comp.equals("LE")) { if (sub.asInt64().getValue() <= param.asInt64().getValue()) return true; } } else if (sub.getBsonType() == BsonType.DOUBLE) { if (comp.equals("GT")) { if (sub.asDouble().getValue() > param.asDouble().getValue()) return true; } else if (comp.equals("GE")) { if (sub.asDouble().getValue() >= param.asDouble().getValue()) return true; } else if (comp.equals("LT")) { if (sub.asDouble().getValue() < param.asDouble().getValue()) return true; } else if (comp.equals("LE")) { if (sub.asDouble().getValue() <= param.asDouble().getValue()) return true; } } else if (sub.getBsonType() == BsonType.DATE_TIME) { if (comp.equals("GT")) { if (sub.asDateTime().getValue() > param.asDateTime().getValue()) return true; } else if (comp.equals("GE")) { if (sub.asDateTime().getValue() >= param.asDateTime().getValue()) return true; } else if (comp.equals("LT")) { if (sub.asDateTime().getValue() < param.asDateTime().getValue()) return true; } else if (comp.equals("LE")) { if (sub.asDateTime().getValue() <= param.asDateTime().getValue()) return true; } } } } return false; } if (sub.getBsonType() == BsonType.DOCUMENT) { if (isCompExtensionFilterPassed(type, comp, paramArray, sub.asDocument()) == true) { return true; } } } return false; } private BsonArray makeMasterQueryObjects(PollParameters p) { BsonArray queryList = new BsonArray(); /** * vocabularyName : If specified, only vocabulary elements drawn from * one of the specified vocabularies will be included in the results. * Each element of the specified list is the formal URI name for a * vocabulary; e.g., one of the URIs specified in the table at the end * of Section 7.2. If omitted, all vocabularies are considered. */ if (p.getVocabularyName() != null) { BsonArray paramArray = getParamBsonArray(p.getVocabularyName()); BsonDocument queryObject = getQueryObject(new String[] { "type" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * EQ_name : If specified, the result will only include vocabulary * elements whose names are equal to one of the specified values. If * this parameter and WD_name are both omitted, vocabulary elements are * included regardless of their names. */ if (p.getEQ_name() != null) { BsonArray paramArray = getParamBsonArray(p.getEQ_name()); BsonDocument queryObject = getQueryObject(new String[] { "id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * WD_name : If specified, the result will only include vocabulary * elements that either match one of the specified names, or are direct * or indirect descendants of a vocabulary element that matches one of * the specified names. The meaning of “direct or indirect descendant” * is described in Section 6.5. (WD is an abbreviation for “with * descendants.”) If this parameter and EQ_name are both omitted, * vocabulary elements are included regardless of their names. */ if (p.getWD_name() != null) { BsonArray paramArray = getWDParamBsonArray(p.getWD_name()); BsonDocument queryObject = getQueryObject(new String[] { "id" }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } /** * HASATTR : If specified, the result will only include vocabulary * elements that have a non-null attribute whose name matches one of the * values specified in this parameter. */ if (p.getHASATTR() != null) { String[] attrArr = p.getHASATTR().split(","); for (int i = 0; i < attrArr.length; i++) { String attrString = attrArr[i].trim(); BsonDocument query = getExistsQueryObject("attributes", attrString, new BsonBoolean(true)); if (query != null) queryList.add(query); } } /** * EQATTR_attrnam : This is not a single parameter, but a family of * parameters. If a parameter of this form is specified, the result will * only include vocabulary elements that have a non-null attribute named * attrname, and where the value of that attribute matches one of the * values specified in this parameter. */ if (p.getParams() != null) { Iterator<String> paramIter = p.getParams().keySet().iterator(); while (paramIter.hasNext()) { String paramName = paramIter.next(); String paramValues = p.getParams().get(paramName); if (paramName.contains("EQATTR_")) { String type = paramName.substring(7, paramName.length()); BsonArray paramArray = getParamBsonArray(paramValues); BsonDocument queryObject = getQueryObject( new String[] { "attributes." + encodeMongoObjectKey(type) }, paramArray); if (queryObject != null) { queryList.add(queryObject); } } } } return queryList; } public void addScheduleToQuartz(SubscriptionType subscription) { try { JobDataMap map = new JobDataMap(); map.put("jobData", SubscriptionType.asBsonDocument(subscription)); JobDetail job = newJob(MongoSubscriptionTask.class) .withIdentity(subscription.getSubscriptionID(), subscription.getPollParameters().getQueryName()) .setJobData(map).storeDurably(false).build(); Trigger trigger = newTrigger() .withIdentity(subscription.getSubscriptionID(), subscription.getPollParameters().getQueryName()) .startNow().withSchedule(cronSchedule(subscription.getSchedule())).build(); if (MongoSubscription.sched.isStarted() != true) MongoSubscription.sched.start(); MongoSubscription.sched.scheduleJob(job, trigger); Configuration.logger.log(Level.INFO, "Subscription ID: " + subscription.getSubscriptionID() + " is added to quartz scheduler. "); } catch (SchedulerException e) { Configuration.logger.log(Level.ERROR, e.toString()); } catch (RuntimeException e) { Configuration.logger.log(Level.ERROR, e.toString()); } } private boolean addScheduleToDB(SubscriptionType s, String userID, List<String> friendList) { MongoCollection<BsonDocument> collection = Configuration.mongoDatabase.getCollection("Subscription", BsonDocument.class); BsonDocument subscription = collection .find(new BsonDocument("subscriptionID", new BsonString(s.getSubscriptionID()))).first(); if (subscription == null) { collection.insertOne(SubscriptionType.asBsonDocument(s)); } Configuration.logger.log(Level.INFO, "Subscription ID: " + s.getSubscriptionID() + " is added to DB. "); return true; } private void removeScheduleFromQuartz(SubscriptionType subscription) { try { MongoSubscription.sched.unscheduleJob( triggerKey(subscription.getSubscriptionID(), subscription.getPollParameters().getQueryName())); MongoSubscription.sched.deleteJob( jobKey(subscription.getSubscriptionID(), subscription.getPollParameters().getQueryName())); Configuration.logger.log(Level.INFO, "Subscription ID: " + subscription.getSubscriptionID() + " is removed from scheduler"); } catch (SchedulerException e) { Configuration.logger.log(Level.ERROR, e.toString()); } } }