View Javadoc
1   /**
2    * This file Copyright (c) 2003-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.gui.controlx.list;
35  
36  
37  import java.util.ArrayList;
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.Comparator;
41  import java.util.Iterator;
42  import java.util.List;
43  
44  import org.apache.commons.lang.StringUtils;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  
49  /**
50   * @author Sameer Charles $Id$
51   */
52  public abstract class AbstractListModel implements ListModel {
53  
54      private static Logger log = LoggerFactory.getLogger(AbstractListModel.class);
55  
56      /**
57       * sort or group by order
58       */
59      public static final String DESCENDING = "DESC";
60  
61      /**
62       * sort or group by order
63       */
64      public static final String ASCENDING = "ASC";
65  
66      /**
67       * sort by field name
68       */
69      protected String sortBy;
70  
71      /**
72       * sort by order
73       */
74      protected String sortByOrder;
75  
76      /**
77       * group by field name
78       */
79      protected String groupBy;
80  
81      /**
82       * group by order
83       */
84      protected String groupByOrder;
85  
86      /**
87       * Used to get values out of the nodes/objects handled by the list
88       */
89      private ValueProvider valueProvider;
90  
91      /**
92       * this must be implemented by implementing classes
93       * @return Iterator over found records
94       * @see ListModelIterator
95       */
96      @Override
97      public ListModelIterator getListModelIterator() {
98          try {
99              Collection items = getResult();
100             items = doSort(items);
101             return createIterator(items);
102         }
103         catch (Exception re) {
104             log.error("can't create the list model iterator, will return an empty list", re);
105             return new ListModelIteratorImpl(this, new ArrayList());
106         }
107     }
108 
109     @Override
110     public Iterator iterator() {
111         return getListModelIterator();
112     }
113 
114     /**
115      * @return the collection of the items passed to the iterator
116      */
117     protected abstract Collection getResult() throws Exception;
118 
119     /**
120      * Create the iterator
121      * @param items
122      * @return
123      */
124     protected ListModelIterator createIterator(Collection items) {
125         if(!(items instanceof List)){
126             throw new RuntimeException("items must be a List");
127         }
128         return new ListModelIteratorImpl(this, (List) items);
129     }
130 
131     /**
132      * set sort by field
133      * @param name
134      */
135     @Override
136     public void setSortBy(String name) {
137         this.sortBy = name;
138     }
139 
140     /**
141      * set sort by field and order ('ASCENDING' | 'DESCENDING')
142      * @param name
143      * @param order
144      */
145     @Override
146     public void setSortBy(String name, String order) {
147         this.sortBy = name;
148         this.sortByOrder = order;
149     }
150 
151     /**
152      * set group by field
153      * @param name
154      */
155     @Override
156     public void setGroupBy(String name) {
157         this.groupBy = name;
158     }
159 
160     /**
161      * set group by field and order ('ASCENDING' | 'DESCENDING')
162      * @param name
163      * @param order
164      */
165     @Override
166     public void setGroupBy(String name, String order) {
167         this.groupBy = name;
168         this.groupByOrder = order;
169     }
170 
171     /**
172      * get sort on field name
173      * @return String field name
174      */
175     @Override
176     public String getSortBy() {
177         return this.sortBy;
178     }
179 
180     /**
181      * get sort by ordering
182      * @return order ('ASCENDING' | 'DESCENDING')
183      */
184     @Override
185     public String getSortByOrder() {
186         return this.sortByOrder;
187     }
188 
189     /**
190      * get group on field name
191      * @return String field name
192      */
193     @Override
194     public String getGroupBy() {
195         return this.groupBy;
196     }
197 
198     /**
199      * get group by ordering
200      * @return order ('ASCENDING' | 'DESCENDING')
201      */
202     @Override
203     public String getGroupByOrder() {
204         return this.groupByOrder;
205     }
206 
207     /**
208      * sort
209      * @param collection
210      * @return sorted collection
211      */
212     protected Collection doSort(Collection collection) {
213         if(!(collection instanceof List)){
214             log.warn("can sort only collections of type {} but got a {}", List.class, collection.getClass());
215             return collection;
216         }
217         List list = (List) collection;
218         if (StringUtils.isNotEmpty(this.getGroupBy())) {
219             ListComparator comparator = newComparator();
220             comparator.setSortBy(this.getGroupBy());
221             comparator.setOrder(this.getGroupByOrder());
222             Collections.sort(list, comparator);
223         }
224         if (StringUtils.isNotEmpty(this.getGroupBy()) && StringUtils.isNotEmpty(this.getSortBy())) { // sub sort
225             ListComparator comparator = newComparator();
226             comparator.setPreSort(this.getGroupBy());
227             comparator.setSortBy(this.getSortBy());
228             comparator.setOrder(this.getSortByOrder());
229             Collections.sort(list, comparator);
230         }
231         if (StringUtils.isEmpty(this.getGroupBy()) && StringUtils.isNotEmpty(this.getSortBy())) {
232             ListComparator comparator = newComparator();
233             comparator.setSortBy(this.getSortBy());
234             comparator.setOrder(this.getSortByOrder());
235             Collections.sort(list, comparator);
236         }
237         return list;
238     }
239 
240     protected ListComparator newComparator() {
241         return new ListComparator();
242     }
243 
244     /**
245      * @param valueProvider the valueProvider to set
246      */
247     public void setValueProvider(ValueProvider valueProvider) {
248         this.valueProvider = valueProvider;
249     }
250 
251     /**
252      * @return the valueProvider
253      */
254     public ValueProvider getValueProvider() {
255         if (valueProvider == null) {
256             valueProvider = DefaultValueProvider.getInstance();
257         }
258         return valueProvider;
259     }
260 
261     /**
262      * Use by the list iterator to resolve the id
263      */
264     protected String resolveId(int index, Object value){
265         return Integer.toString(index);
266     }
267 
268     /**
269      * Does simple or sub ordering
270      */
271     protected class ListComparator implements Comparator {
272 
273         private String preSort;
274 
275         private String sortBy;
276 
277         private String order;
278 
279         @Override
280         public int compare(Object object, Object object1) {
281             if (StringUtils.isNotEmpty(this.sortBy) && StringUtils.isEmpty(this.preSort)) {
282                 return this.sort(object, object1);
283             }
284             else if (StringUtils.isNotEmpty(this.sortBy) && StringUtils.isNotEmpty(this.preSort)) {
285                 return this.subSort(object, object1);
286             }
287             return 0;
288         }
289 
290         /**
291          * group by
292          * @param object to be compared
293          * @param object1 to be compared
294          */
295         protected int sort(Object object, Object object1) {
296             Comparable firstKey = (Comparable) getValueProvider().getValue(this.sortBy, object);
297             Comparable secondKey = (Comparable) getValueProvider().getValue(this.sortBy, object1);
298             if (this.getOrder().equalsIgnoreCase(ASCENDING)) {
299                 return firstKey.compareTo(secondKey);
300             }
301 
302             return secondKey.compareTo(firstKey);
303         }
304 
305         /**
306          * sub sort
307          * @param object to be compared
308          * @param object1 to be compared
309          */
310         protected int subSort(Object object, Object object1) {
311             String firstKey = (String) getValueProvider().getValue(this.preSort, object);
312             String secondKey = (String) getValueProvider().getValue(this.preSort, object1);
313             Comparable subSortFirstKey = (Comparable) getValueProvider().getValue(this.sortBy, object);
314             Comparable subSortSecondKey = (Comparable) getValueProvider().getValue(this.sortBy, object1);
315             if (firstKey.equalsIgnoreCase(secondKey)) {
316                 if (this.getOrder().equalsIgnoreCase(ASCENDING)) {
317                     return subSortFirstKey.compareTo(subSortSecondKey);
318                 }
319                 return subSortSecondKey.compareTo(subSortFirstKey);
320             }
321             return -1;
322         }
323 
324         public String getPreSort() {
325             return preSort;
326         }
327 
328         public void setPreSort(String preSort) {
329             this.preSort = preSort;
330         }
331 
332         public String getSortBy() {
333             return sortBy;
334         }
335 
336         public void setSortBy(String sortBy) {
337             this.sortBy = sortBy;
338         }
339 
340         public String getOrder() {
341             if (order == null) {
342                 return ASCENDING;
343             }
344             return order;
345         }
346 
347         public void setOrder(String order) {
348             this.order = order;
349         }
350 
351     }
352 }