1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.datalist;
20
21 import java.util.Collection;
22 import java.util.Iterator;
23 import java.util.Map;
24
25 import javax.el.ValueExpression;
26 import javax.faces.FacesException;
27 import javax.faces.component.ContextCallback;
28 import javax.faces.component.UIComponent;
29 import javax.faces.component.UINamingContainer;
30 import javax.faces.component.visit.VisitCallback;
31 import javax.faces.component.visit.VisitContext;
32 import javax.faces.component.visit.VisitResult;
33 import javax.faces.context.FacesContext;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.myfaces.component.UserRoleAware;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class AbstractHtmlDataList
55 extends org.apache.myfaces.component.html.ext.HtmlDataTableHack
56 implements UserRoleAware
57 {
58 public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataList";
59 private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.List";
60
61 private static Log log = LogFactory.getLog(AbstractHtmlDataList.class);
62 private static final int PROCESS_DECODES = 1;
63 private static final int PROCESS_VALIDATORS = 2;
64 private static final int PROCESS_UPDATES = 3;
65 private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
66
67 private transient FacesContext _facesContext;
68
69
70
71
72
73
74 public void processDecodes(FacesContext context)
75 {
76
77 if (context == null)
78 throw new NullPointerException("context");
79 if (!isRendered())
80 return;
81
82 setRowIndex(-1);
83 processChildren(context, PROCESS_DECODES);
84 setRowIndex(-1);
85 try
86 {
87 decode(context);
88 }
89 catch (RuntimeException e)
90 {
91 context.renderResponse();
92 throw e;
93 }
94 }
95
96 public void processUpdates(FacesContext context)
97 {
98 if (context == null)
99 throw new NullPointerException("context");
100 if (!isRendered())
101 return;
102
103 setRowIndex(-1);
104 processChildren(context, PROCESS_UPDATES);
105 setRowIndex(-1);
106 checkUpdateModelError(context);
107 }
108
109 public void processValidators(FacesContext context)
110 {
111 if (context == null)
112 throw new NullPointerException("context");
113 if (!isRendered())
114 return;
115
116 setRowIndex(-1);
117 processChildren(context, PROCESS_VALIDATORS);
118 setRowIndex(-1);
119 checkUpdateModelError(context);
120 }
121
122
123
124
125
126
127 public void processChildren(FacesContext context, int processAction)
128 {
129
130 int first = getFirst();
131 int rows = getRows();
132 int last = rows == 0 ? getRowCount() : first + rows;
133
134 if (log.isTraceEnabled())
135 {
136 log.trace("processing " + getChildCount()
137 + " children: starting at " + first
138 + ", ending at " + last);
139 }
140
141 for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++)
142 {
143
144 setRowIndex(rowIndex);
145
146 if (!isRowAvailable())
147 {
148 if (log.isTraceEnabled())
149 {
150 log.trace("scrolled past the last row, aborting");
151 }
152 break;
153 }
154
155 for (Iterator it = getChildren().iterator(); it.hasNext();)
156 {
157 UIComponent child = (UIComponent) it.next();
158 if (child.isRendered())
159 process(context, child, processAction);
160 }
161 }
162 }
163
164
165
166
167
168 private void process(FacesContext context, UIComponent component,
169 int processAction)
170 {
171 switch (processAction)
172 {
173 case PROCESS_DECODES:
174 component.processDecodes(context);
175 break;
176 case PROCESS_VALIDATORS:
177 component.processValidators(context);
178 break;
179 case PROCESS_UPDATES:
180 component.processUpdates(context);
181 break;
182 }
183 }
184
185 public void setRowIndex(int rowIndex)
186 {
187 super.setRowIndex(rowIndex);
188 String rowIndexVar = getRowIndexVar();
189 String rowCountVar = getRowCountVar();
190 if (rowIndexVar != null || rowCountVar != null)
191 {
192 Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
193 if (rowIndex >= 0)
194 {
195
196 if (rowIndexVar != null)
197 {
198 requestMap.put(getRowIndexVar(), new Integer(rowIndex));
199 }
200 if (rowCountVar != null)
201 {
202 requestMap.put(getRowCountVar(), new Integer(getRowCount()));
203 }
204 }
205 else
206 {
207
208 if (rowIndexVar != null)
209 {
210 requestMap.remove(getRowIndexVar());
211 }
212 if (rowCountVar != null)
213 {
214 requestMap.remove(getRowCountVar());
215 }
216 }
217 }
218 }
219
220 @Override
221 protected void restoreDescendantComponentStates(Object state)
222 {
223 restoreDescendantComponentStates(getChildren().iterator(), state, true);
224 }
225
226 @Override
227 protected Object saveDescendantComponentStates()
228 {
229 return saveDescendantComponentStates(getChildren().iterator(), true);
230 }
231
232 @Override
233 protected Map<String,Object> saveFullDescendantComponentStates(FacesContext facesContext)
234 {
235 return saveFullDescendantComponentStates(facesContext, null, getChildren().iterator(), true, getContainerClientId(facesContext));
236 }
237
238 @Override
239 protected void restoreFullDescendantComponentStates(FacesContext facesContext, Object initialState)
240 {
241 restoreFullDescendantComponentStates(facesContext, getChildren().iterator(), initialState, true);
242 }
243
244 @Override
245 protected void restoreFullDescendantComponentDeltaStates(FacesContext facesContext,
246 Map<String, Object> rowState, Object initialState)
247 {
248 restoreFullDescendantComponentDeltaStates(facesContext, getChildren().iterator(), rowState, initialState, true, getContainerClientId(facesContext));
249 }
250
251 @Override
252 protected Collection<Object[]> saveDescendantInitialComponentStates(FacesContext facesContext)
253 {
254 return saveDescendantInitialComponentStates(facesContext, getChildren().iterator(), true);
255 }
256
257 @Override
258 public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
259 throws FacesException
260 {
261 if (context == null || clientId == null || callback == null)
262 {
263 throw new NullPointerException();
264 }
265
266 final String baseClientId = getClientId(context);
267
268
269 boolean returnValue = baseClientId.equals(clientId);
270
271 boolean isCachedFacesContext = isTemporalFacesContext();
272 if (!isCachedFacesContext)
273 {
274 setTemporalFacesContext(context);
275 }
276
277 pushComponentToEL(context, this);
278 try
279 {
280 if (returnValue)
281 {
282 try
283 {
284 callback.invokeContextCallback(context, this);
285 return true;
286 }
287 catch (Exception e)
288 {
289 throw new FacesException(e);
290 }
291 }
292
293
294 for (Iterator<UIComponent> it = this.getFacets().values().iterator(); !returnValue && it.hasNext();)
295 {
296 returnValue = it.next().invokeOnComponent(context, clientId, callback);
297 }
298
299 if (returnValue)
300 {
301 return returnValue;
302 }
303
304
305 if (clientId.startsWith(baseClientId))
306 {
307
308
309 char separator = UINamingContainer.getSeparatorChar(context);
310 ValueExpression rowKeyVE = getValueExpression("rowKey");
311 boolean rowKeyFound = false;
312
313 if (rowKeyVE != null)
314 {
315 int oldRow = this.getRowIndex();
316 try
317 {
318
319 int rowsToProcess = getRows();
320
321 if (rowsToProcess == 0)
322 {
323 rowsToProcess = getRowCount();
324 }
325 int rowIndex = getFirst();
326 for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
327 {
328 setRowIndex(rowIndex);
329 if (!isRowAvailable())
330 {
331 break;
332 }
333
334 if (clientId.startsWith(getContainerClientId(context)))
335 {
336 rowKeyFound = true;
337 break;
338 }
339 }
340
341 if (rowKeyFound)
342 {
343 for (Iterator<UIComponent> it1 = getChildren().iterator();
344 !returnValue && it1.hasNext();)
345 {
346
347 returnValue = it1.next().invokeOnComponent(context, clientId, callback);
348 }
349 }
350 }
351 finally
352 {
353 this.setRowIndex(oldRow);
354 }
355 }
356
357
358 if (rowKeyVE == null && clientId.matches(baseClientId + separator+"[0-9]+"+separator+".*"))
359 {
360 String subId = clientId.substring(baseClientId.length() + 1);
361 String clientRow = subId.substring(0, subId.indexOf(separator));
362
363
364 int oldRow = this.getRowIndex();
365
366
367 try
368 {
369
370
371 this.setRowIndex(Integer.parseInt(clientRow));
372
373
374 if (!isRowAvailable())
375 {
376 return false;
377 }
378
379 for (Iterator<UIComponent> it1 = getChildren().iterator();
380 !returnValue && it1.hasNext();)
381 {
382
383 returnValue = it1.next().invokeOnComponent(context, clientId, callback);
384 }
385 }
386 finally
387 {
388
389
390 this.setRowIndex(oldRow);
391 }
392 }
393 }
394 }
395 finally
396 {
397
398 popComponentFromEL(context);
399 if (!isCachedFacesContext)
400 {
401 setTemporalFacesContext(null);
402 }
403 }
404
405 return returnValue;
406 }
407
408 @Override
409 public boolean visitTree(VisitContext context, VisitCallback callback)
410 {
411 if (!isVisitable(context))
412 {
413 return false;
414 }
415
416 boolean isTemporalFacesContext = isTemporalFacesContext();
417 if (!isTemporalFacesContext)
418 {
419 setTemporalFacesContext(context.getFacesContext());
420 }
421
422 int oldRowIndex = getRowIndex();
423
424 setRowIndex(-1);
425
426 pushComponentToEL(context.getFacesContext(), this);
427 try
428 {
429 VisitResult visitResult = context.invokeVisitCallback(this,
430 callback);
431 switch (visitResult)
432 {
433
434 case COMPLETE:
435 return true;
436
437 case REJECT:
438 return false;
439
440
441 default:
442
443 Collection<String> subtreeIdsToVisit = context
444 .getSubtreeIdsToVisit(this);
445 boolean doVisitChildren = subtreeIdsToVisit != null
446 && !subtreeIdsToVisit.isEmpty();
447 if (doVisitChildren)
448 {
449
450 for (UIComponent facet : getFacets().values())
451 {
452 if (facet.visitTree(context, callback))
453 {
454 return true;
455 }
456 }
457 Boolean skipIterationHint = (Boolean) context.getFacesContext().getAttributes().get(SKIP_ITERATION_HINT);
458 if (skipIterationHint != null && skipIterationHint.booleanValue())
459 {
460
461 if (getChildCount() > 0) {
462 for (UIComponent child : getChildren()) {
463 if (child.visitTree(context, callback)) {
464 return true;
465 }
466 }
467 }
468 }
469 else
470 {
471
472 int rowsToProcess = getRows();
473
474 if (rowsToProcess == 0)
475 {
476 rowsToProcess = getRowCount();
477 }
478 int rowIndex = getFirst();
479 for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
480 {
481 setRowIndex(rowIndex);
482 if (!isRowAvailable())
483 {
484 return false;
485 }
486
487 for (UIComponent child : getChildren())
488 {
489 if (child.visitTree(context, callback))
490 {
491 return true;
492 }
493 }
494 }
495 }
496 }
497 }
498 }
499 finally
500 {
501
502 popComponentFromEL(context.getFacesContext());
503 setRowIndex(oldRowIndex);
504 if (!isTemporalFacesContext)
505 {
506 setTemporalFacesContext(null);
507 }
508 }
509
510
511 return false;
512 }
513
514 @Override
515 protected FacesContext getFacesContext()
516 {
517 if (_facesContext == null)
518 {
519 return super.getFacesContext();
520 }
521 else
522 {
523 return _facesContext;
524 }
525 }
526
527 private boolean isTemporalFacesContext()
528 {
529 return _facesContext != null;
530 }
531
532 private void setTemporalFacesContext(FacesContext facesContext)
533 {
534 _facesContext = facesContext;
535 }
536
537
538
539
540
541
542
543 public abstract String getRowCountVar();
544
545
546
547
548
549
550
551 public abstract String getRowIndexVar();
552
553
554
555
556
557
558
559
560
561
562
563
564 public abstract String getLayout();
565
566
567
568
569
570
571 public abstract String getItemStyleClass();
572
573
574
575
576
577
578 public abstract String getItemOnClick();
579 }