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.

Sunday, February 1, 2009

Problems with the Mozilla Component.utils.Sandbox

Writing a Firefox extension can be time consuming for the first time, the documentation is more reference oriented, more oriented to C++ than the JavaScript version, but it is the worst when there are bugs and you waste hours of work. That is what happened to me with the Sandbox APIs of Firefox 3. After talking to members of the FireBug extension on its Google groups forum, I found out that I am not alone with Sandbox frustrations.

The Sandbox

The sandbox, introduced in full in FF3, is a container that allows extension developers to run code in lower security. This is helpful for interacting with browser web pages or for running code from a server. The Sandbox API Documentation is pretty light, and gives no useful examples for real-world applications. The primary use of the sandbox is probably to work with pages, but they show no example on how to do that.

My Problem

When I was working on an extension I write for work, I found that I had some extremely peculiar results. As an illustration, lets say there are two types of JavaScript objects in a page that you want to work with. The first, is a single instance object that looks up other JS objects, and the second, a 'normal' JS object that we want to create. So for my example, lets say we want to lookup an object, pass that object into a constructor and then run a method on that new object:

  var obj = TheRegistry.lookupObject('customId1');
  var ref = new ObjectReference(obj);
  ref.save();

Now, I want to run this code in my extension, so I setup the sandbox and execute the code like this:

  var evalInSandbox = function(win, script, vars)
  {
    win = getUnwrapped(win);
    var sandbox = new Components.utils.Sandbox(win);
    sandbox.window = win;
    sandbox.document = sandbox.window.document;
    sandbox.XPathResult = Components.interfaces.nsIDOMXPathResult;
    sandbox.__proto__ = win;
    if (vars)
    {
      for (var prop in vars)
      {
        sandbox[prop] = vars[prop];
      }
    }
    return Components.utils.evalInSandbox(
      "(function() { " + script + "\n })();", sandbox);
  };
  
  var getUnwrapped = function(obj)
  {
    while (obj.wrappedJSObject)
    {
      obj = obj.wrappedJSObject;
    }
    return obj;
  };
  
  var doSomething = function(window)
  {
    evalInSandbox(window,
      "var obj = TheRegistry.lookupObject('customId1');"+
      "var ref = new ObjectReference(obj);"+
      "ref.save();");
  }

What I was surprised to find out is that ref had no 'save' method, but I knew that was not the case. Looking further into it, ref == obj. What the heck?! I tried wrapping the code with with (window) { ... }, using new window.ObjectReference(obj), but nothing would work. Finally I gave up on the code and used a FireBug technique to inject a script tag into the page's DOM.

Wrap Up

I wrote this article, not to teach, but hopefully to save other people some time so if the google 'mozilla sandbox bugs' or something similar, they may find this. Hopefully Mozilla will fix the sandbox and improve its documentation, but until then, watch out for bugs, and stay away from creating page objects using the 'new' keyword inside of the sandbox, it just doesn't work.

BTW, the google group discussion I mentioned can be found here.

Tuesday, January 27, 2009

JSF Component Binding Stinks

Whoever came up with JSF component binding should be taken out back. While a nice thought, it really is just a purely awful piece of design and was not thought through at all.

Too harsh? Well, it sounds harsh, but when you consider all the flaws and bugs it causes, it isn't.

1. The problem

I have been telling people on the MyFaces mailing list to always ensure that they use binding with request scope beans, but I have realized that this advice was now bad. My advice should have been to never use binding at all, or to at least only use a setter, but no getter.

The reason behind this, is that there is a fundemental flaw in how binding was designed. Binding is too completely separate pieces of functionality, jammed together in one implementation:

  1. Component factory
  2. Component access from code

The latter is what people normally use binding for. This is how the framework uses binding in a JSP component tag:

  1. Does the tag have the binding attribute set?
    1. If so, call the getter method
      1. If returns not null, use that value
      2. Else, create a new component
        1. Call the setter with the new component

What you now see is that the getter method acts as both a normal JavaBean property getter as well as a factory. The problem is that 90% of the time, the lifetime of this member variable is too long. Almost always, the component in the bean should only be ever stored as long as the view is being processed. Take this example:

Developer has a managed bean with a request scope with a bound component. The page navigates from view1 to view2.

Jspx Code:

  <?xml version='1.0' encoding='utf-8'?>
  <jsp:root
    version="2.1"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:jsp="http://java.sun.com/JSP/Page">
    <jsp:directive.page contentType="text/html;charset=utf-8"/>
    <f:view>
      <html>
        <body>
          <h:form>
            <h:outputText binding="#{myBean.textComponent}" />
          </h:form>
        </body>
      </html>
    </f:view>
  </jsp:root>

Now the views would probably be different, but it is not unusual for someone to reuse #{myBean.textComponent} in the page. Now what happens is that view1 causes the #{myBean.textComponent} to be set since it would return null on the restore view. View 2 is navigated to, but the #{myBean.textComponent} returns the component from view 1, so it is not re-created. Now we have an illegal state, a component is shared between two views.

There could have been two ways of fixing this:

  1. There could have been a create or factory attribute on the JSP tag and only that attribute could ever create the component and the set method on the binding would be used, but never the getter method.
  2. The JSP tag component creation should be smart enough to always check that a component is never shared across views. Therefore, if a binding expression returns a component that already has a parent and by looking up the tree, the view root is not the current view root, a new component should have been created.

So what is the best work around for this problem?

Well the best solution is to never use binding under any circumstances, ever, no exceptions. This is the only safe way to write JSF pages. If your bean needs to access a component, use findComponent or invokeOnComponent to get the component.

The other alternative is to check the view root yourself in you bean when the getter is called. If the view has changed, return null. Example:

  package blog;
  
  import java.util.Map;
  
  import javax.faces.component.UIComponent;
  import javax.faces.component.UIViewRoot;
  import javax.faces.context.FacesContext;
  
  public class MyBean
  {
    public void setMyComponent(UIComponent myComponent)
    {
      this.myComponent = myComponent;
    }
  
    public UIComponent getMyComponent()
    {
      checkViewRoot();
      return this.myComponent;
    }
  
    private void checkViewRoot()
    {
      UIViewRoot current = FacesContext.getCurrentInstance().getViewRoot();
      if (this.viewRoot == null || (current != null && current != this.viewRoot))
      {
        this.viewRoot = current;
        // view is new or has changed, make sure the component is not re-used
        this.myComponent = null;
      }
    }
  
    private UIComponent myComponent;
    private UIViewRoot viewRoot;
  }

Ugly? Bad performance? Yes! Unfortunately this may be the best solution if you have to use component binding. From what I have seen from JSF 2.0 I think there may be factory support, so that component binding to be able to gain access to a component in a bean is separated from component creation. I hope so. Until then, I strongly recommend that you forget that the binding attribute exists at all.