/* * ************************************************************************************* * 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.interval; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventPropertyGetter; import com.espertech.esper.client.EventType; import com.espertech.esper.collection.Pair; import com.espertech.esper.epl.core.PropertyResolutionDescriptor; import com.espertech.esper.epl.core.StreamTypeService; import com.espertech.esper.epl.datetime.eval.DatetimeMethodEnum; import com.espertech.esper.epl.datetime.eval.ExprDotNodeFilterAnalyzerDTIntervalDesc; import com.espertech.esper.epl.expression.*; import com.espertech.esper.util.JavaClassHelper; import java.util.Calendar; import java.util.Date; import java.util.List; public class IntervalOpImpl implements IntervalOp { private ExprEvaluator evaluatorTimestamp; private Integer parameterStreamNum; private String parameterPropertyStart; private String parameterPropertyEnd; private final IntervalOpEval intervalOpEval; public IntervalOpImpl(DatetimeMethodEnum method, String methodNameUse, StreamTypeService streamTypeService, List<ExprNode> expressions) throws ExprValidationException { ExprEvaluator evaluatorEndTimestamp = null; Class timestampType; if (expressions.get(0) instanceof ExprStreamUnderlyingNode) { ExprStreamUnderlyingNode und = (ExprStreamUnderlyingNode) expressions.get(0); parameterStreamNum = und.getStreamId(); EventType type = streamTypeService.getEventTypes()[parameterStreamNum]; parameterPropertyStart = type.getStartTimestampPropertyName(); if (parameterPropertyStart == null) { throw new ExprValidationException("For date-time method '" + methodNameUse + "' the first parameter is event type '" + type.getName() + "', however no timestamp property has been defined for this event type"); } timestampType = type.getPropertyType(parameterPropertyStart); EventPropertyGetter getter = type.getGetter(parameterPropertyStart); evaluatorTimestamp = new ExprEvaluatorStreamLongProp(parameterStreamNum, getter); if (type.getEndTimestampPropertyName() != null) { parameterPropertyEnd = type.getEndTimestampPropertyName(); EventPropertyGetter getterEndTimestamp = type.getGetter(type.getEndTimestampPropertyName()); evaluatorEndTimestamp = new ExprEvaluatorStreamLongProp(parameterStreamNum, getterEndTimestamp); } else { parameterPropertyEnd = parameterPropertyStart; } } else { evaluatorTimestamp = expressions.get(0).getExprEvaluator(); timestampType = evaluatorTimestamp.getType(); String unresolvedPropertyName = null; if (expressions.get(0) instanceof ExprIdentNode) { ExprIdentNode identNode = (ExprIdentNode) expressions.get(0); parameterStreamNum = identNode.getStreamId(); parameterPropertyStart = identNode.getResolvedPropertyName(); parameterPropertyEnd = parameterPropertyStart; unresolvedPropertyName = identNode.getUnresolvedPropertyName(); } if (!JavaClassHelper.isDatetimeClass(evaluatorTimestamp.getType())) { // ident node may represent a fragment if (unresolvedPropertyName != null) { Pair<PropertyResolutionDescriptor, String> propertyDesc = ExprIdentNodeUtil.getTypeFromStream(streamTypeService, unresolvedPropertyName, false, true); if (propertyDesc.getFirst().getFragmentEventType() != null) { EventType type = propertyDesc.getFirst().getFragmentEventType().getFragmentType(); parameterPropertyStart = type.getStartTimestampPropertyName(); if (parameterPropertyStart == null) { throw new ExprValidationException("For date-time method '" + methodNameUse + "' the first parameter is event type '" + type.getName() + "', however no timestamp property has been defined for this event type"); } timestampType = type.getPropertyType(parameterPropertyStart); EventPropertyGetter getterFragment = streamTypeService.getEventTypes()[parameterStreamNum].getGetter(unresolvedPropertyName); EventPropertyGetter getterStartTimestamp = type.getGetter(parameterPropertyStart); evaluatorTimestamp = new ExprEvaluatorStreamLongPropFragment(parameterStreamNum, getterFragment, getterStartTimestamp); if (type.getEndTimestampPropertyName() != null) { parameterPropertyEnd = type.getEndTimestampPropertyName(); EventPropertyGetter getterEndTimestamp = type.getGetter(type.getEndTimestampPropertyName()); evaluatorEndTimestamp = new ExprEvaluatorStreamLongPropFragment(parameterStreamNum, getterFragment, getterEndTimestamp); } else { parameterPropertyEnd = parameterPropertyStart; } } } else { throw new ExprValidationException("For date-time method '" + methodNameUse + "' the first parameter expression returns '" + evaluatorTimestamp.getType() + "', however requires a Date, Calendar, Long-type return value or event (with timestamp)"); } } } IntervalComputer intervalComputer = IntervalComputerFactory.make(method, expressions); // evaluation without end timestamp if (evaluatorEndTimestamp == null) { if (JavaClassHelper.isSubclassOrImplementsInterface(timestampType, Calendar.class)) { intervalOpEval = new IntervalOpEvalCal(intervalComputer); } else if (JavaClassHelper.isSubclassOrImplementsInterface(timestampType, Date.class)) { intervalOpEval = new IntervalOpEvalDate(intervalComputer); } else if (JavaClassHelper.getBoxedType(timestampType) == Long.class) { intervalOpEval = new IntervalOpEvalLong(intervalComputer); } else { throw new IllegalArgumentException("Invalid interval first parameter type '" + timestampType + "'"); } } else { if (JavaClassHelper.isSubclassOrImplementsInterface(timestampType, Calendar.class)) { intervalOpEval = new IntervalOpEvalCalWithEnd(intervalComputer, evaluatorEndTimestamp); } else if (JavaClassHelper.isSubclassOrImplementsInterface(timestampType, Date.class)) { intervalOpEval = new IntervalOpEvalDateWithEnd(intervalComputer, evaluatorEndTimestamp); } else if (JavaClassHelper.getBoxedType(timestampType) == Long.class) { intervalOpEval = new IntervalOpEvalLongWithEnd(intervalComputer, evaluatorEndTimestamp); } else { throw new IllegalArgumentException("Invalid interval first parameter type '" + timestampType + "'"); } } } /** * Obtain information used by filter analyzer to handle this dot-method invocation as part of query planning/indexing. * * @param typesPerStream event types * @param currentMethod * @param currentParameters * @param inputDesc descriptor of what the input to this interval method is * */ public ExprDotNodeFilterAnalyzerDTIntervalDesc getFilterDesc(EventType[] typesPerStream, DatetimeMethodEnum currentMethod, List<ExprNode> currentParameters, ExprDotNodeFilterAnalyzerInput inputDesc) { // with intervals is not currently query planned if (currentParameters.size() > 1) { return null; } // Get input (target) int targetStreamNum; String targetPropertyStart; String targetPropertyEnd; if (inputDesc instanceof ExprDotNodeFilterAnalyzerInputStream) { ExprDotNodeFilterAnalyzerInputStream targetStream = (ExprDotNodeFilterAnalyzerInputStream) inputDesc; targetStreamNum = targetStream.getStreamNum(); EventType targetType = typesPerStream[targetStreamNum]; targetPropertyStart = targetType.getStartTimestampPropertyName(); targetPropertyEnd = targetType.getEndTimestampPropertyName() != null ? targetType.getEndTimestampPropertyName() : targetPropertyStart; } else if (inputDesc instanceof ExprDotNodeFilterAnalyzerInputProp) { ExprDotNodeFilterAnalyzerInputProp targetStream = (ExprDotNodeFilterAnalyzerInputProp) inputDesc; targetStreamNum = targetStream.getStreamNum(); targetPropertyStart = targetStream.getPropertyName(); targetPropertyEnd = targetStream.getPropertyName(); } else { return null; } // check parameter info if (parameterPropertyStart == null) { return null; } return new ExprDotNodeFilterAnalyzerDTIntervalDesc(currentMethod, typesPerStream, targetStreamNum, targetPropertyStart, targetPropertyEnd, parameterStreamNum, parameterPropertyStart, parameterPropertyEnd); } public Object evaluate(long startTs, long endTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { Object parameter = evaluatorTimestamp.evaluate(eventsPerStream, isNewData, context); if (parameter == null) { return parameter; } return intervalOpEval.evaluate(startTs, endTs, parameter, eventsPerStream, isNewData, context); } public static interface IntervalOpEval { public Object evaluate(long startTs, long endTs, Object parameter, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context); } public abstract static class IntervalOpEvalDateBase implements IntervalOpEval { protected final IntervalComputer intervalComputer; public IntervalOpEvalDateBase(IntervalComputer intervalComputer) { this.intervalComputer = intervalComputer; } } public static class IntervalOpEvalDate extends IntervalOpEvalDateBase { public IntervalOpEvalDate(IntervalComputer intervalComputer) { super(intervalComputer); } public Object evaluate(long startTs, long endTs, Object parameter, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { long time = ((Date) parameter).getTime(); return intervalComputer.compute(startTs, endTs, time, time, eventsPerStream, isNewData, context); } } public static class IntervalOpEvalLong extends IntervalOpEvalDateBase { public IntervalOpEvalLong(IntervalComputer intervalComputer) { super(intervalComputer); } public Object evaluate(long startTs, long endTs, Object parameter, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { long time = (Long) parameter; return intervalComputer.compute(startTs, endTs, time, time, eventsPerStream, isNewData, context); } } public static class IntervalOpEvalCal extends IntervalOpEvalDateBase { public IntervalOpEvalCal(IntervalComputer intervalComputer) { super(intervalComputer); } public Object evaluate(long startTs, long endTs, Object parameter, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { long time = ((Calendar) parameter).getTimeInMillis(); return intervalComputer.compute(startTs, endTs, time, time, eventsPerStream, isNewData, context); } } public abstract static class IntervalOpEvalDateWithEndBase implements IntervalOpEval { protected final IntervalComputer intervalComputer; private final ExprEvaluator evaluatorEndTimestamp; protected IntervalOpEvalDateWithEndBase(IntervalComputer intervalComputer, ExprEvaluator evaluatorEndTimestamp) { this.intervalComputer = intervalComputer; this.evaluatorEndTimestamp = evaluatorEndTimestamp; } public abstract Object evaluate(long startTs, long endTs, Object parameterStartTs, Object parameterEndTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context); public Object evaluate(long startTs, long endTs, Object parameterStartTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { Object paramEndTs = evaluatorEndTimestamp.evaluate(eventsPerStream, isNewData, context); if (paramEndTs == null) { return null; } return evaluate(startTs, endTs, parameterStartTs, paramEndTs, eventsPerStream, isNewData, context); } } public static class IntervalOpEvalDateWithEnd extends IntervalOpEvalDateWithEndBase { public IntervalOpEvalDateWithEnd(IntervalComputer intervalComputer, ExprEvaluator evaluatorEndTimestamp) { super(intervalComputer, evaluatorEndTimestamp); } public Object evaluate(long startTs, long endTs, Object parameterStartTs, Object parameterEndTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return intervalComputer.compute(startTs, endTs, ((Date) parameterStartTs).getTime(), ((Date) parameterEndTs).getTime(), eventsPerStream, isNewData, context); } } public static class IntervalOpEvalLongWithEnd extends IntervalOpEvalDateWithEndBase { public IntervalOpEvalLongWithEnd(IntervalComputer intervalComputer, ExprEvaluator evaluatorEndTimestamp) { super(intervalComputer, evaluatorEndTimestamp); } public Object evaluate(long startTs, long endTs, Object parameterStartTs, Object parameterEndTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return intervalComputer.compute(startTs, endTs, (Long) parameterStartTs, (Long) parameterEndTs, eventsPerStream, isNewData, context); } } public static class IntervalOpEvalCalWithEnd extends IntervalOpEvalDateWithEndBase { public IntervalOpEvalCalWithEnd(IntervalComputer intervalComputer, ExprEvaluator evaluatorEndTimestamp) { super(intervalComputer, evaluatorEndTimestamp); } public Object evaluate(long startTs, long endTs, Object parameterStartTs, Object parameterEndTs, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return intervalComputer.compute(startTs, endTs, ((Calendar) parameterStartTs).getTimeInMillis(), ((Calendar) parameterEndTs).getTimeInMillis(), eventsPerStream, isNewData, context); } } }