1 // WARNING: This file was automatically generated. Do not edit it directly,
2 // or you will lose your changes.
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22 package org.apache.myfaces.trinidad.component;
23
24 import java.io.IOException;
25 import java.util.AbstractMap;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import javax.faces.component.UIComponent;
33 import javax.faces.component.visit.VisitCallback;
34 import javax.faces.component.visit.VisitContext;
35 import javax.faces.context.FacesContext;
36 import javax.faces.event.AbortProcessingException;
37 import javax.faces.event.PhaseId;
38 import javax.faces.render.Renderer;
39 import org.apache.myfaces.trinidad.bean.FacesBean;
40 import org.apache.myfaces.trinidad.bean.PropertyKey;
41 import org.apache.myfaces.trinidad.model.CollectionModel;
42 import org.apache.myfaces.trinidad.model.LocalRowKeyIndex;
43 import org.apache.myfaces.trinidad.model.ModelUtils;
44 import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
45 import org.apache.myfaces.trinidad.util.ComponentUtils;
46
47 /**
48 *
49 * <p>UIXIterator is a component that performs iteration over its child components. It is similar to UIXTable
50 * but has no chrome.
51 * Each child is repeatedly stamped as many times as necessary.
52 * Iteration is done starting at the index given by the "first" attribute,
53 * for as many indices as specified by the "rows" attribute.
54 * If "rows" returns 0, then the iteration continues until
55 * there are no more elements in the underlying data.
56 * </p>
57 * <p>
58 * While the <tr:forEach>
59 * will be sufficient for most user's needs, it does not work with a JSF
60 * DataModel, or CollectionModel. It also cannot be bound to EL expressions that
61 * use component-managed EL variables
62 * (such as the "var" variable on an <tr:table>), because
63 * a forEach tag runs during
64 * The <tr:iterator> tag was created to
65 * address these issues.
66 * </p>
67 * <p>
68 * To list all, the benefits of UIXIterator over forEach:
69 * <ul>
70 * <li>Access to component-managed EL variables</li>
71 * <li>Full support for CollectionModel and DataModel</li>
72 * <li>Does not require creating multiple copies of children,
73 * so more memory efficient</li>
74 * <li>Much better at dealing with adding and deleting children,
75 * at least when used with a CollectionModel with a good
76 * implementation of getRowKey()</li>
77 * <li>Supports "binding", and all other forms of JSF component
78 * manipulation</li>
79 * </ul>
80 * and the negative aspects:
81 * <ul>
82 * <li>Leaves behind a component in the hierarchy, which causes
83 * problems with components like panelFormLayout that try to handle each child
84 * individually.</li>
85 * <li>Because there's only one of each child, the same limitations
86 * on "binding", etc., as apply inside a table also apply to iterator.</li>
87 * </ul>
88 * </p>
89 * <p>By default, it processes up to 25 rows. Use the rows attribute to alter this behavior.</p>
90 *
91 * <h4>Events:</h4>
92 * <table border="1" width="100%" cellpadding="3" summary="">
93 * <tr bgcolor="#CCCCFF" class="TableHeadingColor">
94 * <th align="left">Type</th>
95 * <th align="left">Phases</th>
96 * <th align="left">Description</th>
97 * </tr>
98 * <tr class="TableRowColor">
99 * <td valign="top"><code>org.apache.myfaces.trinidad.event.AttributeChangeEvent</code></td>
100 * <td valign="top" nowrap>Invoke<br>Application<br>Apply<br>Request<br>Values</td>
101 * <td valign="top">Event delivered to describe an attribute change. Attribute change events are not delivered for any programmatic change to a property. They are only delivered when a renderer changes a property without the application's specific request. An example of an attribute change event might include the width of a column that supported client-side resizing.</td>
102 * </tr>
103 * </table>
104 */
105 public class UIXIterator extends UIXCollection
106 implements LocalRowKeyIndex,
107 FlattenedComponent
108 {
109 static public final FacesBean.Type TYPE = new FacesBean.Type(
110 UIXCollection.TYPE);
111 static public final PropertyKey VAR_STATUS_KEY =
112 TYPE.registerKey("varStatus", String.class, PropertyKey.CAP_NOT_BOUND);
113 static public final PropertyKey VALUE_KEY =
114 TYPE.registerKey("value");
115 static public final PropertyKey ROWS_KEY =
116 TYPE.registerKey("rows", Integer.class, Integer.valueOf(25));
117 static public final PropertyKey FIRST_KEY =
118 TYPE.registerKey("first", Integer.class, Integer.valueOf(0));
119
120 static public final String COMPONENT_FAMILY =
121 "org.apache.myfaces.trinidad.Iterator";
122 static public final String COMPONENT_TYPE =
123 "org.apache.myfaces.trinidad.Iterator";
124
125 /**
126 * Construct an instance of the UIXIterator.
127 */
128 public UIXIterator()
129 {
130 super(null);
131 }
132
133
134 /**
135 * Override to return true.
136 */
137 @Override
138 public boolean getRendersChildren()
139 {
140 return true;
141 }
142
143 /**
144 * Sets up the iteration context for each child and processes it
145 */
146 public <S> boolean processFlattenedChildren(
147 final FacesContext context,
148 ComponentProcessingContext cpContext,
149 final ComponentProcessor<S> childProcessor,
150 final S callbackContext) throws IOException
151 {
152 boolean processedChildren;
153
154 setupFlattenedContext(context, cpContext);
155
156 try
157 {
158 // Mimic what would normally happen in the non-flattening case for encodeBegin():
159 __processFlattenedChildrenBegin();
160
161 setupFlattenedChildrenContext(context, cpContext);
162
163 try
164 {
165 Runner runner = new IndexedRunner(cpContext)
166 {
167 @Override
168 protected void process(UIComponent kid, ComponentProcessingContext cpContext) throws IOException
169 {
170 kid.pushComponentToEL(context, null);
171
172 try
173 {
174 childProcessor.processComponent(context, cpContext, kid, callbackContext);
175 }
176 finally
177 {
178 kid.popComponentFromEL(context);
179 }
180 }
181 };
182
183 processedChildren = runner.run();
184 Exception exp = runner.getException();
185 if (exp != null)
186 {
187 if (exp instanceof RuntimeException)
188 throw (RuntimeException) exp;
189
190 if (exp instanceof IOException)
191 throw (IOException) exp;
192 throw new IllegalStateException(exp);
193 }
194 }
195 finally
196 {
197 tearDownFlattenedChildrenContext(context, cpContext);
198 }
199 }
200 finally
201 {
202 tearDownFlattenedContext(context, cpContext);
203 }
204
205 return processedChildren;
206 }
207
208 /**
209 * Returns <code>true</code> if this FlattenedComponent is currently flattening its children
210 * @param context FacesContext
211 * @return <code>true</code> if this FlattenedComponent is currently flattening its children
212 */
213 public boolean isFlatteningChildren(FacesContext context)
214 {
215 // if we don't have a Renderer, then we're flattening
216 return (getRendererType() == null);
217 }
218
219 /**
220 * Repeatedly render the children as many times as needed.
221 */
222 @Override
223 public void encodeChildren(final FacesContext context)
224 throws IOException
225 {
226 if (!isRendered())
227 return;
228
229 // if this is the table there will be a rendererType:
230 if (getRendererType() != null)
231 {
232 Renderer renderer = getRenderer(context);
233 if (renderer != null)
234 {
235 renderer.encodeChildren(context, this);
236 }
237 }
238 else // this is not the table. it must be the iterator
239 {
240 Runner runner = new IndexedRunner()
241 {
242 @Override
243 protected void process(
244 UIComponent kid,
245 ComponentProcessingContext cpContext
246 ) throws IOException
247 {
248 kid.encodeAll(context);
249 }
250 };
251 runner.run();
252 Exception exp = runner.getException();
253 if (exp != null)
254 {
255 if (exp instanceof RuntimeException)
256 throw (RuntimeException) exp;
257
258 if (exp instanceof IOException)
259 throw (IOException) exp;
260 throw new IllegalStateException(exp);
261 }
262 }
263 }
264
265 /**
266 * Enhances the varStatusMap created by the super class to include:<ul>
267 * <li>begin - the index of the first row being rendered
268 * <li>first - true if the current row is the first row
269 * <li>count - indicates which iteration this is. This always starts at one,
270 * and increases (by one) as the loop progresses.
271 * <li>step - this is always one.
272 * </ul>
273 */
274 @Override
275 protected Map<String, Object> createVarStatusMap()
276 {
277 final Map<String, Object> map = super.createVarStatusMap();
278 return new AbstractMap<String, Object>()
279 {
280 @Override
281 public Object get(Object key)
282 {
283 // some of these keys are from <c:forEach>, ie:
284 // javax.servlet.jsp.jstl.core.LoopTagStatus
285 if ("begin".equals(key)) // from jstl
286 {
287 return Integer.valueOf(getFirst());
288 }
289 if ("first".equals(key)) // from jstl
290 {
291 boolean isFirst = (getFirst() == getRowIndex());
292 return Boolean.valueOf(isFirst);
293 }
294 if ("count".equals(key)) // from jstl
295 {
296 int count = getRowIndex() - getFirst() + 1;
297 return Integer.valueOf(count);
298 }
299 if ("step".equals(key)) // from jstl
300 {
301 return Integer.valueOf(1);
302 }
303 return map.get(key);
304 }
305
306 @Override
307 public Set<Map.Entry<String, Object>> entrySet()
308 {
309 return map.entrySet();
310 }
311 };
312 }
313
314 @Override
315 protected CollectionModel createCollectionModel(
316 CollectionModel current,
317 Object value)
318 {
319 CollectionModel model = ModelUtils.toCollectionModel(value);
320 // initialize to -1. we need to do this incase some application logic
321 // changed this index. Also, some JSF1.0 RI classes were initially starting
322 // with a rowIndex of 0.
323 // we need this to be -1 because of name-transformation.
324 model.setRowIndex(-1);
325 assert model.getRowIndex() == -1 : "RowIndex did not reset to -1";
326 return model;
327 }
328
329 @Override
330 protected void processFacetsAndChildren(
331 final FacesContext context,
332 final PhaseId phaseId)
333 {
334 Runner runner = new IndexedRunner()
335 {
336 @Override
337 protected void process(UIComponent kid, ComponentProcessingContext cpContext)
338 {
339 UIXIterator.this.processComponent(context, kid, phaseId);
340 }
341 };
342 runner.run();
343 }
344
345 // Extract the current row token from the clientId
346 private String _getClientToken(String clientIdPrefix, String cellClientId)
347 {
348 int tokenStartIndex = clientIdPrefix.length() + 1;
349 int tokenEndIndex = cellClientId.indexOf(':', tokenStartIndex);
350
351 if (tokenEndIndex != -1)
352 {
353 return cellClientId.substring(tokenStartIndex, tokenEndIndex);
354 }
355 else
356 {
357 return null;
358 }
359 }
360
361 @Override
362 protected boolean visitData(
363 final VisitContext visitContext,
364 final VisitCallback visitCallback)
365 {
366 Collection<String> subtreeIds = visitContext.getSubtreeIdsToVisit(this);
367
368 // create a special VisitContext that doesn't visit the Facets
369 // of column components since they aren't visited on each row
370 final VisitContext noColumnFacetContext = new NoColumnFacetsVisitContext(visitContext);
371
372 // runner to use to process the rows
373 Runner runner;
374
375 if (VisitContext.ALL_IDS.equals(subtreeIds))
376 {
377 // we're processing all of the rows, so use the indexed runner (plus, we can't call size() on
378 // the ALL_IDS collection, so we don't have a whole lot of choice here
379 runner = new IndexedRunner()
380 {
381 @Override
382 protected void process(UIComponent kid, ComponentProcessingContext cpContext)
383 {
384 if (UIXComponent.visitTree(noColumnFacetContext, kid, visitCallback))
385 {
386 throw new AbortProcessingException();
387 }
388 }
389 };
390 }
391 else
392 {
393 // We are only visiting a subset of the tree, so figure out which rows to visit
394
395 String ourClientIdPrefix = getClientId(visitContext.getFacesContext());
396
397 int subtreeIdCount = subtreeIds.size();
398
399 // build up a set of the row keys to visit rather than iterating
400 // and visiting every row
401 Set<String> rowsToVisit;
402
403 if (subtreeIdCount > 1)
404 {
405 rowsToVisit = new HashSet<String>(subtreeIdCount);
406
407 for (String currClientId : subtreeIds)
408 {
409 String clientToken = _getClientToken(ourClientIdPrefix, currClientId);
410
411 if (clientToken != null)
412 {
413 rowsToVisit.add(clientToken);
414 }
415 }
416 }
417 else
418 {
419 String clientToken = _getClientToken(ourClientIdPrefix,
420 subtreeIds.iterator().next());
421
422 if (clientToken != null)
423 {
424 rowsToVisit = Collections.singleton(clientToken);
425 }
426 else
427 {
428 rowsToVisit = Collections.emptySet();
429 }
430 }
431
432 // we didn't visit any data
433 if (rowsToVisit.isEmpty())
434 return false;
435
436 // visit only the rows we need to
437 runner = new KeyedRunner(rowsToVisit)
438 {
439 @Override
440 protected void process(
441 UIComponent kid,
442 ComponentProcessingContext cpContext
443 ) throws IOException
444 {
445 if (UIXComponent.visitTree(noColumnFacetContext, kid, visitCallback))
446 {
447 throw new AbortProcessingException();
448 }
449 }
450 };
451 }
452
453 try
454 {
455 runner.run();
456 }
457 finally
458 {
459 return (runner.getException() instanceof AbortProcessingException);
460 }
461 }
462
463 /**
464 * Abstract class for processing rows
465 */
466 private abstract class Runner implements ComponentProcessor<Object>
467 {
468 public Runner()
469 {
470 this(null);
471 }
472
473 public Runner(ComponentProcessingContext cpContext)
474 {
475 _cpContext = cpContext;
476 }
477
478 public abstract boolean run();
479
480 /**
481 * Sets up the context for the child and processes it
482 */
483 public void processComponent(
484 FacesContext context,
485 ComponentProcessingContext cpContext,
486 UIComponent component,
487 Object callbackContext) throws IOException
488 {
489 try
490 {
491 process(component, cpContext);
492 }
493 catch (IOException ioe)
494 {
495 throw ioe;
496 }
497 catch (AbortProcessingException ape)
498 {
499 // we're done, so abort
500 _exception = ape;
501 throw ape;
502 }
503 catch (Exception e)
504 {
505 _exception = e;
506 }
507 }
508
509 public Exception getException()
510 {
511 return _exception;
512 }
513
514 protected abstract void process(UIComponent comp, ComponentProcessingContext cpContext)
515 throws Exception;
516
517 protected final ComponentProcessingContext getComponentProcessingContext()
518 {
519 return _cpContext;
520 }
521
522 public final void setException(Exception e)
523 {
524 _exception = e;
525 }
526
527 private Exception _exception = null;
528
529 private final ComponentProcessingContext _cpContext;
530 }
531
532 /**
533 * Class for visiting getRows() by index rows starting getFirst()
534 */
535 private abstract class IndexedRunner extends Runner
536 {
537 public IndexedRunner()
538 {
539 this(null);
540 }
541
542 public IndexedRunner(ComponentProcessingContext cpContext)
543 {
544 super(cpContext);
545 }
546
547 public final boolean run()
548 {
549 FacesContext context = FacesContext.getCurrentInstance();
550 ComponentProcessingContext cpContext = getComponentProcessingContext();
551
552 List<UIComponent> stamps = getStamps();
553 int oldIndex = getRowIndex();
554 int first = getFirst();
555 int rows = getRows();
556 int end = (rows <= 0) //show everything
557 ? Integer.MAX_VALUE
558 : first + rows;
559
560 boolean processedChild = false;
561
562 try
563 {
564 for(int i=first; i<end; i++)
565 {
566 setRowIndex(i);
567 if (isRowAvailable())
568 {
569 // latch processedChild the first time we process a child
570 processedChild |= (cpContext != null)
571 ? UIXComponent.processFlattenedChildren(context, cpContext, this, stamps, null)
572 : UIXComponent.processFlattenedChildren(context, this, stamps, null);
573 }
574 else
575 break;
576 }
577 }
578 catch (IOException e)
579 {
580 setException(e);
581 }
582 finally
583 {
584 setRowIndex(oldIndex);
585 }
586
587 return processedChild;
588 }
589 }
590
591 /**
592 * Runner that visits the rows specified by the client row key tokens
593 */
594 private abstract class KeyedRunner extends Runner
595 {
596 public KeyedRunner(Iterable<String> clientKeys)
597 {
598 super();
599 _clientKeys = clientKeys;
600 }
601
602 public final boolean run()
603 {
604 FacesContext context = FacesContext.getCurrentInstance();
605
606 List<UIComponent> stamps = getStamps();
607 int oldIndex = getRowIndex();
608
609 boolean processedChild = false;
610
611 try
612 {
613 // need to convert row key tokens to row keys
614 ClientRowKeyManager rowKeyManager = getClientRowKeyManager();
615
616 for(String clientKey : _clientKeys)
617 {
618 Object rowKey = rowKeyManager.getRowKey(context, UIXIterator.this, clientKey);
619
620 if (rowKey != null)
621 {
622 setRowKey(rowKey);
623 if (isRowAvailable())
624 {
625 // latch processedChild the first time we process a child
626 processedChild |= UIXComponent.processFlattenedChildren(context, this, stamps, null);
627 }
628 }
629 }
630 }
631 catch (IOException e)
632 {
633 setException(e);
634 }
635 finally
636 {
637 setRowIndex(oldIndex);
638 }
639
640 return processedChild;
641 }
642
643 private final Iterable<String> _clientKeys;
644 }
645
646 @Override
647 void __encodeBegin(FacesContext context) throws IOException
648 {
649 _fixupFirst();
650 super.__encodeBegin(context);
651 }
652
653 // make sure the current range exists on the model:
654 // see bug 4143852:
655 private void _fixupFirst()
656 {
657 int first = getFirst();
658 // if we are starting from row zero then there is no problem:
659 if (first == 0)
660 return;
661
662 // Negative "first" makes no sense. Given the logic below,
663 // it forces iterator to scroll to the end unnecessarily.
664 if (first < 0)
665 {
666 setFirst(0);
667 return;
668 }
669
670 CollectionModel model = getCollectionModel();
671 int oldIndex = model.getRowIndex();
672 try
673 {
674 model.setRowIndex(first);
675 // if the starting row doesn't exist then we need to scroll back:
676 if (!model.isRowAvailable())
677 {
678 int size = model.getRowCount();
679 int rows = getRows();
680 // if the rowCount is unknown OR
681 // the blockSize is show all OR
682 // there are fewer rows than the blockSize on the table
683 // then start from the beginning:
684 if ((size <= 0) || (rows <= 0) || (size <= rows))
685 first = 0;
686 else
687 {
688 // scroll to the last page:
689 first = size - rows;
690 model.setRowIndex(first);
691 // make sure the row is indeed available:
692 if (!model.isRowAvailable())
693 {
694 // row is not available. this happens when getRowCount() lies.
695 // Some DataModel implementations seem to have rowCount methods which
696 // lie. see bug 4157186
697 first = 0;
698 }
699 }
700 setFirst(first);
701 }
702 }
703 finally
704 {
705 model.setRowIndex(oldIndex);
706 }
707 }
708
709 /**
710 * Gets <html>
711 * Name of the EL variable used to reference the varStatus information.
712 * Once this component has completed rendering, this variable is
713 * removed (or reverted back to its previous value).
714 * The VarStatus provides contextual information about the state of the
715 * component to EL expressions. For components that iterate, varStatus
716 * also provides loop counter information. Please see the this
717 * component's documentation for the specific properties on the varStatus.
718 * The common properties on varStatus include:
719 * <ul>
720 * <li>"model" - returns the CollectionModel for this component.</li>
721 * <li>"index" - returns the zero based row index.</li>
722 * <li>"hierarchicalIndex" - returns an array containing zero based row index.</li>
723 * <li>"hierarchicalLabel" - returns a string label representing 1 based index of this row.</li>
724 * <li>"rowKey" - returns the current rowKey in the collection.</li>
725 * <li>"current" - returns the current row in the collection.</li>
726 * </ul></html>
727 *
728 * @return the new varStatus value
729 */
730 final public String getVarStatus()
731 {
732 return ComponentUtils.resolveString(getProperty(VAR_STATUS_KEY));
733 }
734
735 /**
736 * Sets <html>
737 * Name of the EL variable used to reference the varStatus information.
738 * Once this component has completed rendering, this variable is
739 * removed (or reverted back to its previous value).
740 * The VarStatus provides contextual information about the state of the
741 * component to EL expressions. For components that iterate, varStatus
742 * also provides loop counter information. Please see the this
743 * component's documentation for the specific properties on the varStatus.
744 * The common properties on varStatus include:
745 * <ul>
746 * <li>"model" - returns the CollectionModel for this component.</li>
747 * <li>"index" - returns the zero based row index.</li>
748 * <li>"hierarchicalIndex" - returns an array containing zero based row index.</li>
749 * <li>"hierarchicalLabel" - returns a string label representing 1 based index of this row.</li>
750 * <li>"rowKey" - returns the current rowKey in the collection.</li>
751 * <li>"current" - returns the current row in the collection.</li>
752 * </ul></html>
753 *
754 * @param varStatus the new varStatus value
755 */
756 final public void setVarStatus(String varStatus)
757 {
758 setProperty(VAR_STATUS_KEY, (varStatus));
759 }
760
761 /**
762 * Gets the data model being used by this component.
763 * The specific model class is
764 * <code>org.apache.myfaces.trinidad.model.CollectionModel</code>.
765 *
766 * You may also use other model instances, e.g.,
767 * <code>java.util.List</code> ,
768 * array, and <code>javax.faces.model.DataModel</code>.
769 * This component will automatically convert the instance
770 * into a <code>CollectionModel</code>.
771 *
772 * @return the new value value
773 */
774 final public Object getValue()
775 {
776 return getProperty(VALUE_KEY);
777 }
778
779 /**
780 * Sets the data model being used by this component.
781 * The specific model class is
782 * <code>org.apache.myfaces.trinidad.model.CollectionModel</code>.
783 *
784 * You may also use other model instances, e.g.,
785 * <code>java.util.List</code> ,
786 * array, and <code>javax.faces.model.DataModel</code>.
787 * This component will automatically convert the instance
788 * into a <code>CollectionModel</code>.
789 *
790 * @param value the new value value
791 */
792 final public void setValue(Object value)
793 {
794 setProperty(VALUE_KEY, (value));
795 }
796
797 /**
798 * Gets the maximum number of rows to display in a single range of rows.
799 * Some ranges might have fewer
800 * than the number of rows specified by this attribute (eg: the last range
801 * might have an insufficient number of rows).
802 * To display all rows at once, set this attribute to 0.
803 * The default is 25.
804 *
805 * @return the new rows value
806 */
807 final public int getRows()
808 {
809 return ComponentUtils.resolveInteger(getProperty(ROWS_KEY), 25);
810 }
811
812 /**
813 * Sets the maximum number of rows to display in a single range of rows.
814 * Some ranges might have fewer
815 * than the number of rows specified by this attribute (eg: the last range
816 * might have an insufficient number of rows).
817 * To display all rows at once, set this attribute to 0.
818 * The default is 25.
819 *
820 * @param rows the new rows value
821 */
822 final public void setRows(int rows)
823 {
824 setProperty(ROWS_KEY, Integer.valueOf(rows));
825 }
826
827 /**
828 * Gets the index of the first row in the currently range of rows.
829 * This index is zero-based. This attribute is used to control
830 * which range of rows to display to the user.
831 *
832 * @return the new first value
833 */
834 final public int getFirst()
835 {
836 return ComponentUtils.resolveInteger(getProperty(FIRST_KEY), 0);
837 }
838
839 /**
840 * Sets the index of the first row in the currently range of rows.
841 * This index is zero-based. This attribute is used to control
842 * which range of rows to display to the user.
843 *
844 * @param first the new first value
845 */
846 final public void setFirst(int first)
847 {
848 setProperty(FIRST_KEY, Integer.valueOf(first));
849 }
850
851 @Override
852 public String getFamily()
853 {
854 return COMPONENT_FAMILY;
855 }
856
857 @Override
858 protected FacesBean.Type getBeanType()
859 {
860 return TYPE;
861 }
862
863 /**
864 * Construct an instance of the UIXIterator.
865 */
866 protected UIXIterator(
867 String rendererType
868 )
869 {
870 super(rendererType);
871 }
872
873 static
874 {
875 TYPE.lock();
876 }
877 }