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 }