/* ===============================================================================
*
* 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.lang.reflect.Constructor;
import java.text.Collator;
import java.util.Locale;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.infoglue.cms.controllers.kernel.impl.simple.LuceneController;
import org.infoglue.cms.entities.content.ContentVO;
import org.infoglue.cms.entities.content.ContentVersionVO;
import org.infoglue.cms.exception.SystemException;
import org.infoglue.deliver.controllers.kernel.impl.simple.TemplateController;
/**
* A <code>SortElement</code> object is created for each content/content version
* to be sorted. If the <code>SortElement</code> is constructed using a content
* and the content version is needed, the content version to use is decided by
* fetching the language used by the <code>TemplateController</code>.
* <p>
* Strictly speaking we never sort on a content or a content version, we are
* sorting on a content <strong>and</strong> the content version indicated by the
* language used by the <code>TemplateController</code> at the same time.
* </p>
*/
public class SortElement implements Comparable
{
private final static Logger logger = Logger.getLogger(SortElement.class.getName());
/**
* The controller to use when interacting with the model.
*/
private final TemplateController controller;
/**
* The content version to sort.
*/
private ContentVersionVO contentVersionVO;
/**
* The content to sort.
*/
private ContentVO contentVO;
/**
* The comparable of the element to sort.
*/
private CompoundComparable comparable = null; //new CompoundComparable();
/**
* Constructs a sort element for the specified content.
*
* @param contentVO the content to sort.
* @param controller the controller to use when interacting with the model.
*/
SortElement(final TemplateController controller, final ContentVO contentVO)
{
this.controller = controller;
this.contentVO = contentVO;
if(this.controller != null)
{
try
{
this.comparable = new CompoundComparable(controller.getLocale());
}
catch (SystemException e)
{
logger.error("Error:" + e.getMessage());
}
}
}
/**
* Constructs a sort element for the specified content version.
*
* @param contentVO the content to sort.
* @param controller the controller to use when interacting with the model.
*/
SortElement(final TemplateController controller, final ContentVersionVO contentVersionVO)
{
this.controller = controller;
this.contentVersionVO = contentVersionVO;
if(this.controller != null)
{
try
{
logger.info("controller.getLocale():" + controller.getLocale());
this.comparable = new CompoundComparable(controller.getLocale());
}
catch (SystemException e)
{
logger.error("Error:" + e.getMessage());
}
}
}
/**
* 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)
{
comparable.add(getProperty(getContentVO(), 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)
{
comparable.add(getProperty(getContentVersionVO(), name), ascending);
}
/**
* 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)
{
final Integer contentId = getContentId();
String stringValue = controller.getContentAttribute(contentId, controller.getLanguageId(), name);
if(!caseSensitive)
stringValue = stringValue.toLowerCase();
comparable.add(castAttribute(name, clazz, stringValue), ascending);
}
/**
* Cast the specified string value to the specified class (which must be a <code>Comparable</code>.
*
* @param name the name of the content version attribute (used for debug only).
* @param clazz the class to cast to. Must implement the <code>Comparable</code> interface.
* @param stringValue the value to cast.
* @throws IllegalArgumentException if the cast fails.
*/
private Comparable castAttribute(final String name, final Class clazz, final String stringValue)
{
if(String.class.equals(clazz))
{
return stringValue;
}
try
{
final Constructor ctor = clazz.getConstructor(new Class[] { String.class });
final String s = (Number.class.isAssignableFrom(clazz) && stringValue.equals("")) ? "0" : stringValue;
return (Comparable) ctor.newInstance(new Object[] { s });
}
catch(Exception e)
{
e.printStackTrace();
throw new IllegalArgumentException("Unable to cast [" + name + "] to [" + clazz.getName() + "].");
}
}
/**
* Returns the identifier of the content element.
*
* @return the identifier.
*/
private Integer getContentId()
{
return (contentVO != null) ? getContentVO().getContentId() : getContentVersionVO().getContentId();
}
/**
* Returns the value of the specified property of the specified object.
*
* @param o object whose property is to be extracted.
* @param name the name of the property to be extracted.
* @returns the value of the specified property of the specified object.
*/
private Comparable getProperty(final Object o, final String name)
{
try
{
return (Comparable) PropertyUtils.getProperty(o, name);
}
catch(Exception e)
{
e.printStackTrace();
throw new IllegalArgumentException("Illegal property [" + name + "] : " + e);
}
}
/**
* Returns the content version value object. This is a convenience method as we don't
* if the element was constructed using a content or a content version.
*
* @return the content version value object.
*/
public ContentVersionVO getContentVersionVO()
{
if(contentVersionVO == null)
{
contentVersionVO = controller.getContentVersion(contentVO.getContentId());
}
return contentVersionVO;
}
/**
* Returns the content value object. This is a convenience method as we don't
* if the element was constructed using a content or a content version.
*
* @return the content value object.
*/
public ContentVO getContentVO()
{
if(contentVO == null)
{
contentVO = controller.getContent(contentVersionVO.getContentId());
}
return contentVO;
}
/**
* Compares two <code>SortStruct</code> objects by comparing their <code>SortComparable</code>:s.
*
* @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(Object o)
{
if(!(o instanceof SortElement))
{
throw new ClassCastException();
}
final SortElement other = (SortElement) o;
//return collation.compare(comparable, other.comparable);
return comparable.compareTo(other.comparable);
}
}