com.sun.faces.renderkit.SelectItemsIterator Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.faces.renderkit;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Map;
import java.util.ListIterator;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.lang.reflect.Array;
import javax.faces.model.SelectItem;
import javax.faces.context.FacesContext;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItem;
import javax.faces.component.UISelectItems;
import javax.faces.component.UISelectMany;
import javax.faces.component.UISelectOne;
/**
* Package private class for iterating over the set of {@link SelectItem}s
* for a parent {@link UISelectMany} or {@link UISelectOne}.
*
* // RELEASE_PENDING (rlubke,driscoll) performanc review
*/
public final class SelectItemsIterator implements Iterator {
// ------------------------------------------------------------ Constructors
/**
* Construct an iterator instance for the specified parent component.
*
* @param ctx the {@link FacesContext} for the current request
* @param parent The parent {@link UIComponent} whose children will be
* processed
*/
public SelectItemsIterator(FacesContext ctx, UIComponent parent) {
kids = parent.getChildren().listIterator();
this.ctx = ctx;
}
// ------------------------------------------------------ Instance Variables
/**
* Iterator over the SelectItem elements pointed at by a
* UISelectItems
component, or null
.
*/
private ComponentAwareSelectItemIterator items;
/**
* Iterator over the children of the parent component.
*/
private ListIterator kids;
/**
* Expose single SelectItems via an Iterator. This iterator will be
* reset/reused for each individual SelectItem instance encountered.
*/
private SingleElementIterator singleItemIterator;
/**
* The {@link FacesContext} for the current request.
*/
private FacesContext ctx;
// -------------------------------------------------------- Iterator Methods
/**
* Return true
if the iteration has more elements.
*/
public boolean hasNext() {
if (items != null) {
if (items.hasNext()) {
return (true);
} else {
items = null;
}
}
Object next = findNextValidChild();
while (next != null) {
initializeItems(next);
if (items != null) {
return true;
} else {
next = findNextValidChild();
}
}
return false;
}
/**
* Return the next element in the iteration.
*
* @throws NoSuchElementException if there are no more elements
*/
@SuppressWarnings({"unchecked"})
public SelectItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
if (items != null) {
return (items.next());
}
return next();
}
public UIComponent currentSelectComponent() {
UIComponent result = items.currentSelectComponent();
return result;
}
/**
* Throw UnsupportedOperationException.
*/
public void remove() {
throw new UnsupportedOperationException();
}
// --------------------------------------------------------- Private Methods
/**
*
* Initializes the items
instance variable with an
* Iterator
appropriate to the UISelectItem(s) value.
*
*/
private void initializeItems(Object kid) {
if (kid instanceof UISelectItem) {
UISelectItem ui = (UISelectItem) kid;
SelectItem item = (SelectItem) ui.getValue();
if (item == null) {
item = new SelectItem(ui.getItemValue(),
ui.getItemLabel(),
ui.getItemDescription(),
ui.isItemDisabled(),
ui.isItemEscaped(),
ui.isNoSelectionOption());
}
updateSingeItemIterator(ui, item);
items = singleItemIterator;
} else if (kid instanceof UISelectItems) {
UISelectItems ui = (UISelectItems) kid;
Object value = ui.getValue();
if (value != null) {
if (value instanceof SelectItem) {
updateSingeItemIterator(ui, (SelectItem) value);
items = singleItemIterator;
} else if (value.getClass().isArray()) {
items = new ArrayIterator(ctx, (UISelectItems) kid, value);
} else if (value instanceof Iterable) {
items = new IterableItemIterator(ctx,
(UISelectItems) kid,
(Iterable) value);
} else if (value instanceof Map) {
items = new MapIterator((Map) value, ui.getParent());
} else {
throw new IllegalArgumentException();
}
}
if (items != null && !items.hasNext()) {
items = null;
}
}
}
/**
* @return the next valid child for processing
*/
private Object findNextValidChild() {
if (kids.hasNext()) {
Object next = kids.next();
while (kids.hasNext() && !(next instanceof UISelectItem || next instanceof UISelectItems)) {
next = kids.next();
}
if (next instanceof UISelectItem || next instanceof UISelectItems) {
return next;
}
}
return null;
}
/**
* Update the singleItemIterator
with the provided
* item
* @param item the {@link SelectItem} to expose as an Iterator
*/
private void updateSingeItemIterator(UIComponent selectComponent, SelectItem item) {
if (singleItemIterator == null) {
singleItemIterator = new SingleElementIterator();
}
singleItemIterator.updateItem(selectComponent, item);
}
// ---------------------------------------------------------- Nested Classes
/**
* Exposes single {@link SelectItem} instances as an Iterator.
*/
private static final class SingleElementIterator implements ComponentAwareSelectItemIterator {
private SelectItem item;
private transient UIComponent selectComponent;
private boolean nextCalled;
// ----------------------------------------------- Methods from ComponentAwareSelectItemIterator
public UIComponent currentSelectComponent() {
return selectComponent;
}
// ----------------------------------------------- Methods from Iterator
public boolean hasNext() {
return !nextCalled;
}
public SelectItem next() {
if (nextCalled) {
throw new NoSuchElementException();
}
nextCalled = true;
return item;
}
public void remove() {
throw new UnsupportedOperationException();
}
// ----------------------------------------------------- Private Methods
private void updateItem(UIComponent selectComponent, SelectItem item) {
this.item = item;
this.selectComponent = selectComponent;
nextCalled = false;
}
} // END SingleElementIterator
/**
* Iterates over a Map
of values exposing each entry as a SelectItem.
* Note that this will do so re-using the same SelectItem but changing
* the value and label as appropriate.
*/
private static final class MapIterator implements ComponentAwareSelectItemIterator {
private SelectItem item = new SelectItem();
private Iterator iterator;
private transient UIComponent parent;
// -------------------------------------------------------- Constructors
private MapIterator(Map map, UIComponent parent) {
this.iterator = map.entrySet().iterator();
this.parent = parent;
}
// ----------------------------------------------- Methods from ComponentAwareSelectItemIterator
public UIComponent currentSelectComponent() {
return parent;
}
// ----------------------------------------------- Methods from Iterator
public boolean hasNext() {
return iterator.hasNext();
}
public SelectItem next() {
Map.Entry entry = (Map.Entry) iterator.next();
Object key = entry.getKey();
Object value = entry.getValue();
item.setLabel(((key != null) ? key.toString() : value.toString()));
item.setValue(((value != null) ? value : ""));
return item;
}
public void remove() {
throw new UnsupportedOperationException();
}
} // END MapIterator
/**
*
* Base class to support iterating over Collections or Arrays that may
* or may not contain SelectItem
instances.
*
*/
private static abstract class GenericObjectSelectItemIterator implements ComponentAwareSelectItemIterator {
/**
* SelectItem that is updated based on the current Object being
* iterated over.
*/
private GenericObjectSelectItem genericObjectSI;
/**
* The source UISelectItems
.
*/
protected transient UISelectItems sourceComponent;
// -------------------------------------------------------- Constructors
protected GenericObjectSelectItemIterator(UISelectItems sourceComponent) {
this.sourceComponent = sourceComponent;
}
// -------------------------------------------------------- Constructors
public UIComponent currentSelectComponent() {
return sourceComponent;
}
// --------------------------------------------------- Protected Methods
protected SelectItem getSelectItemFor(FacesContext ctx, Object value) {
if (genericObjectSI == null) {
genericObjectSI = new GenericObjectSelectItem(sourceComponent);
}
genericObjectSI.updateItem(ctx, value);
return genericObjectSI;
}
// ------------------------------------------------------ Nested Classes
/**
* A SelectItem
implementation to support generating
* unique SelectItem
values based on ValueExpressions
* from the owning {@link UISelectItems} instance.
*/
@SuppressWarnings({"serial"})
private static final class GenericObjectSelectItem extends SelectItem {
private static final String VAR = "var";
private static final String ITEM_VALUE = "itemValue";
private static final String ITEM_LABEL = "itemLabel";
private static final String ITEM_DESCRIPTION = "itemDescription";
private static final String ITEM_ESCAPED = "itemLabelEscaped";
private static final String ITEM_DISABLED = "itemDisabled";
private static final String NO_SELECTION_OPTION = "noSelectionOption";
private static final String NO_SELECTION_VALUE = "noSelectionValue";
/**
* The request-scoped variable under which the current object
* will be exposed.
*/
private String var;
private UISelectItems sourceComponent;
// -------------------------------------------------------- Constructors
private GenericObjectSelectItem(UISelectItems sourceComponent) {
var = (String) sourceComponent.getAttributes().get(VAR);
this.sourceComponent = sourceComponent;
}
// ----------------------------------------------------- Private Methods
/**
* Updates the SelectItem
properties based on the
* current value.
*
* @param ctx the {@link FacesContext} for the current request
* @param value the value to build the updated values from
*/
private void updateItem(FacesContext ctx, Object value) {
Map reqMap =
ctx.getExternalContext().getRequestMap();
Object oldVarValue = null;
if (var != null) {
oldVarValue = reqMap.put(var, value);
}
try {
Map attrs = sourceComponent.getAttributes();
Object itemValueResult = attrs.get(ITEM_VALUE);
Object itemLabelResult = attrs.get(ITEM_LABEL);
Object itemDescriptionResult = attrs.get(ITEM_DESCRIPTION);
Object itemEscapedResult = attrs.get(ITEM_ESCAPED);
Object itemDisabledResult = attrs.get(ITEM_DISABLED);
Object noSelectionValueResult = attrs.get(NO_SELECTION_VALUE);
Object noSelectionOptionResult = attrs.get(NO_SELECTION_OPTION);
setValue(((itemValueResult != null) ? itemValueResult : value));
setLabel(((itemLabelResult != null)
? itemLabelResult.toString()
: value.toString()));
setDescription(((itemDescriptionResult != null)
? itemDescriptionResult.toString()
: null));
setEscape(((itemEscapedResult != null)
? Boolean.valueOf(itemEscapedResult.toString())
: true));
setDisabled(((itemDisabledResult != null)
? Boolean.valueOf(itemDisabledResult.toString())
: false));
if (null != noSelectionOptionResult) {
setNoSelectionOption(Boolean.valueOf(noSelectionOptionResult.toString()));
} else if (null != noSelectionValueResult) {
setNoSelectionOption(getValue().equals(noSelectionValueResult));
}
} finally {
if (var != null) {
if (oldVarValue != null) {
reqMap.put(var, oldVarValue);
} else {
reqMap.remove(var);
}
}
}
}
// --------------------------------------- Methods from Serializable
private void writeObject(ObjectOutputStream out) throws IOException {
throw new NotSerializableException();
}
private void readObject(ObjectInputStream in) throws IOException {
throw new NotSerializableException();
}
} // END GenericObjectSelectItem
} // END GenericObjectSelectItemIterator
private static interface ComponentAwareSelectItemIterator extends Iterator {
public UIComponent currentSelectComponent();
}
/**
* Handles arrays of SelectItem
s, generic Objects,
* or combintations of both.
*
* A single GenericObjectSelectItem
will be leverage for any
* non-SelectItem
objects encountered.
*/
private static final class ArrayIterator extends GenericObjectSelectItemIterator {
private FacesContext ctx;
private Object array;
private int count;
private int index;
// -------------------------------------------------------- Constructors
private ArrayIterator(FacesContext ctx,
UISelectItems sourceComponent,
Object array) {
super(sourceComponent);
this.ctx = ctx;
this.array = array;
count = Array.getLength(array);
}
// ----------------------------------------------- Methods from Iterator
public boolean hasNext() {
return (index < count);
}
public SelectItem next() {
if (index >= count) {
throw new NoSuchElementException();
}
Object item = Array.get(array, index++);
if (item instanceof SelectItem) {
return (SelectItem) item;
} else {
return getSelectItemFor(ctx, item);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
} // END ArrayIterator
/**
* Handles Collections of SelectItem
s, generic Objects,
* or combintations of both.
*
* A single GenericObjectSelectItem
will be leverage for any
* non-SelectItem
objects encountered.
*/
private static final class IterableItemIterator extends GenericObjectSelectItemIterator {
private FacesContext ctx;
private Iterator iterator;
// -------------------------------------------------------- Constructors
private IterableItemIterator(FacesContext ctx,
UISelectItems sourceComponent,
Iterable iterable) {
super(sourceComponent);
this.ctx = ctx;
this.iterator = iterable.iterator();
}
// ----------------------------------------------- Methods from Iterator
public boolean hasNext() {
return iterator.hasNext();
}
public SelectItem next() {
Object item = iterator.next();
if (item instanceof SelectItem) {
return (SelectItem) item;
} else {
return getSelectItemFor(ctx, item);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
} // END CollectionItemIterator
}