Save This Page
Home » trinidad-1.2.8-src-all » org.apache.myfaces.trinidad » component » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
   10    *  http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing,
   13    *  software distributed under the License is distributed on an
   14    *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    *  KIND, either express or implied.  See the License for the
   16    *  specific language governing permissions and limitations
   17    *  under the License.
   18    */
   19   package org.apache.myfaces.trinidad.component;
   20   
   21   import java.io.InputStream;
   22   import java.io.IOException;
   23   import java.net.URL;
   24   import java.util.ArrayList;
   25   import java.util.Iterator;
   26   import java.util.List;
   27   import java.util.Map;
   28   import java.util.NoSuchElementException;
   29   import java.util.Properties;
   30   
   31   import javax.el.ELContext;
   32   import javax.el.ELException;
   33   import javax.el.MethodExpression;
   34   import javax.el.ValueExpression;
   35   
   36   import javax.faces.component.NamingContainer;
   37   import javax.faces.component.UIComponent;
   38   import javax.faces.context.FacesContext;
   39   import javax.faces.el.EvaluationException;
   40   import javax.faces.el.MethodBinding;
   41   import javax.faces.el.ValueBinding;
   42   import javax.faces.event.AbortProcessingException;
   43   import javax.faces.event.FacesEvent;
   44   import javax.faces.event.FacesListener;
   45   import javax.faces.render.RenderKit;
   46   import javax.faces.render.Renderer;
   47   
   48   import org.apache.myfaces.trinidad.bean.FacesBean;
   49   import org.apache.myfaces.trinidad.bean.FacesBeanFactory;
   50   import org.apache.myfaces.trinidad.bean.PropertyKey;
   51   import org.apache.myfaces.trinidad.bean.util.ValueMap;
   52   import org.apache.myfaces.trinidad.change.AttributeComponentChange;
   53   import org.apache.myfaces.trinidad.context.RequestContext;
   54   import org.apache.myfaces.trinidad.event.AttributeChangeEvent;
   55   import org.apache.myfaces.trinidad.event.AttributeChangeListener;
   56   import org.apache.myfaces.trinidad.logging.TrinidadLogger;
   57   import org.apache.myfaces.trinidad.render.ExtendedRenderer;
   58   import org.apache.myfaces.trinidad.render.LifecycleRenderer;
   59   
   60   
   61   /**
   62    * Base implementation of components for all of Trinidad.  UIXComponentBase
   63    * offers a number of features not supplied by the standard UIComponentBase
   64    * class:
   65    * <ul>
   66    * <li>Use of FacesBean for better and easier state saving</li>
   67    * <li>Support of the LifecycleRenderer class for greater Renderer
   68    *  control over the lifecycle</li>
   69    * <li>Built-in support for both the "partialTriggers" attribute
   70    *   (declarative support for being a PPR target) and for triggering
   71    *   such components (for being a the source of a PPR-causing event).</li>
   72    * </ul>
   73    * <h3>FacesBean and UIXComponentBase</h3>
   74    * <p>
   75    * UIXComponentBase differs from UIXComponent most particularly
   76    * in its use of FacesBeans to store all state.  This offers
   77    * a number of advantages:
   78    * <ul>
   79    * <li>Subclassers - if they use FacesBean for their state as well -
   80    *   do not need to write overrides of saveState() and restoreState().
   81    *   </li>
   82    * <li>State is optimized by default</li>
   83    * <li>Future optimizations - partly exposed today with
   84    *    markInitialState() - can offer major state saving improvements.
   85    * </ul>
   86    * </p>
   87    */
   88   // TODO Write Class Javadoc
   89   // TODO Thorough review against UIComponentBase
   90   abstract public class UIXComponentBase extends UIXComponent
   91   {
   92     // Created up top to ensure it's present while we're processing
   93     // class initialization code.
   94     static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(UIXComponentBase.class);
   95   
   96     static public final FacesBean.Type TYPE = _createType();
   97     static public final PropertyKey ID_KEY =
   98       TYPE.registerKey("id", String.class, PropertyKey.CAP_NOT_BOUND);
   99     static private final PropertyKey _GENERATED_ID_KEY =
  100       TYPE.registerKey("_genId", String.class, PropertyKey.CAP_NOT_BOUND);
  101     static public final PropertyKey RENDERED_KEY =
  102       TYPE.registerKey("rendered", Boolean.class, Boolean.TRUE);
  103     static public final PropertyKey BINDING_KEY =
  104       TYPE.registerKey("binding");
  105     static public final PropertyKey TRANSIENT_KEY =
  106       TYPE.registerKey("transient", Boolean.class,
  107                        PropertyKey.CAP_NOT_BOUND |
  108                        PropertyKey.CAP_TRANSIENT);
  109     static public final PropertyKey RENDERER_TYPE_KEY =
  110       TYPE.registerKey("rendererType", String.class, PropertyKey.CAP_NOT_BOUND);
  111     static private final PropertyKey _LISTENERS_KEY =
  112       TYPE.registerKey("listeners", FacesListener[].class, PropertyKey.CAP_LIST);
  113     static private final PropertyKey _ATTRIBUTE_CHANGE_LISTENER_KEY =
  114       TYPE.registerKey("attributeChangeListener", MethodExpression.class);
  115     // =-=AEW "parent", "rendersChildren", "childCount", "children",
  116     // "facets", "facetsAndChildren", "family" all are technically
  117     // bean properties, but they aren't exposed here...
  118   
  119     static
  120     {
  121       // Register a couple of PropertyKeys against names that
  122       // the RI's UIComponentTag implementation is shoving
  123       // into all components.  This is purely an optimization, but
  124       // a very useful one.
  125       TYPE.registerKey("javax.faces.webapp.COMPONENT_IDS",
  126                        List.class,
  127                        PropertyKey.CAP_NOT_BOUND);
  128       TYPE.registerKey("javax.faces.webapp.FACET_NAMES",
  129                        List.class,
  130                        PropertyKey.CAP_NOT_BOUND);
  131       TYPE.lock();
  132     }
  133   
  134     public UIXComponentBase()
  135     {
  136     }
  137   
  138     public UIXComponentBase(String rendererType)
  139     {
  140       setRendererType(rendererType);
  141     }
  142   
  143     protected FacesBean createFacesBean(
  144       String rendererType)
  145     {
  146       FacesBean bean = FacesBeanFactory.createFacesBean(getClass(),
  147                                                         rendererType);
  148       UIXFacesBean uixBean = (UIXFacesBean) bean;
  149       uixBean.init(this, getBeanType());
  150       return uixBean;
  151     }
  152   
  153     protected PropertyKey getPropertyKey(String name)
  154     {
  155       PropertyKey key = getBeanType().findKey(name);
  156       if (key == null)
  157         key = PropertyKey.createPropertyKey(name);
  158   
  159       return key;
  160     }
  161   
  162     protected FacesBean.Type getBeanType()
  163     {
  164       return TYPE;
  165     }
  166   
  167     @Override
  168     public FacesBean getFacesBean()
  169     {
  170       if (_facesBean == null)
  171         _init(null);
  172   
  173       return _facesBean;
  174     }
  175   
  176     @Override
  177     public String getContainerClientId(FacesContext context, UIComponent child)
  178     {
  179       return getContainerClientId(context);
  180     }
  181   
  182     @Override
  183     public void addAttributeChangeListener(AttributeChangeListener acl)
  184     {
  185       addFacesListener(acl);
  186     }
  187   
  188     @Override
  189     public void removeAttributeChangeListener(AttributeChangeListener acl)
  190     {
  191       removeFacesListener(acl);
  192     }
  193   
  194     @Override
  195     public AttributeChangeListener[] getAttributeChangeListeners()
  196     {
  197       return (AttributeChangeListener[])
  198         getFacesListeners(AttributeChangeListener.class);
  199     }
  200   
  201     @Override
  202     public void setAttributeChangeListener(MethodExpression mb)
  203     {
  204       setProperty(_ATTRIBUTE_CHANGE_LISTENER_KEY, mb);
  205     }
  206   
  207     @Deprecated
  208     public void setAttributeChangeListener(MethodBinding mb)
  209     {
  210       setAttributeChangeListener(adaptMethodBinding(mb));
  211     }
  212   
  213     @Override
  214     public MethodExpression getAttributeChangeListener()
  215     {
  216       return (MethodExpression) getProperty(_ATTRIBUTE_CHANGE_LISTENER_KEY);
  217     }
  218   
  219   
  220     @Override
  221     public ValueExpression getValueExpression(String name)
  222     {
  223       if (name == null)
  224         throw new NullPointerException();
  225   
  226       PropertyKey key = getPropertyKey(name);
  227   
  228       // Support standard RI behavior where getValueBinding()
  229       // doesn't complain about being asked for a ValueBinding -
  230       // but continue supporting strict behavior at FacesBean layer.
  231       if (!key.getSupportsBinding())
  232         return null;
  233   
  234       return getFacesBean().getValueExpression(key);
  235     }
  236   
  237     @Override
  238     public void setValueExpression(String name,
  239                                    ValueExpression expression)
  240     {
  241       if (name == null)
  242         throw new NullPointerException();
  243   
  244       if ((expression != null) && expression.isLiteralText())
  245       {
  246         ELContext context =
  247             FacesContext.getCurrentInstance().getELContext();
  248         getAttributes().put(name, expression.getValue(context));
  249       }
  250       else
  251       {
  252         PropertyKey key = getPropertyKey(name);
  253         getFacesBean().setValueExpression(key, expression);
  254       }
  255     }
  256   
  257   
  258   
  259     /**
  260      */
  261     @Override
  262     public ValueBinding getValueBinding(String name)
  263     {
  264       if (name == null)
  265         throw new NullPointerException();
  266   
  267       PropertyKey key = getPropertyKey(name);
  268   
  269       // Support standard RI behavior where getValueBinding()
  270       // doesn't complain about being asked for a ValueBinding -
  271       // but continue supporting strict behavior at FacesBean layer.
  272       if (!key.getSupportsBinding())
  273         return null;
  274   
  275       return getFacesBean().getValueBinding(key);
  276     }
  277   
  278   
  279     @Override
  280     public void setValueBinding(String name, ValueBinding binding)
  281     {
  282       if (name == null)
  283         throw new NullPointerException();
  284   
  285       PropertyKey key = getPropertyKey(name);
  286       getFacesBean().setValueBinding(key, binding);
  287     }
  288   
  289   
  290     @Override
  291     public Map<String, Object> getAttributes()
  292     {
  293       if (_attributes == null)
  294         _init(null);
  295   
  296       return _attributes;
  297     }
  298   
  299     // ------------------------------------------------------------- Properties
  300   
  301   
  302   
  303     @Override
  304     public String getClientId(FacesContext context)
  305     {
  306       // NOTE - client ids cannot be cached because the generated
  307       // value has to be dynamically calculated in some cases (UIData)
  308   
  309       String clientId = getId();
  310       if (clientId == null)
  311       {
  312         clientId = (String) getProperty(_GENERATED_ID_KEY);
  313         if (clientId == null)
  314         {
  315           clientId = context.getViewRoot().createUniqueId();
  316           setProperty(_GENERATED_ID_KEY, clientId);
  317         }
  318       }
  319   
  320       // Search for an ancestor that is a naming container
  321       UIComponent containerComponent = getParent();
  322       while (null != containerComponent)
  323       {
  324         if (containerComponent instanceof NamingContainer)
  325         {
  326           String contClientId;
  327   
  328           // Pass additional context information to naming containers which extend UIXComponent:
  329           if (containerComponent instanceof UIXComponent)
  330             contClientId = ((UIXComponent)containerComponent).getContainerClientId(context, this);
  331           else
  332             contClientId = containerComponent.getContainerClientId(context);
  333   
  334           StringBuilder bld = __getSharedStringBuilder();
  335           bld.append(contClientId).append(NamingContainer.SEPARATOR_CHAR).append(clientId);
  336           clientId = bld.toString();
  337           break;
  338         }
  339   
  340         containerComponent = containerComponent.getParent();
  341       }
  342   
  343       Renderer renderer = getRenderer(context);
  344       if (null != renderer)
  345         clientId = renderer.convertClientId(context, clientId);
  346   
  347       return clientId;
  348     }
  349   
  350   
  351     /**
  352      * Gets the identifier for the component.
  353      */
  354     @Override
  355     public String getId()
  356     {
  357       return (String) getProperty(ID_KEY);
  358     }
  359   
  360   
  361     /**
  362      * Sets the identifier for the component.  The identifier
  363      * must follow a subset of the syntax allowed in HTML:
  364      * <ul>
  365      * <li>Must not be a zero-length String.</li>
  366      * <li>First character must be an ASCII letter (A-Za-z) or an underscore ('_').</li>
  367      * <li>Subsequent characters must be an ASCII letter or digit (A-Za-z0-9), an underscore ('_'), or a dash ('-').
  368      * </ul>
  369      */
  370     @Override
  371     public void setId(String id)
  372     {
  373       // =-=AEW Currently, setId() assumes that resetting to
  374       // the same value *is not* short-circuited.
  375       _validateId(id);
  376       // If we're setting the ID to null, don't discard
  377       // the _GENERATED_ID
  378       if (id != null)
  379         setProperty(_GENERATED_ID_KEY, null);
  380   
  381       setProperty(ID_KEY, id);
  382     }
  383   
  384   
  385   
  386     @Override
  387     abstract public String getFamily();
  388   
  389   
  390     @Override
  391     public UIComponent getParent()
  392     {
  393       return _parent;
  394     }
  395   
  396   
  397     /**
  398      * <p>Set the parent <code>UIComponent</code> of this
  399      * <code>UIComponent</code>.</p>
  400      *
  401      * @param parent The new parent, or <code>null</code> for the root node
  402      *  of a component tree
  403      */
  404     @Override
  405     public void setParent(UIComponent parent)
  406     {
  407       _parent = parent;
  408     }
  409   
  410   
  411     @Override
  412     public boolean isRendered()
  413     {
  414       return getBooleanProperty(RENDERED_KEY, true);
  415     }
  416   
  417   
  418     @Override
  419     public void setRendered(boolean rendered)
  420     {
  421       setBooleanProperty(RENDERED_KEY, rendered);
  422     }
  423   
  424     public boolean isTransient()
  425     {
  426       return getBooleanProperty(TRANSIENT_KEY, false);
  427     }
  428   
  429     public void setTransient(boolean newTransient)
  430     {
  431       setBooleanProperty(TRANSIENT_KEY, newTransient);
  432     }
  433   
  434     @Override
  435     public String getRendererType()
  436     {
  437       // Don't create the FacesBean just to get the renderer type;
  438       // Generally, rendererType will be the first property
  439       // set, which will trigger the code below in setRendererType()
  440       // to run correctly.
  441       if (_facesBean == null)
  442         return null;
  443   
  444       return (String) getProperty(RENDERER_TYPE_KEY);
  445     }
  446   
  447     @Override
  448     public void setRendererType(String rendererType)
  449     {
  450       String oldRendererType = getRendererType();
  451       if (oldRendererType == null)
  452       {
  453         if (rendererType == null)
  454           return;
  455       }
  456       else if (oldRendererType.equals(rendererType))
  457       {
  458         return;
  459       }
  460   
  461       // prepare the faces bean
  462       _init(rendererType);
  463       setProperty(RENDERER_TYPE_KEY, rendererType);
  464     }
  465   
  466   
  467     @Override
  468     public boolean getRendersChildren()
  469     {
  470       Renderer renderer = getRenderer(getFacesContext());
  471       if (renderer == null)
  472         return false;
  473   
  474       return renderer.getRendersChildren();
  475     }
  476   
  477   
  478   
  479   
  480     // ------------------------------------------------ Tree Management Methods
  481   
  482   
  483   
  484     @Override
  485     public UIComponent findComponent(String id)
  486     {
  487       if (id == null)
  488         throw new NullPointerException();
  489   
  490       if ("".equals(id))
  491         throw new IllegalArgumentException();
  492   
  493       UIComponent from = this;
  494       // If it starts with the separator character, it's
  495       // an absolute path: start at the top
  496       if (id.charAt(0) == NamingContainer.SEPARATOR_CHAR)
  497       {
  498         id = id.substring(1);
  499         while (from.getParent() != null)
  500           from = from.getParent();
  501       }
  502       // If it's a NamingContainer, start right here
  503       else if (this instanceof NamingContainer)
  504       {
  505         ;
  506       }
  507       // Otherwise, go up to look for NamingContainer (or the top)
  508       else
  509       {
  510         while (from.getParent() != null)
  511         {
  512           from = from.getParent();
  513           if (from instanceof NamingContainer)
  514             break;
  515         }
  516       }
  517   
  518       // Evaluate each part of the expression
  519       String searchId;
  520       int separatorIndex = id.indexOf(NamingContainer.SEPARATOR_CHAR);
  521       if (separatorIndex < 0)
  522         searchId = id;
  523       else
  524         searchId = id.substring(0, separatorIndex);
  525   
  526       if (searchId.equals(from.getId()))
  527       {
  528         // Don't need to look inside if we're already there
  529         ;
  530       }
  531       else
  532       {
  533         from = _findInsideOf(from, searchId);
  534       }
  535   
  536       // Final ID:  break, and return whatever we've found
  537       if (separatorIndex < 0)
  538       {
  539         return from;
  540       }
  541       // Just an intermediate step.  Make sure we're at a NamingContainer,
  542       // and then ask it to find the rest of the expression.
  543       else
  544       {
  545         if (from == null)
  546           return null;
  547   
  548         if (!(from instanceof NamingContainer))
  549           throw new IllegalArgumentException();
  550         return from.findComponent(id.substring(separatorIndex + 1));
  551       }
  552     }
  553   
  554   
  555   
  556     /**
  557      * <p>Create (if necessary) and return a List of the children associated
  558      * with this component.</p>
  559      */
  560     @Override
  561     public List<UIComponent> getChildren()
  562     {
  563       if (_children == null)
  564         _children = new ChildArrayList(this);
  565   
  566       return _children;
  567     }
  568   
  569     @Override
  570     public int getChildCount()
  571     {
  572       if (_children == null)
  573         return 0;
  574       return getChildren().size();
  575     }
  576   
  577   
  578     /**
  579      * <p>Create (if necessary) and return a Map of the facets associated
  580      * with this component.</p>
  581      */
  582     @Override
  583     public Map<String, UIComponent> getFacets()
  584     {
  585   
  586       if (_facets == null)
  587         _facets = new FacetHashMap(this);
  588   
  589       return _facets;
  590     }
  591   
  592   
  593     @Override
  594     public UIComponent getFacet(String facetName)
  595     {
  596       if (facetName == null)
  597         throw new NullPointerException();
  598       if (_facets == null)
  599         return null;
  600       return getFacets().get(facetName);
  601     }
  602   
  603   
  604     /**
  605      * Returns an Iterator over the names of all facets.
  606      * Unlike getFacets().keySet().iterator(), this does
  607      * not require instantiating a Map if there are
  608      * no facets.  (Note that this is not part of the
  609      * UIComponent API.)
  610      */
  611     public Iterator<String> getFacetNames()
  612     {
  613       if (_facets == null)
  614         return _EMPTY_STRING_ITERATOR;
  615       return _facets.keySet().iterator();
  616     }
  617   
  618   
  619     // TODO: Optimize to a compound iterator
  620     @Override
  621     public Iterator<UIComponent> getFacetsAndChildren()
  622     {
  623       // =-=AEW Is this supposed to be an immutable Iterator?
  624       if (_facets == null)
  625       {
  626         if (_children == null)
  627           return _EMPTY_UICOMPONENT_ITERATOR;
  628   
  629         return _children.iterator();
  630       }
  631       else
  632       {
  633         if (_children == null)
  634           return _facets.values().iterator();
  635       }
  636   
  637       ArrayList<UIComponent> childrenAndFacets = new ArrayList<UIComponent>();
  638       for(UIComponent facet : _facets.values())
  639       {
  640         childrenAndFacets.add(facet);
  641       }
  642   
  643       for(UIComponent child : _children)
  644       {
  645         childrenAndFacets.add(child);
  646       }
  647   
  648       if (childrenAndFacets.isEmpty())
  649         return _EMPTY_UICOMPONENT_ITERATOR;
  650   
  651       return childrenAndFacets.iterator();
  652     }
  653   
  654   
  655     // ------------------------------------------- Event processing methods
  656   
  657     @Override
  658     public void broadcast(FacesEvent event)
  659       throws AbortProcessingException
  660     {
  661       if (event == null)
  662         throw new NullPointerException();
  663   
  664       if (_LOG.isFine())
  665         _LOG.fine("Broadcasting event " + event + " to " + this);
  666   
  667       UIComponent component = event.getComponent();
  668       if (component != null)
  669       {
  670         RequestContext adfContext = RequestContext.getCurrentInstance();
  671         if (adfContext != null)
  672           adfContext.partialUpdateNotify(component);
  673       }
  674   
  675       Iterator<FacesListener> iter =
  676         (Iterator<FacesListener>)getFacesBean().entries(_LISTENERS_KEY);
  677   
  678       while (iter.hasNext())
  679       {
  680         FacesListener listener = iter.next();
  681         if (event.isAppropriateListener(listener))
  682         {
  683           event.processListener(listener);
  684         }
  685       }
  686   
  687       if (event instanceof AttributeChangeEvent)
  688       {
  689         broadcastToMethodExpression(event, getAttributeChangeListener());
  690       }
  691     }
  692   
  693   
  694     // ------------------------------------------- Lifecycle Processing Methods
  695   
  696   
  697     @Override
  698     public void decode(FacesContext context)
  699     {
  700       if (context == null)
  701         throw new NullPointerException();
  702   
  703       // Find all the partialTriggers and save on the context
  704       Map<String, Object> attrs = getAttributes();
  705       Object triggers = attrs.get("partialTriggers");
  706       if (triggers instanceof String[])
  707       {
  708         RequestContext adfContext = RequestContext.getCurrentInstance();
  709         if (adfContext != null)
  710           adfContext.addPartialTriggerListeners(this, (String[]) triggers);
  711       }
  712   
  713       __rendererDecode(context);
  714     }
  715   
  716     @Override
  717     public void encodeBegin(FacesContext context) throws IOException
  718     {
  719       if (context == null)
  720         throw new NullPointerException();
  721   
  722       if (!isRendered())
  723         return;
  724   
  725       _cacheRenderer(context);
  726       Renderer renderer = getRenderer(context);
  727       // if there is a Renderer for this component
  728       if (renderer != null)
  729       {
  730         renderer.encodeBegin(context, this);
  731       }
  732     }
  733   
  734     @Override
  735     public void encodeChildren(FacesContext context) throws IOException
  736     {
  737       if (context == null)
  738         throw new NullPointerException();
  739   
  740       if (!isRendered())
  741         return;
  742   
  743       Renderer renderer = getRenderer(context);
  744       // if there is a Renderer for this component
  745       if (renderer != null)
  746       {
  747         renderer.encodeChildren(context, this);
  748       }
  749     }
  750   
  751     @Override
  752     public void encodeEnd(FacesContext context) throws IOException
  753     {
  754       if (context == null)
  755         throw new NullPointerException();
  756   
  757       if (isRendered())
  758       {
  759         Renderer renderer = getRenderer(context);
  760         // if there is a Renderer for this component
  761         if (renderer != null)
  762         {
  763           renderer.encodeEnd(context, this);
  764         }
  765       }
  766     }
  767   
  768     /**
  769      * Encodes a component and all of its children, whether
  770      * getRendersChildren() is true or false.  When rendersChildren
  771      * is false, each child whose "rendered" property is true
  772      * will be sequentially rendered;  facets will be ignored.
  773      */
  774     @Override
  775     public void encodeAll(FacesContext context) throws IOException
  776     {
  777       if (context == null)
  778         throw new NullPointerException();
  779   
  780       // This code ends up calling isRendered() once overall,
  781       // plus up to three times more for encodeBegin(),
  782       // encodeChildren(), and encodeEnd().
  783       __encodeRecursive(context, this);
  784     }
  785   
  786     @Override
  787     public void queueEvent(FacesEvent event)
  788     {
  789       if (event == null)
  790         throw new NullPointerException();
  791   
  792       UIComponent parent = getParent();
  793       if (parent == null)
  794         throw new IllegalStateException();
  795   
  796       parent.queueEvent(event);
  797     }
  798   
  799     // ----------------------------------------------- Lifecycle Phase Handlers
  800   
  801     @Override
  802     public void processDecodes(FacesContext context)
  803     {
  804       if (context == null)
  805         throw new NullPointerException();
  806   
  807       if (!isRendered())
  808         return;
  809   
  810       // Process all facets and children of this component
  811       decodeChildren(context);
  812   
  813       // Process this component itself
  814       decode(context);
  815   
  816     }
  817   
  818     @Override
  819     public void processValidators(FacesContext context)
  820     {
  821       if (context == null)
  822         throw new NullPointerException();
  823   
  824       if (!isRendered())
  825         return;
  826   
  827       // Process all facets and children of this component
  828       validateChildren(context);
  829     }
  830   
  831     @Override
  832     public void processUpdates(FacesContext context)
  833     {
  834       if (context == null)
  835         throw new NullPointerException();
  836   
  837       if (!isRendered())
  838         return;
  839   
  840       // Process all facets and children of this component
  841       updateChildren(context);
  842     }
  843   
  844     @Override
  845     public Object processSaveState(FacesContext context)
  846     {
  847       if (context == null)
  848         throw new NullPointerException();
  849   
  850       if (_LOG.isFiner())
  851         _LOG.finer("processSaveState() on " + this);
  852   
  853       if (((_children == null) || _children.isEmpty()) &&
  854           ((_facets == null) || _facets.isEmpty()))
  855       {
  856         return saveState(context);
  857       }
  858       else
  859       {
  860         TreeState state = new TreeState();
  861         state.saveState(context, this);
  862         if (state.isEmpty())
  863           return null;
  864   
  865         return state;
  866       }
  867     }
  868   
  869     // TODO  will have deep problems if UIComponent.saveState() ever
  870     //   returns a String.
  871     // TODO crashes and burns if there are fewer children or missing
  872     //  facets from when state was saved.
  873     @Override
  874     public void processRestoreState(FacesContext context, Object state)
  875     {
  876       if (context == null)
  877         throw new NullPointerException();
  878   
  879       if (_LOG.isFiner())
  880         _LOG.finer("processRestoreState() on " + this);
  881   
  882       // If we saved a "TreeState", use it to restore everything
  883       if (state instanceof TreeState)
  884       {
  885         ((TreeState) state).restoreState(context, this);
  886       }
  887       // Otherwise, we had no children or facets, and just use
  888       // the "state" object
  889       else
  890       {
  891         restoreState(context, state);
  892       }
  893     }
  894   
  895     @Override
  896     public void markInitialState()
  897     {
  898       // -= Simon Lessard =-
  899       // FIXME: Set to true, but never read
  900       //_initialStateMarked = true;
  901       getFacesBean().markInitialState();
  902     }
  903   
  904     public Object saveState(FacesContext context)
  905     {
  906       return getFacesBean().saveState(context);
  907     }
  908   
  909     public void restoreState(FacesContext context, Object stateObj)
  910     {
  911       getFacesBean().restoreState(context, stateObj);
  912     }
  913   
  914   
  915     @Override
  916     public String toString()
  917     {
  918       String className = getClass().getName();
  919       int periodIndex = className.lastIndexOf('.');
  920       if (periodIndex >= 0)
  921         className = className.substring(periodIndex + 1);
  922   
  923       return className + "[" + getFacesBean().toString() + ", id=" + getId() + "]";
  924     }
  925   
  926     /**
  927      * <p>Return the {@link FacesContext} instance for the current request.</p>
  928      */
  929     @Override
  930     protected FacesContext getFacesContext()
  931     {
  932       // If we ever have a way for a component to get notified
  933       // when it's finished being used for a given request,
  934       // we could cache this as an instance variable.
  935       return FacesContext.getCurrentInstance();
  936     }
  937   
  938   
  939     /**
  940      * Delegates to LifecycleRenderer, if present,
  941      * otherwise calls decodeChildrenImpl.
  942      *
  943      * @param context the current FacesContext
  944      */
  945     final protected void decodeChildren(FacesContext context)
  946     {
  947       LifecycleRenderer renderer = getLifecycleRenderer(context);
  948       // if there is a HierarchyRenderer for this component
  949       if (renderer != null)
  950       {
  951         if (renderer.decodeChildren(context, this))
  952           return;
  953       }
  954   
  955       decodeChildrenImpl(context);
  956     }
  957   
  958     /**
  959      * Calls processDecodes on all facets and children of this
  960      * component.
  961      * @param context the current FacesContext
  962      */
  963     protected void decodeChildrenImpl(FacesContext context)
  964     {
  965       Iterator<UIComponent> kids = getFacetsAndChildren();
  966       while (kids.hasNext())
  967       {
  968         UIComponent kid = kids.next();
  969         kid.processDecodes(context);
  970       }
  971     }
  972   
  973   
  974     /**
  975      * Delegates to LifecycleRenderer, if present,
  976      * otherwise calls validateChildrenImpl.
  977      *
  978      * @param context the current FacesContext
  979      */
  980     final protected void validateChildren(FacesContext context)
  981     {
  982       LifecycleRenderer renderer = getLifecycleRenderer(context);
  983       // if there is a ExtendedRenderer for this component
  984       if (renderer != null)
  985       {
  986         if (renderer.validateChildren(context, this))
  987           return;
  988       }
  989   
  990       validateChildrenImpl(context);
  991     }
  992   
  993     /**
  994      * Calls processValidators on all facets and children of this
  995      * component.
  996      * @param context the current FacesContext
  997      */
  998     protected void validateChildrenImpl(FacesContext context)
  999     {
 1000       // Process all the facets and children of this component
 1001       Iterator<UIComponent> kids = getFacetsAndChildren();
 1002       while (kids.hasNext())
 1003       {
 1004         UIComponent kid = kids.next();
 1005         kid.processValidators(context);
 1006       }
 1007     }
 1008   
 1009   
 1010     /**
 1011      * Delegates to LifecycleRenderer, if present,
 1012      * otherwise calls upateChildrenImpl.
 1013      *
 1014      * @param context the current FacesContext
 1015      */
 1016     final protected void updateChildren(FacesContext context)
 1017     {
 1018       LifecycleRenderer renderer = getLifecycleRenderer(context);
 1019       // if there is a ExtendedRenderer for this component
 1020       if (renderer != null)
 1021       {
 1022         if (renderer.updateChildren(context, this))
 1023           return;
 1024       }
 1025   
 1026       updateChildrenImpl(context);
 1027     }
 1028   
 1029     protected void updateChildrenImpl(FacesContext context)
 1030     {
 1031       // Process all the facets and children of this component
 1032       Iterator<UIComponent> kids = getFacetsAndChildren();
 1033       while (kids.hasNext())
 1034       {
 1035         UIComponent kid = kids.next();
 1036         kid.processUpdates(context);
 1037       }
 1038     }
 1039   
 1040     @Override
 1041     protected void addFacesListener(FacesListener listener)
 1042     {
 1043       if (listener == null)
 1044         throw new NullPointerException();
 1045   
 1046       getFacesBean().addEntry(_LISTENERS_KEY, listener);
 1047     }
 1048   
 1049     @Override
 1050     protected void removeFacesListener(FacesListener listener)
 1051     {
 1052       if (listener == null)
 1053         throw new NullPointerException();
 1054   
 1055       getFacesBean().removeEntry(_LISTENERS_KEY, listener);
 1056     }
 1057   
 1058     @Override
 1059     protected FacesListener[] getFacesListeners(Class clazz)
 1060     {
 1061       if (clazz == null)
 1062         throw new NullPointerException();
 1063   
 1064       if (!FacesListener.class.isAssignableFrom(clazz))
 1065         throw new IllegalArgumentException();
 1066   
 1067       return (FacesListener[])
 1068          getFacesBean().getEntries(_LISTENERS_KEY, clazz);
 1069     }
 1070   
 1071     protected void addAttributeChange(
 1072       String attributeName,
 1073       Object attributeValue)
 1074     {
 1075       AttributeComponentChange aa =
 1076         new AttributeComponentChange(attributeName, attributeValue);
 1077       RequestContext adfContext = RequestContext.getCurrentInstance();
 1078       adfContext.getChangeManager().addComponentChange(getFacesContext(), this, aa);
 1079     }
 1080   
 1081     void __rendererDecode(FacesContext context)
 1082     {
 1083       _cacheRenderer(context);
 1084       Renderer renderer = getRenderer(context);
 1085       // if there is a Renderer for this component
 1086       if (renderer != null)
 1087       {
 1088         renderer.decode(context, this);
 1089       }
 1090     }
 1091   
 1092     private void _cacheRenderer(FacesContext context)
 1093     {
 1094       Renderer renderer = _getRendererImpl(context);
 1095       _cachedRenderer = renderer;
 1096   
 1097       // cache the lifecycle renderer
 1098       if (renderer instanceof LifecycleRenderer)
 1099       {
 1100         _cachedLifecycleRenderer = (LifecycleRenderer)renderer;
 1101       }
 1102       else
 1103       {
 1104         _cachedLifecycleRenderer = null;
 1105       }
 1106     }
 1107   
 1108     private Renderer _getRendererImpl(FacesContext context)
 1109     {
 1110       String rendererType = getRendererType();
 1111       if (rendererType != null)
 1112       {
 1113         RenderKit renderKit = context.getRenderKit();
 1114         Renderer renderer = renderKit.getRenderer(getFamily(), rendererType);
 1115         if (renderer == null)
 1116         {
 1117           _LOG.warning("CANNOT_FIND_RENDERER", new Object[]{this, rendererType});
 1118         }
 1119   
 1120         return renderer;
 1121       }
 1122   
 1123       return null;
 1124     }
 1125   
 1126     private LifecycleRenderer _getLifecycleRendererImpl(FacesContext context)
 1127     {
 1128       Renderer renderer = _getRendererImpl(context);
 1129       if (renderer instanceof LifecycleRenderer)
 1130       {
 1131         return (LifecycleRenderer)renderer;
 1132       }
 1133   
 1134       return null;
 1135     }
 1136   
 1137     @Override
 1138     protected Renderer getRenderer(FacesContext context)
 1139     {
 1140       Renderer renderer = _cachedRenderer;
 1141       if (renderer != _UNDEFINED_RENDERER)
 1142         return renderer;
 1143   
 1144       return _getRendererImpl(context);
 1145     }
 1146   
 1147     protected LifecycleRenderer getLifecycleRenderer(FacesContext context)
 1148     {
 1149       LifecycleRenderer renderer = _cachedLifecycleRenderer;
 1150       if (renderer != _UNDEFINED_LIFECYCLE_RENDERER)
 1151         return renderer;
 1152   
 1153       return _getLifecycleRendererImpl(context);
 1154   
 1155     }
 1156   
 1157     protected void setProperty(PropertyKey key, Object value)
 1158     {
 1159       getFacesBean().setProperty(key, value);
 1160     }
 1161   
 1162     protected Object getProperty(PropertyKey key)
 1163     {
 1164       return getFacesBean().getProperty(key);
 1165     }
 1166   
 1167     protected void setBooleanProperty(PropertyKey key, boolean value)
 1168     {
 1169       getFacesBean().setProperty(key, value ? Boolean.TRUE : Boolean.FALSE);
 1170     }
 1171   
 1172     protected boolean getBooleanProperty(PropertyKey key, boolean defaultValue)
 1173     {
 1174       Object o = getFacesBean().getProperty(key);
 1175       if (defaultValue)
 1176         return !Boolean.FALSE.equals(o);
 1177       else
 1178         return Boolean.TRUE.equals(o);
 1179     }
 1180   
 1181     protected void setIntProperty(PropertyKey key, int value)
 1182     {
 1183       getFacesBean().setProperty(key, Integer.valueOf(value));
 1184     }
 1185   
 1186     protected int getIntProperty(PropertyKey key, int defaultValue)
 1187     {
 1188       Number n = (Number) getFacesBean().getProperty(key);
 1189       if (n == null)
 1190         return defaultValue;
 1191   
 1192       return n.intValue();
 1193     }
 1194   
 1195   
 1196     /**
 1197      * Return the number of facets.  This is more efficient than
 1198      * calling getFacets().size();
 1199      */
 1200     @Override
 1201     public int getFacetCount()
 1202     {
 1203       if (_facets == null)
 1204         return 0;
 1205   
 1206       return _facets.size();
 1207     }
 1208   
 1209   
 1210     /**
 1211      * Broadcast an event to a MethodBinding.
 1212      * This can be used to support MethodBindings such as the "actionListener"
 1213      * binding on ActionSource components:
 1214      * &lt;tr:commandButton actionListener="#{mybean.myActionListener}">
 1215      * @deprecated
 1216      */
 1217     protected final void broadcastToMethodBinding(
 1218       FacesEvent event,
 1219       MethodBinding method) throws AbortProcessingException
 1220     {
 1221       if (method != null)
 1222       {
 1223         try
 1224         {
 1225           FacesContext context = getFacesContext();
 1226           method.invoke(context, new Object[] { event });
 1227         }
 1228         catch (EvaluationException ee)
 1229         {
 1230           Throwable t = ee.getCause();
 1231           // Unwrap AbortProcessingExceptions
 1232           if (t instanceof AbortProcessingException)
 1233             throw ((AbortProcessingException) t);
 1234           throw ee;
 1235         }
 1236       }
 1237     }
 1238   
 1239     /**
 1240      * Given a MethodBinding, create a MethodExpression that
 1241      * adapts it.
 1242      */
 1243     static public MethodExpression adaptMethodBinding(MethodBinding binding)
 1244     {
 1245       return new MethodBindingMethodExpression(binding);
 1246     }
 1247   
 1248     /**
 1249      * Broadcast an event to a MethodExpression.
 1250      * This can be used to support MethodBindings such as the "actionListener"
 1251      * binding on ActionSource components:
 1252      * &lt;tr:commandButton actionListener="#{mybean.myActionListener}">
 1253      */
 1254     protected final void broadcastToMethodExpression(
 1255       FacesEvent event,
 1256       MethodExpression method) throws AbortProcessingException
 1257     {
 1258       if (method != null)
 1259       {
 1260         try
 1261         {
 1262           FacesContext context = getFacesContext();
 1263           method.invoke(context.getELContext(), new Object[] { event });
 1264         }
 1265         catch (ELException ee)
 1266         {
 1267           Throwable t = ee.getCause();
 1268           // Unwrap AbortProcessingExceptions
 1269           if (t instanceof AbortProcessingException)
 1270             throw ((AbortProcessingException) t);
 1271           throw ee;
 1272         }
 1273       }
 1274     }
 1275   
 1276   
 1277     /**
 1278      * <p>
 1279      * This gets a single threadlocal shared stringbuilder instance, each time you call
 1280      * __getSharedStringBuilder it sets the length of the stringBuilder instance to 0.
 1281      * </p><p>
 1282      * This allows you to use the same StringBuilder instance over and over.
 1283      * You must call toString on the instance before calling __getSharedStringBuilder again.
 1284      * </p>
 1285      * Example that works
 1286      * <pre><code>
 1287      * StringBuilder sb1 = __getSharedStringBuilder();
 1288      * sb1.append(a).append(b);
 1289      * String c = sb1.toString();
 1290      *
 1291      * StringBuilder sb2 = __getSharedStringBuilder();
 1292      * sb2.append(b).append(a);
 1293      * String d = sb2.toString();
 1294      * </code></pre>
 1295      * <br><br>
 1296      * Example that doesn't work, you must call toString on sb1 before
 1297      * calling __getSharedStringBuilder again.
 1298      * <pre><code>
 1299      * StringBuilder sb1 = __getSharedStringBuilder();
 1300      * StringBuilder sb2 = __getSharedStringBuilder();
 1301      *
 1302      * sb1.append(a).append(b);
 1303      * String c = sb1.toString();
 1304      *
 1305      * sb2.append(b).append(a);
 1306      * String d = sb2.toString();
 1307      * </code></pre>
 1308      *
 1309      */
 1310     static StringBuilder __getSharedStringBuilder()
 1311     {
 1312       StringBuilder sb = _STRING_BUILDER.get();
 1313   
 1314       if (sb == null)
 1315       {
 1316         sb = new StringBuilder();
 1317         _STRING_BUILDER.set(sb);
 1318       }
 1319   
 1320       // clear out the stringBuilder by setting the length to 0
 1321       sb.setLength(0);
 1322   
 1323       return sb;
 1324     }
 1325   
 1326     /**
 1327      * render a component. this is called by renderers whose
 1328      * getRendersChildren() return true.
 1329      */
 1330     void __encodeRecursive(FacesContext context, UIComponent component)
 1331       throws IOException
 1332     {
 1333       if (component.isRendered())
 1334       {
 1335         component.encodeBegin(context);
 1336         if (component.getRendersChildren())
 1337         {
 1338           component.encodeChildren(context);
 1339         }
 1340         else
 1341         {
 1342           if (component.getChildCount() > 0)
 1343           {
 1344             for(UIComponent child : component.getChildren())
 1345             {
 1346               __encodeRecursive(context, child);
 1347             }
 1348           }
 1349         }
 1350   
 1351         component.encodeEnd(context);
 1352       }
 1353     }
 1354   
 1355   
 1356     static private UIComponent _findInsideOf(
 1357       UIComponent from,
 1358       String id)
 1359     {
 1360       Iterator<UIComponent> kids = from.getFacetsAndChildren();
 1361       while (kids.hasNext())
 1362       {
 1363         UIComponent kid = kids.next();
 1364         if (id.equals(kid.getId()))
 1365           return kid;
 1366   
 1367         if (!(kid instanceof NamingContainer))
 1368         {
 1369           UIComponent returned = _findInsideOf(kid, id);
 1370           if (returned != null)
 1371             return returned;
 1372         }
 1373       }
 1374   
 1375       return null;
 1376     }
 1377   
 1378     /**
 1379      * <p>Verify that the specified component id is safe to add to the tree.
 1380      * </p>
 1381      *
 1382      * @param id The proposed component id to check for validity
 1383      *
 1384      * @exception IllegalArgumentException if <code>id</code>
 1385      *  is <code>null</code> or contains invalid characters
 1386      */
 1387     private void _validateId(String id)
 1388     {
 1389       if (id == null)
 1390         return;
 1391   
 1392   
 1393       int n = id.length();
 1394       if (0 == n ||
 1395           NamingContainer.SEPARATOR_CHAR == id.charAt(0))
 1396         _throwBadId(id);
 1397   
 1398       for (int i = 0; i < n; i++)
 1399       {
 1400         char c = id.charAt(i);
 1401         if (i == 0)
 1402         {
 1403           if (!Character.isLetter(c) && (c != '_'))
 1404             _throwBadId(id);
 1405         }
 1406         else
 1407         {
 1408           if (!(Character.isLetter(c) ||
 1409                 Character.isDigit(c) ||
 1410                 (c == '-') || (c == '_')))
 1411           {
 1412             _throwBadId(id);
 1413           }
 1414         }
 1415       }
 1416     }
 1417   
 1418     private void _throwBadId(String id)
 1419     {
 1420       throw new IllegalArgumentException(_LOG.getMessage(
 1421         "ILLEGAL_ID", id));
 1422     }
 1423   
 1424     private void _init(
 1425       String rendererType)
 1426     {
 1427       FacesBean oldBean = _facesBean;
 1428       _facesBean = createFacesBean(rendererType);
 1429       if (oldBean != null)
 1430         _facesBean.addAll(oldBean);
 1431   
 1432       _attributes = new ValueMap(_facesBean);
 1433     }
 1434   
 1435     private FacesBean                _facesBean;
 1436     private List<UIComponent>        _children;
 1437     private Map<String, Object>      _attributes;
 1438     private Map<String, UIComponent> _facets;
 1439     private UIComponent              _parent;
 1440   
 1441     // Cached instance of the Renderer for this component.
 1442     // The instance will be re-retrieved in encodeBegin()
 1443     private transient Renderer _cachedRenderer = _UNDEFINED_RENDERER;
 1444     private transient LifecycleRenderer _cachedLifecycleRenderer =
 1445                                                   _UNDEFINED_LIFECYCLE_RENDERER;
 1446   
 1447     // -= Simon Lessard =-
 1448     // FIXME: _initialStateMarked is never read
 1449     //        So commented out, is that ok? If so, this attribute should be deleted
 1450     //private transient boolean _initialStateMarked;
 1451   
 1452     private static final Iterator<String> _EMPTY_STRING_ITERATOR =
 1453       new EmptyIterator<String>();
 1454   
 1455     private static final Iterator<UIComponent> _EMPTY_UICOMPONENT_ITERATOR =
 1456       new EmptyIterator<UIComponent>();
 1457   
 1458   
 1459     static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
 1460                                                           new ThreadLocal<StringBuilder>();
 1461   
 1462     static private FacesBean.Type _createType()
 1463     {
 1464       try
 1465       {
 1466         ClassLoader cl = _getClassLoader();
 1467         URL url = cl.getResource("META-INF/faces-bean-type.properties");
 1468         if (url != null)
 1469         {
 1470           Properties properties = new Properties();
 1471           InputStream is = url.openStream();
 1472           try
 1473           {
 1474             properties.load(is);
 1475             String className = (String)
 1476               properties.get(UIXComponentBase.class.getName());
 1477             return (FacesBean.Type) cl.loadClass(className).newInstance();
 1478           }
 1479           finally
 1480           {
 1481             is.close();
 1482           }
 1483         }
 1484       }
 1485       catch (Exception e)
 1486       {
 1487         _LOG.severe("CANNOT_LOAD_TYPE_PROPERTIES", e);
 1488       }
 1489   
 1490       // For testing purposes, return a valid Type
 1491       return new FacesBean.Type();
 1492     }
 1493   
 1494     static private ClassLoader _getClassLoader()
 1495     {
 1496       ClassLoader loader = Thread.currentThread().getContextClassLoader();
 1497       if (loader == null)
 1498         loader = FacesBeanFactory.class.getClassLoader();
 1499       return loader;
 1500     }
 1501   
 1502     static private class RendererImpl extends Renderer
 1503     {
 1504     }
 1505   
 1506     static private class ExtendedRendererImpl extends ExtendedRenderer
 1507     {
 1508     }
 1509   
 1510     private static class EmptyIterator<T> implements Iterator<T>
 1511     {
 1512       public boolean hasNext()
 1513       {
 1514         return false;
 1515       }
 1516   
 1517       public T next()
 1518       {
 1519         throw new NoSuchElementException();
 1520       }
 1521   
 1522       public void remove()
 1523       {
 1524         throw new UnsupportedOperationException();
 1525       }
 1526   
 1527     }
 1528   
 1529     static private final LifecycleRenderer _UNDEFINED_LIFECYCLE_RENDERER =
 1530                                                   new ExtendedRendererImpl();
 1531     static private final Renderer _UNDEFINED_RENDERER = new RendererImpl();
 1532   }

Save This Page
Home » trinidad-1.2.8-src-all » org.apache.myfaces.trinidad » component » [javadoc | source]