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

com.sun.faces.el.CompositeComponentAttributesELResolver Maven / Gradle / Ivy

Go to download

This is the master POM file for Oracle's Implementation of the JSF 2.2 Specification.

There is a newer version: 2.4.0
Show newest version
/*
 * 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.el;

import java.beans.FeatureDescriptor;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.HashMap;
import java.util.logging.Logger;

import javax.el.ELResolver;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.el.MethodExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.el.CompositeComponentExpressionHolder;

import com.sun.faces.util.Util;
import com.sun.faces.component.CompositeComponentStackManager;
import static com.sun.faces.component.CompositeComponentStackManager.StackType.TreeCreation;
import static com.sun.faces.component.CompositeComponentStackManager.StackType.Evaluation;
import com.sun.faces.util.FacesLogger;

import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;

/**
 * 

* This {@link ELResolver} will handle the resolution of attrs * when processing a composite component instance. *

*/ public class CompositeComponentAttributesELResolver extends ELResolver { // Log instance for this class private static final Logger LOGGER = FacesLogger.CONTEXT.getLogger(); /** * Implicit object related only to the cc implicitObject. */ private static final String COMPOSITE_COMPONENT_ATTRIBUTES_NAME = "attrs"; /** * Implicit object related only to the cc implicit object * and refers to the composite component parent (if any). */ private static final String COMPOSITE_COMPONENT_PARENT_NAME = "parent"; /** * Key to which we store the mappings between composite component instances * and their ExpressionEvalMap. */ private static final String EVAL_MAP_KEY = CompositeComponentAttributesELResolver.class.getName() + "_EVAL_MAP"; // ------------------------------------------------- Methods from ELResolver /** *

* If base is a composite component and property * is attrs, return a new ExpressionEvalMap * which wraps the composite component's attributes map. *

* *

* The ExpressionEvalMap simple evaluates any {@link ValueExpression} * instances stored in the composite component's attribute map and returns * the result. *

* *

* If base is a composite component and property * is parent attempt to resolve the composite componet parent * of the current composite component by calling * {@link UIComponent#getCompositeComponentParent(javax.faces.component.UIComponent)}) * and returning that value. *

* * @see javax.el.ELResolver#getValue(javax.el.ELContext, Object, Object) * @see com.sun.faces.el.CompositeComponentAttributesELResolver.ExpressionEvalMap */ public Object getValue(ELContext context, Object base, Object property) { Util.notNull("context", context); if (base != null && (base instanceof UIComponent) && UIComponent.isCompositeComponent((UIComponent) base) && property != null) { String propertyName = property.toString(); if (COMPOSITE_COMPONENT_ATTRIBUTES_NAME.equals(propertyName)) { UIComponent c = (UIComponent) base; context.setPropertyResolved(true); FacesContext ctx = (FacesContext) context.getContext(FacesContext.class); return getEvalMapFor(c, ctx); } if (COMPOSITE_COMPONENT_PARENT_NAME.equals(propertyName)) { UIComponent c = (UIComponent) base; context.setPropertyResolved(true); FacesContext ctx = (FacesContext) context.getContext(FacesContext.class); CompositeComponentStackManager m = CompositeComponentStackManager.getManager(ctx); UIComponent ccp = m.getParentCompositeComponent(TreeCreation, ctx, c); if (ccp == null) { ccp = m.getParentCompositeComponent(Evaluation, ctx, c); } return ccp; } } return null; } /** *

* Readonly, so return null. *

* * @see ELResolver#getType(javax.el.ELContext, Object, Object) */ public Class getType(ELContext context, Object base, Object property) { Util.notNull("context", context); if (!(base instanceof ExpressionEvalMap && property instanceof String)) { return null; } Class exprType = null; Class metaType = null; ExpressionEvalMap evalMap = (ExpressionEvalMap) base; ValueExpression ve = evalMap.getExpression((String) property); if (ve != null) { exprType = ve.getType(context); } if (!"".equals(property)) { FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class); UIComponent cc = UIComponent.getCurrentCompositeComponent(facesContext); BeanInfo metadata = (BeanInfo) cc.getAttributes().get(UIComponent.BEANINFO_KEY); assert(null != metadata); PropertyDescriptor[] attributes = metadata.getPropertyDescriptors(); if (null != attributes) { for (PropertyDescriptor cur : attributes) { if (property.equals(cur.getName())) { Object type = cur.getValue("type"); if (null != type) { assert(type instanceof Class); metaType = (Class) type; break; } } } } } if (metaType != null) { // override exprType only if metaType is narrower: if (exprType == null || exprType.isAssignableFrom(metaType)) { context.setPropertyResolved(true); return metaType; } } return exprType; } /** *

* This is a no-op. *

* * @see ELResolver#setValue(javax.el.ELContext, Object, Object, Object) */ public void setValue(ELContext context, Object base, Object property, Object value) { Util.notNull("context", context); } /** *

* Readonly, so return true *

* * @see javax.el.ELResolver#isReadOnly(javax.el.ELContext, Object, Object) */ public boolean isReadOnly(ELContext context, Object base, Object property) { Util.notNull("context", context); return true; } /** *

* This ELResolver currently returns no feature descriptors * as we have no way to effectively iterate over the UIComponent * attributes Map. *

* * @see javax.el.ELResolver#getFeatureDescriptors(javax.el.ELContext, Object) */ public Iterator getFeatureDescriptors(ELContext context, Object base) { Util.notNull("context", context); return null; } /** *

* attrs is considered a String property. *

* * @see javax.el.ELResolver#getCommonPropertyType(javax.el.ELContext, Object) */ public Class getCommonPropertyType(ELContext context, Object base) { Util.notNull("context", context); return String.class; } // --------------------------------------------------------- Private Methods /** *

* Creates (if necessary) and caches an ExpressionEvalMap * instance associated with the owning {@link UIComponent} *

* * @param c the owning {@link UIComponent} * @param ctx the {@link FacesContext} for the current request * @return an ExpressionEvalMap for the specified component */ public Map getEvalMapFor(UIComponent c, FacesContext ctx) { Map ctxAttributes = ctx.getAttributes(); //noinspection unchecked Map> topMap = (Map>) ctxAttributes.get(EVAL_MAP_KEY); Map evalMap = null; if (topMap == null) { topMap = new HashMap>(); ctxAttributes.put(EVAL_MAP_KEY, topMap); evalMap = new ExpressionEvalMap(ctx, c); topMap.put(c, evalMap); } else { evalMap = topMap.get(c); if (evalMap == null) { evalMap = new ExpressionEvalMap(ctx, c); topMap.put(c, evalMap); } else { // JAVASERVERFACES-2508 - running as Portlet2 FacesContext must be updated for rendering, or // ExpressionEvalMap would have to be reconstructed for the second Portlet phase ((ExpressionEvalMap)evalMap).updateFacesContext(ctx); } } return evalMap; } // ---------------------------------------------------------- Nested Classes /** * Simple Map implementation to evaluate any ValueExpression * stored directly within the provided attributes map. */ private static final class ExpressionEvalMap implements Map, CompositeComponentExpressionHolder { private Map attributesMap; private PropertyDescriptor[] declaredAttributes; private Map declaredDefaultValues; private FacesContext ctx; private UIComponent cc; // -------------------------------------------------------- Constructors ExpressionEvalMap(FacesContext ctx, UIComponent cc) { this.cc = cc; this.attributesMap = cc.getAttributes(); BeanInfo metadata = (BeanInfo) this.attributesMap.get(UIComponent.BEANINFO_KEY); if (null != metadata) { this.declaredAttributes = metadata.getPropertyDescriptors(); this.declaredDefaultValues = new HashMap(5); } this.ctx = ctx; } // --------------------- Methods from CompositeComponentExpressionHolder public ValueExpression getExpression(String name) { Object ve = cc.getValueExpression(name); return ((ve instanceof ValueExpression) ? (ValueExpression) ve : null); } // ---------------------------------------------------- Methods from Map public int size() { throw new UnsupportedOperationException(); } public boolean isEmpty() { throw new UnsupportedOperationException(); } public boolean containsKey(Object key) { boolean result = attributesMap.containsKey(key); if (!result) { result = null != getDeclaredDefaultValue(key); } return result; } public boolean containsValue(Object value) { throw new UnsupportedOperationException(); } public Object get(Object key) { Object v = attributesMap.get(key); if (v == null) { v = getDeclaredDefaultValue(key); if (v != null) { return ((ValueExpression) v).getValue(ctx.getELContext()); } } if (v != null && v instanceof MethodExpression) { return v; } return v; } public Object put(String key, Object value) { // Unlinke AttributesMap.get() which will obtain a value from // a ValueExpression, AttributesMap.put(), when passed a value, // will never call ValueExpression.setValue(), so we have to take // matters into our own hands... ValueExpression ve = cc.getValueExpression(key); if (ve != null) { ve.setValue(ctx.getELContext(), value); } else { attributesMap.put(key, value); } return null; } public Object remove(Object key) { throw new UnsupportedOperationException(); } public void putAll(Map t) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } public Set keySet() { throw new UnsupportedOperationException(); } public Collection values() { throw new UnsupportedOperationException(); } public Set> entrySet() { throw new UnsupportedOperationException(); } private Object getDeclaredDefaultValue(Object key) { Object result = null; // If it's not in the cache... if (!declaredDefaultValues.containsKey(key)) { // iterate through the property descriptors... boolean found = false; for (PropertyDescriptor cur : declaredAttributes) { // and if you find a match... if (cur.getName().equals(key)) { found = true; // put it in the cache, returning the value. declaredDefaultValues.put(key, result = cur.getValue("default")); break; } } // Otherwise, if no attribute was declared if (!found) { // put null into the cache for future lookups. declaredDefaultValues.put(key, null); } } else { // It's in the cache, just return the value. result = declaredDefaultValues.get(key); } return result; } public void updateFacesContext(FacesContext ctx) { if (this.ctx != ctx) { this.ctx = ctx; } } } }