public Comparable getValue(String query) { Object rawValue = doGetValue(query); return (Comparable) ClauseParser.parseValue(rawValue); }
public boolean exists(String query) { return getValue(query) != null; }
public static Clause parse(String key, Object value) throws JSONException { if (key == null) { // The Root object, and objects inside arrays should be treated as $and. key = LogicalOperator.$and.name(); } key = key.trim(); LogicalOperator operator = LogicalOperator.parse(key); switch (operator) { case $or: return new LogicalClause(key, value); case $and: return new LogicalClause(key, value); case $not: return new LogicalClause(key, value); default: { return new ConditionalClause(key, value); } } }
/** * The test in this conditional clause are implicitly ANDed together, so return false if any of them is false, and continue the loop for each test that is true; * * @return */ @Override public boolean evaluate(FieldManager fieldManager, IndentPrinter printer) { Comparable fieldValue = fieldManager.getValue(fieldName); for (ConditionalTest test : conditionalTests) { boolean result = test.operator.apply(fieldValue, test.parameter); printer.print("- %s => %b", test.operator.description(fieldManager.getDescription(fieldName), fieldValue, test.parameter), result); if (!result) { return false; } } return true; } }
public ConditionalClause(String field, Object inputValue) { this.fieldName = field.trim(); ApptentiveLog.v(INTERACTIONS, " + ConditionalClause for query: \"%s\"", fieldName); if (inputValue instanceof JSONObject && !isComplexType((JSONObject) inputValue)) { conditionalTests = getConditions((JSONObject) inputValue); } else { conditionalTests = new ArrayList<>(); conditionalTests.add(new ConditionalTest(ConditionalOperator.$eq, ClauseParser.parseValue(inputValue))); } }
@Test public void criteriaApplicationVersionName() throws JSONException { AppRelease appRelease = AppReleaseManager.generateCurrentAppRelease(targetContext, null); String json = loadTextAssetAsString(TEST_DATA_DIR + "criteria/testCriteriaApplicationVersionName.json"); json = json.replace("APPLICATION_VERSION_NAME", appRelease.getVersionName()); InteractionCriteria criteria = new InteractionCriteria(json); FieldManager fieldManager = new FieldManager(targetContext, new VersionHistory(), new EventData(), new Person(), new Device(), appRelease); assertTrue(criteria.isMet(fieldManager)); }
private List<ConditionalTest> getConditions(JSONObject conditionObject) { List<ConditionalTest> conditionalTests = new ArrayList<ConditionalTest>(); Iterator<String> operators = conditionObject.keys(); while (operators.hasNext()) { String operator = operators.next(); Object value = null; if (!conditionObject.isNull(operator)) { value = ClauseParser.parseValue(conditionObject.opt(operator)); } conditionalTests.add(new ConditionalTest(ConditionalOperator.parse(operator), value)); } return conditionalTests; }
@Override public boolean evaluate(FieldManager fieldManager, IndentPrinter printer) { // to compress logs we 'inline' single $and operators boolean printOperator = !LogicalOperator.$and.equals(operator) || children.size() > 1; if (printOperator) { printer.print("- %s:", operator.name()); printer.startBlock(); } try { return evaluateOperator(fieldManager, printer); } finally { if (printOperator) { printer.endBlock(); } } }
protected LogicalClause(String key, Object value) throws JSONException { operatorName = key.trim(); operator = LogicalOperator.parse(operatorName); children = new ArrayList<>(); ApptentiveLog.v(INTERACTIONS, " + LogicalClause of type \"%s\"", operatorName); if (value instanceof JSONArray) { JSONArray jsonArray = (JSONArray) value; for (int i = 0; i < jsonArray.length(); i++) { JSONObject child = (JSONObject) jsonArray.get(i); children.add(ClauseParser.parse(null, child)); } } else if (value instanceof JSONObject) { JSONObject jsonObject = (JSONObject) value; Iterator<String> it = jsonObject.keys(); while (it.hasNext()) { String currentKey = it.next(); if (!jsonObject.isNull(currentKey)) { children.add(ClauseParser.parse(currentKey, jsonObject.get(currentKey))); } else { children.add(ClauseParser.parse(currentKey, null)); } } } else { ApptentiveLog.w(INTERACTIONS, "Unrecognized LogicalClause: %s", value.toString()); } }
public boolean isMet(FieldManager fieldManager, boolean verbose) { try { Clause rootClause = ClauseParser.parse(json); boolean ret = false; if (rootClause != null) { IndentPrinter printer = verbose ? new IndentBufferedPrinter() : IndentPrinter.NULL; ret = rootClause.evaluate(fieldManager, printer); if (verbose) { ApptentiveLog.i(INTERACTIONS, "Criteria evaluated => %b", ret); ApptentiveLog.d(INTERACTIONS, "Criteria evaluation details:\n%s", printer); } } else { if (verbose) { ApptentiveLog.i(INTERACTIONS, "Criteria could not be evaluated: no clause found"); } } return ret; } catch (Exception e) { ApptentiveLog.e(INTERACTIONS, e, "Exception while evaluating interaction criteria"); logException(e); } return false; } }
public static Clause parse(String json) throws JSONException { ApptentiveLog.v(INTERACTIONS, "+ Parsing Interaction Criteria."); if (json == null) { ApptentiveLog.e(INTERACTIONS, "+ Interaction Criteria is null."); return null; } JSONObject root = new JSONObject(json); Clause ret = ClauseParser.parse(null, root); ApptentiveLog.v(INTERACTIONS, "+ Finished parsing Interaction Criteria."); return ret; }
private boolean evaluateOperator(FieldManager fieldManager, IndentPrinter printer) { if (operator == LogicalOperator.$and) { for (Clause clause : children) { boolean ret = clause.evaluate(fieldManager, printer); if (!ret) { return false; boolean ret = clause.evaluate(fieldManager, printer); if (ret) { return true; boolean ret = clause.evaluate(fieldManager, printer); return !ret; ApptentiveLog.v(INTERACTIONS, " - </%s>", operator.name()); return false;
public static ConditionalOperator parse(String name) { if (name != null) { try { return ConditionalOperator.valueOf(name); } catch (IllegalArgumentException e) { throw new RuntimeException(String.format("Unrecognized ConditionalOperator: %s", name), e); } } return unknown; }
public static LogicalOperator parse(String name) { if (name != null) { name = name.trim(); try { return LogicalOperator.valueOf(name); } catch (IllegalArgumentException e) { logException(e); } } return unknown; } }
public static QueryPart parse(String name) { if (name != null) { name = name.trim(); try { return QueryPart.valueOf(name); } catch (IllegalArgumentException e) { ApptentiveLog.e(INTERACTIONS, "Unrecognized QueryPart: \"%s\". Defaulting to \"unknown\"", name); logException(e); } } return other; } }
public ConditionalTest(ConditionalOperator operator, Object parameter) { ApptentiveLog.v(INTERACTIONS, " + ConditionalTest: %s: %s", operator.name(), Util.classToString(parameter)); this.operator = operator; if (parameter != null && !(parameter instanceof Comparable)) { throw new IllegalArgumentException(String.format("Encountered non-Comparable parameter: %s", Util.classToString(parameter))); } this.parameter = (Comparable) parameter; }
@Test public void defaultValues() throws JSONException { String json = loadTextAssetAsString(TEST_DATA_DIR + "testDefaultValues.json"); InteractionCriteria criteria = new InteractionCriteria(json); FieldManager fieldManager = new FieldManager(targetContext, new VersionHistory(), new EventData(), new Person(), new Device(), new AppRelease()); assertNotNull("Criteria was null, but it shouldn't be.", criteria); assertTrue(criteria.isMet(fieldManager)); } }
@Test public void predicateParsing() throws JSONException { String json = loadTextAssetAsString(TEST_DATA_DIR + "testPredicateParsing.json"); try { Clause criteria = ClauseParser.parse(json); assertNotNull("Criteria was null, but it shouldn't be.", criteria); } catch (JSONException e) { ApptentiveLog.e(e, "Error parsing test JSON."); assertNotNull(e); } } }
@Test public void cornerCasesThatShouldBeTrue() throws JSONException { String json = loadTextAssetAsString(TEST_DATA_DIR + "testCornerCasesThatShouldBeTrue.json"); InteractionCriteria criteria = new InteractionCriteria(json); EventData eventData = new EventData(); Device device = new Device(); device.getCustomData().put("key_with_null_value", null); FieldManager fieldManager = new FieldManager(targetContext, new VersionHistory(), eventData, new Person(), device, new AppRelease()); assertNotNull("Criteria was null, but it shouldn't be.", criteria); assertTrue(criteria.isMet(fieldManager)); ApptentiveLog.e("Finished test."); }
private void doTest(String testFile) throws JSONException { String json = loadTextAssetAsString(TEST_DATA_DIR + testFile); InteractionCriteria criteria = new InteractionCriteria(json); Device device = new Device(); FieldManager fieldManager = new FieldManager(targetContext, new VersionHistory(), new EventData(), new Person(), device, new AppRelease()); device.getCustomData().put(" string_qwerty ", "qwerty"); device.getCustomData().put(" string with spaces ", "string with spaces"); /* TODO: It looks like we weren't trimming custom_data keys before storing them. What is the implication of doing that? We can't store a key under " key " and then retrieve it with "key" */ assertTrue(criteria.isMet(fieldManager)); } }