org.apache.myfaces.trinidad.util

## Class ComponentReference<T extends javax.faces.component.UIComponent>

- java.lang.Object
- - org.apache.myfaces.trinidad.util.ComponentReference<T>

- All Implemented Interfaces:
    Serializable

      public abstract class ComponentReference<T extends javax.faces.component.UIComponent>
      extends Object
      implements Serializable

  A utility to store a reference to an `UIComponent`. Application developers should use this tool if they need to have a reference to an instance of the `UIComponent` class in `managed beans` that are longer than requested scoped --for example Session and Application Scoped. The reference will return the UIComponent, if any, with the same scoped id as the Component used to create the reference, in the current UIViewRoot. Use `newUIComponentReference()` to create a `ComponentReference` and use the `getComponent()` to look up the referenced `UIComponent`. For example, a current weather application might have have a session scoped weatehrBean containing the current list of locations to report the weather on and support using a selectMany component to remove the locations:

  The weatherBean might looks like this:

       public class WeatherBean implements Serializable
       {
         public void setLocationsToRemove(UIXSelectMany locationsToRemove)
         {
           _locationsToRemove = locationsToRemove;
         }

         public UIXSelectMany getLocationsToRemove()
         {
           return _locationsToRemove;
         }

         public void removeLocationListener(ActionEvent actionEvent)
         {
           ... code calling getLocationsToRemove() to get the UIXSelectMany ...
         }

         private UIXSelectMany _locationsToRemove
       }

  This code has several problems:
  1. Since UIComponents aren't Serializable, the class will fail serialization during fail-over when default Serialization attempts to serialize _locationsToRemove.
  2. If the user opens two windows on this page, only the last window rendered have the correct UIXSelectMany instance. If the remove locations button is pressed on the first window after rendering the second window, the wrong UIXSelectMany instance will be used.
  3. Since UIComponents aren't thread-safe, the above case could also result in bizare behavior if requests from both windows were being processed by the application server at the same time.
  4. If the Trinidad view state token cache isn't used, or if the user navigates to this page using the backbutton, a new UIXSelectMany instance will be created, which also won't match the instance we are holding onto.
  5. If we don't clear the UIXSelectMany instance when we navigate off of this page, we will continue to pin the page's UIComponent tree in memory for the lifetime of the Session.
  Rewritten using ComponentReference, the weatherBean might looks like this:

       public class WeatherBean implements Serializable
       {
         public void setLocationsToRemove(UIXSelectMany locationsToRemove)
         {
           _locationsToRemoveRef = UIComponentReference.newUIComponentReference(locationsToRemove);
         }

         public UIXSelectMany getLocationsToRemove()
         {
           return _locationsToRemoveRef.getComponent();
         }

         public void removeLocationListener(ActionEvent actionEvent)
         {
           ... code calling getLocationsToRemove() to get the UIXSelectMany ...
         }

         private UIComponentReference _locationsToRemoveRef
       }

  The above code saves a reference to the component passed to the managed bean and then retrieves the correct instance given the current UIViewRoot for this request whenever `getLocationsToRemove()` is called.

  Please note:

  - This class is not completely thread-safe, since it depends on `UIComponent` APIs, however the class is safe to use as long as either of the following is true
    1. The component passed to `newUIComponentReference` has an id and is in the component hierarchy when newUIComponentReference is called and all subsequent calls to `getComponent` are made from Threads with a valid FacesContext
    2. The first call to `getComponent` is on the same Thread that `newUIComponentReference` was called on
  - The passed in `UIComponent` is required to have an `ID`
  - The reference will break if the `UIComponent` is moved between `NamingContainer`s or if any of the ancestor `NamingContainer`s have their IDs changed.
  - The reference is persistable. However `UIComponent`s are not `Serializable` and therefore can not be used at any scope longer than request.
  See Also:
    `newUIComponentReference(UIComponent)`, `getComponent()`, Serialized Form

- - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `protected static List<Object>` | `calculateComponentPath(javax.faces.component.UIComponent component)` Creates the "component path" started by the given `UIComponent` up the `UIViewRoot` of the underlying component tree.
    `protected static String` | `calculateScopedId(javax.faces.component.UIComponent component, String componentId)`
    `abstract void` | `ensureInitialization()` Called by the framework to ensure that deferred ComponentReferences are completely initialized before the UIComponent that the ComponentReference is associated with is not longer valid.
    `boolean` | `equals(Object o)` ComponentRefs are required to test for equivalence by the equivalence of their scoped ids
    `T` | `getComponent()` This method will use a calculated "component path" to walk down to the `UIComponent` that is referenced by this class.
    `protected abstract String` | `getComponentId()` Returns the id of the Component that this ComponentReference points to
    `protected abstract String` | `getScopedId()` Returns the scoped id for this ComponentReference
    `protected static javax.faces.component.UIViewRoot` | `getUIViewRoot(javax.faces.component.UIComponent component)`
    `int` | `hashCode()` ComponentRefs must use the hash code of their scoped id as their hash code
    `static <T extends javax.faces.component.UIComponent> ComponentReference<T>` | `newUIComponentReference(T component)` Factory method to create an instance of the `ComponentReference` class, which returns a Serializable and often thread-safe reference to a `UIComponent`.
    `protected void` | `setComponentPath(List<Object> componentPath)`
    `String` | `toString()`
    `protected Object` | `writeReplace()`

    - ### Methods inherited from class java.lang.Object

      `clone, finalize, getClass, notify, notifyAll, wait, wait, wait`

- - ### Method Detail

    - #### newUIComponentReference

          public static <T extends javax.faces.component.UIComponent> ComponentReference<T> newUIComponentReference(T component)

      Factory method to create an instance of the `ComponentReference` class, which returns a Serializable and often thread-safe reference to a `UIComponent`.
      Parameters:
        `component` - the `UIComponent` to create a reference to.
      Returns:
        `ComponentReference` the reference to the component
      Throws:
        `NullPointerException` - if component is `null`

    - #### getComponent

          public final T getComponent()

      This method will use a calculated "component path" to walk down to the `UIComponent` that is referenced by this class. If the component can not be found, the `getComponent()` will return `null`.
      Returns:
        the referenced `UIComponent` or `null` if it can not be found.
      Throws:
        `IllegalStateException` - if the component used to create the ComponentReference is not in the component tree or does not have an `Id`
      See Also:
        `newUIComponentReference(UIComponent)`

    - #### ensureInitialization

          public abstract void ensureInitialization()

      Called by the framework to ensure that deferred ComponentReferences are completely initialized before the UIComponent that the ComponentReference is associated with is not longer valid.
      Throws:
        `IllegalStateException` - if ComponentReference isn't already initialized and the component used to create the ComponentReference is not in the component tree or does not have an `Id`

    - #### equals

          public final boolean equals(Object o)

      ComponentRefs are required to test for equivalence by the equivalence of their scoped ids
      Overrides:
        `equals` in class `Object`
      Parameters:
        `o` -
      Returns:

    - #### hashCode

          public final int hashCode()

      ComponentRefs must use the hash code of their scoped id as their hash code
      Overrides:
        `hashCode` in class `Object`
      Returns:

    - #### toString

          public final String toString()

      Overrides:
        `toString` in class `Object`

    - #### getScopedId

          protected abstract String getScopedId()

      Returns the scoped id for this ComponentReference
      Returns:

    - #### getComponentId

          protected abstract String getComponentId()

      Returns the id of the Component that this ComponentReference points to
      Returns:

    - #### setComponentPath

          protected final void setComponentPath(List<Object> componentPath)

    - #### calculateComponentPath

          protected static List<Object> calculateComponentPath(javax.faces.component.UIComponent component)

      Creates the "component path" started by the given `UIComponent` up the `UIViewRoot` of the underlying component tree. The hierarchy is stored in a `List` of `Object`s (the `componentHierarchyList` parameter). If the given `UIComponent` is nested in a `Facet` of a `UIComponent`, we store the name of the actual `facet` in the list. If it is a regular child, we store its position/index.

      To calculate the `scopedID` we add the ID of every `NamingContainer` that we hit, while walking up the component tree, to the `scopedIdList`.

      Parameters:
        `component` - The `UIComponent` for this current iteration
      See Also:
        `newUIComponentReference(T)`

    - #### calculateScopedId

          protected static String calculateScopedId(javax.faces.component.UIComponent component,
                                 String componentId)

    - #### writeReplace

          protected Object writeReplace()
                                 throws ObjectStreamException

      Throws:
        `ObjectStreamException`

    - #### getUIViewRoot

          protected static javax.faces.component.UIViewRoot getUIViewRoot(javax.faces.component.UIComponent component)

Copyright © 2001-2017 The Apache Software Foundation. All Rights Reserved.