The JavaServer Faces Managed Bean Facility

A first class Inversion of Control (IoC) Facility for POJOs?

Written by Chris Schalk, Oracle Corporation
July 2005

Inversion of Control and POJOs

Before server-side Java development really took off, developers were always tasked with managing all of their classes. This was the norm with non-distributed Java applications. However as Java has evolved into more of a server-side technology, Java server "containers" became more and more responsible for running applications. Another fact was that in order for server-side Java applications to work properly they need a bit more "plumbing". For example if one writes a Java servlet, they can't just type "java myservlet" and expect it to run. Obviously a servlet container is needed to provide the plumbing necessary for handing Http requests to the servlet for it to execute. As Java containers matured and became more sophisticated, there has become a growing need to be able to manage server-side objects in a simple and efficient way. What has transpired is the rise a certain "description of service", for lack of a better term, titled "Inversion of Control" (Ioc) where control and management of useful server-side objects is largely handed over to a container instead of being left to the application developer.

As containers took on more responsibility of managing server-side objects, so has the popularity of simple Java objects which are often referred to as Plain Old Java Objects, or simply "POJOs". POJOs have come screaming back into popularity mainly because some of the container based development started to get too cumbersome, as seen with previous versions of Enterprise JavaBeans, and thus a POJO revolt ensued where Java developers realizing that pretty much all of their server-side programming needs can be accomplished with POJOs serving as the simple but universally useful object to be at the core of server-side applications.

As IoC and POJO's have risen in popularity, there have been many articles written on various containers/frameworks implementing IoC, they tend to highlight Spring, HiveMind and PicoContainer. What is surprisingly absent are articles describing how JavaServer Faces' Managed Bean facility is also an IoC framework which makes management of JavaBeans or POJOs a snap for JSF developers. The remainder of this article will describe the key aspects of IoC and how JSF's Managed Beans Facility is also qualified to be mentioned in the same league as the other IoC containers/frameworks.

What are some of the key concepts associated with IoC?

IoC is still a relatively new concept and the definition can sometimes be a little fluid, but in general here are the core facets of IoC.

  • Control of instantiation (constructor) and setter based injection of managed objects. - This negates the need for developers to explicitly instantiate server-side objects and set their respective properties. Customizable instantiation is another facet of IoC containers in that they can control when objects are loaded such as upon invocation of application sometimes referred to as "eager instantiation" or in a lazily loaded fashion.
  • Dependency Handling- Since objects can be dependent, this a definite requirement for IoC. Handling cyclical dependencies is also a benefit.
  • Lifecycle Support - The ability to easily set the duration of lifecycle of the managed objects.
  • Configuration Support - A simple way to configure the objects that will be managed by the IoC container.

Many times IoC is referred to as being supported by certain "containers", and I use the term "containers" loosely as these are really frameworks which run on containers, but regardless, the common examples we see being discussed usually involved the big IoC three: Spring, HiveMind and PicoContainer. What is still a little surprising is that compared to the general definitions of IoC/DI I don't see much mentioned about JSF's managed beans facility being mentioned as an "IoC" container, but I would argue that it really is.

What follows is both a detailed examination of the JSF Managed Bean facility presented in a way to show how it fully addresses the requirements of an "IoC" container.

JSF's Managed Bean Facility - A true IoC Container

Control of Instantiation

The first criteria for IoC is being able to manage all aspects of instantiation of Java Objects. JSF's managed beans facility offers a robust solution for creating and initializing managed beans. Before JSF when dealing with JavaBeans in pages, you could use JSP's <jsp:usebean> tag which allowed for the instantiation of a JavaBean for a specified scope.

JSF has improved on this simple feature of JSP quite a bit. With JSF, you can now register any Java class with a no-argument constructor as a managed bean by referencing it in an XML configuration file - faces-config.xml. Let's say I have a Java Class (or POJO), "User" which has fields for firstName, lastName, phone and email:

package mb;
public class User {
String firstName;
String lastName;
String phone;
String email; public User() { } public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } public void setPhone(String phone) { this.phone = phone; } public String getPhone() { return phone; } public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } }

I can register this bean in a faces-config.xml as:

 <managed-bean>
<managed-bean-name>Userbean</managed-bean-name>
<managed-bean-class>mb.User</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Now I can use the bean named "Userbean" in my JSF application at any time. This is done by using JSF's Expression Language. For example to bind a JSF user interface component (UI Component) to one of the properties of my Userbean, I use the expression #{Userbean.firstName} as a value argument to a JSF UI Component. Here is an example of binding the firstName property of the bean to a JSF inputText (UIInput) UI Component.

 <h:inputText value="#{Userbean.firstName}"/>

So now upon any form submissions the value entered into the input text field will be applied to the property of my Java Bean.

Managed Bean Property Initialization

An important feature of JSF's managed bean facility is it's ability to initialize properties from the configuration file. So for example I could define initial property values for my Userbean by adding the additional managed properties to the configuration.

So to set an initial set of values for some of my bean properties I can use the following.

<managed-bean>
<managed-bean-name>Userbean</managed-bean-name>
<managed-bean-class>mb.User</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>firstName</property-name>
<value>chris</value>
</managed-property>
<managed-property>
<property-name>lastName</property-name>
<value>schalk</value>
</managed-property>
<managed-property>
<property-name>phone</property-name>
<value>1-650-555-1234</value>
</managed-property>
</managed-bean>

To see the effect of this, I could build a JSF page which has several inputText fields bound to the properties and run the page. At first run, I will see the initial values set from my configuration:

Here is the JSF source of a form with input fields bound to my bean properties:

<h:panelGrid columns="2" >
<h:outputLabel value="First Name"/><h:inputText value="#{Userbean.firstName}"/>
<h:outputLabel value="Last Name"/><h:inputText value="#{Userbean.lastName}"/>
<h:outputLabel value="Phone"/><h:inputText value="#{Userbean.phone}"/>
<h:outputLabel value="Email"/><h:inputText value="#{Userbean.email}"/>
<h:commandButton value="Update"/>
</h:panelGrid>

and at initial runtime here is what we see..

Notice the Email field does not have an initial value.. Recall we didn't set this initially in our faces-config.xml.

Another feature regarding managed properties worth pointing out is in additional to managing simple properties, as shown above, JSF's managed bean facility can also handle both Lists and Maps as managed properties. For example I could add a "tasks" List to my Userbean as such:

 List tasks;

I would also add the necessary setters and getters as well as make sure to import java.util.List. I could then initialize the List with values as a managed property.

<managed-property>
  <property-name>tasks</property-name>
  <list-entries>
    <value>Finish JSF IoC POJO Article</value>
    <value>Finish .Net J2EE Article</value>
    <value>Revise RSS How To</value>
  </list-entries>
</managed-property> 

And to see the initialized values at runtime I could add a dataTable component to my JSP page..

<p>Current Tasks:</p>
<h:dataTable value="#{Userbean.tasks}" var="row" border="1"> <h:column> <h:outputText value="#{row}"/> </h:column> </h:dataTable>

and here is what the runtime looks like:

Defining Maps as a managed property is very similar to managing a List except instead of entering list values, you specify map-entries.

For example I could add a Map, "recentBlogEntries" to my Userbean along with the appropriate setters, getters and java.util.Map import.

Here is how I could initialize my recentBlogEntries Map properties in the faces-config.xml.

<managed-property>
<property-name>recentBlogEntries</property-name>
<map-entries>
<map-entry> <key>ODD</key> <value>http://www.jroller.com/page/cschalk/?anchor=just_added_adf_faces_content</value> </map-entry> <map-entry>
<key>ASPvsJSF</key> <value>http://www.jroller.com/page/cschalk/?anchor=is_jsf_ready_to_take</value> </map-entry> <map-entry>
<key>WebGalileoFaces</key> <value>http://www.jroller.com/page/cschalk/?anchor=how_to_use_webgalileo_faces1</value> </map-entry> </map-entries>

</managed-property>

And to display the initialized Blog Map properties I would add the following code to my JSF page. Notice the expression used to display the Map value.:

<p>A few recent blog entries:</p>
<p>Key: ODD</p>
<p>Location: <h:outputText value="#{Userbean.recentBlogEntries['ODD']}"/></p>
<p>Key: ASPvsJSF</p>
<p>Location: <h:outputText value="#{Userbean.recentBlogEntries['ASPvsJSF']}"/></p>

Note: I could also just dump the entire contents of the Map by just using the expression: #{Userbean.recentBlogEntries}in an outputText component.

Here is what the runtime looks like with some of the blogEntriesMap values displayed:

In addition to using Maps and Lists and as managed properties of existing beans, it is also possible to declare new Lists and Maps as managed beans themselves. For example I could create a new "Events" List entirely in my Faces-config. Here is a new, independent List which is defined entirely in the Faces-config and is not a property of my Userbean:

<managed-bean>
  <managed-bean-name>Events</managed-bean-name>
  <managed-bean-class>java.util.ArrayList</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
<list-entries> <value>JavaOne</value> <value>Oracle Openworld</value> <value>JavaPro Live</value> </list-entries> </managed-bean>

Notice that the managed-bean-class is the concrete "ArrayList" and not the "List" interface.

As you can see, the JSF managed beans facility provides a very high degree of control of instantiation and initialization. Next we'll review how JSF handles dependencies between managed beans.

Dependency Handling

The ability to handle depencies in between Java objects is also a requirement for IoC. Although JSF does not handle cyclical dependencies, managed beans can refer to each other using expression language. For example I could create a new List of tasks called "newtasks" purely in my faces-config.xml, I could then refer to values in the new list as expressions while setting properties of my existing "tasks" list.

Here's how this would be done:

First I can declare a "newtasks" List in my faces-config.xml.

<managed-bean>
<managed-bean-name>newtasks</managed-bean-name>
<managed-bean-class>java.util.ArrayList</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<list-entries>
<value>Do Bughunt</value>
<value>Finish Autobinding Spec</value>
<value>Present at Oracle Developer Day</value>
</list-entries>
</managed-bean>

I can then refer to it in other locations such as in the "tasks" property of the original "Userbean" managed bean. Here is how I can add the new tasks to the other set of List values. Notice that I can refer to the individual List items using an array style element referencing with brackets"[ ]".

...
<managed-property> <property-name>tasks</property-name> <list-entries> <value>Finish JSF IoC POJO Article</value> <value>Finish .Net J2EE Article</value> <value>Revise RSS How To</value> <value>#{newtasks[0]}</value> <value>#{newtasks[1]}</value> <value>#{newtasks[2]}</value> </list-entries> </managed-property>

At runtime, I will see the concatenated list of tasks.

You may be inclined to think that I have to declare the "newtasks" List before the value are assigned to the existing "tasks" properties, but no worries, the JSF managed beans facility can make sure the dependent bean is available for the calling bean regardless of what order it was defined in the faces-config.xml file. Another important point about managed beans referencing each other is that a managed bean can only refer to other beans provide their scope is equal or has a longer lifespan than the calling object. This brings us to our next requirement for IoC.

LifeCycle Support

A requirement for IoC is handling lifecycle support. In fact JSF's managed bean facility handles lifecycle support extremely well in that it is specifically geared toward defining lifecycle scope for HTTP requests as opposed to a more generic form which is common in other IoC containers. Similar to the scope parameters as specified by the JSP UseBean tag, the JSF scope sets the lifecycle with the following:

  • none: A managed bean with this scope is not stored anywhere, it is created "on demand" whenever it is needed.
  • request: A bean with a request scope will have it's value stored only for the duration of a single request. Upon subsequent requests on the same object, a new clean version will be instantiated.
  • session: A bean with session scope will be stored onto the session meaning that the bean's properties will stay alive during multiple requests. A shopping cart bean would be set to a session scope. Objects stored onto the session are naturally threadsafe and will expire when the session times out if not cleared by the application explicitly. You wouldn't want anyone else looking in your shopping cart!
  • application: Objects created with application scope will exist during the entire lifetime of the container. An example of when usage makes sense could be for a JDBC datasource object.

You may notice that the "page" scope is not available in JSF. This is by design as managed beans are not tied specifically to pages whereas in traditional JSP, you would define the scope of a bean using a UseBean tag, and in this sense it makes sense to offer a page scope since the bean originated from the page.

As you can define the lifecycle of the beans using the scope setting, you must take care to only refer to other beans which exist either the same scope or larger scope. You can not refer to another managed bean with a smaller scope.

Managed beans registered with scope: Can only refer to other managed beans with these scopes:
none none
request none, request, session, application
session none, session, application
application none, application

 

Configuration Support

With the previous examples, you've seen how JSF's Managed Bean facility uses a simple XML file format to register and initialize properties of managed beans. This works well with a framework geared towards Web applications where the focus is on the user interface and not necessarily back end coding. This aspect minizes Java coding to only be necessary when you wish to invoke custom application logic, otherwise the primary job of JSF which is to present a Web UI to a client and have it automatically synchronized with a set of managed objects which are bound the components presented in the page can require literally no Java coding.

Summary

With the rise in popularity of simple POJOs and a container-centric view on how to manage these objects. The general set of requirements associated with the term Inversion of Control has matured and it is very clear now that JavaServer Faces' Managed Bean facility rises to the challenge of being a first class IoC container. While it may not completely offer all of the fine grained control (such as cyclical dependencies) of some of the other IoC containers, it is still perfectly suited to be a IoC container for a Web user-interface framework oriented towards managing objects to be used within the context of Web requests. Additionally we mustn't forget that it is possible to use both JSF managed bean facility in conjunction with other more strictly server-oriented frameworks as well, including the big IoC three.

 

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy