/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.epl.datetime.interval; import com.espertech.esper.client.EventBean; import com.espertech.esper.epl.datetime.eval.DatetimeMethodEnum; import com.espertech.esper.epl.expression.core.*; import com.espertech.esper.epl.expression.time.ExprTimePeriod; import com.espertech.esper.epl.expression.time.ExprTimePeriodEvalDeltaConst; import com.espertech.esper.epl.expression.time.ExprTimePeriodEvalDeltaNonConst; import com.espertech.esper.epl.expression.time.TimeAbacus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class IntervalComputerFactory { public static IntervalComputer make(DatetimeMethodEnum method, List<ExprNode> expressions, TimeAbacus timeAbacus) throws ExprValidationException { ExprOptionalConstant[] parameters = getParameters(expressions, timeAbacus); if (method == DatetimeMethodEnum.BEFORE) { if (parameters.length == 0) { return new IntervalComputerBeforeNoParam(); } IntervalStartEndParameterPair pair = IntervalStartEndParameterPair.fromParamsWithLongMaxEnd(parameters); if (pair.isConstant()) { return new IntervalComputerConstantBefore(pair); } return new IntervalComputerBeforeWithDeltaExpr(pair); } else if (method == DatetimeMethodEnum.AFTER) { if (parameters.length == 0) { return new IntervalComputerAfterNoParam(); } IntervalStartEndParameterPair pair = IntervalStartEndParameterPair.fromParamsWithLongMaxEnd(parameters); if (pair.isConstant()) { return new IntervalComputerConstantAfter(pair); } return new IntervalComputerAfterWithDeltaExpr(pair); } else if (method == DatetimeMethodEnum.COINCIDES) { if (parameters.length == 0) { return new IntervalComputerCoincidesNoParam(); } IntervalStartEndParameterPair pair = IntervalStartEndParameterPair.fromParamsWithSameEnd(parameters); if (pair.isConstant()) { return new IntervalComputerConstantCoincides(pair); } return new IntervalComputerCoincidesWithDeltaExpr(pair); } else if (method == DatetimeMethodEnum.DURING || method == DatetimeMethodEnum.INCLUDES) { if (parameters.length == 0) { if (method == DatetimeMethodEnum.DURING) { return new IntervalComputerDuringNoParam(); } return new IntervalComputerIncludesNoParam(); } IntervalStartEndParameterPair pair = IntervalStartEndParameterPair.fromParamsWithSameEnd(parameters); if (parameters.length == 1) { return new IntervalComputerDuringAndIncludesThreshold(method == DatetimeMethodEnum.DURING, pair.getStart().getEvaluator()); } if (parameters.length == 2) { return new IntervalComputerDuringAndIncludesMinMax(method == DatetimeMethodEnum.DURING, pair.getStart().getEvaluator(), pair.getEnd().getEvaluator()); } return new IntervalComputerDuringMinMaxStartEnd(method == DatetimeMethodEnum.DURING, getEvaluators(expressions, timeAbacus)); } else if (method == DatetimeMethodEnum.FINISHES) { if (parameters.length == 0) { return new IntervalComputerFinishesNoParam(); } validateConstantThreshold("finishes", parameters[0]); return new IntervalComputerFinishesThreshold(parameters[0].getEvaluator()); } else if (method == DatetimeMethodEnum.FINISHEDBY) { if (parameters.length == 0) { return new IntervalComputerFinishedByNoParam(); } validateConstantThreshold("finishedby", parameters[0]); return new IntervalComputerFinishedByThreshold(parameters[0].getEvaluator()); } else if (method == DatetimeMethodEnum.MEETS) { if (parameters.length == 0) { return new IntervalComputerMeetsNoParam(); } validateConstantThreshold("meets", parameters[0]); return new IntervalComputerMeetsThreshold(parameters[0].getEvaluator()); } else if (method == DatetimeMethodEnum.METBY) { if (parameters.length == 0) { return new IntervalComputerMetByNoParam(); } validateConstantThreshold("metBy", parameters[0]); return new IntervalComputerMetByThreshold(parameters[0].getEvaluator()); } else if (method == DatetimeMethodEnum.OVERLAPS || method == DatetimeMethodEnum.OVERLAPPEDBY) { if (parameters.length == 0) { if (method == DatetimeMethodEnum.OVERLAPS) { return new IntervalComputerOverlapsNoParam(); } return new IntervalComputerOverlappedByNoParam(); } if (parameters.length == 1) { return new IntervalComputerOverlapsAndByThreshold(method == DatetimeMethodEnum.OVERLAPS, parameters[0].getEvaluator()); } return new IntervalComputerOverlapsAndByMinMax(method == DatetimeMethodEnum.OVERLAPS, parameters[0].getEvaluator(), parameters[1].getEvaluator()); } else if (method == DatetimeMethodEnum.STARTS) { if (parameters.length == 0) { return new IntervalComputerStartsNoParam(); } validateConstantThreshold("starts", parameters[0]); return new IntervalComputerStartsThreshold(parameters[0].getEvaluator()); } else if (method == DatetimeMethodEnum.STARTEDBY) { if (parameters.length == 0) { return new IntervalComputerStartedByNoParam(); } validateConstantThreshold("startedBy", parameters[0]); return new IntervalComputerStartedByThreshold(parameters[0].getEvaluator()); } throw new IllegalArgumentException("Unknown datetime method '" + method + "'"); } private static void validateConstantThreshold(String method, ExprOptionalConstant param) throws ExprValidationException { if (param.getOptionalConstant() != null && (param.getOptionalConstant()).longValue() < 0) { throw new ExprValidationException("The " + method + " date-time method does not allow negative threshold value"); } } private static ExprOptionalConstant[] getParameters(List<ExprNode> expressions, TimeAbacus timeAbacus) { ExprOptionalConstant[] parameters = new ExprOptionalConstant[expressions.size() - 1]; for (int i = 1; i < expressions.size(); i++) { parameters[i - 1] = getExprOrConstant(expressions.get(i), timeAbacus); } return parameters; } private static IntervalDeltaExprEvaluator[] getEvaluators(List<ExprNode> expressions, TimeAbacus timeAbacus) { IntervalDeltaExprEvaluator[] parameters = new IntervalDeltaExprEvaluator[expressions.size() - 1]; for (int i = 1; i < expressions.size(); i++) { parameters[i - 1] = getExprOrConstant(expressions.get(i), timeAbacus).getEvaluator(); } return parameters; } private static ExprOptionalConstant getExprOrConstant(ExprNode exprNode, final TimeAbacus timeAbacus) { if (exprNode instanceof ExprTimePeriod) { final ExprTimePeriod timePeriod = (ExprTimePeriod) exprNode; if (!timePeriod.isHasMonth() && !timePeriod.isHasYear()) { // no-month and constant if (exprNode.isConstantResult()) { double sec = timePeriod.evaluateAsSeconds(null, true, null); final long l = timeAbacus.deltaForSecondsDouble(sec); IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return l; } }; return new ExprOptionalConstant(eval, l); } else { // no-month and not constant IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { double sec = timePeriod.evaluateAsSeconds(eventsPerStream, isNewData, context); return timeAbacus.deltaForSecondsDouble(sec); } }; return new ExprOptionalConstant(eval, null); } } else { // has-month and constant if (exprNode.isConstantResult()) { final ExprTimePeriodEvalDeltaConst timerPeriodConst = timePeriod.constEvaluator(null); IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return timerPeriodConst.deltaAdd(reference); } }; return new ExprOptionalConstant(eval, null); } else { // has-month and not constant final ExprTimePeriodEvalDeltaNonConst timerPeriodNonConst = timePeriod.nonconstEvaluator(); IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return timerPeriodNonConst.deltaAdd(reference, eventsPerStream, isNewData, context); } }; return new ExprOptionalConstant(eval, null); } } } else if (ExprNodeUtility.isConstantValueExpr(exprNode)) { ExprConstantNode constantNode = (ExprConstantNode) exprNode; final long l = ((Number) constantNode.getConstantValue(null)).longValue(); IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return l; } }; return new ExprOptionalConstant(eval, l); } else { final ExprEvaluator evaluator = exprNode.getExprEvaluator(); IntervalDeltaExprEvaluator eval = new IntervalDeltaExprEvaluator() { public long evaluate(long reference, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return ((Number) evaluator.evaluate(eventsPerStream, isNewData, context)).longValue(); } }; return new ExprOptionalConstant(eval, null); } } /** * After. */ public static class IntervalComputerConstantAfter extends IntervalComputerConstantBase implements IntervalComputer { public IntervalComputerConstantAfter(IntervalStartEndParameterPair pair) { super(pair, true); } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return computeInternal(leftStart, leftEnd, rightStart, rightEnd, start, end); } public static Boolean computeInternal(long leftStart, long leftEnd, long rightStart, long rightEnd, long start, long end) { long delta = leftStart - rightEnd; return start <= delta && delta <= end; } } public static class IntervalComputerAfterWithDeltaExpr implements IntervalComputer { private final IntervalDeltaExprEvaluator start; private final IntervalDeltaExprEvaluator finish; public IntervalComputerAfterWithDeltaExpr(IntervalStartEndParameterPair pair) { this.start = pair.getStart().getEvaluator(); this.finish = pair.getEnd().getEvaluator(); } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long rangeStartDelta = start.evaluate(rightStart, eventsPerStream, newData, context); long rangeEndDelta = finish.evaluate(rightStart, eventsPerStream, newData, context); if (rangeStartDelta > rangeEndDelta) { return IntervalComputerConstantAfter.computeInternal(leftStart, leftEnd, rightStart, rightEnd, rangeEndDelta, rangeStartDelta); } else { return IntervalComputerConstantAfter.computeInternal(leftStart, leftEnd, rightStart, rightEnd, rangeStartDelta, rangeEndDelta); } } } public static class IntervalComputerAfterNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftStart > rightEnd; } } /** * Before. */ public static class IntervalComputerConstantBefore extends IntervalComputerConstantBase implements IntervalComputer { public IntervalComputerConstantBefore(IntervalStartEndParameterPair pair) { super(pair, true); } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return computeInternal(leftStart, leftEnd, rightStart, start, end); } public static Boolean computeInternal(long left, long leftEnd, long right, long start, long end) { long delta = right - leftEnd; return start <= delta && delta <= end; } } public static class IntervalComputerBeforeWithDeltaExpr implements IntervalComputer { private final IntervalDeltaExprEvaluator start; private final IntervalDeltaExprEvaluator finish; public IntervalComputerBeforeWithDeltaExpr(IntervalStartEndParameterPair pair) { this.start = pair.getStart().getEvaluator(); this.finish = pair.getEnd().getEvaluator(); } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long rangeStartDelta = start.evaluate(leftEnd, eventsPerStream, newData, context); long rangeEndDelta = finish.evaluate(leftEnd, eventsPerStream, newData, context); if (rangeStartDelta > rangeEndDelta) { return IntervalComputerConstantBefore.computeInternal(leftStart, leftEnd, rightStart, rangeEndDelta, rangeStartDelta); } else { return IntervalComputerConstantBefore.computeInternal(leftStart, leftEnd, rightStart, rangeStartDelta, rangeEndDelta); } } } public static class IntervalComputerBeforeNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftEnd < rightStart; } } /** * Coincides. */ public static class IntervalComputerConstantCoincides implements IntervalComputer { protected final long start; protected final long end; public IntervalComputerConstantCoincides(IntervalStartEndParameterPair pair) throws ExprValidationException { start = pair.getStart().getOptionalConstant(); end = pair.getEnd().getOptionalConstant(); if (start < 0 || end < 0) { throw new ExprValidationException("The coincides date-time method does not allow negative start and end values"); } } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return computeInternal(leftStart, leftEnd, rightStart, rightEnd, start, end); } public static Boolean computeInternal(long left, long leftEnd, long right, long rightEnd, long startThreshold, long endThreshold) { return Math.abs(left - right) <= startThreshold && Math.abs(leftEnd - rightEnd) <= endThreshold; } } public static class IntervalComputerCoincidesWithDeltaExpr implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerCoincidesWithDeltaExpr.class); private final IntervalDeltaExprEvaluator start; private final IntervalDeltaExprEvaluator finish; public IntervalComputerCoincidesWithDeltaExpr(IntervalStartEndParameterPair pair) { this.start = pair.getStart().getEvaluator(); this.finish = pair.getEnd().getEvaluator(); } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long startValue = start.evaluate(Math.min(leftStart, rightStart), eventsPerStream, newData, context); long endValue = finish.evaluate(Math.min(leftEnd, rightEnd), eventsPerStream, newData, context); if (startValue < 0 || endValue < 0) { log.warn("The coincides date-time method does not allow negative start and end values"); return null; } return IntervalComputerConstantCoincides.computeInternal(leftStart, leftEnd, rightStart, rightEnd, startValue, endValue); } } public static class IntervalComputerCoincidesNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftStart == rightStart && leftEnd == rightEnd; } } /** * During And Includes. */ public static class IntervalComputerDuringNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return rightStart < leftStart && leftEnd < rightEnd; } } public static class IntervalComputerIncludesNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftStart < rightStart && rightEnd < leftEnd; } } public static class IntervalComputerDuringAndIncludesThreshold implements IntervalComputer { private final boolean during; private final IntervalDeltaExprEvaluator threshold; public IntervalComputerDuringAndIncludesThreshold(boolean during, IntervalDeltaExprEvaluator threshold) { this.during = during; this.threshold = threshold; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long thresholdValue = threshold.evaluate(leftStart, eventsPerStream, newData, context); if (during) { long deltaStart = leftStart - rightStart; if (deltaStart <= 0 || deltaStart > thresholdValue) { return false; } long deltaEnd = rightEnd - leftEnd; return !(deltaEnd <= 0 || deltaEnd > thresholdValue); } else { long deltaStart = rightStart - leftStart; if (deltaStart <= 0 || deltaStart > thresholdValue) { return false; } long deltaEnd = leftEnd - rightEnd; return !(deltaEnd <= 0 || deltaEnd > thresholdValue); } } } public static class IntervalComputerDuringAndIncludesMinMax implements IntervalComputer { private final boolean during; private final IntervalDeltaExprEvaluator minEval; private final IntervalDeltaExprEvaluator maxEval; public IntervalComputerDuringAndIncludesMinMax(boolean during, IntervalDeltaExprEvaluator minEval, IntervalDeltaExprEvaluator maxEval) { this.during = during; this.minEval = minEval; this.maxEval = maxEval; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long min = minEval.evaluate(leftStart, eventsPerStream, newData, context); long max = maxEval.evaluate(rightEnd, eventsPerStream, newData, context); if (during) { return computeInternalDuring(leftStart, leftEnd, rightStart, rightEnd, min, max, min, max); } else { return computeInternalIncludes(leftStart, leftEnd, rightStart, rightEnd, min, max, min, max); } } public static boolean computeInternalDuring(long left, long leftEnd, long right, long rightEnd, long startMin, long startMax, long endMin, long endMax) { if (startMin <= 0) { startMin = 1; } long deltaStart = left - right; if (deltaStart < startMin || deltaStart > startMax) { return false; } long deltaEnd = rightEnd - leftEnd; return !(deltaEnd < endMin || deltaEnd > endMax); } public static boolean computeInternalIncludes(long left, long leftEnd, long right, long rightEnd, long startMin, long startMax, long endMin, long endMax) { if (startMin <= 0) { startMin = 1; } long deltaStart = right - left; if (deltaStart < startMin || deltaStart > startMax) { return false; } long deltaEnd = leftEnd - rightEnd; return !(deltaEnd < endMin || deltaEnd > endMax); } } public static class IntervalComputerDuringMinMaxStartEnd implements IntervalComputer { private final boolean during; private final IntervalDeltaExprEvaluator minStartEval; private final IntervalDeltaExprEvaluator maxStartEval; private final IntervalDeltaExprEvaluator minEndEval; private final IntervalDeltaExprEvaluator maxEndEval; public IntervalComputerDuringMinMaxStartEnd(boolean during, IntervalDeltaExprEvaluator[] parameters) { this.during = during; minStartEval = parameters[0]; maxStartEval = parameters[1]; minEndEval = parameters[2]; maxEndEval = parameters[3]; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long minStart = minStartEval.evaluate(rightStart, eventsPerStream, newData, context); long maxStart = maxStartEval.evaluate(rightStart, eventsPerStream, newData, context); long minEnd = minEndEval.evaluate(rightEnd, eventsPerStream, newData, context); long maxEnd = maxEndEval.evaluate(rightEnd, eventsPerStream, newData, context); if (during) { return IntervalComputerDuringAndIncludesMinMax.computeInternalDuring(leftStart, leftEnd, rightStart, rightEnd, minStart, maxStart, minEnd, maxEnd); } else { return IntervalComputerDuringAndIncludesMinMax.computeInternalIncludes(leftStart, leftEnd, rightStart, rightEnd, minStart, maxStart, minEnd, maxEnd); } } } /** * Finishes. */ public static class IntervalComputerFinishesNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return rightStart < leftStart && (leftEnd == rightEnd); } } public static class IntervalComputerFinishesThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerFinishesThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerFinishesThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(leftEnd, rightEnd), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } if (rightStart >= leftStart) { return false; } long delta = Math.abs(leftEnd - rightEnd); return delta <= threshold; } } /** * Finishes-By. */ public static class IntervalComputerFinishedByNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftStart < rightStart && (leftEnd == rightEnd); } } public static class IntervalComputerFinishedByThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerFinishedByThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerFinishedByThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(rightEnd, leftEnd), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } if (leftStart >= rightStart) { return false; } long delta = Math.abs(leftEnd - rightEnd); return delta <= threshold; } } /** * Meets. */ public static class IntervalComputerMeetsNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return leftEnd == rightStart; } } public static class IntervalComputerMeetsThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerMeetsThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerMeetsThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(leftEnd, rightStart), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } long delta = Math.abs(rightStart - leftEnd); return delta <= threshold; } } /** * Met-By. */ public static class IntervalComputerMetByNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return rightEnd == leftStart; } } public static class IntervalComputerMetByThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerMetByThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerMetByThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(leftStart, rightEnd), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } long delta = Math.abs(leftStart - rightEnd); return delta <= threshold; } } /** * Overlaps. */ public static class IntervalComputerOverlapsNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return (leftStart < rightStart) && (rightStart < leftEnd) && (leftEnd < rightEnd); } } public static class IntervalComputerOverlapsAndByThreshold implements IntervalComputer { private final boolean overlaps; private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerOverlapsAndByThreshold(boolean overlaps, IntervalDeltaExprEvaluator thresholdExpr) { this.overlaps = overlaps; this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { if (overlaps) { long threshold = thresholdExpr.evaluate(leftStart, eventsPerStream, newData, context); return computeInternalOverlaps(leftStart, leftEnd, rightStart, rightEnd, 0, threshold); } else { long threshold = thresholdExpr.evaluate(rightStart, eventsPerStream, newData, context); return computeInternalOverlaps(rightStart, rightEnd, leftStart, leftEnd, 0, threshold); } } public static boolean computeInternalOverlaps(long left, long leftEnd, long right, long rightEnd, long min, long max) { boolean match = (left < right) && (right < leftEnd) && (leftEnd < rightEnd); if (!match) { return false; } long delta = leftEnd - right; return min <= delta && delta <= max; } } public static class IntervalComputerOverlapsAndByMinMax implements IntervalComputer { private final boolean overlaps; private final IntervalDeltaExprEvaluator minEval; private final IntervalDeltaExprEvaluator maxEval; public IntervalComputerOverlapsAndByMinMax(boolean overlaps, IntervalDeltaExprEvaluator minEval, IntervalDeltaExprEvaluator maxEval) { this.overlaps = overlaps; this.minEval = minEval; this.maxEval = maxEval; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { if (overlaps) { long minThreshold = minEval.evaluate(leftStart, eventsPerStream, newData, context); long maxThreshold = maxEval.evaluate(leftEnd, eventsPerStream, newData, context); return IntervalComputerOverlapsAndByThreshold.computeInternalOverlaps(leftStart, leftEnd, rightStart, rightEnd, minThreshold, maxThreshold); } else { long minThreshold = minEval.evaluate(rightStart, eventsPerStream, newData, context); long maxThreshold = maxEval.evaluate(rightEnd, eventsPerStream, newData, context); return IntervalComputerOverlapsAndByThreshold.computeInternalOverlaps(rightStart, rightEnd, leftStart, leftEnd, minThreshold, maxThreshold); } } } /** * OverlappedBy. */ public static class IntervalComputerOverlappedByNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return (rightStart < leftStart) && (leftStart < rightEnd) && (rightEnd < leftEnd); } } /** * Starts. */ public static class IntervalComputerStartsNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return (leftStart == rightStart) && (leftEnd < rightEnd); } } public static class IntervalComputerStartsThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerStartsThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerStartsThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(leftStart, rightStart), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } long delta = Math.abs(leftStart - rightStart); return delta <= threshold && (leftEnd < rightEnd); } } /** * Started-by. */ public static class IntervalComputerStartedByNoParam implements IntervalComputer { public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { return (leftStart == rightStart) && (leftEnd > rightEnd); } } public static class IntervalComputerStartedByThreshold implements IntervalComputer { private static final Logger log = LoggerFactory.getLogger(IntervalComputerStartedByThreshold.class); private final IntervalDeltaExprEvaluator thresholdExpr; public IntervalComputerStartedByThreshold(IntervalDeltaExprEvaluator thresholdExpr) { this.thresholdExpr = thresholdExpr; } public Boolean compute(long leftStart, long leftEnd, long rightStart, long rightEnd, EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { long threshold = thresholdExpr.evaluate(Math.min(leftStart, rightStart), eventsPerStream, newData, context); if (threshold < 0) { log.warn("The 'finishes' date-time method does not allow negative threshold"); return null; } long delta = Math.abs(leftStart - rightStart); return delta <= threshold && (leftEnd > rightEnd); } } }