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

javax.faces.component.UIComponentBase Maven / Gradle / Ivy

There is a newer version: 4.1.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 javax.faces.component;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Standard implementation of the UIComponent base class; all standard JSF
 * components extend this class.
 * 

* Disclaimer: The official definition for the behaviour of * this class is the JSF 1.1 specification but for legal reasons the * specification cannot be replicated here. Any javadoc here therefore * describes the current implementation rather than the spec, though * this class has been verified as correctly implementing the spec. * * see Javadoc of JSF Specification for more. * * @author Manfred Geiler (latest modification by $Author: lu4242 $) * @version $Revision: 949071 $ $Date: 2010-05-27 21:22:17 -0500 (Thu, 27 May 2010) $ */ @JSFComponent(type = "javax.faces.ComponentBase", family = "javax.faces.ComponentBase", desc = "base component when all components must inherit", tagClass = "javax.faces.webapp.UIComponentELTag", configExcluded = true) @JSFJspProperty(name = "binding" , returnType = "javax.faces.component.UIComponent", longDesc = "Identifies a backing bean property (of type UIComponent or appropriate subclass) to bind to this component instance. This value must be an EL expression.", desc="backing bean property to bind to this component instance") public abstract class UIComponentBase extends UIComponent { private static Log log = LogFactory.getLog(UIComponentBase.class); private static final ThreadLocal _STRING_BUILDER = new ThreadLocal(); private static final Iterator _EMPTY_UICOMPONENT_ITERATOR = new _EmptyIterator(); private _ComponentAttributesMap _attributesMap = null; private List _childrenList = null; private Map _facetMap = null; private List _facesListeners = null; private String _clientId = null; private String _id = null; private UIComponent _parent = null; private boolean _transient = false; private transient FacesContext _facesContext; public UIComponentBase() { } /** * Get a map through which all the UIComponent's properties, value-bindings * and non-property attributes can be read and written. *

* When writing to the returned map: *

    *
  • If this component has an explicit property for the specified key * then the setter method is called. An IllegalArgumentException is * thrown if the property is read-only. If the property is readable * then the old value is returned, otherwise null is returned. *
  • Otherwise the key/value pair is stored in a map associated with * the component. *
* Note that value-bindings are not written by put calls to this map. * Writing to the attributes map using a key for which a value-binding * exists will just store the value in the attributes map rather than * evaluating the binding, effectively "hiding" the value-binding from * later attributes.get calls. Setter methods on components commonly do * not evaluate a binding of the same name; they just store the * provided value directly on the component. *

* When reading from the returned map: *

    *
  • If this component has an explicit property for the specified key * then the getter method is called. If the property exists, but is * read-only (ie only a setter method is defined) then an * IllegalArgumentException is thrown. *
  • If the attribute map associated with the component has an entry * with the specified key, then that is returned. *
  • If this component has a value-binding for the specified key, then * the value-binding is evaluated to fetch the value. *
  • Otherwise, null is returned. *
* Note that components commonly define getter methods such that they * evaluate a value-binding of the same name if there isn't yet a * local property. *

* Assigning values to the map which are not explicit properties on * the underlying component can be used to "tunnel" attributes from * the JSP tag (or view-specific equivalent) to the associated renderer * without modifying the component itself. *

* Any value-bindings and non-property attributes stored in this map * are automatically serialized along with the component when the view * is serialized. */ public Map getAttributes() { if (_attributesMap == null) { _attributesMap = new _ComponentAttributesMap(this); } return _attributesMap; } /** * Get the named value-binding associated with this component. *

* Value-bindings are stored in a map associated with the component, * though there is commonly a property (setter/getter methods) * of the same name defined on the component itself which * evaluates the value-binding when called. * * @deprecated Replaced by getValueExpression */ public ValueBinding getValueBinding(String name) { ValueExpression expression = getValueExpression(name); if (expression != null) { if (expression instanceof _ValueBindingToValueExpression) { return ((_ValueBindingToValueExpression) expression).getValueBinding(); } return new _ValueExpressionToValueBinding(expression); } return null; } /** * Put the provided value-binding into a map of value-bindings * associated with this component. * * @deprecated Replaced by setValueExpression */ public void setValueBinding(String name, ValueBinding binding) { setValueExpression(name, binding == null ? null : new _ValueBindingToValueExpression(binding)); } /** * Get a string which can be output to the response which uniquely * identifies this UIComponent within the current view. *

* The component should have an id attribute already assigned to it; * however if the id property is currently null then a unique id * is generated and set for this component. This only happens when * components are programmatically created without ids, as components * created by a ViewHandler should be assigned ids when they are created. *

* If this component is a descendant of a NamingContainer then the * client id is of form "{namingContainerId}:{componentId}". Note that * the naming container's id may itself be of compound form if it has * an ancestor naming container. Note also that this only applies to * naming containers; other UIComponent types in the component's * ancestry do not affect the clientId. *

* Finally the renderer associated with this component is asked to * convert the id into a suitable form. This allows escaping of any * characters in the clientId which are significant for the markup * language generated by that renderer. */ public String getClientId(FacesContext context) { if (context == null) throw new NullPointerException("context"); if (_clientId != null) return _clientId; boolean idWasNull = false; String id = getId(); if (id == null) { //Although this is an error prone side effect, we automatically create a new id //just to be compatible to the RI UIViewRoot viewRoot = context.getViewRoot(); if (viewRoot != null) { id = viewRoot.createUniqueId(); } else { // The RI throws a NPE throw new FacesException( "Cannot create clientId. No id is assigned for component to create an id and UIViewRoot is not defined: " + getPathToComponent(this)); } setId(id); //We remember that the id was null and log a warning down below idWasNull = true; } UIComponent namingContainer = _ComponentUtils.findParentNamingContainer(this, false); if (namingContainer != null) { String containerClientId = namingContainer.getContainerClientId(context); if (containerClientId != null ) { StringBuilder bld = __getSharedStringBuilder(); _clientId = bld.append(containerClientId).append(NamingContainer.SEPARATOR_CHAR).append(id).toString(); } else { _clientId = id; } } else { _clientId = id; } Renderer renderer = getRenderer(context); if (renderer != null) { _clientId = renderer.convertClientId(context, _clientId); } if (idWasNull && log.isWarnEnabled()) { log.warn("WARNING: Component " + _clientId + " just got an automatic id, because there was no id assigned yet. " + "If this component was created dynamically (i.e. not by a JSP tag) you should assign it an " + "explicit static id or assign it the id you get from " + "the createUniqueId from the current UIViewRoot " + "component right after creation! Path to Component: " + getPathToComponent(this)); } return _clientId; } /** * Get a string which uniquely identifies this UIComponent within the scope of the nearest ancestor NamingContainer * component. The id is not necessarily unique across all components in the current view. */ @JSFProperty (rtexprvalue = true) public String getId() { return _id; } /** * invokeOnComponent must be implemented in UIComponentBase too... */ public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException{ if (isCachedFacesContext()) { return super.invokeOnComponent(context, clientId, callback); } else { try { setCachedFacesContext(context); return super.invokeOnComponent(context, clientId, callback); } finally { setCachedFacesContext(null); } } } /** * Set an identifier for this component which is unique within the * scope of the nearest ancestor NamingContainer component. The id is * not necessarily unique across all components in the current view. *

* The id must start with an underscore if it is generated by the JSF * framework, and must not start with an underscore if it has * been specified by the user (eg in a JSP tag). *

* The first character of the id must be an underscore or letter. * Following characters may be letters, digits, underscores or dashes. *

* Null is allowed as a parameter, and will reset the id to null. *

* The clientId of this component is reset by this method; see * getClientId for more info. * * @throws IllegalArgumentException if the id is not valid. */ public void setId(String id) { isIdValid(id); _id = id; _clientId = null; } public UIComponent getParent() { return _parent; } public void setParent(UIComponent parent) { _parent = parent; } /** * Indicates whether this component or its renderer manages the * invocation of the rendering methods of its child components. * When this is true: *

    *
  • This component's encodeBegin method will only be called * after all the child components have been created and added * to this component. *
  • This component's encodeChildren method will be called * after its encodeBegin method. Components for which this * method returns false do not get this method invoked at all. *
  • No rendering methods will be called automatically on * child components; this component is required to invoke the * encodeBegin/encodeEnd/etc on them itself. *
*/ public boolean getRendersChildren() { Renderer renderer = getRenderer(getFacesContext()); return renderer != null ? renderer.getRendersChildren() : false; } /** * Return a list of the UIComponent objects which are direct children * of this component. *

* The list object returned has some non-standard behaviour: *

    *
  • The list is type-checked; only UIComponent objects can be added. *
  • If a component is added to the list with an id which is the same * as some other component in the list then an exception is thrown. However * multiple components with a null id may be added. *
  • The component's parent property is set to this component. If the * component already had a parent, then the component is first removed * from its original parent's child list. *
*/ public List getChildren() { if (_childrenList == null) { _childrenList = new _ComponentChildrenList(this); } return _childrenList; } /** * Return the number of direct child components this component has. *

* Identical to getChildren().size() except that when this component * has no children this method will not force an empty list to be * created. */ public int getChildCount() { return _childrenList == null ? 0 : _childrenList.size(); } /** * Standard method for finding other components by id, inherited by * most UIComponent objects. *

* The lookup is performed in a manner similar to finding a file * in a filesystem; there is a "base" at which to start, and the * id can be for something in the "local directory", or can include * a relative path. Here, NamingContainer components fill the role * of directories, and ":" is the "path separator". Note, however, * that although components have a strict parent/child hierarchy, * component ids are only prefixed ("namespaced") with the id of * their parent when the parent is a NamingContainer. *

* The base node at which the search starts is determined as * follows: *

    *
  • When expr starts with ':', the search starts with the root * component of the tree that this component is in (ie the ancestor * whose parent is null). *
  • Otherwise, if this component is a NamingContainer then the search * starts with this component. *
  • Otherwise, the search starts from the nearest ancestor * NamingContainer (or the root component if there is no NamingContainer * ancestor). *
* * @param expr is of form "id1:id2:id3". * @return UIComponent or null if no component with the specified id is * found. */ public UIComponent findComponent(String expr) { if (expr == null) throw new NullPointerException("expr"); if (expr.length() == 0) return null; UIComponent findBase; if (expr.charAt(0) == NamingContainer.SEPARATOR_CHAR) { findBase = _ComponentUtils.getRootComponent(this); expr = expr.substring(1); } else { if (this instanceof NamingContainer) { findBase = this; } else { findBase = _ComponentUtils.findParentNamingContainer(this, true /* root if not found */); } } int separator = expr.indexOf(NamingContainer.SEPARATOR_CHAR); if (separator == -1) { return _ComponentUtils.findComponent(findBase, expr); } String id = expr.substring(0, separator); findBase = _ComponentUtils.findComponent(findBase, id); if (findBase == null) { return null; } if (!(findBase instanceof NamingContainer)) throw new IllegalArgumentException("Intermediate identifier " + id + " in search expression " + expr + " identifies a UIComponent that is not a NamingContainer"); return findBase.findComponent(expr.substring(separator + 1)); } public Map getFacets() { if (_facetMap == null) { _facetMap = new _ComponentFacetMap(this); } return _facetMap; } public UIComponent getFacet(String name) { return _facetMap == null ? null : _facetMap.get(name); } public Iterator getFacetsAndChildren() { // we can't use _facetMap and _childrenList here directly, // because some component implementation could keep their // own properties for facets and children and just override // getFacets() and getChildren() (e.g. seen in PrimeFaces). // See MYFACES-2611 for details. if (getFacetCount() == 0) { if (getChildCount() == 0) return _EMPTY_UICOMPONENT_ITERATOR; return getChildren().iterator(); } else { if (getChildCount() == 0) return getFacets().values().iterator(); return new _FacetsAndChildrenIterator(getFacets(), getChildren()); } } /** * Invoke any listeners attached to this object which are listening * for an event whose type matches the specified event's runtime * type. *

* This method does not propagate the event up to parent components, * ie listeners attached to parent components don't automatically * get called. *

* If any of the listeners throws AbortProcessingException then * that exception will prevent any further listener callbacks * from occurring, and the exception propagates out of this * method without alteration. *

* ActionEvent events are typically queued by the renderer associated * with this component in its decode method; ValueChangeEvent events by * the component's validate method. In either case the event's source * property references a component. At some later time the UIViewRoot * component iterates over its queued events and invokes the broadcast * method on each event's source object. * * @param event must not be null. */ public void broadcast(FacesEvent event) throws AbortProcessingException { if (event == null) throw new NullPointerException("event"); try { if (_facesListeners == null) return; for (Iterator it = _facesListeners.iterator(); it.hasNext(); ) { FacesListener facesListener = it.next(); if (event.isAppropriateListener(facesListener)) { event.processListener(facesListener); } } } catch(Exception ex) { if (ex instanceof AbortProcessingException) { throw (AbortProcessingException) ex; } throw new FacesException("Exception while calling broadcast on component : "+getPathToComponent(this), ex); } } /** * Check the submitted form parameters for data associated with this * component. This default implementation delegates to this component's * renderer if there is one, and otherwise ignores the call. */ public void decode(FacesContext context) { if (context == null) throw new NullPointerException("context"); try { Renderer renderer = getRenderer(context); if (renderer != null) { renderer.decode(context, this); } } catch(Exception ex) { throw new FacesException("Exception while decoding component : "+getPathToComponent(this), ex); } } public void encodeBegin(FacesContext context) throws IOException { if (context == null) throw new NullPointerException("context"); try { setCachedFacesContext(context); if (!isRendered()) return; Renderer renderer = getRenderer(context); if (renderer != null) { renderer.encodeBegin(context, this); } } catch (Exception ex) { throw new FacesException("Exception while calling encodeBegin on component : "+getPathToComponent(this), ex); } finally { setCachedFacesContext(null); } } public void encodeChildren(FacesContext context) throws IOException { if (context == null) throw new NullPointerException("context"); boolean isCachedFacesContext = isCachedFacesContext(); try { if (!isCachedFacesContext) { setCachedFacesContext(context); } if (!isRendered()) return; Renderer renderer = getRenderer(context); if (renderer != null) { renderer.encodeChildren(context, this); } } finally { if (!isCachedFacesContext) { setCachedFacesContext(null); } } } public void encodeEnd(FacesContext context) throws IOException { if (context == null) throw new NullPointerException("context"); try { setCachedFacesContext(context); if (!isRendered()) return; Renderer renderer = getRenderer(context); if (renderer != null) { renderer.encodeEnd(context, this); } } catch (Exception ex) { throw new FacesException("Exception while calling encodeEnd on component : "+getPathToComponent(this), ex); } finally { setCachedFacesContext(null); } } protected void addFacesListener(FacesListener listener) { if (listener == null) throw new NullPointerException("listener"); if (_facesListeners == null) { _facesListeners = new ArrayList(); } _facesListeners.add(listener); } protected FacesListener[] getFacesListeners(Class clazz) { if(clazz == null) { throw new NullPointerException("Class is null"); } if(!FacesListener.class.isAssignableFrom(clazz)) { throw new IllegalArgumentException("Class " + clazz.getName() + " must implement " + FacesListener.class); } if (_facesListeners == null) { return (FacesListener[])Array.newInstance(clazz, 0); } List lst = null; for (Iterator it = _facesListeners.iterator(); it.hasNext();) { FacesListener facesListener = it.next(); if (clazz.isAssignableFrom(facesListener.getClass())) { if (lst == null) lst = new ArrayList(); lst.add(facesListener); } } if (lst == null) { return (FacesListener[]) Array.newInstance(clazz, 0); } return lst.toArray((FacesListener[])Array.newInstance(clazz, lst.size())); } protected void removeFacesListener(FacesListener listener) { if(listener == null) { throw new NullPointerException("listener is null"); } if (_facesListeners != null) { _facesListeners.remove(listener); } } public void queueEvent(FacesEvent event) { if (event == null) throw new NullPointerException("event"); UIComponent parent = getParent(); if (parent == null) { throw new IllegalStateException("component is not a descendant of a UIViewRoot"); } parent.queueEvent(event); } public void processDecodes(FacesContext context) { if (context == null) throw new NullPointerException("context"); try { setCachedFacesContext(context); if (!isRendered()) return; for (Iterator it = getFacetsAndChildren(); it.hasNext();) { it.next().processDecodes(context); } try { decode(context); } catch (RuntimeException e) { context.renderResponse(); throw e; } } finally { setCachedFacesContext(null); } } public void processValidators(FacesContext context) { if (context == null) throw new NullPointerException("context"); try { setCachedFacesContext(context); if (!isRendered()) return; for (Iterator it = getFacetsAndChildren(); it.hasNext(); ) { it.next().processValidators(context); } } finally { setCachedFacesContext(null); } } /** * This isn't an input component, so just pass on the processUpdates * call to child components and facets that might be input components. *

* Components that were never rendered can't possibly be receiving * update data (no corresponding fields were ever put into the response) * so if this component is not rendered then this method does not * invoke processUpdates on its children. */ public void processUpdates(FacesContext context) { if (context == null) throw new NullPointerException("context"); try { setCachedFacesContext(context); if (!isRendered()) return; for (Iterator it = getFacetsAndChildren(); it.hasNext(); ) { it.next().processUpdates(context); } } finally { setCachedFacesContext(null); } } public Object processSaveState(FacesContext context) { if (context == null) throw new NullPointerException("context"); if (isTransient()) return null; Map facetMap = null; int facetCount = getFacetCount(); if (facetCount > 0) { for (Iterator> it = getFacets().entrySet().iterator(); it.hasNext();) { Entry entry = it.next(); UIComponent component = entry.getValue(); if (!component.isTransient()) { if (facetMap == null) facetMap = new HashMap(facetCount, 1); facetMap.put(entry.getKey(), component.processSaveState(context)); } } } List childrenList = null; int childCount = getChildCount(); if (childCount > 0) { for (Iterator it = getChildren().iterator(); it.hasNext();) { UIComponent child = (UIComponent) it.next(); if (!child.isTransient()) { if (childrenList == null) { childrenList = new ArrayList(childCount); } Object childState = child.processSaveState(context); if (childState != null) { childrenList.add(childState); } } } } Object savedState; try { savedState = saveState(context); } catch(Exception ex) { throw new FacesException("Exception while saving state of component : "+getPathToComponent(this), ex); } return new Object[] { savedState, facetMap, childrenList }; } public void processRestoreState(FacesContext context, Object state) { if (context == null) throw new NullPointerException("context"); Object[] stateValues = (Object[]) state; Object myState = stateValues[0]; Map facetMap = (Map)stateValues[1]; List childrenList = (List)stateValues[2]; if(facetMap != null && getFacetCount() > 0) { for (Iterator> it = getFacets().entrySet().iterator(); it.hasNext(); ) { Entry entry = it.next(); Object facetState = facetMap.get(entry.getKey()); if (facetState != null) { entry.getValue().processRestoreState(context, facetState); } else { context.getExternalContext().log("No state found to restore facet " + entry.getKey()); } } } if (childrenList != null && getChildCount() > 0) { int idx = 0; for (Iterator it = getChildren().iterator(); it.hasNext(); ) { UIComponent child = it.next(); if(!child.isTransient()) { Object childState = childrenList.get(idx++); if (childState != null) { child.processRestoreState(context, childState); } else { context.getExternalContext().log("No state found to restore child of component " + getId()); } } } } try { restoreState(context, myState); } catch(Exception ex) { throw new FacesException("Exception while restoring state of component : "+getPathToComponent(this), ex); } } protected FacesContext getFacesContext() { if (_facesContext == null) { return FacesContext.getCurrentInstance(); } else { return _facesContext; } } protected Renderer getRenderer(FacesContext context) { if (context == null) throw new NullPointerException("context"); String rendererType = getRendererType(); if (rendererType == null) return null; RenderKit renderKit = context.getRenderKit(); Renderer renderer = renderKit.getRenderer(getFamily(), rendererType); if (renderer == null) { getFacesContext().getExternalContext().log("No Renderer found for component " + getPathToComponent(this) + " (component-family=" + getFamily() + ", renderer-type=" + rendererType + ")"); log.warn("No Renderer found for component " + getPathToComponent(this) + " (component-family=" + getFamily() + ", renderer-type=" + rendererType + ")"); } return renderer; } private String getPathToComponent(UIComponent component) { StringBuffer buf = new StringBuffer(); if(component == null) { buf.append("{Component-Path : "); buf.append("[null]}"); return buf.toString(); } getPathToComponent(component,buf); buf.insert(0,"{Component-Path : "); buf.append("}"); return buf.toString(); } private void getPathToComponent(UIComponent component, StringBuffer buf) { if(component == null) return; StringBuffer intBuf = new StringBuffer(); intBuf.append("[Class: "); intBuf.append(component.getClass().getName()); if(component instanceof UIViewRoot) { intBuf.append(",ViewId: "); intBuf.append(((UIViewRoot) component).getViewId()); } else { intBuf.append(",Id: "); intBuf.append(component.getId()); } intBuf.append("]"); buf.insert(0,intBuf.toString()); getPathToComponent(component.getParent(), buf); } @JSFProperty( literalOnly = true, istransient = true, tagExcluded = true) public boolean isTransient() { return _transient; } public void setTransient(boolean transientFlag) { _transient = transientFlag; } /** * Serializes objects which are "attached" to this component but which are * not UIComponent children of it. Examples are validator and listener * objects. To be precise, it returns an object which implements * java.io.Serializable, and which when serialized will persist the * state of the provided object. *

* If the attachedObject is a List then every object in the list is saved * via a call to this method, and the returned wrapper object contains * a List object. *

* If the object implements StateHolder then the object's saveState is * called immediately, and a wrapper is returned which contains both * this saved state and the original class name. However in the case * where the StateHolder.isTransient method returns true, null is * returned instead. *

* If the object implements java.io.Serializable then the object is simply * returned immediately; standard java serialization will later be used * to store this object. *

* In all other cases, a wrapper is returned which simply stores the type * of the provided object. When deserialized, a default instance of that * type will be recreated. */ public static Object saveAttachedState(FacesContext context, Object attachedObject) { if (attachedObject == null) return null; if (attachedObject instanceof List) { List lst = new ArrayList(((List)attachedObject).size()); for (Iterator it = ((List)attachedObject).iterator(); it.hasNext(); ) { Object value = it.next(); if (value != null) { lst.add(saveAttachedState(context, value)); } } return new _AttachedListStateWrapper(lst); } else if (attachedObject instanceof StateHolder) { if (((StateHolder)attachedObject).isTransient()) { return null; } return new _AttachedStateWrapper(attachedObject.getClass(), ((StateHolder)attachedObject).saveState(context)); } else if (attachedObject instanceof Serializable) { return attachedObject; } else { return new _AttachedStateWrapper(attachedObject.getClass(), null); } } public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException { if (context == null) throw new NullPointerException("context"); if (stateObj == null) return null; if (stateObj instanceof _AttachedListStateWrapper) { List lst = ((_AttachedListStateWrapper)stateObj).getWrappedStateList(); List restoredList = new ArrayList(lst.size()); for (Iterator it = lst.iterator(); it.hasNext(); ) { restoredList.add(restoreAttachedState(context, it.next())); } return restoredList; } else if (stateObj instanceof _AttachedStateWrapper) { Class clazz = ((_AttachedStateWrapper)stateObj).getClazz(); Object restoredObject; try { restoredObject = clazz.newInstance(); } catch (InstantiationException e) { throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (restoredObject instanceof StateHolder) { Object wrappedState = ((_AttachedStateWrapper)stateObj).getWrappedStateObject(); ((StateHolder)restoredObject).restoreState(context, wrappedState); } return restoredObject; } else { return stateObj; } } /** * Invoked after the render phase has completed, this method * returns an object which can be passed to the restoreState * of some other instance of UIComponentBase to reset that * object's state to the same values as this object currently * has. */ public Object saveState(FacesContext context) { Object values[] = new Object[7]; values[0] = _id; values[1] = _rendered; values[2] = _rendererType; values[3] = _clientId; values[4] = saveAttributesMap(); values[5] = saveAttachedState(context, _facesListeners); values[6] = saveBindings(context); return values; } /** * Invoked in the "restore view" phase, this initialises this * object's members from the values saved previously into the * provided state object. *

* @param state is an object previously returned by * the saveState method of this class. */ public void restoreState(FacesContext context, Object state) { Object values[] = (Object[])state; _id = (String)values[0]; _rendered = (Boolean)values[1]; _rendererType = (String)values[2]; _clientId = (String)values[3]; restoreAttributesMap(values[4]); _facesListeners = (List)restoreAttachedState(context, values[5]); restoreValueExpressionMap(context, values[6]); } private Object saveAttributesMap() { return _attributesMap != null ? _attributesMap.getUnderlyingMap() : null; } private void restoreAttributesMap(Object stateObj) { if (stateObj != null) { _attributesMap = new _ComponentAttributesMap(this, (Map)stateObj); } else { _attributesMap = null; } } private Object saveBindings(FacesContext context) { if (bindings != null) { HashMap stateMap = new HashMap(bindings.size(), 1); for (Iterator> it = bindings.entrySet().iterator(); it.hasNext(); ) { Entry entry = it.next(); stateMap.put(entry.getKey(), saveAttachedState(context, entry.getValue())); } return stateMap; } return null; } private void restoreValueExpressionMap(FacesContext context, Object stateObj) { if (stateObj != null) { Map stateMap = (Map)stateObj; int initCapacity = (stateMap.size() * 4 + 3) / 3; bindings = new HashMap(initCapacity); for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry)it.next(); bindings.put((String)entry.getKey(), (ValueExpression)restoreAttachedState(context, entry.getValue())); } } else { bindings = null; } } /** * @param string the component id, that should be a vaild one. */ private void isIdValid(String string) { //is there any component identifier ? if(string == null) return; //Component identifiers must obey the following syntax restrictions: //1. Must not be a zero-length String. if(string.length()==0) { throw new IllegalArgumentException("component identifier must not be a zero-length String"); } // If new id is the same as old it must be valid if (string.equals(_id)) { return; } //2. First character must be a letter or an underscore ('_'). if(!Character.isLetter(string.charAt(0)) && string.charAt(0) !='_') { throw new IllegalArgumentException("component identifier's first character must be a letter or an underscore ('_')! But it is \""+string.charAt(0)+"\""); } for (int i = 1; i < string.length(); i++) { char c = string.charAt(i); //3. Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-'). if(!Character.isLetterOrDigit(c) && c !='-' && c !='_') { throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, a digit, an underscore ('_'), or a dash ('-')! But component identifier contains \""+c+"\""); } } } T getExpressionValue(String attribute, T explizitValue, T defaultValueIfExpressionNull) { return _ComponentUtils.getExpressionValue(this, attribute, explizitValue, defaultValueIfExpressionNull); } /** *

* This gets a single threadlocal shared stringbuilder instance, each time you call * __getSharedStringBuilder it sets the length of the stringBuilder instance to 0. *

* This allows you to use the same StringBuilder instance over and over. * You must call toString on the instance before calling __getSharedStringBuilder again. *

* Example that works *

     * StringBuilder sb1 = __getSharedStringBuilder();
     * sb1.append(a).append(b);
     * String c = sb1.toString();
     *
     * StringBuilder sb2 = __getSharedStringBuilder();
     * sb2.append(b).append(a);
     * String d = sb2.toString();
     * 
*

* Example that doesn't work, you must call toString on sb1 before * calling __getSharedStringBuilder again. *

     * StringBuilder sb1 = __getSharedStringBuilder();
     * StringBuilder sb2 = __getSharedStringBuilder();
     *
     * sb1.append(a).append(b);
     * String c = sb1.toString();
     *
     * sb2.append(b).append(a);
     * String d = sb2.toString();
     * 
* */ static StringBuilder __getSharedStringBuilder() { StringBuilder sb = _STRING_BUILDER.get(); if (sb == null) { sb = new StringBuilder(); _STRING_BUILDER.set(sb); } // clear out the stringBuilder by setting the length to 0 sb.setLength(0); return sb; } boolean isCachedFacesContext() { return _facesContext != null; } void setCachedFacesContext(FacesContext facesContext) { _facesContext = facesContext; } //------------------ GENERATED CODE BEGIN (do not modify!) -------------------- private static final boolean DEFAULT_RENDERED = true; private Boolean _rendered = null; private String _rendererType = null; public void setRendered(boolean rendered) { _rendered = Boolean.valueOf(rendered); } /** * A boolean value that indicates whether this component should be rendered. * Default value: true. **/ @JSFProperty public boolean isRendered() { return getExpressionValue("rendered", _rendered, DEFAULT_RENDERED); } public void setRendererType(String rendererType) { _rendererType = rendererType; } public String getRendererType() { return getExpressionValue("rendererType", _rendererType, null); } //------------------ GENERATED CODE END --------------------------------------- /** * @since 1.2 */ public int getFacetCount() { return _facetMap == null ? 0 : _facetMap.size(); } }