Source for org.jfree.formula.typing.DefaultComparator

   1: /**
   2:  * =========================================
   3:  * LibFormula : a free Java formula library
   4:  * =========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/libformula/
   7:  *
   8:  * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  *
  26:  * ------------
  27:  * $Id: DefaultComparator.java,v 1.7 2007/05/07 22:57:01 mimil Exp $
  28:  * ------------
  29:  * (C) Copyright 2006-2007, by Pentaho Corporation.
  30:  */
  31: package org.jfree.formula.typing;
  32: 
  33: import java.math.BigDecimal;
  34: 
  35: import org.jfree.formula.FormulaContext;
  36: import org.jfree.util.ObjectUtilities;
  37: 
  38: /**
  39:  * Creation-Date: 03.11.2006, 16:15:28
  40:  * 
  41:  * @author Thomas Morgner
  42:  */
  43: public class DefaultComparator implements ExtendedComparator
  44: {
  45:   private FormulaContext context;
  46: 
  47:   public static final Integer LESS = new Integer(-1);
  48: 
  49:   public static final Integer EQUAL = new Integer(0);
  50: 
  51:   private static final Integer MORE = new Integer(1);
  52: 
  53:   public DefaultComparator()
  54:   {
  55:   }
  56: 
  57:   public void inititalize(final FormulaContext context)
  58:   {
  59:     this.context = context;
  60:   }
  61: 
  62:   public boolean isEqual(final Type type1, final Object value1,
  63:       final Type type2, final Object value2)
  64:   {
  65:     // this is rather easy. If at least one of the types is a numeric,
  66:     // try to compare them as numbers. (And here it gets messy.)
  67: 
  68:     final TypeRegistry typeRegistry = context.getTypeRegistry();
  69:     try
  70:     {
  71:       final Number number1 = typeRegistry.convertToNumber(type1, value1);
  72:       final Number number2 = typeRegistry.convertToNumber(type2, value2);
  73:       final BigDecimal bd1 = new BigDecimal(number1.toString());
  74:       final BigDecimal bd2 = new BigDecimal(number2.toString());
  75:       if (bd1.signum() != bd2.signum())
  76:       {
  77:         return false;
  78:       }
  79: 
  80:       final BigDecimal result = bd1.subtract(bd2);
  81:       return (result.signum() == 0);
  82:     }
  83:     catch (TypeConversionException nfe)
  84:     {
  85:       // ignore ..
  86:     }
  87: 
  88:     if (type1.isFlagSet(Type.TEXT_TYPE) || type2.isFlagSet(Type.TEXT_TYPE))
  89:     {
  90:       String text1 = null;
  91:       String text2 = null;
  92:       try
  93:       {
  94:         // Convert both values to text ..
  95:         text1 = typeRegistry.convertToText(type1, value1);
  96:         text2 = typeRegistry.convertToText(type2, value2);
  97:       }
  98:       catch (TypeConversionException nfe)
  99:       {
 100:         // ignore ..
 101:       }
 102: 
 103:       if (text1 == null && text2 == null)
 104:       {
 105:         return true;
 106:       }
 107:       if (text1 == null || text2 == null)
 108:       {
 109:         return false;
 110:       }
 111:       return ObjectUtilities.equal(text1, text2);
 112: 
 113:     }
 114: 
 115:     // Fall back to Java's equals method and hope the best ..
 116:     return (ObjectUtilities.equal(value1, value2));
 117:   }
 118: 
 119:   /**
 120:    * Returns null, if the types are not comparable and are not convertible at
 121:    * all.
 122:    * 
 123:    * @param type1
 124:    * @param value1
 125:    * @param type2
 126:    * @param value2
 127:    * @return
 128:    */
 129:   public Integer compare(final Type type1, final Object value1,
 130:       final Type type2, final Object value2)
 131:   {
 132:     // this is rather easy. If at least one of the types is a numeric,
 133:     // try to compare them as numbers. (And here it gets messy.)
 134:     if (value1 == null && value2 == null)
 135:     {
 136:       return DefaultComparator.EQUAL;
 137:     }
 138:     if (value1 == null)
 139:     {
 140:       return DefaultComparator.LESS;
 141:     }
 142:     if (value2 == null)
 143:     {
 144:       return DefaultComparator.MORE;
 145:     }
 146: 
 147:     // First, we try to compare both types directly. This is the least-expensive
 148:     // solution, as it does
 149:     // not include any conversion operations ..
 150:     if (type1.isFlagSet(Type.SCALAR_TYPE) && type2.isFlagSet(Type.SCALAR_TYPE))
 151:     {
 152:       // this is something else
 153:       if (value1 instanceof Comparable && value2 instanceof Comparable)
 154:       {
 155:         final Comparable c1 = (Comparable) value1;
 156:         try
 157:         {
 158:           final int result = c1.compareTo(value2);
 159:           if (result == 0)
 160:           {
 161:             return DefaultComparator.EQUAL;
 162:           }
 163:           else if (result > 0)
 164:           {
 165:             return DefaultComparator.MORE;
 166:           }
 167:           else
 168:           {
 169:             return DefaultComparator.LESS;
 170:           }
 171:         }
 172:         catch (Exception e)
 173:         {
 174:           // ignore any exception ..
 175:         }
 176:       }
 177:     }
 178: 
 179:     // Next, we check the types on a numeric level.
 180:     final TypeRegistry typeRegistry = context.getTypeRegistry();
 181:     try
 182:     {
 183:       final Number number1 = typeRegistry.convertToNumber(type1, value1);
 184:       final Number number2 = typeRegistry.convertToNumber(type2, value2);
 185:       final BigDecimal bd1 = new BigDecimal(number1.toString());
 186:       final BigDecimal bd2 = new BigDecimal(number2.toString());
 187: 
 188:       if (bd1.signum() != bd2.signum())
 189:       {
 190:         if (bd1.signum() < 0)
 191:         {
 192:           return DefaultComparator.LESS;
 193:         }
 194:         else if (bd1.signum() > 0)
 195:         {
 196:           return DefaultComparator.MORE;
 197:         }
 198:       }
 199: 
 200:       final BigDecimal result = bd1.subtract(bd2);
 201:       if (result.signum() == 0)
 202:       {
 203:         return DefaultComparator.EQUAL;
 204:       }
 205:       if (result.signum() > 0)
 206:       {
 207:         return DefaultComparator.MORE;
 208:       }
 209:       return DefaultComparator.LESS;
 210:     }
 211:     catch (TypeConversionException nfe)
 212:     {
 213:       // Ignore ..
 214:     }
 215: 
 216:     // And finally convert them to text and compare the text values ..
 217:     // Convert both values to text ..
 218:     String text1 = null;
 219:     String text2 = null;
 220:     try
 221:     {
 222:       text1 = typeRegistry.convertToText(type1, value1);
 223:       text2 = typeRegistry.convertToText(type2, value2);
 224:     }
 225:     catch (TypeConversionException e)
 226:     {
 227:     }
 228: 
 229:     if (text1 == null && text2 == null)
 230:     {
 231:       return DefaultComparator.EQUAL;
 232:     }
 233:     if (text1 == null)
 234:     {
 235:       return DefaultComparator.LESS;
 236:     }
 237:     if (text2 == null)
 238:     {
 239:       return DefaultComparator.MORE;
 240:     }
 241: 
 242:     final int result = text1.compareTo(text2);
 243:     if (result == 0)
 244:     {
 245:       return DefaultComparator.EQUAL;
 246:     }
 247:     else if (result > 0)
 248:     {
 249:       return DefaultComparator.MORE;
 250:     }
 251:     else
 252:     {
 253:       return DefaultComparator.LESS;
 254:     }
 255:   }
 256: }