All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.omnifaces.util.selectitems.SelectItemsCollector Maven / Gradle / Ivy

There is a newer version: 4.5.1
Show newest version
/*
 * Copyright OmniFaces
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.omnifaces.util.selectitems;

import static java.lang.String.format;
import static org.omnifaces.util.Utils.isEmpty;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UISelectItem;
import jakarta.faces.component.UISelectItems;
import jakarta.faces.context.FacesContext;
import jakarta.faces.model.SelectItem;
import jakarta.faces.model.SelectItemGroup;

import org.omnifaces.el.ScopedRunner;
import org.omnifaces.model.ExtendedSelectItem;

/**
 * Collection of utility methods for collecting {@link SelectItem} instances from various sources.
 *
 * @author Arjan Tijms
 *
 */
public final class SelectItemsCollector {

	private static final String ERROR_UNKNOWN_SELECT_TYPE =
		"A value expression of type '%s' is disallowed for a select item";

	private SelectItemsCollector() {
		//
	}

	/**
	 * This method gets all select items that are expressed via {@link UISelectItem} or {@link UISelectItems}
	 * children of the given parent component.
	 * 

* Note that if {@link SelectItemGroup} instances are present then those will be inserted directly in the returned list * and the using code still has to iterate over its children recursively to obtain all separate {@link SelectItem} instances. * * @param parent the parent whose children are scanned * @param context The involved faces context. * @return list of select items obtained from parent's children. */ public static List collectFromParent(FacesContext context, UIComponent parent) { List selectItems = new ArrayList<>(); // Iterate over all children of the parent component. Non-UISelectItem/s children are automatically skipped. for (UIComponent child : parent.getChildren()) { if (child instanceof UISelectItem) { UISelectItem uiSelectItem = (UISelectItem) child; selectItems.add(getFromUISelectItem(uiSelectItem)); } else if (child instanceof UISelectItems) { UISelectItems uiSelectItems = (UISelectItems) child; if (uiSelectItems.getValue() != null) { selectItems.addAll(collectFromUISelectItems(context, uiSelectItems)); } } } return selectItems; } private static SelectItem getFromUISelectItem(UISelectItem uiSelectItem) { Object value = uiSelectItem.getValue(); if (value instanceof SelectItem) { // A single SelectItem can be added directly without any further processing. return (SelectItem)value; } else if (value == null) { // No value binding specified, create a select item out of the properties of the UI component. return new ExtendedSelectItem(uiSelectItem); } else { // A value binding was specified, but of a type we don't support. throw new IllegalArgumentException(format(ERROR_UNKNOWN_SELECT_TYPE, value.getClass().toString())); } } private static Collection collectFromUISelectItems(FacesContext context, UISelectItems uiSelectItems) { Object value = uiSelectItems.getValue(); if (value instanceof SelectItem) { // A single SelectItem can be added directly without any further processing. return Collections.singleton((SelectItem) value); } else if (value instanceof Object[]) { // An array of objects is supposed to be transformed by the SelectItems iteration construct. return collectFromUISelectItemsIterator(context, uiSelectItems, Arrays.asList((Object[]) value)); } else if (value instanceof Iterable) { // An iterable (Collection, List, etc) is also supposed to be transformed by the SelectItems iteration construct. return collectFromUISelectItemsIterator(context, uiSelectItems, (Iterable) value); } else if (value instanceof Map) { // A map has its own algorithm for how it should be turned into a list of SelectItems. return SelectItemsBuilder.fromMap((Map)value); } else { // A value binding was specified, but of a type we don't support. throw new IllegalArgumentException(format(ERROR_UNKNOWN_SELECT_TYPE, value.getClass().toString())); } } /** * This method runs the algorithm expressed by a UISelectItems component that uses the var iterator construct to generate * a list of SelectItems. * * @param uiSelectItems The involved select items component. * @param items The available select items. * @param facesContext The involved faces context. * @return list of SelectItem obtained from the given parameters */ public static List collectFromUISelectItemsIterator(FacesContext facesContext, UISelectItems uiSelectItems, Iterable items) { List selectItems = new ArrayList<>(); Map attributes = uiSelectItems.getAttributes(); String var = (String) attributes.get("var"); // Helper class that's used to set the item value in (EL) scope using the name set by "var" during the iteration. // If during each iteration the value of this is changed, any value expressions in the attribute // map referring it will resolve to that particular instance. ScopedRunner scopedRunner = new ScopedRunner(facesContext); for (Object item : items) { // If the item is already a SelectItem, take it directly. // NOTE: I'm not 100% sure if this is right, since it now allows a collection to consist // out of a mix of SelectItems and non-SelectItems. Should we maybe always process the iterator // if there's a "var", "itemLabel" or "itemValue" present, or should we process the entire collection // as SelectItems if the first element is a SelectItem and throw an exception as soon as we encounter // a non-SelectItem? if (item instanceof SelectItem) { selectItems.add((SelectItem)item); continue; } if (!isEmpty(var)) { scopedRunner.with(var, item); } // During each iteration, just resolve all attributes again. scopedRunner.invoke(() -> { Object itemValue = getItemValue(attributes, item); Object noSelectionValue = attributes.get("noSelectionValue"); boolean itemValueIsNoSelectionValue = noSelectionValue != null && noSelectionValue.equals(itemValue); selectItems.add(new SelectItem( itemValue, getItemLabel(attributes, itemValue), getItemDescription(attributes), getBooleanAttribute(attributes, "itemDisabled", false), getBooleanAttribute(attributes, "itemLabelEscaped", true), getBooleanAttribute(attributes, "noSelectionOption", false) || itemValueIsNoSelectionValue )); }); } return selectItems; } /** * Gets the optional value. It defaults to the item itself if not specified. * * @param attributes the attributes from which the label is fetched. * @param item default value if no item value present * @return the value, or the item if none is present */ private static Object getItemValue(Map attributes, Object item) { Object itemValue = attributes.get("itemValue"); if (itemValue == null) { itemValue = item; } return itemValue; } /** * Gets the optional label. It defaults to the item value if not specified. * * @param attributes the attributes from which the label is fetched. * @param itemValue default value if no item value present * @return the label, or the item value if none present */ private static String getItemLabel(Map attributes, Object itemValue) { Object itemLabelObj = attributes.get("itemLabel"); String itemLabel; if (itemLabelObj != null) { itemLabel = itemLabelObj.toString(); } else { itemLabel = itemValue.toString(); } return itemLabel; } /** * Gets the optional description. * * @param attributes the attributes from which the description is fetched. * @return the description, or null if none present. */ private static String getItemDescription(Map attributes) { Object itemDescriptionObj = attributes.get("itemDescription"); String itemDescription = null; if (itemDescriptionObj != null) { itemDescription = itemDescriptionObj.toString(); } return itemDescription; } /** * Gets the name boolean attribute. It defaults to false if not specified. * @param attributes the attributes from which the attribute is fetched. * @param key name of the attribute * @return the boolean represented by the attribute or false if there's no such attribute */ private static boolean getBooleanAttribute(Map attributes, String key, boolean defaultValue) { Object valueObj = attributes.get(key); boolean value = defaultValue; if (valueObj != null) { value = Boolean.parseBoolean(valueObj.toString()); } return value; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy