1 package org.andromda.cartridges.jsf.component.html;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.ListIterator;
8 import javax.faces.context.FacesContext;
9 import javax.faces.el.ValueBinding;
10 import org.apache.commons.beanutils.PropertyUtils;
11 import org.apache.commons.lang.ObjectUtils;
12 import org.apache.commons.lang.StringUtils;
13 import org.apache.myfaces.component.html.ext.HtmlDataTable;
14
15
16
17
18
19
20
21 public class HtmlExtendedDataTable
22 extends HtmlDataTable
23 {
24
25
26
27
28
29
30 public Object getValue()
31 {
32 Object value = super.getValue();
33 Object backingValue = this.getBackingValue();
34 if (backingValue != null)
35 {
36 final Class valueType = this.getValueType();
37 final Class backingValueType = this.getBackingValueType();
38 if (valueType != backingValueType)
39 {
40 throw new IllegalArgumentException("The 'value' and 'backingValue' must be of the same type");
41 }
42 final String identifierColumnsString = this.getIdentifierColumns();
43 final String[] identifierColumns =
44 StringUtils.isBlank(identifierColumnsString) ? new String[0]
45 : StringUtils.trimToEmpty(identifierColumnsString).split(
46 "\\s*,\\s*");
47
48
49 if (backingValue instanceof Collection)
50 {
51 if (!(backingValue instanceof List))
52 {
53 backingValue = new ArrayList((Collection)backingValue);
54 }
55 if (!(value instanceof List))
56 {
57 value = new ArrayList((Collection)value);
58 }
59 final List backingValues = (List)backingValue;
60 final List values = (List)value;
61 for (final ListIterator iterator = backingValues.listIterator(); iterator.hasNext();)
62 {
63 final Object backingValueItem = iterator.next();
64 for (final Iterator valueIterator = values.iterator(); valueIterator.hasNext();)
65 {
66 final Object valueItem = valueIterator.next();
67 if (this.equal(
68 backingValueItem,
69 valueItem,
70 identifierColumns))
71 {
72 iterator.set(valueItem);
73 break;
74 }
75 }
76 }
77 value = backingValues;
78 }
79
80
81 else if (backingValue.getClass().isArray())
82 {
83 final Object[] backingValues = (Object[])backingValue;
84 final Object[] values = value != null ? (Object[])value : new Object[0];
85 for (int backingValueCtr = 0; backingValueCtr < backingValues.length; backingValueCtr++)
86 {
87 final Object backingValueItem = backingValues[backingValueCtr];
88 for (int valueCtr = 0; valueCtr < values.length; valueCtr++)
89 {
90 final Object valueItem = values[valueCtr];
91 if (this.equal(
92 backingValueItem,
93 valueItem,
94 identifierColumns))
95 {
96 backingValues[backingValueCtr] = valueItem;
97 break;
98 }
99 }
100 }
101 value = backingValues;
102 }
103 else
104 {
105 throw new IllegalArgumentException("The backing value must be a collection or array");
106 }
107 }
108 this.updateModelValue(value);
109 return value;
110 }
111
112
113
114
115
116
117
118
119
120
121 private boolean equal(
122 final Object object1,
123 final Object object2,
124 final String[] properties)
125 {
126 boolean equal = object1 == object2;
127 if (!equal && object1 != null && object2 != null)
128 {
129 for (int ctr = 0; ctr < properties.length; ctr++)
130 {
131 final String property = properties[ctr];
132 if (StringUtils.isNotBlank(property))
133 {
134 final Object value1 = this.getProperty(
135 object1,
136 property);
137 final Object value2 = this.getProperty(
138 object2,
139 property);
140 if (value1 != null && value2 != null)
141 {
142 equal = value1.equals(value2);
143 if (!equal)
144 {
145 break;
146 }
147 }
148 }
149 }
150 }
151 return equal;
152 }
153
154
155
156
157
158
159 public void updateModelValue(final Object value)
160 {
161 final ValueBinding binding = getValueBinding(VALUE);
162 if (binding != null)
163 {
164 binding.setValue(
165 this.getFacesContext(),
166 value);
167 }
168 }
169
170
171
172
173 private static final String VALUE = "value";
174
175
176
177
178
179
180 private Class getBackingValueType()
181 {
182 return this.getBindingType(BACKING_VALUE);
183 }
184
185
186
187
188
189
190
191 public Class getValueType()
192 {
193 return this.getBindingType(VALUE);
194 }
195
196
197
198
199
200
201
202 private Class getBindingType(final String name)
203 {
204 Class type = null;
205 ValueBinding binding = getValueBinding(name);
206 if (binding != null)
207 {
208 final FacesContext context = this.getFacesContext();
209 type = binding.getType(context);
210 }
211 return type;
212 }
213
214 private Object getProperty(
215 final Object bean,
216 final String property)
217 {
218 try
219 {
220 return PropertyUtils.getProperty(
221 bean,
222 property);
223 }
224 catch (final Throwable throwable)
225 {
226 throw new RuntimeException(throwable);
227 }
228 }
229
230 private Object backingValue = null;
231
232
233
234
235 public static final String BACKING_VALUE = "backingValue";
236
237
238
239
240
241
242 protected Object getBackingValue()
243 {
244 if (this.backingValue == null)
245 {
246 final ValueBinding binding = this.getValueBinding(BACKING_VALUE);
247 this.backingValue = binding == null ? null : binding.getValue(getFacesContext());
248 }
249 return this.backingValue;
250 }
251
252
253
254
255 private String identifierColumns;
256
257
258
259
260 public static final String IDENTIFIER_COLUMNS = "identifierColumns";
261
262
263
264
265
266
267 protected String getIdentifierColumns()
268 {
269 if (this.identifierColumns == null)
270 {
271 this.identifierColumns = (String)this.getAttributes().get(IDENTIFIER_COLUMNS);
272 if (this.identifierColumns == null)
273 {
274 final ValueBinding binding = this.getValueBinding(IDENTIFIER_COLUMNS);
275 this.identifierColumns =
276 binding == null ? null : ObjectUtils.toString(binding.getValue(getFacesContext()));
277 }
278 }
279 return this.identifierColumns;
280 }
281 }