001    package net.databinder.models.hib;
002    
003    /*
004     * Databinder: a simple bridge from Wicket to Hibernate
005     * Copyright (C) 2006  Nathan Hamblen nathan@technically.us
006    
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    
022    import java.io.Serializable;
023    
024    import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;
025    import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
026    import org.apache.wicket.extensions.markup.html.repeater.util.SingleSortState;
027    import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
028    import org.hibernate.Criteria;
029    import org.hibernate.criterion.CriteriaSpecification;
030    import org.hibernate.criterion.Order;
031    
032    /**
033     * <h1>CriteriaSorter</h1>
034     * <i>Copyright (C) 2008 The Scripps Research Institute</i>
035     * <p>A Criteria based sorter suitable for adding to a HibernateProvider</p> 
036     *  * <pre>
037     * // a default sort by name, ascending and case insensitive: 
038     * CriteriaSorter sorter = new CriteriaSorter("name",true,false); 
039     * IDataProvider provider = new DatabinderProvider(objectClass, criteriaBuilder, sorter);
040     * </pre>
041     *  * @author Mark Southern (southern at scripps dot edu)
042     */
043    public class CriteriaSorter implements ISortStateLocator, CriteriaBuilder, Serializable {
044    
045        private SingleSortState sortState;
046    
047        private String defaultProperty = null;
048    
049        boolean asc, cased;
050    
051        public CriteriaSorter() {
052            this(null, true, true);
053        }
054    
055        public CriteriaSorter(String defaultProperty) {
056            this(defaultProperty, true, true);
057        }
058    
059        public CriteriaSorter(String defaultProperty, boolean asc) {
060            this(defaultProperty, asc, true);
061        }
062    
063        /**
064         * @param defaultProperty - property for a default sort before any is set
065         * @param asc - sort ascending/descending
066         * @param cased - sort cased/case insensitive
067         */
068        public CriteriaSorter(String defaultProperty, boolean asc, boolean cased) {
069            sortState = new SingleSortState();
070            this.defaultProperty = defaultProperty;
071            this.asc = asc;
072            this.cased = cased;
073        }
074    
075        public void build(Criteria criteria) {
076            SortParam sort = sortState.getSort();
077            String property;
078            if (sort != null && sort.getProperty() != null) {
079                property = sort.getProperty();
080                asc = sort.isAscending();
081            }
082            else {
083                property = defaultProperty;
084            }
085            if (property != null) {
086                if (property.contains(".")) {
087                    // for 'dot' properties we need to add aliases
088                    // e.g. for the property 'orderbook.order.item.name' we need to add an aliases for 'order' and 'order.item'
089                    String path[] = property.split("\\.");
090                    for (int ii = 0; ii < path.length - 1; ii++) {
091                        StringBuffer sb = new StringBuffer();
092                        for (int jj = 0; jj <= ii; jj++) {
093                            if (sb.length() > 0)
094                                sb.append(".");
095                            sb.append(path[jj]);
096                        }
097                        criteria.createAlias(sb.toString(), path[ii], CriteriaSpecification.LEFT_JOIN);
098                    }
099                    // when we have a 'dot' property we want to sort by the sub tables field
100                    // e.g. for the property 'orderbook.order.item.name' we need to sort by 'item.name'
101                    if (path.length > 1)
102                        property = String.format("%s.%s", path[path.length - 2], path[path.length - 1]);
103                    else
104                        property = path[path.length - 1];
105                }
106                Order order = asc ? Order.asc(property) : Order.desc(property);
107                order = cased ? order : order.ignoreCase();
108                criteria.addOrder(order);
109            }
110        }
111    
112        public ISortState getSortState() {
113            return sortState;
114        }
115    
116        public void setSortState(ISortState state) {
117            sortState = (SingleSortState) state;
118        }
119    }