001 /** 002 * ========================================= 003 * LibFormula : a free Java formula library 004 * ========================================= 005 * 006 * Project Info: http://reporting.pentaho.org/libformula/ 007 * 008 * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors. 009 * 010 * This library is free software; you can redistribute it and/or modify it under the terms 011 * of the GNU Lesser General Public License as published by the Free Software Foundation; 012 * either version 2.1 of the License, or (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 016 * See the GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public License along with this 019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 020 * Boston, MA 02111-1307, USA. 021 * 022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 023 * in the United States and other countries.] 024 * 025 * 026 * ------------ 027 * $Id: DefaultComparator.java 3521 2007-10-16 10:55:14Z tmorgner $ 028 * ------------ 029 * (C) Copyright 2006-2007, by Pentaho Corporation. 030 */ 031 package org.jfree.formula.typing; 032 033 import java.math.BigDecimal; 034 035 import org.jfree.formula.FormulaContext; 036 import org.jfree.util.ObjectUtilities; 037 038 /** 039 * Creation-Date: 03.11.2006, 16:15:28 040 * 041 * @author Thomas Morgner 042 */ 043 public class DefaultComparator implements ExtendedComparator 044 { 045 private FormulaContext context; 046 047 public static final Integer LESS = new Integer(-1); 048 049 public static final Integer EQUAL = new Integer(0); 050 051 private static final Integer MORE = new Integer(1); 052 053 public DefaultComparator() 054 { 055 } 056 057 public void inititalize(final FormulaContext context) 058 { 059 this.context = context; 060 } 061 062 public boolean isEqual(final Type type1, final Object value1, 063 final Type type2, final Object value2) 064 { 065 // this is rather easy. If at least one of the types is a numeric, 066 // try to compare them as numbers. (And here it gets messy.) 067 068 final TypeRegistry typeRegistry = context.getTypeRegistry(); 069 try 070 { 071 final Number number1 = typeRegistry.convertToNumber(type1, value1); 072 final Number number2 = typeRegistry.convertToNumber(type2, value2); 073 final BigDecimal bd1 = new BigDecimal(number1.toString()); 074 final BigDecimal bd2 = new BigDecimal(number2.toString()); 075 if (bd1.signum() != bd2.signum()) 076 { 077 return false; 078 } 079 080 final BigDecimal result = bd1.subtract(bd2); 081 return (result.signum() == 0); 082 } 083 catch (TypeConversionException nfe) 084 { 085 // ignore .. 086 } 087 088 if (type1.isFlagSet(Type.TEXT_TYPE) || type2.isFlagSet(Type.TEXT_TYPE)) 089 { 090 String text1 = null; 091 String text2 = null; 092 try 093 { 094 // Convert both values to text .. 095 text1 = typeRegistry.convertToText(type1, value1); 096 text2 = typeRegistry.convertToText(type2, value2); 097 } 098 catch (TypeConversionException nfe) 099 { 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 // failure here can be ignored. 228 } 229 230 if (text1 == null && text2 == null) 231 { 232 return DefaultComparator.EQUAL; 233 } 234 if (text1 == null) 235 { 236 return DefaultComparator.LESS; 237 } 238 if (text2 == null) 239 { 240 return DefaultComparator.MORE; 241 } 242 243 final int result = text1.compareTo(text2); 244 if (result == 0) 245 { 246 return DefaultComparator.EQUAL; 247 } 248 else if (result > 0) 249 { 250 return DefaultComparator.MORE; 251 } 252 else 253 { 254 return DefaultComparator.LESS; 255 } 256 } 257 }