/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/
package org.infoglue.cms.util.sorters;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.apache.log4j.Logger;
import org.infoglue.cms.controllers.kernel.impl.simple.LuceneController;
import org.infoglue.cms.entities.content.Content;
import org.infoglue.cms.entities.content.ContentVO;
import org.infoglue.cms.entities.content.ContentVersion;
import org.infoglue.cms.entities.content.ContentVersionVO;
import org.infoglue.deliver.controllers.kernel.impl.simple.TemplateController;
/**
* A <code>CompoundComparable</code> is a compound comparable.
*/
class CompoundComparable implements Comparable
{
private final static Logger logger = Logger.getLogger(CompoundComparable.class.getName());
private Collator collation = Collator.getInstance();
/**
* The list of contained comparables.
*/
private final List comparables = new ArrayList();
/**
* Each order in this list indicates how the comparable at the same position should be sorted (ascending or not).
*/
private final List orders = new ArrayList(); // type: <Boolean>
private CompoundComparable()
{
logger.warn("no location");
}
public CompoundComparable(Locale locale)
{
if(locale != null)
collation = Collator.getInstance(locale);
}
/**
* Compares two <code>CompoundComparable</code> objects by comparing all
* contained comparable against each other.
*
* @param o the object to ne compared.
* @return a negative integer, zero, or a positive integer if this object is less than,
* equal to, or greater than the specified object.
*/
public final int compareTo(final Object o)
{
if(!(o instanceof CompoundComparable))
{
throw new ClassCastException();
}
final CompoundComparable other = (CompoundComparable) o;
if(other.comparables.size() != comparables.size())
{
throw new IllegalStateException("Trying to compare SortComparable with different number of elements.");
}
for(int i=0; i<comparables.size(); i++)
{
final int result = compareTo(other, i);
if(result != 0)
{
return result;
}
}
return 0;
}
/**
* Compares the n:th comparable of two <code>SortComparable</code> objects.
*
* @param other the other <code>CompoundComparable</code> object.
* @param index indicates which contained comparable to compare.
* @return a negative integer, zero, or a positive integer if the n:th comparable of this object
* is less than, equal to, or greater than the n:th comparable of the specified object.
*/
private final int compareTo(final CompoundComparable other, final int index)
{
final Comparable c1 = (Comparable) comparables.get(index);
final Comparable c2 = (Comparable) other.comparables.get(index);
final Boolean ascending = (Boolean) orders.get(index);
return ascending.booleanValue() ? c1.compareTo(c2) : c2.compareTo(c1);
//return ascending.booleanValue() ? collation.compare(c1, c2) : collation.compare(c2, c1);
}
/**
* Adds the specified comparable. The comparable will be sorted in the specified order.
*
* @param c the comparable to add.
* @param ascending indicates the sort order of the comparable.
*/
public final void add(final Comparable c, final boolean ascending)
{
comparables.add(c);
orders.add(new Boolean(ascending));
}
}
/**
* Utility class for sorting content/content version objects.
* Any number of properties and/or attributes of the content/content versions can be used in the sort.
*/
public class ContentSort
{
/**
* The controller to use when interacting with the model.
*/
TemplateController controller;
/**
* The elements to sort.
*/
private final List elements = new ArrayList(); // type: <SortElement>
/**
* Constructs a sorter for the specified elements.
*
* @param controller the controller to use when interacting with the model.
* @param elements the list of objects to sort.
*/
public ContentSort(final TemplateController controller, final Collection elements)
{
this.controller = controller;
addElements(elements);
}
public void clear()
{
this.controller = null;
this.elements.clear();
}
/**
* Sets the elements to sort.
*
* @param elements the list of objects to sort.
*/
private final void addElements(final Collection elements)
{
if(elements == null || elements.isEmpty())
{
return;
}
final Object element = elements.toArray()[0];
if(element instanceof Content)
{
initializeWithContent(elements);
}
if(element instanceof ContentVO)
{
initializeWithContentVO(elements);
}
if(element instanceof ContentVersion)
{
initializeWithContentVersion(elements);
}
if(element instanceof ContentVersionVO)
{
initializeWithContentVersionVO(elements);
}
}
/**
* Sets the elements to sort.
*
* @param the list of <code>Content</code> objects to sort.
*/
private final void initializeWithContent(final Collection elements)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
addElement(((Content) i.next()).getValueObject());
}
}
/**
* Sets the elements to sort.
*
* @param the list of <code>ContentVO</code> objects to sort.
*/
private final void initializeWithContentVO(final Collection elements)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
addElement((ContentVO) i.next());
}
}
/**
* Sets the elements to sort.
*
* @param the list of <code>ContentVersion</code> objects to sort.
*/
private final void initializeWithContentVersion(final Collection elements)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
addElement(((ContentVersion) i.next()).getValueObject());
}
}
/**
* Sets the elements to sort.
*
* @param the list of <code>ContentVersionVO</code> objects to sort.
*/
private final void initializeWithContentVersionVO(final Collection elements)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
addElement((ContentVersionVO) i.next());
}
}
/**
* Use the specified content property in the sort.
*
* @paran name the name of the content property.
* @param ascending indicates the sort order to use when sorting on the specified property.
*/
public void addContentProperty(final String name, final boolean ascending)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
((SortElement) i.next()).addContentProperty(name, ascending);
}
}
/**
* Use the specified content version property in the sort.
*
* @paran name the name of the content version property.
* @param ascending indicates the sort order to use when sorting on the specified property.
*/
public void addContentVersionProperty(final String name, final boolean ascending)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
((SortElement) i.next()).addContentVersionProperty(name, ascending);
}
}
/**
* Use the specified content version attribute in the sort. The type (Comparable) used when
* sorting on the attribute will be <code>String</code>.
*
* @paran name the name of the content version attribute.
* @param ascending indicates the sort order to use when sorting on the specified attribute.
*/
public void addContentVersionAttribute(final String name, final boolean ascending, final boolean caseSensitive)
{
addContentVersionAttribute(name, String.class, ascending, caseSensitive);
}
/**
* Use the specified content version attribute in the sort. The type (Comparable) used when
* sorting on the attribute will be the specified class.
*
* @paran name the name of the content version attribute.
* @param className indicates the name of the <code>Comparable</code> to use when sorting on the attribute.
* @param ascending indicates the sort order to use when sorting on the specified attribute.
*/
public void addContentVersionAttribute(final String name, final String className, final boolean ascending, final boolean caseSensitive)
{
try
{
addContentVersionAttribute(name, Class.forName(className), ascending, caseSensitive);
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* Use the specified content version attribute in the sort. The type (Comparable) used when
* sorting on the attribute will be the specified class.
*
* @paran name the name of the content version attribute.
* @param clazz indicates the <code>Comparable</code> to use when sorting on the attribute.
* @param ascending indicates the sort order to use when sorting on the specified attribute.
*/
public void addContentVersionAttribute(final String name, final Class clazz, final boolean ascending, final boolean caseSensitive)
{
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
((SortElement) i.next()).addContentVersionAttribute(name, clazz, ascending, caseSensitive);
}
}
/**
* Adds the specified <code>ContentVO</code> object to the elements to sort.
*
* @param contentVO the element to sort.
*/
private void addElement(final ContentVO contentVO)
{
elements.add(new SortElement(controller, contentVO));
}
/**
* Adds the specified <code>ContentVersionVO</code> object to the elements to sort.
*
* @param contentVO the element to sort.
*/
private void addElement(final ContentVersionVO contentVersionVO)
{
elements.add(new SortElement(controller, contentVersionVO));
}
/**
* Returns a list of sorted <code>ContentVO</code> objects.
*
* @return the sorted list.
*/
public List getContentResult()
{
Collections.sort(elements);
final List result = new ArrayList();
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
final SortElement struct = (SortElement) i.next();
result.add(struct.getContentVO());
}
return result;
}
/**
* Returns a list of sorted <code>ContentVO</code> objects.
* @param sorts the list using the comparatorClass specified. The comparator must implement the interface org.infoglue.cms.util.sorters.TemplateControllerAwareComparator
* @return the sorted list.
*/
public List getContentResult(String comparatorClass)
{
TemplateControllerAwareComparator comp = null;
if(comparatorClass!=null && !comparatorClass.equals(""))
{
try
{
Class clazz = Class.forName(comparatorClass);
if(clazz!=null)
{
try
{
comp = (TemplateControllerAwareComparator) clazz.newInstance();
comp.setController(this.controller);
}
catch (InstantiationException e)
{
throw new IllegalArgumentException("Couldnt instantiate comparator class " + comparatorClass + " " + e.getMessage());
} catch (IllegalAccessException e)
{
throw new IllegalArgumentException("Couldnt access comparator class " + comparatorClass + " " + e.getMessage());
}
}
}
catch (ClassNotFoundException e)
{
throw new IllegalArgumentException("Couldnt find comparator class " + comparatorClass + " " + e.getMessage());
}
}
else
{
throw new IllegalArgumentException("Must specify a comparator classname");
}
Collections.sort(elements,comp);
final List result = new ArrayList();
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
final SortElement struct = (SortElement) i.next();
result.add(struct.getContentVO());
}
return result;
}
/**
* Returns a list of sorted <code>ContentVersionVO</code> objects.
*
* @return the sorted list.
*/
public List getContentVersionResult()
{
Collections.sort(elements);
final List result = new ArrayList();
for(final Iterator i=elements.iterator(); i.hasNext(); )
{
final SortElement struct = (SortElement) i.next();
result.add(struct.getContentVersionVO());
}
return result;
}
}