org.apache.myfaces.trinidad.util
Class ComponentReference<T extends javax.faces.component.UIComponent>

java.lang.Object
  extended by 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:

See Also:
newUIComponentReference(UIComponent), getComponent(), Serialized Form

Method Summary
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 Objects (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-2012 The Apache Software Foundation. All Rights Reserved.