/* * ************************************************************************************* * 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.expression; import com.espertech.esper.client.EventBean; import com.espertech.esper.epl.datetime.eval.TimePeriod; import com.espertech.esper.util.JavaClassHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayDeque; import java.util.Map; /** * Expression representing a time period. * <p> * Child nodes to this expression carry the actual parts and must return a numeric value. */ public class ExprTimePeriodImpl extends ExprNodeBase implements ExprEvaluator, ExprTimePeriod { private static final Log log = LogFactory.getLog(ExprTimePeriodImpl.class); private final boolean hasYear; private final boolean hasMonth; private final boolean hasWeek; private final boolean hasDay; private final boolean hasHour; private final boolean hasMinute; private final boolean hasSecond; private final boolean hasMillisecond; private boolean hasVariable; private transient ExprEvaluator[] evaluators; private transient TimePeriodAdder[] adders; private static final long serialVersionUID = -7229827032500659319L; /** * Ctor. * @param hasDay true if the expression has that part, false if not * @param hasHour true if the expression has that part, false if not * @param hasMinute true if the expression has that part, false if not * @param hasSecond true if the expression has that part, false if not * @param hasMillisecond true if the expression has that part, false if not */ public ExprTimePeriodImpl(boolean hasYear, boolean hasMonth, boolean hasWeek, boolean hasDay, boolean hasHour, boolean hasMinute, boolean hasSecond, boolean hasMillisecond) { this.hasYear = hasYear; this.hasMonth = hasMonth; this.hasWeek = hasWeek; this.hasDay = hasDay; this.hasHour = hasHour; this.hasMinute = hasMinute; this.hasSecond = hasSecond; this.hasMillisecond = hasMillisecond; } public ExprEvaluator getExprEvaluator() { return this; } /** * Indicator whether the time period has a day part child expression. * @return true for part present, false for not present */ public boolean isHasDay() { return hasDay; } /** * Indicator whether the time period has a hour part child expression. * @return true for part present, false for not present */ public boolean isHasHour() { return hasHour; } /** * Indicator whether the time period has a minute part child expression. * @return true for part present, false for not present */ public boolean isHasMinute() { return hasMinute; } /** * Indicator whether the time period has a second part child expression. * @return true for part present, false for not present */ public boolean isHasSecond() { return hasSecond; } /** * Indicator whether the time period has a millisecond part child expression. * @return true for part present, false for not present */ public boolean isHasMillisecond() { return hasMillisecond; } /** * Indicator whether the time period has a year part child expression. * @return true for part present, false for not present */ public boolean isHasYear() { return hasYear; } /** * Indicator whether the time period has a month part child expression. * @return true for part present, false for not present */ public boolean isHasMonth() { return hasMonth; } /** * Indicator whether the time period has a week part child expression. * @return true for part present, false for not present */ public boolean isHasWeek() { return hasWeek; } /** * Indicator whether the time period has a variable in any of the child expressions. * @return true for variable present, false for not present */ public boolean hasVariable() { return hasVariable; } public void validate(ExprValidationContext validationContext) throws ExprValidationException { evaluators = ExprNodeUtility.getEvaluators(this.getChildNodes()); for (ExprNode childNode : this.getChildNodes()) { validate(childNode); } ArrayDeque<TimePeriodAdder> list = new ArrayDeque<TimePeriodAdder>(); if (hasYear) { list.add(new TimePeriodAdderYear()); } if (hasMonth) { list.add(new TimePeriodAdderMonth()); } if (hasWeek) { list.add(new TimePeriodAdderWeek()); } if (hasDay) { list.add(new TimePeriodAdderDay()); } if (hasHour) { list.add(new TimePeriodAdderHour()); } if (hasMinute) { list.add(new TimePeriodAdderMinute()); } if (hasSecond) { list.add(new TimePeriodAdderSecond()); } if (hasMillisecond) { list.add(new TimePeriodAdderMSec()); } adders = list.toArray(new TimePeriodAdder[list.size()]); } public Map<String, Object> getEventType() { return null; } private void validate(ExprNode expression) throws ExprValidationException { if (expression == null) { return; } Class returnType = expression.getExprEvaluator().getType(); if (!JavaClassHelper.isNumeric(returnType)) { throw new ExprValidationException("Time period expression requires a numeric parameter type"); } if (expression instanceof ExprVariableNode) { hasVariable = true; } } public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { double seconds = 0; for (int i = 0; i < adders.length; i++) { Double result = eval(evaluators[i], eventsPerStream, exprEvaluatorContext); if (result == null) { logWarn(i); return null; } seconds += adders[i].compute(result); } return seconds; } private void logWarn(int ctr) { log.warn("Time period expression returned a null value for expression '" + this.getChildNodes().get(ctr).toExpressionString() + "'"); } public Class getType() { return Double.class; } public boolean isConstantResult() { for (ExprNode child : getChildNodes()) { if (!child.isConstantResult()) { return false; } } return true; } public String toExpressionString() { StringBuilder buf = new StringBuilder(); int exprCtr = 0; if (hasYear) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" years "); } if (hasMonth) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" months "); } if (hasWeek) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" weeks "); } if (hasDay) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" days "); } if (hasHour) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" hours "); } if (hasMinute) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" minutes "); } if (hasSecond) { buf.append(getChildNodes().get(exprCtr++).toExpressionString()); buf.append(" seconds "); } if (hasMillisecond) { buf.append(getChildNodes().get(exprCtr).toExpressionString()); buf.append(" milliseconds "); } return buf.toString(); } public boolean equalsNode(ExprNode node) { if (!(node instanceof ExprTimePeriodImpl)) { return false; } ExprTimePeriodImpl other = (ExprTimePeriodImpl) node; if (hasYear!= other.hasYear) { return false; } if (hasMonth != other.hasMonth) { return false; } if (hasWeek != other.hasWeek) { return false; } if (hasDay != other.hasDay) { return false; } if (hasHour != other.hasHour) { return false; } if (hasMinute != other.hasMinute) { return false; } if (hasSecond != other.hasSecond) { return false; } return (hasMillisecond == other.hasMillisecond); } private Double eval(ExprEvaluator expr, EventBean[] events, ExprEvaluatorContext exprEvaluatorContext) { Object value = expr.evaluate(events, true, exprEvaluatorContext); if (value == null) { return null; } if (value instanceof BigDecimal) { return ((Number) value).doubleValue(); } if (value instanceof BigInteger) { return ((Number) value).doubleValue(); } return ((Number) value).doubleValue(); } public TimePeriod evaluateGetTimePeriod(EventBean[] eventsPerStream, boolean newData, ExprEvaluatorContext context) { int exprCtr = 0; Integer year = null; if (hasYear){ year = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer month = null; if (hasMonth) { month = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer week = null; if (hasWeek) { week = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer day = null; if (hasDay) { day = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer hours = null; if (hasHour) { hours = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer minutes = null; if (hasMinute) { minutes = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer seconds = null; if (hasSecond) { seconds = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } Integer milliseconds = null; if (hasMillisecond) { milliseconds = getInt(evaluators[exprCtr++].evaluate(eventsPerStream, newData, context)); } return new TimePeriod(year, month, week, day, hours, minutes, seconds, milliseconds); } private Integer getInt(Object evaluated) { if (evaluated == null) { return null; } return ((Number) evaluated).intValue(); } public static interface TimePeriodAdder { public double compute(Double value); } public static class TimePeriodAdderYear implements TimePeriodAdder { private static final double MULTIPLIER = 365*24*60*60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderMonth implements TimePeriodAdder { private static final double MULTIPLIER = 30*24*60*60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderWeek implements TimePeriodAdder { private static final double MULTIPLIER = 7*24*60*60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderDay implements TimePeriodAdder { private static final double MULTIPLIER = 24*60*60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderHour implements TimePeriodAdder { private static final double MULTIPLIER = 60*60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderMinute implements TimePeriodAdder { private static final double MULTIPLIER = 60; public double compute(Double value) { return value*MULTIPLIER; } } public static class TimePeriodAdderSecond implements TimePeriodAdder { public double compute(Double value) { return value; } } public static class TimePeriodAdderMSec implements TimePeriodAdder { public double compute(Double value) { return value / 1000d; } } }