// This file is part of OpenTSDB. // Copyright (C) 2015 The OpenTSDB Authors. // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 2.1 of the License, or (at your // option) any later version. This program is distributed in the hope that it // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. You should have received a copy // of the GNU Lesser General Public License along with this program. If not, // see <http://www.gnu.org/licenses/>. package net.opentsdb.query.pojo; import net.opentsdb.query.expression.ExpressionIterator; import net.opentsdb.query.expression.NumericFillPolicy; import net.opentsdb.query.expression.VariableIterator.SetOperator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.jexl2.Script; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.google.common.base.Objects; /** * Pojo builder class used for serdes of the expression component of a query * @since 2.3 */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(builder = Expression.Builder.class) public class Expression extends Validatable { /** An id for this expression for use in output selection or nested expressions */ private String id; /** The raw expression as a string */ private String expr; /** The joiner operator */ private Join join; /** The fill policy to use for ? */ private NumericFillPolicy fill_policy; /** Set of unique variables used by this expression. */ private Set<String> variables; /** The parsed expression via JEXL. */ private Script parsed_expression; /** * Default ctor * @param builder The builder to pull values from */ protected Expression(Builder builder) { id = builder.id; expr = builder.expr; join = builder.join; fill_policy = builder.fillPolicy; } /** @return the id for this expression for use in output selection or * nested expressions */ public String getId() { return id; } /** @return the raw expression as a string */ public String getExpr() { return expr; } /** @return he joiner operator */ public Join getJoin() { return join; } /** @return the fill policy to use for ? */ public NumericFillPolicy getFillPolicy() { return fill_policy; } /** @return A new builder for the expression */ public static Builder Builder() { return new Builder(); } /** Validates the expression * @throws IllegalArgumentException if one or more parameters were invalid */ public void validate() { if (id == null || id.isEmpty()) { throw new IllegalArgumentException("missing or empty id"); } Query.validateId(id); if (expr == null || expr.isEmpty()) { throw new IllegalArgumentException("missing or empty expr"); } // parse it just to make sure we're happy and extract the variable names. // Will throw JexlException parsed_expression = ExpressionIterator.JEXL_ENGINE.createScript(expr); variables = new HashSet<String>(); for (final List<String> exp_list : ExpressionIterator.JEXL_ENGINE.getVariables(parsed_expression)) { for (final String variable : exp_list) { variables.add(variable); } } // others are optional if (join == null) { join = Join.Builder().setOperator(SetOperator.UNION).build(); } } /** @return The parsed expression. May be null if {@link validate} has not * been called yet. */ @JsonIgnore public Script getParsedExpression() { return parsed_expression; } /** @return A set of unique variables for the expression. May be null if * {@link validate} has not been called yet. */ @JsonIgnore public Set<String> getVariables() { return variables; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Expression expression = (Expression) o; return Objects.equal(id, expression.id) && Objects.equal(expr, expression.expr) && Objects.equal(join, expression.join) && Objects.equal(fill_policy, expression.fill_policy); } @Override public int hashCode() { return Objects.hashCode(id, expr, join, fill_policy); } /** * A builder for the downsampler component of a query */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "") public static final class Builder { @JsonProperty private String id; @JsonProperty private String expr; @JsonProperty private Join join; @JsonProperty private NumericFillPolicy fillPolicy; public Builder setId(String id) { Query.validateId(id); this.id = id; return this; } public Builder setExpression(String expr) { this.expr = expr; return this; } public Builder setJoin(Join join) { this.join = join; return this; } public Builder setFillPolicy(NumericFillPolicy fill_policy) { this.fillPolicy = fill_policy; return this; } public Expression build() { return new Expression(this); } } }