/* * @(#) ObjectComparatorManager.java * * Copyright 2002 - 2003 JIDE Software. All rights reserved. */ package com.jidesoft.comparator; import com.jidesoft.utils.CacheMap; import com.jidesoft.utils.RegistrationListener; import java.text.Collator; import java.util.Calendar; import java.util.Comparator; import java.util.Date; /** * A global object that can register comparator with a type and a ComparatorContext. */ public class ObjectComparatorManager { private static final CacheMap<Comparator<?>, ComparatorContext> _cache = new CacheMap<Comparator<?>, ComparatorContext>(new ComparatorContext("")); private static final Comparator<Object> _defaultComparator = new DefaultComparator(); public static void registerComparator(Class<?> clazz, Comparator comparator) { registerComparator(clazz, comparator, ComparatorContext.DEFAULT_CONTEXT); } /** * Registers a comparator with the type specified as class and a comparator context specified as context. * * @param clazz type. * @param comparator the comparator to be registered. * @param context the comparator context. */ public static void registerComparator(Class<?> clazz, Comparator comparator, ComparatorContext context) { if (clazz == null) { throw new IllegalArgumentException("Parameter clazz cannot be null"); } if (context == null) { context = ComparatorContext.DEFAULT_CONTEXT; } if (isAutoInit() && !_inited && !_initing) { initDefaultComparator(); } _cache.register(clazz, comparator, context); } /** * Unregisters comparator associated with the class and context. * * @param clazz the data type. */ public static void unregisterComparator(Class<?> clazz) { unregisterComparator(clazz, ComparatorContext.DEFAULT_CONTEXT); } /** * Unregisters comparator associated with the class and context. * * @param clazz the data type. * @param context the comparator context. */ public static void unregisterComparator(Class<?> clazz, ComparatorContext context) { if (context == null) { context = ComparatorContext.DEFAULT_CONTEXT; } if (isAutoInit() && !_inited && !_initing) { initDefaultComparator(); } _cache.unregister(clazz, context); } /** * Unregisters all comparators associated with the class. * * @param clazz the data type. */ public static void unregisterAllComparators(Class<?> clazz) { _cache.remove(clazz); } /** * Unregisters all the comparators which registered before. */ public static void unregisterAllComparators() { _cache.clear(); } /** * Gets the registered comparator associated with class and default context. * * @param clazz the data type. * * @return the registered comparator. */ public static Comparator getComparator(Class<?> clazz) { return getComparator(clazz, ComparatorContext.DEFAULT_CONTEXT); } /** * Gets the comparator. * * @param clazz the data type. * @param context the comparator context. * * @return the comparator. */ public static Comparator getComparator(Class<?> clazz, ComparatorContext context) { if (isAutoInit() && !_inited && !_initing) { initDefaultComparator(); } if (context == null) { context = ComparatorContext.DEFAULT_CONTEXT; } Comparator object = _cache.getRegisteredObject(clazz, context); if (object != null) { return object; } else { return _defaultComparator; } } /** * Compares the two objects. It will look up in <code>ObjectComparatorManager</code> to find the comparator and * compare. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * * @return the compare result as defined in {@link Comparator#compare(Object, Object)} */ public static int compare(Object o1, Object o2) { return compare(o1, o2, ComparatorContext.DEFAULT_CONTEXT); } /** * Compares the two objects. It will look up in <code>ObjectComparatorManager</code> to find the comparator and * compare. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @param context the comparator context * * @return the compare result as defined in {@link Comparator#compare(Object, Object)} */ public static int compare(Object o1, Object o2, ComparatorContext context) { if (o1 == null && o2 == null) { return 0; } else if (o1 == null) { return -1; } else if (o2 == null) { return 1; } // both not null Class<?> clazz; Class<?> clazz1 = o1.getClass(); Class<?> clazz2 = o2.getClass(); if (clazz1 == clazz2) { clazz = clazz1; } else if (clazz1.isAssignableFrom(clazz2)) { clazz = clazz1; } else if (clazz2.isAssignableFrom(clazz1)) { clazz = clazz2; } else if (clazz1.isAssignableFrom(Comparable.class) && clazz2.isAssignableFrom(Comparable.class)) { clazz = Comparable.class; } else { clazz = Object.class; } return compare(o1, o2, clazz, context); } /** * Compares the two objects. It will look up in <code>ObjectComparatorManager</code> to find the comparator and * compare. This method needs a third parameter which is the data type. This is useful when you have two objects * that have different data types but both extend the same super class. In this case, you may want the super class * as the key to look up in <code>ObjectComparatorManager</code>. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @param clazz the data type of the two objects. If your two objects have the same type, you may just use {@link * #compare(Object, Object)} methods. * * @return the compare result as defined in {@link Comparator#compare(Object, Object)} */ public static int compare(Object o1, Object o2, Class<?> clazz) { return compare(o1, o2, clazz, ComparatorContext.DEFAULT_CONTEXT); } /** * Compares the two objects. It will look up in <code>ObjectComparatorManager</code> to find the comparator and * compare. If it is not found, we will convert the object to string and compare the two strings. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @param clazz the data type of the two objects. If your two objects have the same type, you may just use {@link * #compare(Object, Object)} methods. * @param context the comparator context * * @return the compare result as defined in {@link Comparator#compare(Object, Object)} */ public static int compare(Object o1, Object o2, Class<?> clazz, ComparatorContext context) { Comparator comparator = getComparator(clazz, context); if (comparator != null) { try { return comparator.compare(o1, o2); } catch (Exception e) { // ignore and let the code below handles it. } } if (o1 == o2) { return 0; } else { if (o1 == null) { return -1; } else if (o2 == null) { return 1; } else { // otherwise, compare as string return o1.toString().compareTo(o2.toString()); } } } private static boolean _inited = false; private static boolean _initing = false; private static boolean _autoInit = true; /** * Checks the value of autoInit. * * @return true or false. * * @see #setAutoInit(boolean) */ public static boolean isAutoInit() { return _autoInit; } /** * Sets autoInit to true or false. If autoInit is true, whenever someone tries to call methods like as toString or * fromString, {@link #initDefaultComparator()} will be called if it has never be called. By default, autoInit is * true. * <p/> * This might affect the behavior if users provide their own comparators and want to overwrite default comparators. * In this case, instead of depending on autoInit to initialize default comparators, you should call {@link * #initDefaultComparator()} first, then call registerComparator to add your own comparators. * * @param autoInit false if you want to disable autoInit which means you either don't want those default comparators * registered or you will call {@link #initDefaultComparator()} yourself. */ public static void setAutoInit(boolean autoInit) { _autoInit = autoInit; } /** * Adds a listener to the list that's notified each time a change to the manager occurs. * * @param l the RegistrationListener */ public static void addRegistrationListener(RegistrationListener l) { _cache.addRegistrationListener(l); } /** * Removes a listener from the list that's notified each time a change to the manager occurs. * * @param l the RegistrationListener */ public static void removeRegistrationListener(RegistrationListener l) { _cache.removeRegistrationListener(l); } /** * Returns an array of all the registration listeners registered on this manager. * * @return all of this registration's <code>RegistrationListener</code>s or an empty array if no registration * listeners are currently registered * * @see #addRegistrationListener * @see #removeRegistrationListener */ public static RegistrationListener[] getRegistrationListeners() { return _cache.getRegistrationListeners(); } /** * Gets the available ComparatorContexts registered with the class. * * @param clazz the class. * * @return the available ComparatorContext. */ public static ComparatorContext[] getComparatorContexts(Class<?> clazz) { return _cache.getKeys(clazz, new ComparatorContext[0]); } /** * Initialize default comparator. Please make sure you call this method before you use any comparator related * classes such as SortableTableModel. */ public static void initDefaultComparator() { if (_inited) { return; } _initing = true; try { registerComparator(Object.class, new DefaultComparator()); registerComparator(Boolean.class, new BooleanComparator()); registerComparator(Calendar.class, new CalendarComparator()); registerComparator(Date.class, new DateComparator()); NumberComparator numberComparator = new NumberComparator(); registerComparator(Number.class, numberComparator); registerComparator(double.class, numberComparator); registerComparator(float.class, numberComparator); registerComparator(long.class, numberComparator); registerComparator(int.class, numberComparator); registerComparator(short.class, numberComparator); registerComparator(byte.class, numberComparator); registerComparator(Double.class, numberComparator); registerComparator(Float.class, numberComparator); registerComparator(Long.class, numberComparator); registerComparator(Integer.class, numberComparator); registerComparator(Short.class, numberComparator); registerComparator(Byte.class, numberComparator); NumberComparator absoluteNumberComparator = new NumberComparator(); absoluteNumberComparator.setAbsolute(true); registerComparator(Number.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(double.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(float.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(long.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(int.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(short.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(byte.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Double.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Float.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Long.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Integer.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Short.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Byte.class, absoluteNumberComparator, NumberComparator.CONTEXT_ABSOLUTE); registerComparator(Comparable.class, new FastComparableComparator()); registerComparator(String.class, Collator.getInstance()); Collator caseInsensitiveCollator = Collator.getInstance(); caseInsensitiveCollator.setStrength(Collator.PRIMARY); registerComparator(String.class, caseInsensitiveCollator, new ComparatorContext("Ignorecase")); Collator secondaryCollator = Collator.getInstance(); secondaryCollator.setStrength(Collator.SECONDARY); registerComparator(String.class, secondaryCollator, new ComparatorContext("Secondary")); registerComparator(CharSequence.class, new CharSequenceComparator(), CharSequenceComparator.CONTEXT); registerComparator(CharSequence.class, new CharSequenceComparator(false), CharSequenceComparator.CONTEXT_IGNORE_CASE); registerComparator(CharSequence.class, new AlphanumComparator(), AlphanumComparator.CONTEXT); registerComparator(CharSequence.class, new AlphanumComparator(false), AlphanumComparator.CONTEXT_IGNORE_CASE); } finally { _initing = false; _inited = true; } } /** * If {@link #initDefaultComparator()} is called once, calling it again will have no effect because an internal flag * is set. This method will reset the internal flag so that you can call {@link #initDefaultComparator()} in case * you unregister all comparators using {@link #unregisterAllComparators()}. */ public static void resetInit() { _inited = false; } public static void clear() { resetInit(); _cache.clear(); } }