All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.component.html.ext.SortableModel Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF2.1 features. A JSF2.1 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.myfaces.component.html.ext;

import java.text.CollationKey;
import java.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public final class SortableModel extends BaseSortableModel
{    
    private static final Log log = LogFactory.getLog(SortableModel.class);
    
    private SortCriterion _sortCriterion = null;
    
    /**
     * Create a new SortableModel from the given instance.
     * @param model This will be converted into a {@link DataModel}
     * @see #setWrappedData
     */
    public SortableModel(Object model) 
    {
        super(model);
    }
    
    /**
     * No arg constructor for use as a managed-bean.
     * Must call setWrappedData before using this instance.
     */
    public SortableModel(){}
    
    /**
     * Sets the underlying data being managed by this instance.
     * @param data This Object will be converted into a
     * {@link DataModel}.
     */
    public void setWrappedData(Object data) 
    {
        super.setWrappedData(data);
        setSortCriteria(null);
    }
    
    /**
     * Checks to see if the underlying collection is sortable by the given property.
     * @param property The name of the property to sort the underlying collection by.
     * @return true, if the property implements java.lang.Comparable
     */
    public boolean isSortable(String property) 
    {
        final int oldIndex = _model.getRowIndex();
        try 
        {
            _model.setRowIndex(0);
            if (!_model.isRowAvailable())
                return false; // if there is no data in the table then nothing is sortable
            
            try 
            {   
                Object propertyValue = PropertyUtils.getProperty(_model.getRowData(),property);                
                
                // when the value is null, we don't know if we can sort it.
                // by default let's support sorting of null values, and let the user
                // turn off sorting if necessary:
                return (propertyValue instanceof Comparable) || (propertyValue == null);
            } 
            catch (RuntimeException e) 
            {
                // don't propagate this exception out. This is because it might break
                // the VE.
                log.warn(e);
                return false;
            }
            catch (Exception e) {
                log.warn(e);
                return false;
            }
        } 
        finally 
        {
            _model.setRowIndex(oldIndex);
        }
    }
    
    public List getSortCriteria() 
    {
        return (_sortCriterion == null) ? Collections.EMPTY_LIST : Collections.singletonList(_sortCriterion);
    }
    
    public void setSortCriteria(List criteria) 
    {
        if ((criteria == null) || (criteria.isEmpty())) 
        {
            _sortCriterion = null;
            setComparator(null);
        } 
        else 
        {
            SortCriterion sc = (SortCriterion) criteria.get(0);
            if ((_sortCriterion == null) || (!_sortCriterion.equals(sc))) 
            {
                _sortCriterion = sc;
                
                /*
                 * Sorts the underlying collection by the given property, in the
                 * given direction.
                 * @param property The name of the property to sort by. The value of this
                 * property must implement java.lang.Comparable.
                 * @param isAscending true if the collection is to be sorted in
                 * ascending order.
                 * @todo support -1 for rowCount
                 */
               Comparator comp = new Comp(_sortCriterion.getProperty());                       
                
                if (!_sortCriterion.isAscending())
                    comp = new Inverter(comp);
                setComparator(comp);
            }
        }
    }
    
    public String toString() 
    {
        return "SortableModel[" + _model + "]";
    }
    
    private final class Comp implements Comparator 
    {
        private final String _prop;
        
        private Collator _collator;
        
        private Map _collationKeys;
        
        public Comp(String property) 
        {            
            _prop = property;
            _collator = Collator.getInstance(FacesContext.getCurrentInstance().getViewRoot().getLocale()); 
            _collationKeys = new HashMap();
        }               
        
        public int compare(Object o1, Object o2) 
        {
            Object value1 = null;
            Object value2 = null;
            try {
                value1 = PropertyUtils.getProperty(o1,_prop);  
                value2 = PropertyUtils.getProperty(o2,_prop);  
            }
            catch (Exception exc) {    
                log.error(exc);
            }
                                    
            if (value1 == null)
                return (value2 == null) ? 0 : -1;
            
            if (value2 == null)
                return 1;
            
            // ?? Sometimes, isSortable returns true
            // even if the underlying object is not a Comparable.
            // This happens if the object at rowIndex zero is null.
            // So test before we cast:
            
            if (value1 instanceof String) {
                //if the object is a String we best compare locale-sesitive
                CollationKey collationKey1 = getCollationKey((String)value1);
                CollationKey collationKey2 = getCollationKey((String)value2);
                
                return collationKey1.compareTo(collationKey2);
            }
            else if (value1 instanceof Comparable) 
            {
                return ((Comparable) value1).compareTo(value2);
            } 
            else 
            {
                // if the object is not a Comparable, then
                // the best we can do is string comparison:
                return value1.toString().compareTo(value2.toString());
            }
        }         
        
        private CollationKey getCollationKey(String propertyValue) {
            CollationKey key = (CollationKey)_collationKeys.get(propertyValue);
            if (key == null) {
                key = _collator.getCollationKey(propertyValue);
                _collationKeys.put(propertyValue, key);
            }
                
            return key;
        }
    }
    /**
     *
     */
    private static final class Inverter implements Comparator 
    {
        private final Comparator _comp;
        
        public Inverter(Comparator comp) 
        {
            _comp = comp;
        }
        
        public int compare(Object o1, Object o2) 
        {
            return _comp.compare(o2, o1);
        }              
    }      
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy