/* * 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 * * http://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 com.asual.summer.core.faces; import java.beans.BeanInfo; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.el.ValueExpression; import javax.faces.application.Resource; import javax.faces.component.UIComponent; import javax.faces.component.UINamingContainer; import javax.faces.component.UIViewRoot; import javax.faces.component.behavior.ClientBehaviorHolder; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import org.jboss.el.lang.EvaluationContext; import org.jboss.el.lang.ExpressionBuilder; import com.asual.summer.core.ErrorResolver; import com.asual.summer.core.util.BeanUtils; import com.asual.summer.core.util.RequestUtils; import com.asual.summer.core.util.StringUtils; import com.sun.faces.facelets.el.TagValueExpression; import com.sun.faces.facelets.tag.jsf.ComponentSupport; /** * * @author Rostislav Hristov * */ public class ComponentUtils { final static String ATTRIBUTES = "^-?\\d.*$|idx|varAttr|com.sun.faces.facelets.APPLIED|javax.faces.retargetablehandlers"; static Object getConfig(Component component, String name) { BeanInfo info = (BeanInfo) component.getAttributes().get(UIComponent.BEANINFO_KEY); if (info != null) { TagValueExpression ve = (TagValueExpression) info.getBeanDescriptor().getValue(name); if (ve != null) { return ve.getValue(FacesContext.getCurrentInstance().getELContext()); } } return null; } static String getChildrenText(Component component) { List<String> strings = new ArrayList<String>(); Iterator<UIComponent> fac = component.getFacetsAndChildren(); while (fac.hasNext()) { UIComponent value = fac.next().findComponent("value"); for (UIComponent child : value.getChildren()) { strings.add(child.toString()); } } return StringUtils.join(strings, ""); } static String getValueId(Component component) { try { ValueExpression value = component.getBindings().get("value"); ValueExpression dataValue = component.getBindings().get("dataValue"); try { FacesContext context = FacesContext.getCurrentInstance(); RepeatComponent repeatComponent = getRepeatComponent(component); String componentTag = (String) repeatComponent.getAttributes().get(FacesDecorator.QNAME); if (componentTag != null) { return getExprId(repeatComponent.getBindings().get("dataValue").getExpressionString()) + UINamingContainer.getSeparatorChar(context) + value.getValue(context.getELContext()); } } catch (Exception e) {} if (dataValue != null) { return getExprId(dataValue.getExpressionString()); } if (value == null) { return getExprId(getChildrenText(component)); } return getExprId(value.getExpressionString()); } catch (Exception e) {} return null; } static RepeatComponent getRepeatComponent(Component component) { UIComponent parent = component.getParent(); if (parent instanceof RepeatComponent) { return (RepeatComponent) parent; } else { return getRepeatComponent((Component) parent); } } static String getClientId(Component component) { ValueExpression ve = component.getBindings().get("idx"); if (ve != null) { return (String) ve.getValue(FacesContext.getCurrentInstance().getELContext()); } String id = component.getId(); if (!id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) { return id; } String name = getAttrValue(component, "name"); if (StringUtils.isEmpty(name)) { String valueId = getValueId(component); if (valueId != null) { return valueId; } } return id; } static String getComponentClass(Component component) { return (String) getConfig(component, "componentClass"); } static List<String> getComponentClasses(Component component) { List<String> classes = new ArrayList<String>(); String componentClass = getComponentClass(component); if (!StringUtils.isEmpty(componentClass)) { classes.add(componentClass); } String styleClass = (String) component.getAttributes().get("styleClass"); if (!StringUtils.isEmpty(styleClass)) { classes.add(styleClass); } return classes; } static String getValue(UIComponent component) { return (String) ExpressionBuilder.createNode(component.getChildren().get(0).toString()) .getValue(new EvaluationContext(FacesContext.getCurrentInstance().getELContext(), null, null)); } static String getAttrValue(Component component, String key) { Object value = component.getAttributes().get(key); if (value == null) { ValueExpression expr = component.getBindings().get(key); if (expr != null) { value = expr.getValue(new EvaluationContext(FacesContext.getCurrentInstance().getELContext(), null, null)); } } if (value != null) { return value.toString(); } return null; } static String getFormId(Component component) { String id = component.getClientId(); String name = ComponentUtils.getAttrValue(component, "name"); if ((StringUtils.isEmpty(id) || id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) && StringUtils.isEmpty(name)) { id = ComponentUtils.getValueId(component); } if (!StringUtils.isEmpty(id) && !id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) { return id; } return null; } static String getFormName(Component component) { String name = ComponentUtils.getAttrValue(component, "name"); if (!StringUtils.isEmpty(name)) { return name; } try { return ComponentUtils.getExprId(ComponentUtils.getRepeatComponent(component).getBindings().get("dataValue").getExpressionString()); } catch (Exception e) { return getFormId(component); } } static boolean shouldWriteIdAttribute(Component component, String id) { String componentTag = getComponentTag((UIComponent) component); return (id != null && (isComponentWrapper((UIComponent) component) || componentTag != null) && !"option".equals(componentTag) && (!id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX) || ((component instanceof ClientBehaviorHolder) && !((ClientBehaviorHolder) component).getClientBehaviors().isEmpty()))); } static String getComponentTag(UIComponent component) { if (component instanceof RepeatComponent) { return (String) component.getAttributes().get(FacesDecorator.QNAME); } else { return (String) ComponentUtils.getConfig((Component) component, "componentTag"); } } static boolean isComponentWrapper(UIComponent component) { Object config = ComponentUtils.getConfig((Component) component, "componentWrapper"); if (config != null) { return config instanceof String ? Boolean.valueOf((String) config) : Boolean.valueOf((Boolean) config); } return false; } static Map<String, Object> getAttributes(Component component, String name) { Map<String, Object> attrs = new HashMap<String, Object>(component.getAttributes()); String id = component.getClientId(); if (shouldWriteIdAttribute(component, id)) { attrs.put("id", id); } Map<String, ValueExpression> bindings = component.getBindings(); for (String key : bindings.keySet()) { if (ComponentUtils.shouldWriteAttribute(component, key)) { attrs.put(key, bindings.get(key).getValue(FacesContext.getCurrentInstance().getELContext())); } } if ("form".equals(name)) { String action = ComponentUtils.getAttrValue(component, "action"); attrs.put("action", StringUtils.isEmpty(action) ? RequestUtils.getRequestUri() : RequestUtils.contextRelative(action, true)); String method = ComponentUtils.getAttrValue(component, "method"); attrs.put("method", StringUtils.isEmpty(method) ? "get" : (RequestUtils.isMethodBrowserSupported(method) ? method : "post")); } else if ("input".equals(name)) { attrs.put("id", getFormId(component)); attrs.put("name", getFormName(component)); String type = (String) attrs.get("type"); if ("checkbox".equals(type) || "radio".equals(type)) { if (isMatch(component) && ComponentUtils.getAttrValue(component, "checked") == null) { attrs.put("checked", true); } } Map<String, Map<String, Object>> errors = BeanUtils.getBeanOfType(ErrorResolver.class).getErrors(); attrs.put("value", errors != null && errors.get(getFormId(component)) != null ? errors.get(getFormId(component)).get("value") : ComponentUtils.getAttrValue(component, "value")); } else if ("select".equals(name) || "textarea".equals(name)) { attrs.put("id", getFormId(component)); attrs.put("name", getFormName(component)); } else if ("option".equals(name)) { if (isMatch(component) && ComponentUtils.getAttrValue(component, "selected") == null) { attrs.put("selected", true); } } return attrs; } static boolean shouldWriteAttribute(Component component, String key) { return !Pattern.compile(ATTRIBUTES + "|" + FacesDecorator.ATTRIBUTES + "|" + FacesDecorator.QNAME + "|" + ComponentSupport.MARK_CREATED + "|" + Resource.COMPONENT_RESOURCE_KEY + "|" + UIComponent.BEANINFO_KEY + "|" + UIComponent.FACETS_KEY + "|" + UIComponent.VIEW_LOCATION_KEY, Pattern.CASE_INSENSITIVE).matcher(key).matches(); } static Object contextAttribute(String name, Object value) { if (value != null && "data-ajax-url".equalsIgnoreCase(name) || "href".equalsIgnoreCase(name) || "src".equalsIgnoreCase(name)) { return RequestUtils.contextRelative(value.toString(), true); } return value; } static void writeAttribute(ResponseWriter writer, String name, Object value) throws IOException { if (value != null && !"rendered".equalsIgnoreCase(name) && !"styleClass".equalsIgnoreCase(name)) { writer.writeAttribute(name, contextAttribute(name, value), null); } } static String getExprId(String expr) { List<String> values = Arrays.asList(expr.trim().replaceAll("^(\\$|#)\\{|\\}$", "").split("\\.")); if (values.size() > 1) { return StringUtils.join(values.subList(1, values.size()), "."); } else if (values.size() > 0) { return values.get(0); } return null; } static boolean isMatch(Component component) { try { RepeatComponent repeatComponent = getRepeatComponent(component); Map<String, ValueExpression> bindings = repeatComponent.getBindings(); FacesContext context = FacesContext.getCurrentInstance(); Object dataValue = bindings.get("dataValue").getValue(context.getELContext()); Map<String, Map<String, Object>> errors = BeanUtils.getBeanOfType(ErrorResolver.class).getErrors(); if (errors != null && errors.get(getFormName(component)) != null) { dataValue = errors.get(getFormName(component)).get("value"); } Object valueAttr = RequestUtils.getAttribute(repeatComponent.getVar()); if (dataValue instanceof List<?>) { return ((List<?>) dataValue).contains(valueAttr); } else if (dataValue instanceof Boolean) { return dataValue.equals(Boolean.valueOf(valueAttr.toString())); } else { return dataValue.equals(valueAttr); } } catch (Exception e) { return false; } } static boolean isStyleOrScript(String nodeName) { return "style".equals(nodeName) || "script".equals(nodeName); } }