001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 package org.jboss.dna.graph.properties; 023 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.math.BigDecimal; 027 import java.net.URI; 028 import java.util.Calendar; 029 import java.util.Comparator; 030 import java.util.Date; 031 import java.util.UUID; 032 import org.jboss.dna.graph.GraphI18n; 033 import org.jboss.dna.graph.properties.basic.StringValueFactory; 034 035 /** 036 * @author Randall Hauch 037 */ 038 public class ValueComparators { 039 040 /** 041 * A comparator of string values. 042 */ 043 public static final Comparator<String> STRING_COMPARATOR = new Comparator<String>() { 044 045 public int compare( String o1, 046 String o2 ) { 047 if (o1 == o2) return 0; 048 if (o1 == null) return -1; 049 if (o2 == null) return 1; 050 return o1.compareTo(o2); 051 } 052 }; 053 /** 054 * A comparator of long values. 055 */ 056 public static final Comparator<Long> LONG_COMPARATOR = new Comparator<Long>() { 057 058 public int compare( Long o1, 059 Long o2 ) { 060 if (o1 == o2) return 0; 061 if (o1 == null) return -1; 062 if (o2 == null) return 1; 063 return o1.compareTo(o2); 064 } 065 }; 066 /** 067 * A comparator of double values. 068 */ 069 public static final Comparator<Double> DOUBLE_COMPARATOR = new Comparator<Double>() { 070 071 public int compare( Double o1, 072 Double o2 ) { 073 if (o1 == o2) return 0; 074 if (o1 == null) return -1; 075 if (o2 == null) return 1; 076 return o1.compareTo(o2); 077 } 078 }; 079 /** 080 * A comparator of decimal values. 081 */ 082 public static final Comparator<BigDecimal> DECIMAL_COMPARATOR = new Comparator<BigDecimal>() { 083 084 public int compare( BigDecimal o1, 085 BigDecimal o2 ) { 086 if (o1 == o2) return 0; 087 if (o1 == null) return -1; 088 if (o2 == null) return 1; 089 return o1.compareTo(o2); 090 } 091 }; 092 /** 093 * A comparator of binary values. Although {@link Binary} is {@link Comparable}, this comparator does not rely upon any 094 * particular Binary implementation. Thus, Binary implementations can use this for their {@link Comparable#compareTo(Object)} 095 * implementation. 096 */ 097 public static final Comparator<Binary> BINARY_COMPARATOR = new Comparator<Binary>() { 098 099 public int compare( Binary o1, 100 Binary o2 ) { 101 if (o1 == o2) return 0; 102 if (o1 == null) return -1; 103 if (o2 == null) return 1; 104 try { 105 o1.acquire(); 106 try { 107 o2.acquire(); 108 final long len1 = o1.getSize(); 109 final long len2 = o2.getSize(); 110 if (len1 < len2) return -1; 111 if (len1 > len2) return 1; 112 113 // Compare using the hashes, if available 114 byte[] hash1 = o1.getHash(); 115 byte[] hash2 = o2.getHash(); 116 if (hash1.length != 0 || hash2.length != 0) { 117 assert hash1.length == hash2.length; 118 for (int i = 0; i != hash1.length; ++i) { 119 int diff = hash1[i] - hash2[i]; 120 if (diff != 0) return diff; 121 } 122 return 0; 123 } 124 125 // Otherwise they are the same length ... 126 InputStream stream1 = null; 127 InputStream stream2 = null; 128 try { 129 stream1 = o1.getStream(); 130 stream2 = o2.getStream(); 131 byte[] buffer1 = new byte[1024]; 132 byte[] buffer2 = new byte[1024]; 133 while (true) { 134 int numRead1 = stream1.read(buffer1); 135 if (numRead1 < 0) break; 136 int numRead2 = stream2.read(buffer2); 137 if (numRead1 != numRead2) { 138 throw new IoException(GraphI18n.errorReadingPropertyValueBytes.text()); 139 } 140 for (int i = 0; i != numRead1; ++i) { 141 int diff = buffer1[i] - buffer2[i]; 142 if (diff != 0) return diff; 143 } 144 } 145 return 0; 146 } catch (IOException e) { 147 throw new IoException(GraphI18n.errorReadingPropertyValueBytes.text()); 148 } finally { 149 if (stream1 != null) { 150 try { 151 stream1.close(); 152 } catch (IOException e) { 153 // do nothing 154 } 155 } 156 if (stream2 != null) { 157 try { 158 stream2.close(); 159 } catch (IOException e) { 160 // do nothing 161 } 162 } 163 } 164 } finally { 165 o2.release(); 166 } 167 } finally { 168 o1.release(); 169 } 170 } 171 }; 172 /** 173 * A comparator of boolean values. 174 */ 175 public static final Comparator<Boolean> BOOLEAN_COMPARATOR = new Comparator<Boolean>() { 176 177 public int compare( Boolean o1, 178 Boolean o2 ) { 179 if (o1 == o2) return 0; 180 if (o1 == null) return -1; 181 if (o2 == null) return 1; 182 return o1.compareTo(o2); 183 } 184 }; 185 /** 186 * A comparator of date-time instances. 187 */ 188 public static final Comparator<DateTime> DATE_TIME_COMPARATOR = new Comparator<DateTime>() { 189 190 public int compare( DateTime o1, 191 DateTime o2 ) { 192 if (o1 == o2) return 0; 193 if (o1 == null) return -1; 194 if (o2 == null) return 1; 195 return o1.compareTo(o2); 196 } 197 }; 198 /** 199 * A comparator of date values. 200 */ 201 public static final Comparator<Date> DATE_COMPARATOR = new Comparator<Date>() { 202 203 public int compare( Date o1, 204 Date o2 ) { 205 if (o1 == o2) return 0; 206 if (o1 == null) return -1; 207 if (o2 == null) return 1; 208 return o1.compareTo(o2); 209 } 210 }; 211 /** 212 * A comparator of calendar values. 213 */ 214 public static final Comparator<Calendar> CALENDAR_COMPARATOR = new Comparator<Calendar>() { 215 216 public int compare( Calendar o1, 217 Calendar o2 ) { 218 if (o1 == o2) return 0; 219 if (o1 == null) return -1; 220 if (o2 == null) return 1; 221 return o1.compareTo(o2); 222 } 223 }; 224 /** 225 * A comparator of name values. 226 */ 227 public static final Comparator<Name> NAME_COMPARATOR = new Comparator<Name>() { 228 229 public int compare( Name o1, 230 Name o2 ) { 231 if (o1 == o2) return 0; 232 if (o1 == null) return -1; 233 if (o2 == null) return 1; 234 return o1.compareTo(o2); 235 } 236 }; 237 /** 238 * A comparator of path values. 239 */ 240 public static final Comparator<Path> PATH_COMPARATOR = new Comparator<Path>() { 241 242 public int compare( Path o1, 243 Path o2 ) { 244 if (o1 == o2) return 0; 245 if (o1 == null) return -1; 246 if (o2 == null) return 1; 247 return o1.compareTo(o2); 248 } 249 }; 250 /** 251 * A comparator of URI values. 252 */ 253 public static final Comparator<URI> URI_COMPARATOR = new Comparator<URI>() { 254 255 public int compare( URI o1, 256 URI o2 ) { 257 if (o1 == o2) return 0; 258 if (o1 == null) return -1; 259 if (o2 == null) return 1; 260 return o1.compareTo(o2); 261 } 262 }; 263 /** 264 * A comparator of UUID values. 265 */ 266 public static final Comparator<UUID> UUID_COMPARATOR = new Comparator<UUID>() { 267 268 public int compare( UUID o1, 269 UUID o2 ) { 270 if (o1 == o2) return 0; 271 if (o1 == null) return -1; 272 if (o2 == null) return 1; 273 return o1.compareTo(o2); 274 } 275 }; 276 /** 277 * A comparator of reference values. 278 */ 279 public static final Comparator<Reference> REFERENCE_COMPARATOR = new Comparator<Reference>() { 280 281 public int compare( Reference o1, 282 Reference o2 ) { 283 if (o1 == o2) return 0; 284 if (o1 == null) return -1; 285 if (o2 == null) return 1; 286 return o1.compareTo(o2); 287 } 288 }; 289 /** 290 * A comparator of other values. 291 */ 292 public static final Comparator<Object> OBJECT_COMPARATOR = new Comparator<Object>() { 293 294 @SuppressWarnings( "unchecked" ) 295 public int compare( Object o1, 296 Object o2 ) { 297 if (o1 == o2) return 0; 298 if (o1 == null) return -1; 299 if (o2 == null) return 1; 300 PropertyType type1 = PropertyType.discoverType(o1); 301 PropertyType type2 = PropertyType.discoverType(o2); 302 if (type1 != PropertyType.OBJECT && type2 != PropertyType.OBJECT) { 303 if (type1 == type2) return ((Comparator<Object>)type1.getComparator()).compare(o1, o2); 304 305 // The types are different but the classes are the same ... 306 if (type1.getValueClass().isAssignableFrom(type2.getValueClass())) { 307 return ((Comparator<Object>)type1.getComparator()).compare(o1, o2); 308 } 309 if (type2.getValueClass().isAssignableFrom(type1.getValueClass())) { 310 return ((Comparator<Object>)type2.getComparator()).compare(o1, o2); 311 } 312 } 313 314 // The types are different and must be converted ... 315 String value1 = getStringValueFactory().create(o1); 316 String value2 = getStringValueFactory().create(o2); 317 return value1.compareTo(value2); 318 } 319 }; 320 321 // This is loaded lazily so that there is not a circular dependency between PropertyType (depends on this), 322 // StringValueFactory (depends on PropertyType), and OBJECT_COMPARATOR (which depends on StringValueFactory) ... 323 private static ValueFactory<String> STRING_VALUE_FACTORY; 324 325 protected static final ValueFactory<String> getStringValueFactory() { 326 // No locking is required, because it doesn't matter if we create several instances during initialization ... 327 if (STRING_VALUE_FACTORY == null) { 328 STRING_VALUE_FACTORY = new StringValueFactory(Path.NO_OP_DECODER, Path.NO_OP_ENCODER); 329 } 330 return STRING_VALUE_FACTORY; 331 } 332 }