org.josql.utils
Class JoSQLComparator

java.lang.Object
  extended by org.josql.utils.JoSQLComparator
All Implemented Interfaces:
Comparator

public class JoSQLComparator
extends Object
implements Comparator

This class allows the ORDER BY clause of a JoSQL SQL clause to be used as a Comparator. It should be noted that is the same as performing: Query.execute(List) but there are times when having a separate comparator is desirable. The EXECUTE ON ALL clause is supported but you must call: doExecuteOn(List) first to ensure that they are executed.

This class is basically just a thin wrapper around using the comparator gained by calling: Query.getOrderByComparator().

A note on performance, for small numbers of objects (around 1000) this comparator has (for vanilla accessors, no function calls) pretty comparable performance against a hand-coded Java Comparator that performs the same function. However start to scale the numbers of objects and performance degrades, in testing for ~34000 FileWrapper objects to order by: path DESC, lastModified, name, length took around: 1300ms. The hand-coded Java Comparator took around: 180ms! The upshot is, if you need flexibility and do not need to order large numbers of objects then use this kind of Comparator, if performance and numbers of objects is an issue then hand-rolling your own Comparator is probably best. As a side-note, to perform the following order by: lower(path) DESC, lastModified, name, length using a JoSQLComparator took: about: 1400ms. However modifying the hand-coded Comparator to use: String.compareToIgnoreCase(String) then took about 860ms! And if you using: String.toLowerCase() for each string instead, it then takes about: 1800ms! (Meaning that in certain circumstances JoSQL can be faster!)

Caching

It is not uncommon for a Comparator (even using the effecient merge-sort implementation of Collections.sort(List,Comparator)) to perform thousands (even millions!) of comparisons.

However since JoSQL does not automatically cache the results of calls to functions and results of accessor accesses the performance of this kind of "dynamic" Comparator can quickly degrade. To mitigate this it is possible to turn "caching" on whereby the Comparator will "remember" the results of the functions on a per object basis and use those values instead of calling them again. This is not without it's downside however. Firstly since a reference to the object will be held it is important (if caching is used that you call: clearCache() once the Comparator has been used to free up those references (it was considered using a WeakHashMap but that doesn't provide exactly what's needed here).

It is recommended that caching is turned on when the Comparator is to be used in a sort operation , i.e. calling: Collections.sort(List,Comparator) or similar (however careful consideration needs to be given to the amount of memory that this may consume, i.e. 4 bytes = 1 object reference, plus 1 List, plus 4 bytes per order by "column" it soon adds up)

If the comparator is to be used in a TreeMap or TreeSet then caching should not be used since the values may (and perhaps should) change over time but due to caching the order won't change.


Constructor Summary
JoSQLComparator(Query q)
          Init this file filter with the query already built and parsed.
JoSQLComparator(String q)
          Init this filter with the query.
 
Method Summary
 void clearCache()
          Clear the cache, it is VITAL that you call this method before you use the comparator (if it has been used before) otherwise data objects will be "left around" and preventing the GC from cleaning them up.
 int compare(Object o1, Object o2)
          Compares the objects as according to the ORDER BY clause.
 void doExecuteOn(List l)
          Execute the EXECUTE ON ALL expressions.
 Exception getException()
          The Comparator.compare(Object,Object) method does not allow for any exceptions to be thrown however since the execution of the ORDER BY clause on the objects can cause the throwing of a QueryParseException it should be captured.
 Query getQuery()
          Get the Query we are using to process objects.
 boolean isCaching()
          Return whether this comparator uses caching to improve performance.
 void setCaching(boolean b)
          Set whether the comparator should use caching to improve performance.
 void setQuery(Query q)
          Set a new Query object for use in this filter.
 void setQuery(String q)
          Set a new Query (string form) for use in this filter.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface java.util.Comparator
equals
 

Constructor Detail

JoSQLComparator

public JoSQLComparator(String q)
                throws QueryParseException
Init this filter with the query.

Parameters:
q - The query.
Throws:
QueryParseException - If there is an issue with the parsing of the query.

JoSQLComparator

public JoSQLComparator(Query q)
                throws IllegalStateException,
                       QueryParseException
Init this file filter with the query already built and parsed.

Parameters:
q - The query.
Throws:
IllegalStateException - If the Query object has not been parsed.
QueryParseException - If the FROM class is not as expected.
Method Detail

doExecuteOn

public void doExecuteOn(List l)
                 throws QueryExecutionException
Execute the EXECUTE ON ALL expressions.

Parameters:
l - The list to execute the expressions on.
Throws:
QueryExecutionException

clearCache

public void clearCache()
Clear the cache, it is VITAL that you call this method before you use the comparator (if it has been used before) otherwise data objects will be "left around" and preventing the GC from cleaning them up.


isCaching

public boolean isCaching()
                  throws IllegalStateException
Return whether this comparator uses caching to improve performance.

Returns:
true if caching is on.
Throws:
IllegalStateException - If the query has not yet been parsed or set.

setCaching

public void setCaching(boolean b)
                throws IllegalStateException
Set whether the comparator should use caching to improve performance.

Parameters:
b - Set to true to turn caching on.
Throws:
IllegalStateException - If the query has not yet been parsed or set.

compare

public int compare(Object o1,
                   Object o2)
Compares the objects as according to the ORDER BY clause.

Specified by:
compare in interface Comparator
Parameters:
o1 - The first object.
o2 - The second object.

getException

public Exception getException()
The Comparator.compare(Object,Object) method does not allow for any exceptions to be thrown however since the execution of the ORDER BY clause on the objects can cause the throwing of a QueryParseException it should be captured. If the exception is thrown then this method will return it.

Returns:
The exception thrown by the execution of the ORDER BY clause in compare(Object,Object) or by sub-class/interface specific methods, this may be null if no exception was thrown.

setQuery

public void setQuery(String q)
              throws QueryParseException
Set a new Query (string form) for use in this filter.

Parameters:
q - The Query to use.
Throws:
QueryParseException - If there is an issue with the parsing of the query, or if the FROM class is not as expected.

setQuery

public void setQuery(Query q)
              throws IllegalStateException,
                     QueryParseException
Set a new Query object for use in this filter.

Parameters:
q - The Query to use.
Throws:
IllegalStateException - If the Query object has not been parsed.
QueryParseException - If the FROM class is not as expected.

getQuery

public Query getQuery()
Get the Query we are using to process objects.

Returns:
The Query.


  Copyright © 2008 Gary Bentley. All Rights Reserved.