Package org.apache.expreval.expr

Source Code of org.apache.expreval.expr.GenericExpression

/*
* Copyright (c) 2011.  The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.expreval.expr;

import org.apache.expreval.client.InternalErrorException;
import org.apache.expreval.client.NullColumnValueException;
import org.apache.expreval.client.ResultMissingColumnException;
import org.apache.expreval.expr.literal.DoubleLiteral;
import org.apache.expreval.expr.literal.FloatLiteral;
import org.apache.expreval.expr.literal.IntegerLiteral;
import org.apache.expreval.expr.literal.LongLiteral;
import org.apache.expreval.expr.literal.ShortLiteral;
import org.apache.expreval.expr.node.BooleanValue;
import org.apache.expreval.expr.node.DateValue;
import org.apache.expreval.expr.node.GenericValue;
import org.apache.expreval.expr.node.NumberValue;
import org.apache.expreval.expr.node.ObjectValue;
import org.apache.expreval.expr.node.StringValue;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.WritableByteArrayComparable;
import org.apache.hadoop.hbase.hbql.client.HBqlException;
import org.apache.hadoop.hbase.hbql.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.hbql.impl.AggregateValue;
import org.apache.hadoop.hbase.hbql.impl.InvalidServerFilterException;
import org.apache.hadoop.hbase.hbql.impl.InvalidTypeException;
import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
import org.apache.hadoop.hbase.hbql.util.Lists;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class GenericExpression implements GenericValue {

    // These are used to cache type of the args for exprs with numberic args
    private Class<? extends GenericValue> highestRankingNumericArgFoundInValidate = NumberValue.class;
    private Class                         rankingClass                            = null;
    private boolean                       useDecimal                              = false;
    private boolean                       useByte                                 = false;
    private boolean                       useShort                                = false;
    private boolean                       useInteger                              = false;
    private boolean                       useLong                                 = false;
    private boolean                       useFloat                                = false;
    private boolean                       useDouble                               = false;

    private final ExpressionType type;
    private final List<GenericValue> genericValueList = Lists.newArrayList();
    private final AtomicBoolean      allArgsOptimized = new AtomicBoolean(false);

    private MultipleExpressionContext expressionContext = null;

    private Class getRankingClass() {
        return this.rankingClass;
    }

    protected GenericExpression(final ExpressionType type, final GenericValue... exprs) {
        this(type, Arrays.asList(exprs));
    }

    protected GenericExpression(final ExpressionType type, final List<GenericValue> genericValueList) {
        this.type = type;
        if (genericValueList != null)
            this.getGenericValueList().addAll(genericValueList);
    }

    protected GenericExpression(final ExpressionType type,
                                final GenericValue expr,
                                final List<GenericValue> genericValueList) {
        this.type = type;
        this.getGenericValueList().add(expr);
        if (genericValueList != null)
            this.getGenericValueList().addAll(genericValueList);
    }

    protected FunctionTypeSignature getTypeSignature() {
        return this.type.getTypeSignature();
    }

    public List<GenericValue> getGenericValueList() {
        return this.genericValueList;
    }

    protected List<GenericValue> getSubArgs(final int i) {
        return this.getGenericValueList().subList(i, this.getGenericValueList().size());
    }

    private Class<? extends GenericValue> getHighestRankingNumericArgFoundInValidate() {
        return this.highestRankingNumericArgFoundInValidate;
    }

    // These require getHighestRankingNumericArg() be called first to set value
    protected boolean useDecimal() {
        return this.useDecimal;
    }

    protected Number getValueWithCast(final long result) throws HBqlException {
        if (this.useByte)
            return (byte)result;
        else if (this.useShort)
            return (short)result;
        else if (this.useInteger)
            return (int)result;
        else if (this.useLong)
            return result;
        else
            throw new HBqlException("Invalid class: " + this.getRankingClass().getName());
    }

    protected Number getValueWithCast(final double result) throws HBqlException {
        if (this.useFloat)
            return (float)result;
        else if (this.useDouble)
            return result;
        else
            throw new HBqlException("Invalid class: " + this.getRankingClass().getName());
    }

    protected Class validateNumericArgTypes(final Object... objs) {

        if (this.getRankingClass() == null) {

            // If we do not already know the specific types, then look at the class of both args
            if (this.getHighestRankingNumericArgFoundInValidate() == NumberValue.class)
                this.rankingClass = NumericType.getHighestRankingNumericArg(objs);
            else
                this.rankingClass = this.getHighestRankingNumericArgFoundInValidate();

            this.useDecimal = NumericType.useDecimalNumericArgs(this.getRankingClass());

            this.useByte = NumericType.isAByte(this.getRankingClass());
            this.useShort = NumericType.isAShort(this.getRankingClass());
            this.useInteger = NumericType.isAnInteger(this.getRankingClass());
            this.useLong = NumericType.isALong(this.getRankingClass());
            this.useFloat = NumericType.isAFloat(this.getRankingClass());
            this.useDouble = NumericType.isADouble(this.getRankingClass());
        }

        return this.getRankingClass();
    }

    protected Class<? extends GenericValue> validateNumericTypes() throws HBqlException {

        if (this.getGenericValueList().size() != this.getTypeSignature().getArgCount())
            throw new InvalidTypeException("Incorrect number of arguments in " + this.asString());

        // Return the type of the highest ranking numeric arg
        int highestRank = -1;
        for (int i = 0; i < this.getTypeSignature().getArgCount(); i++) {

            final Class<? extends GenericValue> clazz = this.getExprArg(i).validateTypes(this, false);
            this.validateParentClass(this.getTypeSignature().getArg(i), clazz);

            final int rank = NumericType.getTypeRanking(clazz);
            if (rank > highestRank) {
                highestRank = rank;
                this.highestRankingNumericArgFoundInValidate = clazz;
            }
        }

        return this.getHighestRankingNumericArgFoundInValidate();
    }

    public boolean isAConstant() {

        if (this.getGenericValueList().size() == 0)
            return false;

        for (final GenericValue val : this.getGenericValueList())
            if (!val.isAConstant())
                return false;

        return true;
    }

    public boolean isDefaultKeyword() {
        return false;
    }

    public boolean isAnAggregateValue() {
        return false;
    }

    public void initAggregateValue(final AggregateValue aggregateValue) throws HBqlException {
        throw new InternalErrorException("Not applicable");
    }

    public void applyResultToAggregateValue(final AggregateValue aggregateValue, final Result result) throws HBqlException, ResultMissingColumnException, NullColumnValueException {
        throw new InternalErrorException("Not applicable");
    }

    public boolean hasAColumnReference() {
        for (final GenericValue val : this.getGenericValueList())
            if (val.hasAColumnReference())
                return true;
        return false;
    }

    public boolean isAColumnReference() {
        return false;
    }

    public void reset() {
        for (final GenericValue val : this.getGenericValueList())
            val.reset();
    }

    public void setExpressionContext(final MultipleExpressionContext expressionContext) throws HBqlException {

        this.expressionContext = expressionContext;

        for (final GenericValue val : this.getGenericValueList())
            val.setExpressionContext(expressionContext);
    }

    protected MultipleExpressionContext getExpressionContext() {
        return this.expressionContext;
    }

    private AtomicBoolean getAllArgsOptimized() {
        return this.allArgsOptimized;
    }

    protected void optimizeAllArgs() throws HBqlException {
        if (!this.getAllArgsOptimized().get())
            synchronized (this) {
                if (!this.getAllArgsOptimized().get()) {
                    for (int i = 0; i < this.getGenericValueList().size(); i++)
                        this.setArg(i, this.getExprArg(i).getOptimizedValue());
                    this.getAllArgsOptimized().set(true);
                }
            }
    }

    protected Filter newSingleColumnValueFilter(final ColumnAttrib attrib,
                                                final CompareFilter.CompareOp compareOp,
                                                final WritableByteArrayComparable comparator) throws HBqlException {

        // Bail if expression uses a row key.
        if (attrib.isAKeyAttrib())
            throw new InvalidServerFilterException("Cannot use a key attribute");

        final SingleColumnValueFilter filter = new SingleColumnValueFilter(attrib.getFamilyNameAsBytes(),
                                                                           attrib.getColumnNameAsBytes(),
                                                                           compareOp,
                                                                           comparator);
        filter.setFilterIfMissing(true);
        return filter;
    }

    protected Object getConstantValue(final int pos) throws HBqlException {
        try {
            return this.getExprArg(pos).getValue(null, null);
        }
        catch (ResultMissingColumnException e) {
            throw new InternalErrorException("Missing column: " + e.getMessage());
        }
        catch (NullColumnValueException e) {
            throw new InternalErrorException("Null value: " + e.getMessage());
        }
    }

    public GenericValue getExprArg(final int i) {
        return this.getGenericValueList().get(i);
    }

    public void setArg(final int i, final GenericValue val) {
        this.getGenericValueList().set(i, val);
    }

    public Class<? extends GenericValue> validateTypes(final GenericValue parentExpr,
                                                       final boolean allowCollections) throws HBqlException {

        if (this.getGenericValueList().size() != this.getTypeSignature().getArgCount())
            throw new InvalidTypeException("Incorrect number of arguments in " + this.asString());

        final FunctionTypeSignature typeSignature = this.getTypeSignature();

        for (int i = 0; i < typeSignature.getArgCount(); i++)
            this.validateParentClass(typeSignature.getArg(i), this.getExprArg(i).validateTypes(this, false));

        return typeSignature.getReturnType();
    }

    public GenericValue getOptimizedValue() throws HBqlException {

        this.optimizeAllArgs();

        if (!this.isAConstant())
            return this;

        try {
            final Object obj = this.getValue(null, null);

            if (this.getTypeSignature().getReturnType() == BooleanValue.class
                || this.getTypeSignature().getReturnType() == StringValue.class
                || this.getTypeSignature().getReturnType() == DateValue.class)
                return this.getTypeSignature().newLiteral(obj);

            if (TypeSupport.isParentClass(NumberValue.class, this.getTypeSignature().getReturnType())) {

                if (obj instanceof Short)
                    return new ShortLiteral((Short)obj);

                if (obj instanceof Integer)
                    return new IntegerLiteral((Integer)obj);

                if (obj instanceof Long)
                    return new LongLiteral((Long)obj);

                if (obj instanceof Float)
                    return new FloatLiteral((Float)obj);

                if (obj instanceof Double)
                    return new DoubleLiteral((Double)obj);
            }
            throw new InternalErrorException(this.getTypeSignature().getReturnType().getSimpleName());
        }
        catch (ResultMissingColumnException e) {
            throw new InternalErrorException("Missing column: " + e.getMessage());
        }
        catch (NullColumnValueException e) {
            throw new InternalErrorException("Null value: " + e.getMessage());
        }
    }

    public String asString() {

        final StringBuilder sbuf = new StringBuilder("(");

        boolean first = true;
        for (final GenericValue val : this.getGenericValueList()) {
            if (!first)
                sbuf.append(", ");
            sbuf.append(val.asString());
            first = false;
        }

        sbuf.append(")");

        return sbuf.toString();
    }

    public void validateParentClass(final Class<? extends GenericValue> parentClass,
                                    final Class<? extends GenericValue>... childrenClasses) throws InvalidTypeException {

        final List<Class<? extends GenericValue>> classList = Lists.newArrayList();

        for (final Class<? extends GenericValue> childClass : childrenClasses) {

            if (childClass != null) {
                if (TypeSupport.isParentClass(NumberValue.class, parentClass)) {
                    if (!TypeSupport.isParentClass(NumberValue.class, childClass)) {
                        classList.add(childClass);
                    }
                    else {
                        if (!NumericType.isAssignable(parentClass, childClass))
                            classList.add(childClass);
                    }
                }
                else {
                    if (!parentClass.isAssignableFrom(childClass))
                        classList.add(childClass);
                }
            }
        }

        if (classList.size() > 0) {
            final StringBuilder sbuf = new StringBuilder("Expecting type " + parentClass.getSimpleName()
                                                         + " but encountered type"
                                                         + ((classList.size() > 1) ? "s" : "") + " ");
            boolean first = true;
            for (final Class clazz : classList) {
                if (!first)
                    sbuf.append(", ");
                sbuf.append(clazz.getSimpleName());
                first = false;
            }

            sbuf.append(" in expression: " + this.asString());

            throw new InvalidTypeException(sbuf.toString());
        }
    }

    public String getInvalidTypeMsg(final Class<? extends GenericValue>... classes) {

        final List<Class> classList = Lists.newArrayList();

        for (final Class clazz : classes)
            if (clazz != null)
                classList.add(clazz);

        final StringBuilder sbuf = new StringBuilder("Invalid type");
        sbuf.append(((classList.size() > 1) ? "s " : " "));

        boolean first = true;
        for (final Class<? extends GenericValue> clazz : classes) {
            if (!first)
                sbuf.append(", ");
            sbuf.append(clazz.getSimpleName());
            first = false;
        }
        sbuf.append(" in expression " + this.asString());

        return sbuf.toString();
    }

    final List<Class<? extends GenericValue>> types = Arrays.asList(StringValue.class,
                                                                    NumberValue.class,
                                                                    DateValue.class,
                                                                    BooleanValue.class,
                                                                    ObjectValue.class);

    protected Class<? extends GenericValue> getGenericValueClass(final Class<? extends GenericValue> clazz) throws InvalidTypeException {

        for (final Class<? extends GenericValue> type : types)
            if (TypeSupport.isParentClass(type, clazz))
                return type;

        throw new InvalidTypeException(this.getInvalidTypeMsg(clazz));
    }

    public Filter getFilter() throws HBqlException {
        throw new InvalidServerFilterException();
    }
}
TOP

Related Classes of org.apache.expreval.expr.GenericExpression

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.