/*
* Copyright 2011-2012 Blazebit
*/
package com.blazebit.blazefaces.util;
import com.blazebit.blazefaces.apt.JsfFunction;
import com.blazebit.blazefaces.component.Widget;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIInput;
import javax.faces.component.UISelectItem;
import javax.faces.component.UISelectItems;
import javax.faces.component.UniqueIdVendor;
import javax.faces.component.ValueHolder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import javax.faces.validator.BeanValidator;
public class ComponentUtils {
/**
* Algorithm works as follows; - If it's an input component, submitted value
* is checked first since it'd be the value to be used in case validation
* errors terminates jsf lifecycle - Finally the value of the component is
* retrieved from backing bean and if there's a converter, converted value
* is returned
*
* @param context FacesContext instance
* @param component UIComponent instance whose value will be returned
* @return End text
*/
public static String getValueToRender(FacesContext context, UIComponent component) {
if (component instanceof ValueHolder) {
if (component instanceof EditableValueHolder) {
Object submittedValue = ((EditableValueHolder) component).getSubmittedValue();
if (submittedValue != null) {
return submittedValue.toString();
}
}
ValueHolder valueHolder = (ValueHolder) component;
Object value = valueHolder.getValue();
//format the value as string
if (value != null) {
Converter converter = getConverter(context, valueHolder);
if (converter != null) {
return converter.getAsString(context, component, value);
} else {
return value.toString(); //Use toString as a fallback if there is no explicit or implicit converter
}
} else {
//component is a value holder but has no value
return null;
}
}
//component it not a value holder
return null;
}
/**
* Finds appropriate converter for a given value holder
*
* @param context FacesContext instance
* @param component ValueHolder instance to look converter for
* @return Converter
*/
public static Converter getConverter(FacesContext context, ValueHolder component) {
//explicit converter
Converter converter = component.getConverter();
//try to find implicit converter
if (converter == null) {
ValueExpression expr = ((UIComponent) component).getValueExpression("value");
if (expr != null) {
Class<?> valueType = expr.getType(context.getELContext());
if (valueType != null) {
converter = context.getApplication().createConverter(valueType);
}
}
}
return converter;
}
/**
* Algorithm works as follows; - If it's an input component, submitted value
* is checked first since it'd be the value to be used in case validation
* errors terminates jsf lifecycle - Finally the value of the component is
* retrieved from backing bean and if there's a converter, converted value
* is returned
*
* - If the component is not a value holder, toString of component is used
* to support Facelets UIInstructions.
*
* @param context FacesContext instance
* @param component UIComponent instance whose value will be returned
* @return End text
*/
public static String getStringValueToRender(FacesContext facesContext, UIComponent component) {
if (component instanceof ValueHolder) {
if (component instanceof EditableValueHolder) {
Object submittedValue = ((EditableValueHolder) component).getSubmittedValue();
if (submittedValue != null) {
return submittedValue.toString();
}
}
ValueHolder valueHolder = (ValueHolder) component;
Object value = valueHolder.getValue();
if (value == null) {
return "";
}
//first ask the converter
if (valueHolder.getConverter() != null) {
return valueHolder.getConverter().getAsString(facesContext, component, value);
} //Try to guess
else {
ValueExpression expr = component.getValueExpression("value");
if (expr != null) {
Class<?> valueType = expr.getType(facesContext.getELContext());
if (valueType != null) {
Converter converterForType = facesContext.getApplication().createConverter(valueType);
if (converterForType != null) {
return converterForType.getAsString(facesContext, component, value);
}
}
}
}
//No converter found just return the value as string
return value.toString();
} else {
//This would get the plain texts on UIInstructions when using Facelets
String value = component.toString();
if (value != null) {
return value.trim();
} else {
return "";
}
}
}
/**
* Resolves the end text to render by using a specified value
*
* @param context FacesContext instance
* @param component UIComponent instance whose value will be returned
* @return End text
*/
public static String getStringValueToRender(FacesContext facesContext, UIComponent component, Object value) {
if (value == null) {
return null;
}
ValueHolder valueHolder = (ValueHolder) component;
Converter converter = valueHolder.getConverter();
if (converter != null) {
return converter.getAsString(facesContext, component, value);
} else {
ValueExpression expr = component.getValueExpression("value");
if (expr != null) {
Class<?> valueType = expr.getType(facesContext.getELContext());
Converter converterForType = facesContext.getApplication().createConverter(valueType);
if (converterForType != null) {
return converterForType.getAsString(facesContext, component, value);
}
}
}
return value.toString();
}
@JsfFunction
public static UIComponent findParentForm(FacesContext context, UIComponent component) {
UIComponent parent = component.getParent();
while (parent != null) {
if (parent instanceof UIForm) {
return parent;
}
parent = parent.getParent();
}
return null;
}
public static UniqueIdVendor findParentUniqueIdVendor(UIComponent component) {
UIComponent parent = component.getParent();
while (parent != null) {
if (parent instanceof UniqueIdVendor) {
return (UniqueIdVendor) parent;
}
parent = parent.getParent();
}
return null;
}
public static UIComponent findParentNamingContainer(UIComponent component) {
UIComponent parent = component.getParent();
while (parent != null) {
if (parent instanceof NamingContainer) {
return (UIComponent) parent;
}
parent = parent.getParent();
}
return null;
}
public static void decorateAttribute(UIComponent component, String attribute, String value) {
String attributeValue = (String) component.getAttributes().get(attribute);
if (attributeValue != null) {
if (attributeValue.indexOf(value) == -1) {
String decoratedValue = attributeValue + ";" + value;
component.getAttributes().put(attribute, decoratedValue);
} else {
component.getAttributes().put(attribute, attributeValue);
}
} else {
component.getAttributes().put(attribute, value);
}
}
@SuppressWarnings("unchecked")
public static List<SelectItem> createSelectItems(UIComponent component) {
List<SelectItem> items = new ArrayList<SelectItem>();
Iterator<UIComponent> children = component.getChildren().iterator();
while (children.hasNext()) {
UIComponent child = children.next();
if (child instanceof UISelectItem) {
UISelectItem selectItem = (UISelectItem) child;
items.add(new SelectItem(selectItem.getItemValue(), selectItem.getItemLabel()));
} else if (child instanceof UISelectItems) {
Object selectItems = ((UISelectItems) child).getValue();
if (selectItems instanceof SelectItem[]) {
SelectItem[] itemsArray = (SelectItem[]) selectItems;
for (SelectItem item : itemsArray) {
items.add(new SelectItem(item.getValue(), item.getLabel()));
}
} else if (selectItems instanceof Collection) {
Collection<SelectItem> collection = (Collection<SelectItem>) selectItems;
for (SelectItem item : collection) {
items.add(new SelectItem(item.getValue(), item.getLabel()));
}
}
}
}
return items;
}
public static String escapeJQueryId(String id) {
return "#" + id.replaceAll(":", "\\\\\\\\:");
}
public static String findClientIds(FacesContext facesContext, UIComponent component, String idList) {
if (idList == null) {
return "@none";
}
StringBuilder sb = new StringBuilder();
String[] ids = idList.split("[,\\s]+");
for (int i = 0; i < ids.length; i++) {
if (i != 0) {
sb.append(" ");
}
String id = ids[i].trim();
if (id.equals("@all") || id.equals("@none")) {
sb.append(id);
} else if (id.equals("@this")) {
sb.append(component.getClientId(facesContext));
} else if (id.equals("@form")) {
UIComponent form = ComponentUtils.findParentForm(facesContext, component);
if (form == null) {
throw new FacesException("Component " + component.getClientId(facesContext) + " needs to be enclosed in a form");
}
sb.append(form.getClientId(facesContext));
} else if (id.equals("@parent")) {
sb.append(component.getParent().getClientId(facesContext));
} else {
UIComponent comp = component.findComponent(id);
if (comp != null) {
sb.append(comp.getClientId(facesContext));
} else {
throw new FacesException("Cannot find component with identifier \"" + id + "\" referenced from \"" + component.getClientId(facesContext) + "\".");
}
}
}
return sb.toString();
}
@JsfFunction(name = "component")
public static String findComponentClientId(String id) {
UIComponent component = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
component = findComponent(facesContext.getViewRoot(), id);
if (component == null) {
throw new FacesException("Cannot find component " + id + " in view.");
}
return component.getClientId(facesContext);
}
public static UIComponent findComponent(UIComponent base, String id) {
if (id.equals(base.getId())) {
return base;
}
UIComponent kid = null;
UIComponent result = null;
Iterator<UIComponent> kids = base.getFacetsAndChildren();
while (kids.hasNext() && (result == null)) {
kid = (UIComponent) kids.next();
if (id.equals(kid.getId())) {
result = kid;
break;
}
result = findComponent(kid, id);
if (result != null) {
break;
}
}
return result;
}
@JsfFunction(name = "widgetVar")
public static String getWidgetVar(String id) {
UIComponent component = findComponent(FacesContext.getCurrentInstance().getViewRoot(), id);
if(component == null) {
throw new FacesException("Cannot find component " + id + " in view.");
} else if(component instanceof Widget) {
return ((Widget) component).resolveWidgetVar();
} else {
throw new FacesException("Component with id " + id + " is not a Widget");
}
}
public static boolean isLiteralText(UIComponent component) {
return component.getFamily().equalsIgnoreCase("facelets.LiteralText");
}
public static boolean componentIsDisabledOrReadonly(UIComponent component) {
return Boolean.valueOf(String.valueOf(component.getAttributes().get("disabled"))) || Boolean.valueOf(String.valueOf(component.getAttributes().get("readonly")));
}
/**
* Implementation from Apache Commons Lang
*/
public static Locale toLocale(String str) {
if (str == null) {
return null;
}
int len = str.length();
if (len != 2 && len != 5 && len < 7) {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
if (ch0 < 'a' || ch0 > 'z' || ch1 < 'a' || ch1 > 'z') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
if (len == 2) {
return new Locale(str, "");
} else {
if (str.charAt(2) != '_') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
char ch3 = str.charAt(3);
if (ch3 == '_') {
return new Locale(str.substring(0, 2), "", str.substring(4));
}
char ch4 = str.charAt(4);
if (ch3 < 'A' || ch3 > 'Z' || ch4 < 'A' || ch4 > 'Z') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
if (len == 5) {
return new Locale(str.substring(0, 2), str.substring(3, 5));
} else {
if (str.charAt(5) != '_') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
return new Locale(str.substring(0, 2), str.substring(3, 5), str.substring(6));
}
}
}
public static boolean validateEmptyFields(FacesContext context) {
ExternalContext externalContext = context.getExternalContext();
String value = externalContext.getInitParameter(UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME);
if (null == value) {
value = (String) externalContext.getApplicationMap().get(UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME);
}
if (value == null || value.equals("auto")) {
return isBeansValidationAvailable(context);
} else {
return Boolean.valueOf(value);
}
}
public static boolean isBeansValidationAvailable(FacesContext context) {
boolean result = false;
String beanValidationAvailableKey = "javax.faces.private.BEANS_VALIDATION_AVAILABLE";
Map<String, Object> appMap = context.getExternalContext().getApplicationMap();
if (appMap.containsKey(beanValidationAvailableKey)) {
result = (Boolean) appMap.get(beanValidationAvailableKey);
} else {
try {
new BeanValidator();
appMap.put(beanValidationAvailableKey, result = true);
} catch (Throwable t) {
appMap.put(beanValidationAvailableKey, Boolean.FALSE);
}
}
return result;
}
public static boolean isPartialSubmitEnabled(FacesContext context) {
ExternalContext externalContext = context.getExternalContext();
String value = externalContext.getInitParameter(Constants.SUBMIT_PARAM);
return (value == null) ? false : value.equalsIgnoreCase("partial");
}
public static boolean isValueBlank(String value) {
if (value == null) {
return true;
}
return value.trim().equals("");
}
}