/* * ************************************************************************************* * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * 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.eval; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventPropertyGetter; import com.espertech.esper.client.EventType; import com.espertech.esper.epl.datetime.calop.CalendarOp; import com.espertech.esper.epl.datetime.interval.IntervalOp; import com.espertech.esper.epl.datetime.reformatop.ReformatOp; import com.espertech.esper.epl.enummethod.dot.ExprDotEvalTypeInfo; import com.espertech.esper.epl.expression.ExprDotEval; import com.espertech.esper.epl.expression.ExprEvaluatorContext; import com.espertech.esper.util.JavaClassHelper; import java.util.Calendar; import java.util.Date; import java.util.List; public class ExprDotEvalDT implements ExprDotEval { private final ExprDotEvalTypeInfo returnType; private final DTLocalEvaluator evaluator; public ExprDotEvalDT(List<CalendarOp> calendarOps, ReformatOp reformatOp, IntervalOp intervalOp, Class inputType, EventType inputEventType) { this.evaluator = getEvaluator(calendarOps, inputType, inputEventType, reformatOp, intervalOp); if (intervalOp != null) { returnType = ExprDotEvalTypeInfo.scalarOrUnderlying(Boolean.class); } else if (reformatOp != null) { returnType = ExprDotEvalTypeInfo.scalarOrUnderlying(reformatOp.getReturnType()); } else { // only calendar ops if (inputEventType != null) { returnType = ExprDotEvalTypeInfo.scalarOrUnderlying(inputEventType.getPropertyType(inputEventType.getStartTimestampPropertyName())); } else { returnType = ExprDotEvalTypeInfo.scalarOrUnderlying(inputType); } } } public ExprDotEvalTypeInfo getTypeInfo() { return returnType; } public DTLocalEvaluator getEvaluator(List<CalendarOp> calendarOps, Class inputType, EventType inputEventType, ReformatOp reformatOp, IntervalOp intervalOp) { if (inputEventType == null) { if (reformatOp != null) { if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Calendar.class)) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorCalReformat(reformatOp); } return new DTLocalEvaluatorCalOpsReformat(calendarOps, reformatOp); } else if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Date.class)) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorDateReformat(reformatOp); } return new DTLocalEvaluatorDateOpsReformat(calendarOps, reformatOp); } else if (JavaClassHelper.getBoxedType(inputType) == Long.class) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorLongReformat(reformatOp); } return new DTLocalEvaluatorLongOpsReformat(calendarOps, reformatOp); } } else if (intervalOp != null) { if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Calendar.class)) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorCalInterval(intervalOp); } return new DTLocalEvaluatorCalOpsInterval(calendarOps, intervalOp); } else if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Date.class)) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorDateInterval(intervalOp); } return new DTLocalEvaluatorDateOpsInterval(calendarOps, intervalOp); } else if (JavaClassHelper.getBoxedType(inputType) == Long.class) { if (calendarOps.isEmpty()) { return new DTLocalEvaluatorLongInterval(intervalOp); } return new DTLocalEvaluatorLongOpsInterval(calendarOps, intervalOp); } } else { // only calendar ops, nothing else if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Calendar.class)) { return new DTLocalEvaluatorCalOpsCal(calendarOps); } else if (JavaClassHelper.isSubclassOrImplementsInterface(inputType, Date.class)) { return new DTLocalEvaluatorCalOpsDate(calendarOps); } else if (JavaClassHelper.getBoxedType(inputType) == Long.class) { return new DTLocalEvaluatorCalOpsLong(calendarOps); } } throw new IllegalArgumentException("Invalid input type '" + inputType + "'"); } EventPropertyGetter getter = inputEventType.getGetter(inputEventType.getStartTimestampPropertyName()); Class getterResultType = inputEventType.getPropertyType(inputEventType.getStartTimestampPropertyName()); if (reformatOp != null) { DTLocalEvaluator inner = getEvaluator(calendarOps, getterResultType, null, reformatOp, null); return new DTLocalEvaluatorBeanReformat(getter, inner); } if (intervalOp == null) { // only calendar ops DTLocalEvaluator inner = getEvaluator(calendarOps, getterResultType, null, null, null); return new DTLocalEvaluatorBeanCalOps(getter, inner); } // have interval ops but no end timestamp if (inputEventType.getEndTimestampPropertyName() == null) { DTLocalEvaluator inner = getEvaluator(calendarOps, getterResultType, null, null, intervalOp); return new DTLocalEvaluatorBeanIntervalNoEndTS(getter, inner); } // interval ops and have end timestamp EventPropertyGetter getterEndTimestamp = inputEventType.getGetter(inputEventType.getEndTimestampPropertyName()); DTLocalEvaluatorIntervalComp inner = (DTLocalEvaluatorIntervalComp) getEvaluator(calendarOps, getterResultType, null, null, intervalOp); return new DTLocalEvaluatorBeanIntervalWithEnd(getter, getterEndTimestamp, inner); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { if (target == null) { return null; } return evaluator.evaluate(target, eventsPerStream, isNewData, exprEvaluatorContext); } protected static void evaluateCalOps(List<CalendarOp> calendarOps, Calendar cal, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { for (CalendarOp calendarOp : calendarOps) { calendarOp.evaluate(cal, eventsPerStream, isNewData, exprEvaluatorContext); } } private static interface DTLocalEvaluator { public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext); } private abstract static class DTLocalEvaluatorReformatBase implements DTLocalEvaluator { protected final ReformatOp reformatOp; protected DTLocalEvaluatorReformatBase(ReformatOp reformatOp) { this.reformatOp = reformatOp; } } private abstract static class DTLocalEvaluatorCalopReformatBase implements DTLocalEvaluator { protected final List<CalendarOp> calendarOps; protected final ReformatOp reformatOp; protected DTLocalEvaluatorCalopReformatBase(List<CalendarOp> calendarOps, ReformatOp reformatOp) { this.calendarOps = calendarOps; this.reformatOp = reformatOp; } } private static class DTLocalEvaluatorCalReformat extends DTLocalEvaluatorReformatBase { private DTLocalEvaluatorCalReformat(ReformatOp reformatOp) { super(reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { return reformatOp.evaluate((Calendar) target, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorCalOpsReformat extends DTLocalEvaluatorCalopReformatBase { private DTLocalEvaluatorCalOpsReformat(List<CalendarOp> calendarOps, ReformatOp reformatOp) { super(calendarOps, reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = (Calendar) ((Calendar) target).clone(); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return reformatOp.evaluate(cal, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorDateReformat extends DTLocalEvaluatorReformatBase { private DTLocalEvaluatorDateReformat(ReformatOp reformatOp) { super(reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { return reformatOp.evaluate((Date) target, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorDateOpsReformat extends DTLocalEvaluatorCalopReformatBase { private DTLocalEvaluatorDateOpsReformat(List<CalendarOp> calendarOps, ReformatOp reformatOp) { super(calendarOps, reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(((Date) target).getTime()); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return reformatOp.evaluate(cal, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorLongReformat extends DTLocalEvaluatorReformatBase { private DTLocalEvaluatorLongReformat(ReformatOp reformatOp) { super(reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { return reformatOp.evaluate((Long) target, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorLongOpsReformat extends DTLocalEvaluatorCalopReformatBase { private DTLocalEvaluatorLongOpsReformat(List<CalendarOp> calendarOps, ReformatOp reformatOp) { super(calendarOps, reformatOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis((Long) target); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return reformatOp.evaluate(cal, eventsPerStream, isNewData, exprEvaluatorContext); } } /** * Interval methods. */ private interface DTLocalEvaluatorIntervalComp { public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext); } private abstract static class DTLocalEvaluatorIntervalBase implements DTLocalEvaluator, DTLocalEvaluatorIntervalComp { protected final IntervalOp intervalOp; protected DTLocalEvaluatorIntervalBase(IntervalOp intervalOp) { this.intervalOp = intervalOp; } } private abstract static class DTLocalEvaluatorCalOpsIntervalBase implements DTLocalEvaluator, DTLocalEvaluatorIntervalComp { protected final List<CalendarOp> calendarOps; protected final IntervalOp intervalOp; protected DTLocalEvaluatorCalOpsIntervalBase(List<CalendarOp> calendarOps, IntervalOp intervalOp) { this.calendarOps = calendarOps; this.intervalOp = intervalOp; } } private static class DTLocalEvaluatorCalInterval extends DTLocalEvaluatorIntervalBase { private DTLocalEvaluatorCalInterval(IntervalOp intervalOp) { super(intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long time = ((Calendar) target).getTimeInMillis(); return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long start = ((Calendar) startTimestamp).getTimeInMillis(); long end = ((Calendar) endTimestamp).getTimeInMillis(); return intervalOp.evaluate(start, end, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorCalOpsInterval extends DTLocalEvaluatorCalOpsIntervalBase { private DTLocalEvaluatorCalOpsInterval(List<CalendarOp> calendarOps, IntervalOp intervalOp) { super(calendarOps, intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = (Calendar) ((Calendar) target).clone(); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long time = cal.getTimeInMillis(); return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long startLong = ((Calendar) startTimestamp).getTimeInMillis(); long endLong = ((Calendar) endTimestamp).getTimeInMillis(); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(startLong); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long startTime = cal.getTimeInMillis(); long endTime = startTime + (endLong - startLong); return intervalOp.evaluate(startTime, endTime, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorDateInterval extends DTLocalEvaluatorIntervalBase { private DTLocalEvaluatorDateInterval(IntervalOp intervalOp) { super(intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long time = ((Date) target).getTime(); return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long start = ((Date) startTimestamp).getTime(); long end = ((Date) endTimestamp).getTime(); return intervalOp.evaluate(start, end, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorDateOpsInterval extends DTLocalEvaluatorCalOpsIntervalBase { private DTLocalEvaluatorDateOpsInterval(List<CalendarOp> calendarOps, IntervalOp intervalOp) { super(calendarOps, intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(((Date) target).getTime()); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long time = cal.getTimeInMillis(); return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long startLong = ((Date) startTimestamp).getTime(); long endLong = ((Date) endTimestamp).getTime(); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(startLong); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long startTime = cal.getTimeInMillis(); long endTime = startTime + (endLong - startLong); return intervalOp.evaluate(startTime, endTime, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorLongInterval extends DTLocalEvaluatorIntervalBase { private DTLocalEvaluatorLongInterval(IntervalOp intervalOp) { super(intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long time = (Long) target; return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long startTime = (Long) startTimestamp; long endTime = (Long) endTimestamp; return intervalOp.evaluate(startTime, endTime, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorLongOpsInterval extends DTLocalEvaluatorCalOpsIntervalBase { private DTLocalEvaluatorLongOpsInterval(List<CalendarOp> calendarOps, IntervalOp intervalOp) { super(calendarOps, intervalOp); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis((Long) target); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long time = cal.getTimeInMillis(); return intervalOp.evaluate(time, time, eventsPerStream, isNewData, exprEvaluatorContext); } public Object evaluate(Object startTimestamp, Object endTimestamp, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { long startLong = (Long) startTimestamp; long endLong = (Long) endTimestamp; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(startLong); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); long startTime = cal.getTimeInMillis(); long endTime = startTime + (endLong - startLong); return intervalOp.evaluate(startTime, endTime, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorBeanReformat implements DTLocalEvaluator { private final EventPropertyGetter getter; private final DTLocalEvaluator inner; private DTLocalEvaluatorBeanReformat(EventPropertyGetter getter, DTLocalEvaluator inner) { this.getter = getter; this.inner = inner; } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object timestamp = getter.get((EventBean)target); if (timestamp == null) { return null; } return inner.evaluate(timestamp, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorBeanIntervalNoEndTS implements DTLocalEvaluator { private final EventPropertyGetter getter; private final DTLocalEvaluator inner; private DTLocalEvaluatorBeanIntervalNoEndTS(EventPropertyGetter getter, DTLocalEvaluator inner) { this.getter = getter; this.inner = inner; } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object timestamp = getter.get((EventBean)target); if (timestamp == null) { return null; } return inner.evaluate(timestamp, eventsPerStream, isNewData, exprEvaluatorContext); } } private static class DTLocalEvaluatorBeanIntervalWithEnd implements DTLocalEvaluator { private final EventPropertyGetter getterStartTimestamp; private final EventPropertyGetter getterEndTimestamp; private final DTLocalEvaluatorIntervalComp inner; private DTLocalEvaluatorBeanIntervalWithEnd(EventPropertyGetter getterStartTimestamp, EventPropertyGetter getterEndTimestamp, DTLocalEvaluatorIntervalComp inner) { this.getterStartTimestamp = getterStartTimestamp; this.getterEndTimestamp = getterEndTimestamp; this.inner = inner; } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object startTimestamp = getterStartTimestamp.get((EventBean)target); if (startTimestamp == null) { return null; } Object endTimestamp = getterEndTimestamp.get((EventBean)target); if (endTimestamp == null) { return null; } return inner.evaluate(startTimestamp, endTimestamp, eventsPerStream, isNewData, exprEvaluatorContext); } } private abstract class DTLocalEvaluatorCalOpsCalBase { protected final List<CalendarOp> calendarOps; private DTLocalEvaluatorCalOpsCalBase(List<CalendarOp> calendarOps) { this.calendarOps = calendarOps; } } private class DTLocalEvaluatorCalOpsLong extends DTLocalEvaluatorCalOpsCalBase implements DTLocalEvaluator { private DTLocalEvaluatorCalOpsLong(List<CalendarOp> calendarOps) { super(calendarOps); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Long longValue = (Long) target; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(longValue); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return cal.getTimeInMillis(); } } private class DTLocalEvaluatorCalOpsDate extends DTLocalEvaluatorCalOpsCalBase implements DTLocalEvaluator { private DTLocalEvaluatorCalOpsDate(List<CalendarOp> calendarOps) { super(calendarOps); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Date dateValue = (Date) target; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(dateValue.getTime()); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return cal.getTime(); } } private class DTLocalEvaluatorCalOpsCal extends DTLocalEvaluatorCalOpsCalBase implements DTLocalEvaluator { private DTLocalEvaluatorCalOpsCal(List<CalendarOp> calendarOps) { super(calendarOps); } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Calendar calValue = (Calendar) target; Calendar cal = (Calendar) calValue.clone(); evaluateCalOps(calendarOps, cal, eventsPerStream, isNewData, exprEvaluatorContext); return cal; } } private static class DTLocalEvaluatorBeanCalOps implements DTLocalEvaluator { private final EventPropertyGetter getter; private final DTLocalEvaluator inner; private DTLocalEvaluatorBeanCalOps(EventPropertyGetter getter, DTLocalEvaluator inner) { this.getter = getter; this.inner = inner; } public Object evaluate(Object target, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { Object timestamp = getter.get((EventBean)target); if (timestamp == null) { return null; } return inner.evaluate(timestamp, eventsPerStream, isNewData, exprEvaluatorContext); } } }