Tuesday 13 March 2007

Some explicit language about implicit EL objects

As soon as you start playing with ADF Faces and dropping data bound controls onto a page, you will have been exposed to the concept of implicit objects in JSF's Expression Language (EL). An implicit object is similar to a managed bean, but one that is created and maintained by the JSF engine, which you may make reference to with EL.

An understanding of the implicit EL objects gives a better understanding of the managed bean facility, as well as what objects are being created and maintained behind the scenes by the JSF servlet and ADF framework which the JDeveloper programmer can make use of.

#{data}
#{bindings}


As an example most readers who have used ADF Faces will be familiar with the following where an inputText control has been bound to a field in your ADF Faces page definition file:

<af:inputText value="#{bindings.ResourceCode.inputValue}"
  label="#{bindings.ResourceCode.label}"
  required="#{bindings.ResourceCode.mandatory}"
  columns="#{bindings.ResourceCode.displayWidth}"/>


You'll note the bindings keyword in the EL expression. This maps to the page definitions file for the current webpage, or more correctly it references the oracle.adf.model.binding.DCBindingContainer from the ADF Faces binding layer, that was instantiated by the ADF Faces servlet when the user accessed the web page.

In turn you may have seen an EL expression that references #{data}. This refers to the oracle.adf.model.BindingContext, an object responsible among other things for referencing all the DCBindingContainer objects in your ADF Faces application.

Both of these ADF Faces objects are well explained in the ADF Guide for Forms/4GL Programmers and the online documentation.

There are however other implicit objects available for the programmer to work with that may not be as well known.

#{facesContext}

The implicit EL object #{facesContext} maintained by the JSF servlet is instantiated from javax.faces.context.FacesContext, for each JSF request made upon the mid-tier. As the JSF lifecycle processes the current JSF request, the FacesContext instance carries the information about the page to be rendered, essentially the JSF response to the original request.

It's not uncommon in your backing bean code to grab the FacesContext object, but as can be seen is also easily accessible to the JSF webpage through the implicit EL object. You're unlikely to make use of it in your JSF webpages as it wasn't really designed to interact with the JSF webpages directly. But you may use the JSF managed bean facility to initialise properties within the FacesContext at runtime using EL.

#{adfFacesContext}

If you're specifically using ADF Faces, and not just JSF, ADF Faces makes available the implicit EL object #{adfFacesContext} instantiated from oracle.adf.view.faces.context.AdfFacesContext. At its simplest AdfFacesContext represents Oracle's ADF extensions to JSF, and you will have seen within your ViewController project's WEB-INF directory the adf-faces-config.xml file, which stores the design-time settings for this extension. Like the FacesContext object, a single AdfFacesContext is instantiated for each JSF request. Also similar to the FacesContext object, you may have made use of the AdfFacesContext object in your backing bean code.

The JDeveloper documentation page About Value Binding and the ADF Faces Implicit Object gives a good explanation of what's available through this object.

#{view}

The one unusual implicit object is the view object that provides access to the UIViewRoot object from the FacesContext for the current request, essentially the JSF page component tree. Most of the properties within the view object are not useful, but the locale and renderKitId properties may allow you to show different components based on the language or the type of device you're rending in.

#{cookie}
#{header}
#{headerValues}
#{initParam}
#{param}
#{paramValues}


Most of these objects will be familiar to JSP programmers and there is plenty of documentation across the internet on these objects for the uninitiated. I'll quote the JSF 1.1 spec here for quick reference:
  • cookie - an immutable Map of the cookie values for the current request, keyed by cookie name.

  • header - an immutable Map of HTTP header values for the current request, keyed by header name. Only the first value for each header name is included.

  • headerValues - an immutable Map of String arrays containing all of the header values for HTTP headers in the current request, keyed by header name.

  • initParam - an immutable Map of the context initialization parameters for this web application.

  • param - an immutable Map of the request parameters for this request, keyed by parameter name. Only the first value for each parameter name is included.

  • paramValues - an immutable Map of String arrays containing all of the parameter values for request parameters in the current request, keyed by parameter name.

#{requestScope}
#{sessionScope}
#{applicationScope}


When you specify a JSF managed bean in the faces-config.xml file, you also specify the scope of the bean, namely a request, session or application scoped bean. Later on to make request to that bean within EL it's simply a case of specifying something like #{myBean}.

You can be more explicit about which scope the bean exists in and make reference to either the implicit object #{requestScope}, #{sessionScope} or #{applicationScope}. For example #{requestScope.myBean}. If however you make a reference to such a bean and it doesn't exist within this scope, an exception will be thrown.

[There's one little caveat to this approach. Thanks to Brenden Anstey on OTN for his assistance. To reference the bean explicitly specifying the scope, such as #{requestScope.myBean}, you must include the <jsp:useBean> tag as follows]

<jsp:useBean id="myBean" class="MyBean" scope="request"/>

Alternatively if you skip specifying the scope of the bean within your EL, such as #{myBean}, the JSF engine will search the request, session and application scopes respectively to find the bean. If it isn't found, JSF then looks for the specification of the managed bean in the faces-config.xml file under each <managed-bean> tag, and if found, instantiates it. Finally if not found JSF flags an error.

2 comments:

edburns said...

Chris, I have a prototype implementation of the viewScope available, see https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=290

Ed, JSF co-spec lead.

Chris Muir said...

Thanks Ed.

CM.