View Javadoc

1   /*
2    * $Id: GridServerSort.java,v 1.4.10.1 2010/12/23 10:21:09 flefevere Exp $
3    * 
4    */
5   package org.rcfaces.core.internal.tools;
6   
7   import java.util.ArrayList;
8   import java.util.Comparator;
9   import java.util.Date;
10  import java.util.HashMap;
11  import java.util.HashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.faces.FacesException;
17  import javax.faces.component.UIColumn;
18  import javax.faces.component.UIComponent;
19  import javax.faces.component.ValueHolder;
20  import javax.faces.context.FacesContext;
21  import javax.faces.event.FacesListener;
22  import javax.faces.model.DataModel;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.rcfaces.core.component.capability.ISortEventCapability;
27  import org.rcfaces.core.event.SortEvent;
28  import org.rcfaces.core.internal.capability.IGridComponent;
29  import org.rcfaces.core.internal.listener.IScriptListener;
30  import org.rcfaces.core.internal.listener.SortActionListener;
31  import org.rcfaces.core.model.IRangeDataModel;
32  import org.rcfaces.core.model.ISortedComponent;
33  
34  /**
35   * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
36   * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
37   */
38  public final class GridServerSort {
39      private static final String REVISION = "$Revision: 1.4.10.1 $";
40  
41      private static final Log LOG = LogFactory.getLog(GridServerSort.class);
42  
43      private static final Long LONG_0 = new Long(0l);
44  
45      private static final Double DOUBLE_0 = new Double(0.0);
46  
47      private static final Map SORT_ALIASES = new HashMap(8);
48  
49      static {
50          SORT_ALIASES.put(ISortEventCapability.SORT_INTEGER, new SortLong());
51          SORT_ALIASES.put(ISortEventCapability.SORT_NUMBER, new SortDouble());
52          SORT_ALIASES.put(ISortEventCapability.SORT_ALPHA, new SortAlpha());
53          SORT_ALIASES.put(ISortEventCapability.SORT_ALPHA_IGNORE_CASE,
54                  new SortAlphaIgnoreCase());
55          SORT_ALIASES.put(ISortEventCapability.SORT_TIME, new SortDate());
56          SORT_ALIASES.put(ISortEventCapability.SORT_DATE, new SortDate());
57      }
58  
59      public static int[] computeSortedTranslation(FacesContext facesContext,
60              IGridComponent data, DataModel dataModel,
61              ISortedComponent sortedComponents[]) {
62  
63          ISortMethod sortMethods[] = new ISortMethod[sortedComponents.length];
64  
65          for (int i = 0; i < sortMethods.length; i++) {
66              UIColumn columnComponent = (UIColumn) sortedComponents[i]
67                      .getComponent();
68  
69              if ((columnComponent instanceof ISortEventCapability) == false) {
70                  continue;
71              }
72  
73              sortMethods[i] = getSortMethod(
74                      (ISortEventCapability) columnComponent, data);
75          }
76  
77          int rowCount = data.getRowCount();
78  
79          List datas[] = new List[sortedComponents.length];
80          for (int i = 0; i < datas.length; i++) {
81              if (rowCount > 0) {
82                  datas[i] = new ArrayList(rowCount);
83  
84              } else {
85                  datas[i] = new ArrayList();
86              }
87          }
88  
89          if (dataModel instanceof IRangeDataModel) {
90              // Charge tout !
91              ((IRangeDataModel) dataModel).setRowRange(0, rowCount);
92          }
93  
94          try {
95              for (int rowIndex = 0;; rowIndex++) {
96                  data.setRowIndex(rowIndex);
97  
98                  if (data.isRowAvailable() == false) {
99                      break;
100                 }
101 
102                 Object rowData = null;
103                 boolean rowDataInitialized = false;
104 
105                 for (int i = 0; i < datas.length; i++) {
106                     UIComponent column = sortedComponents[i].getComponent();
107 
108                     Object value = null;
109 
110                     if (column instanceof ValueHolder) {
111                         value = ValuesTools.getValue(column);
112                     }
113 
114                     ISortMethod sortMethod = sortMethods[i];
115                     value = sortMethod
116                             .convertValue(facesContext, column, value);
117 
118                     if (value == null) {
119                         if (rowDataInitialized == false) {
120                             rowDataInitialized = true;
121 
122                             rowData = data.getRowData();
123                         }
124                         // Avoid crahes when compare
125                         // then WHY get the full row Data when the column value is null ?
126                         if (rowData instanceof Comparable) {
127                             value = rowData;
128                         }
129                     }
130 
131                     datas[i].add(value);
132                 }
133             }
134         } finally {
135             data.setRowIndex(-1);
136         }
137 
138         int translations[] = new int[datas[0].size()];
139         for (int i = 0; i < translations.length; i++) {
140             translations[i] = i;
141         }
142         if (translations.length < 2) {
143             return translations;
144         }
145 
146         Object ds[][] = new Object[datas.length][];
147         Comparator comparators[] = new Comparator[datas.length];
148         boolean sortOrders[] = new boolean[datas.length];
149         for (int i = 0; i < ds.length; i++) {
150             ds[i] = datas[i].toArray();
151 
152             ISortMethod sortMethod = sortMethods[i];
153             if (sortMethod == null) {
154                 throw new FacesException("No sort method #" + i + " for grid '"
155                         + ((UIComponent) data).getId() + "' of view '"
156                         + facesContext.getViewRoot().getViewId() + "'");
157             }
158 
159             comparators[i] = sortMethod.getComparator();
160             sortOrders[i] = sortedComponents[i].isAscending();
161         }
162 
163         for (int i = 0; i < translations.length; i++) {
164 
165             next_element: for (int j = i; j > 0; j--) {
166                 int j0 = translations[j - 1];
167                 int j1 = translations[j];
168 
169                 for (int k = 0; k < sortMethods.length; k++) {
170                     Object o1 = ds[k][j0];
171                     Object o2 = ds[k][j1];
172 
173                     if (comparators[k] == null) {
174                         continue;
175                     }
176 
177                     int order = comparators[k].compare(o1, o2);
178                     if (order == 0) {
179                         continue;
180                     }
181 
182                     if (sortOrders[k]) {
183                         if (order < 0) {
184                             break next_element;
185                         }
186                     } else if (order > 0) {
187                         break next_element;
188                     }
189 
190                     translations[j] = j0;
191                     translations[j - 1] = j1;
192                     continue next_element;
193                 }
194             }
195         }
196 
197         if (LOG.isDebugEnabled()) {
198             Set set2 = new HashSet(translations.length);
199             LOG.debug("Valid SORT translation ...");
200             for (int i = 0; i < translations.length; i++) {
201                 if (set2.add(new Integer(translations[i])) == false) {
202 
203                     LOG.debug("*** INVALID TRANSLATION ***");
204                     continue;
205                 }
206             }
207         }
208 
209         return translations;
210     }
211 
212     private static ISortMethod getSortMethod(
213             ISortEventCapability columnComponent, IGridComponent gridComponent) {
214 
215         FacesListener facesListeners[] = columnComponent.listSortListeners();
216 
217         for (int j = 0; j < facesListeners.length; j++) {
218             FacesListener facesListener = facesListeners[j];
219 
220             // Priorité coté JAVASCRIPT, on verra le serveur dans un
221             // deuxieme temps ...
222             if (facesListener instanceof SortActionListener) {
223                 return new SortAction((SortActionListener) facesListener,
224                         (UIComponent) columnComponent, gridComponent);
225             }
226 
227             if ((facesListener instanceof IScriptListener) == false) {
228                 continue;
229             }
230 
231             IScriptListener scriptListener = (IScriptListener) facesListener;
232 
233             ISortMethod sortMethod = (ISortMethod) SORT_ALIASES
234                     .get(scriptListener.getCommand());
235             if (sortMethod == null) {
236                 continue;
237             }
238 
239             return sortMethod;
240         }
241 
242         return null;
243     }
244 
245     /**
246      * 
247      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
248      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
249      */
250     private interface ISortMethod {
251 
252         Comparator getComparator();
253 
254         Object convertValue(FacesContext facesContext, UIComponent component,
255                 Object value);
256 
257     }
258 
259     /**
260      * 
261      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
262      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
263      */
264     private static abstract class AbstractSortMethod implements ISortMethod,
265             Comparator {
266         private static final String REVISION = "$Revision: 1.4.10.1 $";
267 
268         public Comparator getComparator() {
269             return this;
270         }
271 
272         public int compare(Object o1, Object o2) {
273             if (o1 == null) {
274                 return (o2 == null) ? 0 : -1;
275 
276             } else if (o2 == null) {
277                 return 1;
278             }
279 
280             return ((Comparable) o1).compareTo(o2);
281         }
282     }
283 
284     /**
285      * 
286      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
287      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
288      */
289     private static class SortLong extends AbstractSortMethod {
290 
291         private static final String REVISION = "$Revision: 1.4.10.1 $";
292 
293         public Object convertValue(FacesContext facesContext,
294                 UIComponent component, Object value) {
295             if (value == null) {
296                 return LONG_0;
297             }
298 
299             if (value instanceof Number) {
300                 return value;
301             }
302 
303             if (value instanceof String) {
304                 String s = (String) value;
305                 if (s.length() < 1) {
306                     return LONG_0;
307                 }
308 
309                 long l = Long.parseLong(s);
310                 if (l == 0l) {
311                     return LONG_0;
312                 }
313 
314                 return new Long(l);
315             }
316 
317             return LONG_0;
318         }
319     }
320 
321     /**
322      * 
323      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
324      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
325      */
326     private static class SortDouble extends AbstractSortMethod {
327         private static final String REVISION = "$Revision: 1.4.10.1 $";
328 
329         public Object convertValue(FacesContext facesContext,
330                 UIComponent component, Object value) {
331             if (value == null) {
332                 return DOUBLE_0;
333             }
334 
335             if (value instanceof Number) {
336                 return value;
337             }
338 
339             if (value instanceof String) {
340                 String s = (String) value;
341                 if (s.length() < 1) {
342                     return DOUBLE_0;
343                 }
344 
345                 double d = Double.parseDouble(s);
346                 if (d == 0.0) {
347                     return DOUBLE_0;
348                 }
349 
350                 return new Double(d);
351             }
352 
353             return DOUBLE_0;
354         }
355     }
356 
357     /**
358      * 
359      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
360      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
361      */
362     private static class SortAlpha extends AbstractSortMethod {
363         private static final String REVISION = "$Revision: 1.4.10.1 $";
364 
365         public Object convertValue(FacesContext facesContext,
366                 UIComponent component, Object value) {
367             if (value == null) {
368                 return "";
369             }
370 
371             if (value instanceof String) {
372                 return value;
373             }
374 
375             value = ValuesTools.valueToString(value, component, facesContext);
376 
377             if (value == null) {
378                 return "";
379             }
380 
381             return value;
382         }
383     }
384 
385     /**
386      * 
387      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
388      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
389      */
390     private static class SortAlphaIgnoreCase extends AbstractSortMethod {
391         private static final String REVISION = "$Revision: 1.4.10.1 $";
392 
393         public Object convertValue(FacesContext facesContext,
394                 UIComponent component, Object value) {
395             if (value == null) {
396                 return "";
397             }
398 
399             if (value instanceof String) {
400                 return ((String) value).toLowerCase();
401             }
402 
403             value = ValuesTools.valueToString(value, component, facesContext);
404             if (value == null) {
405                 return "";
406             }
407 
408             return ((String) value).toLowerCase();
409         }
410     }
411 
412     /**
413      * 
414      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
415      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
416      */
417     private static class SortDate extends AbstractSortMethod {
418         private static final String REVISION = "$Revision: 1.4.10.1 $";
419 
420         public Object convertValue(FacesContext facesContext,
421                 UIComponent component, Object value) {
422             if (value == null) {
423                 return null;
424             }
425 
426             if (value instanceof Date) {
427                 return value;
428             }
429 
430             throw new FacesException(
431                     "Invalid Date for \"date\" sort method ! (class="
432                             + value.getClass() + " object=" + value + ")");
433         }
434     }
435 
436     /**
437      * 
438      * @author Olivier Oeuillot (latest modification by $Author: flefevere $)
439      * @version $Revision: 1.4.10.1 $ $Date: 2010/12/23 10:21:09 $
440      */
441     private static class SortAction extends AbstractSortMethod {
442         private static final String REVISION = "$Revision: 1.4.10.1 $";
443 
444         private final Comparator comparator;
445 
446         private final SortEvent.ISortConverter converter;
447 
448         public SortAction(SortActionListener listener,
449                 UIComponent dataColumnComponent, IGridComponent dataModel) {
450             SortEvent sortEvent = new SortEvent(dataColumnComponent, dataModel);
451 
452             listener.processSort(sortEvent);
453 
454             comparator = sortEvent.getSortComparator();
455             if (comparator == null) {
456                 throw new FacesException("Comparator of sortEvent is NULL !");
457             }
458 
459             converter = sortEvent.getSortConverter();
460         }
461 
462         public Object convertValue(FacesContext facesContext,
463                 UIComponent component, Object value) {
464             if (converter == null) {
465                 return value;
466             }
467 
468             return converter.convertValue(facesContext, component, value);
469         }
470 
471         public Comparator getComparator() {
472             return comparator;
473         }
474     }
475 }