1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.component;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.myfaces.tobago.event.SortActionEvent;
24 import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
25 import org.apache.myfaces.tobago.internal.component.AbstractUISheet;
26 import org.apache.myfaces.tobago.model.SheetState;
27 import org.apache.myfaces.tobago.util.BeanComparator;
28 import org.apache.myfaces.tobago.util.ValueExpressionComparator;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import javax.el.ValueExpression;
33 import javax.faces.component.UIColumn;
34 import javax.faces.component.UICommand;
35 import javax.faces.component.UIComponent;
36 import javax.faces.component.UIInput;
37 import javax.faces.component.UIOutput;
38 import javax.faces.component.UISelectBoolean;
39 import javax.faces.component.UISelectMany;
40 import javax.faces.component.UISelectOne;
41 import javax.faces.context.FacesContext;
42 import javax.faces.model.DataModel;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.Comparator;
47 import java.util.List;
48
49 public class Sorter {
50
51 private static final Logger LOG = LoggerFactory.getLogger(Sorter.class);
52
53 private Comparator comparator;
54
55 public void perform(SortActionEvent sortEvent) {
56 if (LOG.isDebugEnabled()) {
57 LOG.debug("sorterId = {}", sortEvent.getComponent().getId());
58 }
59 UIColumn column = sortEvent.getColumn();
60 AbstractUISheet data = (AbstractUISheet) sortEvent.getComponent();
61
62 Object value = data.getValue();
63 if (value instanceof DataModel) {
64 value = ((DataModel) value).getWrappedData();
65 }
66 FacesContext facesContext = FacesContext.getCurrentInstance();
67 SheetState sheetState = data.getSheetState(facesContext);
68
69 Comparator actualComparator = null;
70
71 if (value instanceof List || value instanceof Object[]) {
72 String sortProperty;
73
74 try {
75 UIComponent child = getFirstSortableChild(column.getChildren());
76 if (child != null) {
77
78 String attributeName = child instanceof AbstractUICommand ? Attributes.LABEL : Attributes.VALUE;
79 if (child.getValueExpression(attributeName) != null) {
80 String var = data.getVar();
81 if (var == null) {
82 LOG.error("No sorting performed. Property var of sheet is not set!");
83 unsetSortableAttribute(column);
84 return;
85 }
86 String expressionString = child.getValueExpression(attributeName).getExpressionString();
87 if (isSimpleProperty(expressionString)) {
88 if (expressionString.startsWith("#{")
89 && expressionString.endsWith("}")) {
90 expressionString =
91 expressionString.substring(2,
92 expressionString.length() - 1);
93 }
94 sortProperty = expressionString.substring(var.length() + 1);
95
96 actualComparator = new BeanComparator(
97 sortProperty, comparator, !sheetState.isAscending());
98
99 if (LOG.isDebugEnabled()) {
100 LOG.debug("Sort property is {}", sortProperty);
101 }
102 } else {
103
104 boolean descending = !sheetState.isAscending();
105 ValueExpression expression = child.getValueExpression("value");
106 actualComparator = new ValueExpressionComparator(facesContext, var, expression, descending, comparator);
107 }
108 } else {
109 LOG.error("No sorting performed. No Expression target found for sorting!");
110 unsetSortableAttribute(column);
111 return;
112 }
113 } else {
114 LOG.error("No sorting performed. Value is not instanceof List or Object[]!");
115 unsetSortableAttribute(column);
116 return;
117 }
118 } catch (Exception e) {
119 LOG.error("Error while extracting sortMethod :" + e.getMessage(), e);
120 if (column != null) {
121 unsetSortableAttribute(column);
122 }
123 return;
124 }
125
126
127
128
129
130
131
132 List<Object> selectedDataRows = null;
133 if (sheetState.getSelectedRows().size() > 0) {
134 selectedDataRows = new ArrayList<Object>(sheetState.getSelectedRows().size());
135 Object dataRow;
136 for (Integer index : sheetState.getSelectedRows()) {
137 if (value instanceof List) {
138 dataRow = ((List) value).get(index);
139 } else {
140 dataRow = ((Object[]) value)[index];
141 }
142 selectedDataRows.add(dataRow);
143 }
144 }
145
146
147 if (value instanceof List) {
148 Collections.sort((List) value, actualComparator);
149 } else {
150 Arrays.sort((Object[]) value, actualComparator);
151 }
152
153
154 if (selectedDataRows != null) {
155 sheetState.getSelectedRows().clear();
156 for (Object dataRow : selectedDataRows) {
157 int index = -1;
158 if (value instanceof List) {
159 for (int i = 0; i < ((List) value).size() && index < 0; i++) {
160 if (dataRow == ((List) value).get(i)) {
161 index = i;
162 }
163 }
164 } else {
165 for (int i = 0; i < ((Object[]) value).length && index < 0; i++) {
166 if (dataRow == ((Object[]) value)[i]) {
167 index = i;
168 }
169 }
170 }
171 if (index >= 0) {
172 sheetState.getSelectedRows().add(index);
173 }
174 }
175 }
176
177 } else {
178 LOG.warn("Sorting not supported for type "
179 + (value != null ? value.getClass().toString() : "null"));
180 }
181 }
182
183
184
185 boolean isSimpleProperty(String expressionString) {
186 if (expressionString.startsWith("#{") && expressionString.endsWith("}")) {
187 String inner = expressionString.substring(2, expressionString.length() - 1);
188 String[] parts = StringUtils.split(inner, ".");
189 for (String part : parts) {
190 if (!StringUtils.isAlpha(part)) {
191 return false;
192 }
193 }
194 return true;
195 }
196 return false;
197 }
198
199 private void unsetSortableAttribute(UIColumn uiColumn) {
200 LOG.warn("removing attribute sortable from column " + uiColumn.getId());
201 uiColumn.getAttributes().put(Attributes.SORTABLE, Boolean.FALSE);
202 }
203
204 private UIComponent getFirstSortableChild(List<UIComponent> children) {
205 UIComponent result = null;
206
207 for (UIComponent child : children) {
208 result = child;
209 if (child instanceof UISelectMany
210 || child instanceof UISelectOne
211 || child instanceof UISelectBoolean
212 || (child instanceof AbstractUICommand && child.getChildren().isEmpty())
213 || (child instanceof UIInput && RendererTypes.HIDDEN.equals(child.getRendererType()))) {
214 continue;
215
216 }
217 if (child instanceof UIOutput) {
218 break;
219 }
220 if (child instanceof UICommand
221 || child instanceof javax.faces.component.UIPanel) {
222 child = getFirstSortableChild(child.getChildren());
223 if (child instanceof UIOutput) {
224 break;
225 }
226 }
227 }
228 return result;
229 }
230
231 public Comparator getComparator() {
232 return comparator;
233 }
234
235 public void setComparator(Comparator comparator) {
236 this.comparator = comparator;
237 }
238 }
239