Package nexj.core.persistence.operator

Source Code of nexj.core.persistence.operator.ComparisonOperator

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.persistence.operator;

import java.math.BigDecimal;

import nexj.core.meta.Primitive;
import nexj.core.meta.Type;
import nexj.core.meta.TypeMismatchException;
import nexj.core.persistence.Converter;
import nexj.core.persistence.Field;
import nexj.core.persistence.OID;
import nexj.core.persistence.OIDHolder;
import nexj.core.persistence.Operator;
import nexj.core.persistence.PersistenceAdapter;
import nexj.core.persistence.Query;

/**
* Comparison expression node.
*/
public abstract class ComparisonOperator extends BinaryOperator
{
   // constants

   /**
    * The boolean comparison is equivalent to the LHS.
    */
   protected final static int BOOL_LHS = 0;

   /**
    * The boolean comparison is equivalent to the negated LHS.
    */
   protected final static int BOOL_NOT = 1;

   /**
    * The boolean comparison is equivalent to TRUE.
    */
   protected final static int BOOL_TRUE = 2;

   /**
    * The boolean comparison is equivalent to FALSE.
    */
   protected final static int BOOL_FALSE = 3;

   /**
    * Constant limits
    */
   private final static Long LONG_MIN_INTEGER = new Long(Integer.MIN_VALUE);
   private final static Long LONG_MAX_INTEGER = new Long(Integer.MAX_VALUE);
   private final static BigDecimal DECIMAL_MIN_INTEGER = BigDecimal.valueOf(Integer.MIN_VALUE);
   private final static BigDecimal DECIMAL_MAX_INTEGER = BigDecimal.valueOf(Integer.MAX_VALUE);
   private final static BigDecimal DECIMAL_MIN_LONG = BigDecimal.valueOf(Long.MIN_VALUE);
   private final static BigDecimal DECIMAL_MAX_LONG = BigDecimal.valueOf(Long.MAX_VALUE);
   private final static Float FLOAT_MIN_INTEGER = new Float(Integer.MIN_VALUE);
   private final static Float FLOAT_MAX_INTEGER = new Float(Integer.MAX_VALUE);
   private final static Float FLOAT_MIN_LONG = new Float(Long.MIN_VALUE);
   private final static Float FLOAT_MAX_LONG = new Float(Long.MAX_VALUE);
   private final static Double DOUBLE_MIN_INTEGER = new Double(Integer.MIN_VALUE);
   private final static Double DOUBLE_MAX_INTEGER = new Double(Integer.MAX_VALUE);
   private final static Double DOUBLE_MIN_LONG = new Double(Long.MIN_VALUE);
   private final static Double DOUBLE_MAX_LONG = new Double(Long.MAX_VALUE);
   private final static Double DOUBLE_MIN_FLOAT = new Double(-Float.MAX_VALUE);
   private final static Double DOUBLE_MAX_FLOAT = new Double(Float.MAX_VALUE);

   // constructors

   /**
    * Constructs the operator.
    */
   protected ComparisonOperator()
   {
      m_type = Primitive.BOOLEAN;
   }

   // operations

   /**
    * @see nexj.core.persistence.Operator#normalize(int)
    */
   public Operator normalize(int nFlags)
   {
      if ((nFlags & NORMALIZE_NORECUR) == 0)
      {
         m_left = m_left.normalize(nFlags);
         m_right = m_right.normalize(nFlags);
      }

      if (m_left.isConstant() && !m_right.isConstant())
      {
         if (isSymmetric())
         {
            Operator left = m_left;
            m_left = m_right;
            m_right = left;
         }
         else
         {
            ComparisonOperator op = createSymmetric();

            op.setParent(m_parent);
            op.setLeft(m_right);
            op.setRight(m_left);

            return op.normalize(nFlags | NORMALIZE_NORECUR);
         }
      }

      Type leftType = m_left.getType();
      Type rightType = m_right.getType();

      if (leftType == null)
      {
         assert m_left.isConstant();
         assert m_right.isConstant();

         setConstantValue(Boolean.valueOf(nullPredicate(m_right.getValue() == null)));

         return this;
      }

      if (rightType == null)
      {
         rightType = leftType;
         m_right.setType(rightType);
      }

      if (!isEquivalence())
      {
         if (rightType == null || m_right.isConstant() && m_right.getValue() == null)
         {
            Operator op = createNullComparison();

            op.setParent(m_parent);

            if (op.getOrdinal() != ConstantOperator.ORDINAL)
            {
               ComparisonOperator cmpOp = (ComparisonOperator)op;

               cmpOp.setLeft(m_left);
               cmpOp.setRight(m_right);
            }

            return op.normalize(nFlags | NORMALIZE_NORECUR);
         }
      }

      setSource(findCommonSource(m_left, m_right), nFlags);

      if (leftType.isPrimitive())
      {
         if (rightType != null)
         {
            if (!rightType.isPrimitive())
            {
               throw new TypeMismatchException(getSymbol());
            }
         }

         if (leftType == Primitive.ANY && m_left.isConstant() && m_right.isConstant())
         {
            foldObjectComparison();
            return this;
         }

         ConversionMapper mapper = null;
         BinaryDescriptor descriptor = null;

         if (m_source != null)
         {
            mapper = m_source.getAdapter().getConversionMapper();
            descriptor = mapper.getBinaryDescriptor(this);
         }

         if (descriptor == null)
         {
            m_source = null;
            mapper = getConversionMapper();
            descriptor = mapper.getBinaryDescriptor(this);

            if (descriptor == null)
            {
               throw new TypeMismatchException(getSymbol());
            }
         }

         Primitive rightPrimitive = (Primitive)rightType;

         if (mapper.getType(rightPrimitive) != mapper.getType(descriptor.getRightType()))
         {
            setRight(new TypeConversionOperator(descriptor.getRightType(), m_right));
            m_right = m_right.normalize(nFlags | NORMALIZE_NORECUR);
         }

         Primitive leftPrimitive = (Primitive)leftType;

         if (mapper.getType(leftPrimitive) != mapper.getType(descriptor.getLeftType()))
         {
            if (m_right.isConstant() && Primitive.isOrderPreserved(leftPrimitive, descriptor.getLeftType()))
            {
               if (m_right.getValue() != null)
               {
                  m_bConstant = false;

                  if (unconvertConstantComparison(leftPrimitive, rightPrimitive, m_right.getValue()))
                  {
                     if (m_bConstant)
                     {
                        return this;
                     }
                  }
                  else
                  {
                     setLeft(new TypeConversionOperator(descriptor.getLeftType(), m_left));
                     m_left = m_left.normalize(nFlags | NORMALIZE_NORECUR);
                  }
               }
            }
            else
            {
               setLeft(new TypeConversionOperator(descriptor.getLeftType(), m_left));
               m_left = m_left.normalize(nFlags | NORMALIZE_NORECUR);
            }
         }

         if (m_left.isConstant())
         {
            assert m_right.isConstant();

            setConstantValue(evaluate());
         }
         else if (m_right.isConstant())
         {
            if (m_left.getOrdinal() == AttributeOperator.ORDINAL)
            {
               AttributeOperator left = (AttributeOperator)m_left;
               Converter converter = left.getConverter();

               if (converter != null && (isEquivalence() ||
                  Primitive.isOrderPreserved(converter.getSourceType(), converter.getDestinationType())))
               {
                  left.setType(converter.getSourceType());
                  left.setNoConversion(true);
                  m_right.setValue(converter.getInverseFunction().invoke(m_right.getValue()));
                  m_right.setType(converter.getSourceType());
               }
            }
            else if (m_left.getType() == Primitive.BOOLEAN && m_right.getValue() != null)
            {
               switch (booleanPredicate(((Boolean)m_right.getValue()).booleanValue()))
               {
                  case BOOL_LHS:
                     return m_left;

                  case BOOL_NOT:
                     NotOperator op = new NotOperator();

                     op.setOperand(m_left);
                     op.normalize(nFlags | NORMALIZE_NORECUR);

                     return op;

                  case BOOL_TRUE:
                     setConstantValue(Boolean.TRUE);
                     break;

                  case BOOL_FALSE:
                     setConstantValue(Boolean.FALSE);
                     break;
               }
            }
         }
      }
      else
      {
         assert m_left.getOrdinal() == AttributeOperator.ORDINAL;

         if (rightType != null)
         {
            if (rightType.isPrimitive() &&
               (rightType != Primitive.ANY || !m_right.isConstant() ||
                m_right.getValue() != null && !(m_right.getValue() instanceof OIDHolder)))
            {
               throw new TypeMismatchException(getSymbol());
            }
         }

         if (m_left.isConstant())
         {
            foldObjectComparison();
            return this;
         }

         if ((nFlags & NORMALIZE_PERSISTENCE) != 0 && m_source != null)
         {
            PersistenceAdapter adapter = m_source.getAdapter();
            Field[] leftFieldArray = adapter.getFields(m_left.getSource());

            if (leftFieldArray != null)
            {
               Field[] rightFieldArray = null;
               Object[] valueArray = null;

               if (m_right.isConstant())
               {
                  if (m_right.getValue() != null)
                  {
                     OID oid = ((OIDHolder)m_right.getValue()).getOID();

                     if (oid != null)
                     {
                        valueArray = adapter.getValues(oid, m_left.getSource());

                        if (leftFieldArray.length != valueArray.length)
                        {
                           throw new TypeMismatchException(getSymbol());
                        }
                     }
                     else if (isEquivalence())
                     {
                        setConstantValue(Boolean.valueOf(nullPredicate(false)));

                        return this;
                     }
                  }
               }
               else
               {
                  assert m_right.getOrdinal() == AttributeOperator.ORDINAL;

                  rightFieldArray = adapter.getFields((Query)m_right.getSource());

                  assert rightFieldArray != null;

                  if (leftFieldArray.length != rightFieldArray.length)
                  {
                     throw new TypeMismatchException(getSymbol());
                  }
               }

               assert leftFieldArray.length > 0;

               Operator result = null;

               if (leftFieldArray.length == 1)
               {
                  Field field = leftFieldArray[0];

                  if (m_left.getQuery().getConstraint() != this)
                  {
                     m_left.setSource(field);
                     m_left.setType(field.getType());

                     if (rightFieldArray != null)
                     {
                        field = rightFieldArray[0];
                        m_right.setSource(field);
                        m_right.setType(field.getType());
                     }
                     else
                     {
                        ConstantOperator cons;
                        Object value = (valueArray == null) ? null : valueArray[0];

                        if (m_right.getOrdinal() == ConstantOperator.ORDINAL)
                        {
                           cons = (ConstantOperator)m_right;
                           cons.setType(Primitive.primitiveOf(value));
                           cons.setValue(value);
                        }
                        else
                        {
                           cons = new ConstantOperator(value);
                           setRight(cons);
                        }
                     }

                     result = this;
                  }
                  else
                  {
                     ComparisonOperator cmp = createSame();

                     cmp.setParent(m_parent);
                     cmp.setLeft(new AttributeOperator(field));

                     if (rightFieldArray != null)
                     {
                        cmp.setRight(new AttributeOperator(rightFieldArray[0]));
                     }
                     else
                     {
                        cmp.setRight(new ConstantOperator((valueArray == null) ? null : valueArray[0]));
                     }

                     result = cmp;
                  }
               }
               else if (isEquivalence())
               {
                  MultiArgOperator combinator;

                  if (rightFieldArray == null && valueArray == null)
                  {
                     combinator = new AndOperator();
                  }
                  else
                  {
                     if (isCombinatorDisjunctive())
                     {
                        combinator = new OrOperator();
                     }
                     else
                     {
                        combinator = new AndOperator();
                     }
                  }

                  combinator.setParent(m_parent);

                  for (int i = 0; i < leftFieldArray.length; ++i)
                  {
                     ComparisonOperator cmp = createSame();

                     cmp.setLeft(new AttributeOperator(leftFieldArray[i]));

                     if (rightFieldArray != null)
                     {
                        cmp.setRight(new AttributeOperator(rightFieldArray[i]));
                     }
                     else
                     {
                        cmp.setRight(new ConstantOperator((valueArray == null) ? null : valueArray[i]));
                     }

                     combinator.addOperand(cmp);
                  }

                  result = combinator;
               }
               else
               {
                  OrOperator or = new OrOperator();

                  or.setParent(m_parent);

                  int nCount = leftFieldArray.length - 1;

                  for (int i = 0; i <= nCount; ++i)
                  {
                     MultiArgOperator combinator;

                     if (i == 0)
                     {
                        combinator = or;
                     }
                     else
                     {
                        combinator = new AndOperator();
                        or.addOperand(combinator);
                     }

                     for (int k = 0; k <= i; ++k)
                     {
                        ComparisonOperator cmp;

                        if (k == i)
                        {
                           if (i == nCount)
                           {
                              cmp = createSame();
                           }
                           else
                           {
                              cmp = createStrict();
                           }
                        }
                        else
                        {
                           cmp = new EqualsOperator();
                        }

                        cmp.setLeft(new AttributeOperator(leftFieldArray[i]));

                        if (rightFieldArray != null)
                        {
                           cmp.setRight(new AttributeOperator(rightFieldArray[i]));
                        }
                        else
                        {
                           cmp.setRight(new ConstantOperator((valueArray == null) ? null : valueArray[i]));
                        }

                        combinator.addOperand(cmp);
                     }
                  }

                  result = or;
               }

               return result.normalize(nFlags & ~NORMALIZE_NORECUR);
            }
         }
      }

      return this;
   }

   /**
    * Folds a constant OID comparison.
    */
   private void foldObjectComparison()
   {
      boolean bReference = false;
      Object[] leftValues = null;

      if (m_left.getValue() != null)
      {
         if (!(m_left.getValue() instanceof OIDHolder))
         {
            throw new TypeMismatchException(getSymbol());
         }

         OID oid = ((OIDHolder)m_left.getValue()).getOID();

         if (oid != null)
         {
            leftValues = oid.getValueArray();
         }
         else
         {
            bReference = true;
         }
      }

      Object[] rightValues = null;

      if (m_right.getValue() != null)
      {
         if (!(m_right.getValue() instanceof OIDHolder))
         {
            throw new TypeMismatchException(getSymbol());
         }

         OID oid = ((OIDHolder)m_right.getValue()).getOID();

         if (oid != null)
         {
            rightValues = oid.getValueArray();
         }
         else
         {
            bReference = true;
         }
      }

      if (bReference && isEquivalence())
      {
         m_value = Boolean.valueOf(nullPredicate(m_left.getValue() == m_right.getValue()));
      }
      else if (leftValues != null)
      {
         int nCount = leftValues.length;

         if (rightValues != null && rightValues.length != nCount)
         {
            throw new TypeMismatchException(getSymbol());
         }
         else
         {
            m_value = compare(leftValues, rightValues, nCount);
         }
      }
      else
      {
         if (rightValues != null)
         {
            m_value = compare(leftValues, rightValues, rightValues.length);
         }
         else
         {
            m_value = compare(null, null);
         }
      }

      setConstant(true);
   }

   /**
    * Compares value arrays of the same dimension.
    * @param leftValues The left value array.
    * @param rightValues The right value array.
    * @param nCount The number of elements to compare.
    * @return The comparison result.
    */
   private Object compare(Object[] leftValues, Object[] rightValues, int nCount)
   {
      --nCount;

      for (int i = 0; i < nCount; ++i)
      {
         Object left = (leftValues == null) ? null : leftValues[i];
         Object right = (rightValues == null) ? null : rightValues[i];
         Object value = compareStrict(left, right);

         if (((Boolean)value).booleanValue() == stopValue() ||
            !isEquivalence() && !((Boolean)Primitive.eq(left, right)).booleanValue())
         {
            return value;
         }
      }

      return compare((leftValues == null) ? null : leftValues[nCount],
         (rightValues == null) ? null : rightValues[nCount]);
   }

   /**
    * Attemts to remove a LHS operand type cast in the constant comparison: (Type)left op const.
    * @param fromType The left operand type.
    * @param toType The right operand type, to which the left operand should be converted.
    * @param value The constant value.
    * @return true if the cast has been removed successfully.
    */
   private boolean unconvertConstantComparison(Primitive fromType, Primitive toType, Object value)
   {
      Comparable min = null;
      Comparable max = null;

      switch (fromType.getOrdinal())
      {
         case Primitive.INTEGER_ORDINAL:
            switch (toType.getOrdinal())
            {
               case Primitive.LONG_ORDINAL:
                  min = LONG_MIN_INTEGER;
                  max = LONG_MAX_INTEGER;
                  break;

               case Primitive.DECIMAL_ORDINAL:
                  min = DECIMAL_MIN_INTEGER;
                  max = DECIMAL_MAX_INTEGER;
                  break;

               case Primitive.FLOAT_ORDINAL:
                  min = FLOAT_MIN_INTEGER;
                  max = FLOAT_MAX_INTEGER;
                  break;

               case Primitive.DOUBLE_ORDINAL:
                  min = DOUBLE_MIN_INTEGER;
                  max = DOUBLE_MAX_INTEGER;
                  break;

               default:
                  return false;
            }

            break;

         case Primitive.LONG_ORDINAL:
            switch (toType.getOrdinal())
            {
               case Primitive.DECIMAL_ORDINAL:
                  min = DECIMAL_MIN_LONG;
                  max = DECIMAL_MAX_LONG;
                  break;

               case Primitive.FLOAT_ORDINAL:
                  min = FLOAT_MIN_LONG;
                  max = FLOAT_MAX_LONG;
                  break;

               case Primitive.DOUBLE_ORDINAL:
                  min = DOUBLE_MIN_LONG;
                  max = DOUBLE_MAX_LONG;
                  break;

               default:
                  return false;
            }

            break;

         case Primitive.DECIMAL_ORDINAL:
            break;

         case Primitive.FLOAT_ORDINAL:
            switch (toType.getOrdinal())
            {
               case Primitive.DOUBLE_ORDINAL:
                  min = DOUBLE_MIN_FLOAT;
                  max = DOUBLE_MAX_FLOAT;
                  break;

               default:
                  return false;
            }

            break;

         default:
            return false;
      }

      if (min != null)
      {
         if (isOutOfBounds(min.compareTo(value), max.compareTo(value)))
         {
            setConstant(true);

            return true;
         }
      }

      switch (fromType.getOrdinal())
      {
         case Primitive.INTEGER_ORDINAL:
         case Primitive.LONG_ORDINAL:

            boolean bRound = false;
            long lValue = 0;

            switch (toType.getOrdinal())
            {
               case Primitive.DECIMAL_ORDINAL:
                  lValue = round((BigDecimal)value);
                  bRound = true;
                  break;

               case Primitive.FLOAT_ORDINAL:
                  lValue = round(((Float)value).doubleValue());
                  bRound = true;
                  break;

               case Primitive.DOUBLE_ORDINAL:
                  lValue = round(((Double)value).doubleValue());
                  bRound = true;
                  break;
            }

            if (bRound)
            {
               if (fromType == Primitive.INTEGER)
               {
                  m_right.setValue(Primitive.createInteger((int)lValue));
               }
               else
               {
                  m_right.setValue(Primitive.createLong(lValue));
               }

               m_right.setType(fromType);

               return true;
            }

            break;
      }

      m_right.setType(fromType);
      m_right.setValue(fromType.getConverter(toType).invoke(value));

      return true;
   }

   /**
    * @see nexj.core.persistence.Operator#evaluate()
    */
   protected Object evaluate()
   {
      if (m_left.getType().isPrimitive())
      {
         return evaluatePrimitive();
      }

      Object leftValue = m_left.getValue();

      if (leftValue instanceof OIDHolder)
      {
         Object rightValue = m_right.getValue();
         OID rightOID = (rightValue instanceof OIDHolder) ? ((OIDHolder)rightValue).getOID() : null;

         return Boolean.valueOf(compareToPredicate(((OIDHolder)leftValue).getOID().compareTo(rightOID)));
      }

      if (leftValue == null)
      {
         return Boolean.valueOf(nullPredicate(m_right.getValue() == null));
      }

      throw new TypeMismatchException(getSymbol());
   }

   /**
    * Processes a comparison between the left operand and the right operand.
    * @param nSign The result of m_left.compareTo(m_right).
    * @return True if the predicate is satisfied.
    */
   protected abstract boolean compareToPredicate(int nSign);

   /**
    * Evaluates the operator. Assumes left side is primitive.
    * @return The result.
    */
   protected abstract Object evaluatePrimitive();

   /**
    * @return True if the operator is symmetric.
    */
   protected abstract boolean isSymmetric();

   /**
    * @return A symmetric operator instance.
    */
   protected abstract ComparisonOperator createSymmetric();

   /**
    * @return True if the operator is an equivalence comparison.
    */
   protected abstract boolean isEquivalence();

   /**
    * @return True if the combinator is disjunctive.
    */
   protected abstract boolean isCombinatorDisjunctive();

   /**
    * @return A new instance of the same class.
    */
   protected abstract ComparisonOperator createSame();

   /**
    * @return A new instance of the inverse comparison operator,
    * or null if such does not exist.
    */
   public abstract ComparisonOperator createInverse();

   /**
    * @return A new instance of the strict version of the operator.
    */
   protected abstract ComparisonOperator createStrict();

   /**
    * @return The equivalent operator for a null right operand.
    */
   protected abstract Operator createNullComparison();

   /**
    * Compares null to null or non-null.
    * @param bNull True if the right operand is null.
    * @return True if the predicate is satisfied.
    */
   protected abstract boolean nullPredicate(boolean bNull);

   /**
    * Compares an expression to a RHS boolean constant.
    * @param bRHS The RHS constant.
    * @return The result of the comparison, one of the BOOL_* constants.
    */
   protected abstract int booleanPredicate(boolean bRHS);

   /**
    * Performs the comparison.
    * @param left The left operand.
    * @param right The right operand.
    * @return The comparison result.
    */
   protected abstract Object compare(Object left, Object right);

   /**
    * Performs the strict version of the comparison.
    * @param left The left operand.
    * @param right The right operand.
    * @return The comparison result.
    */
   protected abstract Object compareStrict(Object left, Object right);

   /**
    * @return The comparison stop value.
    */
   protected abstract boolean stopValue();

   /**
    * Determines whether the value is out of comparison bounds and sets the result value.
    * @param nLower Result of the comparison to the lower bound value.
    * @param nUpper Result of the comparison to the upper bound value.
    * @return True if the value is out of bounds.
    */
   protected abstract boolean isOutOfBounds(int nLower, int nUpper);

   /**
    * Rounds the value according to the operator and sets the constant flag and value if necessary.
    * @param value The value to round.
    * @return The rounded value.
    */
   protected abstract long round(BigDecimal value);

   /**
    * Rounds the value according to the operator and sets the constant flag and value if necessary.
    * @param value The value to round.
    * @return The rounded value.
    */
   protected abstract long round(double value);
}
TOP

Related Classes of nexj.core.persistence.operator.ComparisonOperator

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.