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    }