Thursday, October 25, 2012

Creating an adaptive layout in ADF for desktop vs. tablet

It is often ideal to create pages tailored to be accessed on a mobile device or on the desktop, but not every company has the resources to author and maintain two web sites. What if you could define most of your pages to be the same for both devices but simply adapt the layout based on the device?

The Oracle ADF framework has the necessary tools to make this easy. For example, take an application where you desire to show a list of navigation links that is always accessible and a main content area. On the desktop, you usually have a larger screen that you can work with. There you may choose to use a splitter pane that the user can collapse that is shown on the left side of the browser. On the right would be the details of the current page. On a mobile device, you may not be able to spare the width required to show the splitter and would instead rather show the navigation links in a popup.

The solution is fairly simple in ADF, by leveraging the dynamic declarative component, facet references and JSTL tags (that are supported in either facelets or JSP), you can have a layout that easily adapts to the device.

To create such a site, first create an ADF application. You can do so by downloading a 11.1.2.3.0 JDeveloper from the JDeveloper OTN page. Open JDeveloper and create a new Fusion Web Application (ADF) and accept the defaults. Create a new Page (either JSP or facelets based on your preference). In that page, you will want to add a reference to a page fragment that defines the content for a dynamic declarative component (note that a page template will also work and will allow you to pass an ADF model page template binding if desired). In this component, you will want to pass 2 facets, one for the navigation and one for the body. Should you want the same navigation on every page, you could create a page template and include the declarative component from the page template.

The technique allows you to define the content for the navigation area and the content separately from the layout. By passing these areas as faces to a declarative component, it allows you to dynamically place the content into different locations based on the device.

Example index page showing the usage of the declarative component:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <af:document title="index.jsf" id="d1">
    <af:form id="f1">
      <af:declarativeComponent id="dc" viewId="/dynamicLayout.jsff">
        <f:facet name="navigation">
          <af:navigationPane hint="list" id="np1">
            <af:commandNavigationItem text="Home" id="cni1"/>
            <af:commandNavigationItem text="Manage items 1" id="cni2"/>
            <af:commandNavigationItem text="Manage items 2" id="cni3"/>
            <af:commandNavigationItem text="Manage items 3" id="cni4"/>
            <af:commandNavigationItem text="Manage items 4" id="cni5"/>
            <af:commandNavigationItem text="Manage items 5" id="cni6"/>
            <af:commandNavigationItem text="Manage items 6" id="cni7"/>
            <af:commandNavigationItem text="Manage items 7" id="cni8"/>
            <af:commandNavigationItem text="Manage items 8" id="cni9"/>
            <af:commandNavigationItem text="Manage items 9" id="cni10"/>
            <af:commandNavigationItem text="Manage items 10" id="cni11"/>
            <af:commandNavigationItem text="Manage items 11" id="cni12"/>
            <af:commandNavigationItem text="Manage items 12" id="cni13"/>
            <af:commandNavigationItem text="Manage items 13" id="cni14"/>
            <af:commandNavigationItem text="Manage items 14" id="cni15"/>
            <af:commandNavigationItem text="Manage items 15" id="cni16"/>
            <af:commandNavigationItem text="Manage items 16" id="cni17"/>
            <af:commandNavigationItem text="Manage items 17" id="cni18"/>
          </af:navigationPane>
        </f:facet>
        <f:facet name="content">
          <af:panelGroupLayout layout="scroll" id="pgl2">
            <af:outputText value="lorem ipsum dolor sit amet officia modi anim voluptas studiosius. viribus doloribus tempus, ratione quasi. voluptates laborum quis, unum rerum. quamque cumque dolor explicabo reprehenderit. maiores nostrud ad, mites quidem. honestam quamque placeat, Et propter. ad anim cum acceperat Ut. mollitia iure humani, quaerat acceperat. nec eos culpa reprehenderit dignissimos. aspernatur feris laboriosam dolore.
lorem ipsum dolor sit amet repellat et molestias liberos quia. fugiat enim sint, reddidit earum. magnam eveniet id ut necessitatibus. reprehenderit aliquam commodo viribus dolor. et voluptate et, reprehenderit non. esse reiciendis reddere; culpa.
lorem ipsum dolor sit amet non voluptatem sapiens. officia harum illum ita rerum. iste in ipsa perniciosissimis natus. passim esse abditos animi dolore. quibusdam irure ut, Quis ipsum. tenetur victu ut enim quos. illum orationem se, delectus reddere;. sed velit velit, eaque aliqua. aliquam sapiente lorem voluptatum dolore. aut fugiat totam rerum.
lorem ipsum dolor sit amet nondum voluptatem ab. primo Duis propagabant consequatur non. dolor quia victu quid dolore. dolorem eos Sed odio inscientiam. id aut in, et facilis. quo deserunt sed, sint errorem. studiosius delectus maxime qui ducimus. sapiens soluta alias labore ex. et corporis unam non se. nisi corporis et expedita.
lorem ipsum dolor sit amet facere ex occaecati. magnam quae reprehenderit, culpa acceperat. natus nesciunt quia lorem iste. qui eu aequabile quisquam.
lorem ipsum dolor sit amet quadam earum quidam. perferendis in in, optio dolor. expedita cognovit rerum minus quia. quas qui quanta fuga deleniti. quam labore deinde ducimus materia. praesentium non saepe, si ut. voluptas quia se acceperat.
lorem ipsum dolor sit amet et et rerum quibusdam commodo. aute temeraria nuptias, audientes non. rem voluptate viderat sit irure. alias reddidit aliqua propter pariatur. ad doloribus doloremque, recusandae pariatur. elicere ad ius viribus tempor. dignissimos dolores res, dignissimos optio. consectetur deleniti atque excepturi.
lorem ipsum dolor sit amet est et placeat. religionis et et animi dispersos. modi nulla voluptate, officia esset. consequatur sunt quisquam soluta et. reprehenderit illo et, liberos cupiditate. inesset victu cupiditate magnam.
lorem ipsum dolor sit amet fero se congregavit recusandae ratione. ea ad quamque, nihil nobis. aperiam facilis ea voluptate conpulit. perferendis eveniet suscipit cupidatat ius. cognovit cillum conpulit impedit eligendi. deserunt corporis non aut Et. ut eam rem, non propagabant. molestiae quis commodi nemo.
lorem ipsum dolor sit amet amet aliquip reiciendis esse dolores. et beatae consequatur, unam et. divinae beatae agros, ducimus sint. do provident quo, temeraria qui. omnis Nemo utilem Excepteur minus. qui culpa perspiciatis, ratione in. et exercitationem qui, a libero. minima fero vel quo.
lorem ipsum dolor sit amet et consequatur qui Quis aperiam. voluptatibus nisi ad, viderat corporis. non nihil amet quos in. et numquam earum voluptate totam. voluptatum ad animi, minim et. videlicet perspiciatis nisi, libero propter. repellendus victu propter, rerum officiis. quidam possimus quicquam, dolore nihil. rerum ullamco aliquip, quaerat rerum. asperiores a vitam non.
lorem ipsum dolor sit amet hominum ipsum feris voluptatem ea. eos ad Itaque, dolorem consectetur. qui eligendi voluptatibus distinctio corporis. occaecat eveniet Excepteur, eos nihil. acceperat dolores elicere ea blanditiis. id esse satellitibus vagabantur.
lorem ipsum dolor sit amet consectetur consequatur officia sit nulla. expedita molestiae est nihil deserunt. molestiae adipisci quo iusto reclamantes. sint quia et ea.
lorem ipsum dolor sit amet maiores magnam deleniti. legitimas ex et nulla voluptates. sapiens alias quas victu nulla. veniam fuga eos est dolorum. autem distinctio corrupti, fuga inesset. consequatur autem viribus, officia Ut. propter non reprehenderit et culpa. laboriosam maximas in ipsum repudiandae. dolor et expedita sunt divinae. magnus autem necessitatibus bestiarum.
lorem ipsum dolor sit amet ad tempore opportunitas. aut sit magni, quis elit. sapiente liberos occaecat adipisci delectus. consectetur dignissimos et, inventore officii. impedit nec in, nuptias vitam. in voluptatem rerum minim et. administrabant et et, quo adipisicing. beatae ratione in, pariatur consequatur. quas animis fero si eius. quod rerum molestiae aliqua.
lorem ipsum dolor sit amet qui honestam acceperat animi voluptas. excepturi saepe et, tempus maxime. ut doloremque dolores, illo officiis. eam sed optio, unde Nemo. omnis laborum quis fugiat in. et voluptate aut, inducens in. molestias honestam laboris, mollit facere. voluptatem eos nihil occaecat repellendus. dolor cupiditas pleraque quos mollit. mollit hic conpulit aut.
lorem ipsum dolor sit amet in molestias qui. reclamantes sit reddidit, quis abutebatur. esse deserunt Ut, laboris atque. quas locum At, eaque studiosius. aspexerat elit dispersos, distinctio inesset. quo aut quadam, orationem ullamco. ac inscientiam lorem, amet ut. voluptas ex silvestribus videlicet.
lorem ipsum dolor sit amet aute abutebatur perniciosissimis omnis non. quis ullam sunt, nemo qui. quia id rerum mansuetos nobis. eos quid in si bestiarum. est earum placeat, nulla et. in reddidit sint, homines nostrum. in aut iste, accusamus et. velit in nulla soluta rem. atque honestam At ratio dolorum. natus omnis dolores laborum.
lorem ipsum dolor sit amet ratione aliquid rerum nam assumenda. nihil omnis ut, studiosius id. rem corporis enim quoddam aut. pariatur pleraque est voluptatem Duis. explendam deserunt pleraque numquam qui. commodo dolor sint, studiosius reddere;. Nemo ut voluptas rerum sit. officia sed nec, a est. reprehenderit mites laudantium veniam."
                           id="ot1"/>
          </af:panelGroupLayout>
        </f:facet>
      </af:declarativeComponent>
    </af:form>
  </af:document>
</f:view>

In the declarative component, you will now want to use JSTL to build either a splitter or a button that shows a popup based on the device. ADF has an API for the browser agent that includes capabilities. One of the capabilities that is exposed is if the agent is a touch screen device (Android and iOS devices). By referencing this capability from JSTL, you can change what components are created. Example EL usage:

<c:if test="${adfFacesContext.agent.capabilities['touchScreen'] eq 'none' ? true : false}">

Using this you can create two layouts, each using af:facetRef to include the passed in facets. Note that JDev will report errors that the facet is used more than once, but that is only because it does not know the c:if tag will be sure to only render one set. Example code for the declarative component page fragment:

<?xml version='1.0' encoding='UTF-8'?>
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
                xmlns:f="http://java.sun.com/jsf/core">
  <af:componentDef var="attrs" componentVar="comp">
    <af:xmlContent>
      <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
        <description>Layout dynamically adjusted based on user agent</description>
        <facet>
          <facet-name>
            navigation
          </facet-name>
        </facet>
        <facet>
          <facet-name>
            content
          </facet-name>
        </facet>
      </component>
    </af:xmlContent>
    <c:if test="${adfFacesContext.agent.capabilities['touchScreen'] eq 'none' ? true : false}">
      <af:panelSplitter id="dc_ps1" dimensionsFrom="parent">
        <f:facet name="first">
          <af:facetRef facetName="navigation" />
        </f:facet>
        <f:facet name="second">
          <af:facetRef facetName="content" />
        </f:facet>
      </af:panelSplitter>
    </c:if>
    <c:if test="${adfFacesContext.agent.capabilities['touchScreen'] eq 'none' ? false : true}">
      <af:panelStretchLayout topHeight="2em" bottomHeight="0" id="dc_psl1"
                             dimensionsFrom="children">
        <f:facet name="top">
          <af:panelGroupLayout id="dc_pgl1">
            <af:commandButton id="dc_cil1" text="Open navigation" iconPosition="trailing"
                                 icon="/afr/fusion/dropdown_ena.png">
              <af:showPopupBehavior popupId="dc_navPopup" triggerType="action" align="overlap"/>
            </af:commandButton>
          </af:panelGroupLayout>
        </f:facet>
        <f:facet name="center">
          <af:facetRef facetName="content"/>
        </f:facet>
        <f:facet name="bottom">
          <af:popup id="dc_navPopup">
            <af:facetRef facetName="navigation" />
          </af:popup>
        </f:facet>
      </af:panelStretchLayout>
    </c:if>
  </af:componentDef>
</ui:composition>

Now load the page in a browser and on an iPad and see the layout change. How it looks on the desktop:

desktop image

How it looks on an iPad:

iPad image

How it looks on an iPad with the navigation open:

iPad image

You can download the sample JDeveloper workspace for 11.1.2.3.0 here.

Wednesday, October 3, 2012

tr:forEach to soon provide support for changes to the collection

In order to address the issues that I discussed in my blog regarding the c:forEach tag, I implemented enhancements to the Trinidad forEach tag since I am a developer on that team.

The changes are part of TRINIDAD-1940 which should be part of the future Trinidad 2.1.0 release. Until then, you can try out the changes by using the snapshot build.

The forEach tag documentation does not have the new documentation as the site is currently based on the 2.0.2-SNAPSHOT documentation.

Until then, here is a preview of the new forEach documentation (Content owned by the ASF is covered by the Apache version 2.0 license):

Summary

Tag name: <tr:forEach>

The forEach tag provides additional functionality from the JSTL <c:forEach> tag. The tag is only supported in JSP.

Facelets

The <tr:forEach> is not supported in facelets. As a convenience, the tag handler for the <c:forEach> will be used in facelets when a <tr:forEach> is used in a facelets page, but no Trinidad functionality will be supported.

Supported collections

The Trinidad forEach tag supports the following collections for the items attribute:
  • Java array
  • java.util.List
  • org.apache.myfaces.trinidad.model.CollectionModel
  • java.util.Map

When using a map, the map should be one that has a consistent order. Either the java.util.LinkedHashMap or java.util.TreeMap are examples of maps that provide this functionality. The keys for the maps must implement java.io.Serializable.

Usage

Valid Use Cases

The for each tag is not as efficient as component stamping. When possible, the <tr:iterator> should always be used instead of the for each tag. There are times this is not possible and usually involve the inclusion of content from other pages. For example, if different <jsp:include> tags need to be generated, pointing to different files based on items in a list, a for each tag must be used and not a stamping component like the Trinidad iterator.

ID and Component State

Due to the way JSF and JSP create ValueExpression objects, the for each tag cannot safely map the expressions created and stored on JSF components to the iteration of the for each loop. As a result, it is possible to cause a discrepency between the component's location in the for each tag and the value expressions that are stored in the tag.

Due to this limitation, the forEach tag must place usage requirements on the pages they are placed on. For index based collections (arrays and lists), the components must be mapped to the index of the for each loop and not the item in the collection. In these cases, the index of the for each loop is stored into the value expressions created and stored into the components. This results in the component state (like expanded state of disclosure components) being tied to the index of the for each loop. As a result, a key based collection (map or collection model) is always recommended when the collection may change between requests.

For key based collections (map and collection model), the component IDs must be associated with the key of the collection. This is because the key of the collection is used in the value expressions and if the ID were not bound to the key, then the component state would not match the EL values. You should associate the component to the key using immediate EL in the ID attribute. See the examples below.

Generated IDs

When the collection may change between requests, a key based collection should be used. When this is done, it is not recommended that JSF be allowed to generate the IDs of any components inside the for each tag. The reason is that JSF auto-generated IDs are based on the sequence that they are created in the current page. If items are re-arranged in the for each loop, the IDs will have a different generation order. As a result, JSF will not find the components with auto-generated IDs when it tries to map the JSP tag to the component ID. Existing components will be thrown out and new ones will be created and component state will be lost if this occurs.

Reordering and Collection Modifications

Modifications to the collection in the same JSF view (between requests) are only supported with key based collections. Even with this being supported, the for each tag will not auto-rearrange the children.

When JSP seeks to locate a component that was created in a previous request, it creates the ID that it expects the component to have and then searches the children of the parent component of the tag for the child component with that ID. If the component is not found, a new one will be created. If it is found, the framework does not do anything to the component, it is left to exist where it is found. This means that if you reorder items in your collection between requests, the component order will no longer match the order of the items in the collection. Page authors must reorder the components when changes to the collection are made.

Trinidad supports re-ordering of components using the change manager (org.apache.myfaces.trinidad.change.ChangeManager) and the org.apache.myfaces.trinidad.change.ReorderChildrenComponentChange class. The change manager may be retrieved from the org.apache.myfaces.trinidad.context.RequestContext instance. See the Trinidad demo application for examples on how to reorder the components when the collections changes.

When using a key based collection, it is recommended to use a naming container to simplify tying the component ID to the key. See the examples below.

Examples

Please see the Trinidad demo application for complete examples.

Index Based Collection

<tr:forEach var="person" items="#{forEachBean.simpleList}" varStatus="vs">
  <f:subview id="sv${vs.key}">
    <tr:panelGroupLayout id="personPgl" layout="horizontal">
      <tr:outputText id="personName" value="#{person.firstName} #{person.firstName}"
                     inlineStyle="padding-right: 1em;"/>
      <tr:outputText id="clientId" value="(Client ID: #{component.clientId})"/>
    </tr:panelGroupLayout>
    <tr:spacer id="s1" height="1em" />
  </f:subview>
</tr:forEach>

Key Based Collection

<tr:forEach var="person" items="#{forEachBean.collectionModel}" varStatus="vs">
  <f:subview id="sv${vs.key}">
    <tr:panelGroupLayout id="personPgl" layout="horizontal">
      <tr:outputText id="personName" value="#{person.firstName} #{person.firstName}"
                     inlineStyle="padding-right: 1em;"/>
      <tr:outputText id="clientId" value="(Client ID: #{component.clientId})"/>
    </tr:panelGroupLayout>
    <tr:spacer id="s1" height="1em" />
  </f:subview>
</tr:forEach>

Example Re-Order Code

// Create a list of all the children IDs of the parent component of the for each loop. This must
// contain all the children, not just those created by the for each tag.
List<String> orderedIds = ...;

// Get the reference to the component that is the parent of the for each tag. For finding relative
// components, you may try using
// org.apache.myfaces.trinidad.util.ComponentUtils.findRelativeComponent(UIComponent, String)
UIComponent forEachParent = ...;

ReorderChildrenComponentChange componentChange = new ReorderChildrenComponentChange(orderedIds);
RequestContext requestContext = RequestContext.getCurrentInstance();
ChangeManager cm = requestContext.getChangeManager();
// The component change must be added before the tag execution (before the render response JSF
// phase)
cm.addComponentChange(FacesContext.getCurrentInstance(), forEachParentComponent,
  componentChange);

// Ensure that the view is updated during PPR requests
requestContext.addPartialTarget(forEachParentComponent);
        

Attributes

Name Type Supports EL? Description
begin primitive int or java.lang.Number subclass No index at which iteration begins
end primitive int or java.lang.Number subclass No index at which iteration ends
items Object Only EL the collection to iterate over. Supported classes:
  • Java array
  • java.util.List
  • org.apache.myfaces.trinidad.model.CollectionModel
  • java.util.Map
step primitive int or java.lang.Number subclass No number to increment the index by on each iteration
var String No name of the variable exposed when iterating that references the item in the collection
varStatus String No name of the loop status exposed when iterating.

Properties:

Name Description
index the current index (int)
count the total number of times the for each tag will iterate (int)
begin the index to start at when collections are not used (int)
end the last index when collections are not used (int)
first true if this is the first iteration (boolean)
last true if this is the last iteration (boolean)
key the index (int) for index based collections and when the items has not been specified. The key (java.io.Serializable) for key based collections

Wednesday, January 4, 2012

Component scope

It is often confusing to users what it means by having a JSF component be "in scope," especially in JSF 2. JSF is processed by a set of phases, each one usually iterates the component tree, acting upon each component in turn. Some components, like the h:dataTable, perform stamping.

Note, for more information on stamping, please see my blog on tables.

When a component is being processed, the EL context may be altered. For example, the data table injects "var" and "varStatus" variables into the request scope. This also means that when the table is not being processed, these variables are either not available, or point to another value.

This is what I mean by a component being "in scope," that it is currently being processed by the JSF lifecycle or JSF APIs in a manner congruent with the JSF specification for working with components.

How a component enters scope

A component can enter scope one of three ways:

  1. The JSF lifecycle is being run. This will be the result of calls from methods on the component:
    • processDecodes
    • processValidators
    • processUpdates
    • processSaveState
    • processRestoreState
    • broadcast
  2. During an invokeOnComponent callback
  3. During a visitTree callback

At any other time, it may not be valid to be interacting with the component. Take for example, using Oracle ADF components, an input text component inside of an iterator:

<af:iterator var="item" value="#{bean.items}">
  <af:inputText value="#{item.value}" binding="#{bean.inputText}" />
</af:iterator>

Now consider this Java code for the bean:

private RichInputText _inputText;

public RichInputText getInputText()
{
  return _inputText;
}

public void setInputText(RichInputText text)
{
  _inputText = text;
}

public Object getValue()
{
  return _inputText == null ? null : _inputText.getValue();
}

Should code call the bean's getValue() method, what is the outcome? Well that is indeed the problem. Before the JSF view is built, the value will be null as the component has not been bound yet. Between JSF phases, it will also be null because #{item} will not be present in the EL context.

As this example shows, the attributes and behavior of the component in question change based on what component is currently being operated on. What makes this even more of an issue, is component frameworks that setup and tear down contexts. For example, Oracle ADF faces has a base component class called a oracle.adf.view.rich.component.fragment.ContextSwitchingComponent. When a component is processing its JSF lifecycle, or one of its children is being called back via a visitTree or invokeOnComponent call, the setupContext method has been run. If one of these components is accessed through code, and the context has not been set up yet, unreliable results may occur, or even exceptions may be thrown. One use case is of the ADF page template component. By using context switching, this component alters the EL context so that facets in the page with the <af:pageTemplate /> tag are executed in the EL context they were defined in, and the components inside the page template definition are executed within the context of the page template definition file.

Note that JSF 2 has a compound component like the ADF page template, but I am not sure how it handles EL context resultion.

It is therefore, never a good idea to call methods or evaluate attributes on JSF components unless the caller is sure that the component being accessed is currently in scope. Here is another example:

<af:iterator var="item" value="#{bean.items}">
  <af:pageTemplate viewId="template.jspx" item="#{item}">
    <f:facet name="center">
      <af:outputText id="facetText" value="#{item.itemValue}" />
    </f:facet>
  </f:pageTemplate>
</af:iterator>

Page definition:

...
<af:pageTemplateDef var="attrs">
  <af:xmlContent>
    <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
      <description>This component lays out an entire page.</description>
      <facet>
        <description>The center content.</description>
        <facet-name>center</facet-name>
      </facet>
      <attribute>
        <description>the item.</description>
        <attribute-name>item</attribute-name>
        <attribute-class>com.mycompany.MyItem</attribute-class>
      </attribute>
    </component>
  </af:xmlContent>
  <af:iterator var="item" value="#{item.innerItems}">
    <af:facetRef facetName="center"/>
    <af:outputText id="templateText" value="#{item.itemValue}" />
  </af:iterator>
</af:pageTemplateDef>

This is a very simplified example, but it illustrates the question, what does #{item.itemValue}" evaluate to? In the facet, this should be the item from the bean's items collection, as shown with the output text with id "facetText". Inside the page template, the value should be the item from the inner items collection of the item passed into the page template, show by the output text with the id "templateText". Depending on when this EL is evaluated, different values will be returned. Therefore, is is crucial, that in order to evaluate the RichOutputText.getValue() method, that the call is made while that component is "in scope," or "in context."

Putting a component into context

Components are automatically put into context when they are being validated, updated, broadcasting events, rendering, etc. Sometimes it is necessary to interact with a component outside of its context. For example, perhaps you have backing bean code that wishes to get the input text value. This may be done by knowing a component's client ID, and using the visitTree method. Here is an example:

public void performAction(ActionEvent evt)
{
  String clientId = "template1:table1:0:firstNameInputText";
  FacesContext facesContext = FacesContext.getCurrentInstance();
  VisitContext visitContext = VisitContext.createVisitContext(facesContext,
    Collections.singleton(clientId), EnumSet.of(SKIP_UNRENDERED));
  GetFirstNameCallback callback = new GetFirstNameCallback();
  facesContext.getViewRoot().visitTree(visitContext, callback);

  String firstName = callback.getFirstName();
  ...
}

private static class GetFirstNameCallback
  implements VisitCallback
{
  private String _firstName;

  public String getFirstName()
  {
    return _firstName;
  }

  public VisitResult visit(
    VisitContext visitContext,
    UIComponent  target)
  {
    RichInputText inputText = (RichInputText)target;
    _firstName = (String)inputText.getValue();
    return VisitResult.COMPLETE;
  }
}

Here the code illustrates how to access the input text value for a component in the first row of a table.

Summary

Due to the fact that EL is contextual, it is important that any EL based functionality is only accessed in the correct context for that EL. As such, JSF developers should use caution when interacting with components via their Java APIs. Using visit tree should always be considered when trying to access properties from a component in order to ensure that the expected EL context has been setup when the component attempts to access its data. Failing to do so may cause issues with your programs, and even data contamination.