Thursday, 23 April 2009

Making distinctions between different kinds of JSF managed-beans

JSF has a simple Inversion-of-Control (IoC) container called the JSF Managed Bean Facility (MBF). Although it has a verbose XML syntax, and is not as robust as the Spring BeanFactory, PicoContainer, or the JBoss Microcontainer, the MBF does have the basics of an IoC container, and offers features like dependency injection.

When a POJO is managed by the JSF MBF, it is typically referred to as a managed-bean. But if you're going to create a maintainable JSF webapp/portlet, it is necessary to distinguish between different kinds of managed-beans. This practice will also preserve the clean separation of concerns that JSF provides by implementing the Model-View-Controller (MVC) design pattern:

 

Managed-Bean Type Nickname Typical Scope
Model Managed-Bean model-bean session

Description: This type of managed-bean participates in the "Model" concern of the MVC design pattern. When you see the word "model" -- think DATA. A JSF model-bean should be a POJO that follows the JavaBean design pattern with getters/setters encapsulating properties. The most common use case for a model bean is to be a database entity, or to simply represent a set of rows from the result set of a database query.

Backing Managed-Bean backing-bean request

Description: This type of managed-bean participates in the "View" concern of the MVC design pattern. The purpose of a backing-bean is to support UI logic, and has a 1::1 relationship with a JSF view, or a JSF form in a Facelet composition. Although it typically has JavaBean-style properties with associated getters/setters, these are properties of the View -- not of the underlying application data model. JSF backing-beans may also have JSF actionListener and valueChangeListener methods.

Controller Managed-Bean controller-bean request

Description: This type of managed-bean participates in the "Controller" concern of the MVC design pattern. The purpose of a controller bean is to execute some kind of business logic and return a navigation outcome to the JSF navigation-handler. JSF controller-beans typically have JSF action methods (and not actionListener methods).

Support Managed-Bean support-bean session / application

Description: This type of bean "supports" one or more views in the "View" concern of the MVC design pattern. The typical use case is supplying an ArrayList<SelectItem> to JSF h:selectOneMenu drop-down lists that appear in more than one JSF view. If the data in the dropdown lists is particular to the user, then the bean would be kept in session scope. However, if the data applies to all users (such as a dropdown lists of provinces), then the bean would be kept in application scope, so that it can be cached for all users.

Utility Managed-Bean utility-bean application

Description: This type of bean provides some type of "utility" function to one or more JSF views. A good example of this might be a FileUpload bean that can be reused in multiple web applications.

 

Now... One of the main benefits in making fine distinctions like this is loose coupling. What's that you ask? Well let's first take a look at an example of tight coupling, where MVC concerns can be smashed/confused into a single managed-bean:

 

public class ModelAndBackingAndControllerBean {

	private String fullName; // model-bean property
	private boolean privacyRendered; // backing-bean property

	// model-bean getter
	public String getFullName() {
		return fullName;
	}
	
	// model-bean setter
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	// backing-bean getter
	public boolean isPrivacyRendered() {
		return privacyRendered;
	}

	// backing-bean setter
	public void setPrivacyRendered(boolean privacyRendered) {
		this.privacyRendered = privacyRendered;
	}

	// backing-bean actionListener for UI support logic
	public void togglePrivacySection(ActionEvent actionEvent) {
		privacyRendered = !privacyRendered;
	}

	// controller-bean business logic
	public String submit() {
		System.out.println("fullName=" + fullName);
		return "success";
	}
}

The problem here is that the bean would have to be kept in session scope because of the model-bean property. Additionally, what if we wanted to do some unit testing with mock model data? Can't do it. So in order to fix these problems, and to promote loose coupling, we would have three separate Java classes:

public class ModelBean {

	private String fullName;

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	public String getFullName() {
		return fullName;
	}
}

public class BackingBean {

	private boolean privacyRendered;

	public void setPrivacyRendered(boolean privacyRendered) {
		this.privacyRendered = privacyRendered;
	}

	public boolean isPrivacyRendered() {
		return privacyRendered;
	}

	public void togglePrivacySection(ActionEvent actionEvent) {
		privacyRendered = !privacyRendered;
	}

}

public class ControllerBean {

	private ModelBean modelBean;
	
	public ModelBean getModelBean() {
		return modelBean;
	}

	public void setModelBean(ModelBean modelBean) {
		// Dependency injected from the JSF managed-bean facility
		this.modelBean = modelBean;
	}

	public String submit() {
    	System.out.println("fullName=" + getModelBean().getFullName());
        return "success";
    }

}

 

Now that the beans are found in different classes, they can all be kept in their appropriate scopes. The model-bean can be kept in session scope, and the backing-bean and controller-bean can be kept in request scope, thus saving memory resources on the server.

Finally, we can use the dependency injection features of the JSF MBF in order to inject the model-bean into the controller-bean. This can be seen in the following WEB-INF/faces-config.xml example, where the #{modelBean} Expression Language (EL) binding is used:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
	version="1.2">
	<managed-bean>
		<managed-bean-name>modelBean</managed-bean-name>
		<managed-bean-class>myproject.ModelBean</managed-bean-class>
		<managed-bean-scope>session</managed-bean-scope>
	</managed-bean>
	<managed-bean>
		<managed-bean-name>backingBean</managed-bean-name>
		<managed-bean-class>myproject.BackingBean</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>
	<managed-bean>
		<managed-bean-name>controllerBean</managed-bean-name>
		<managed-bean-class>myproject.ControllerBean</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
		<managed-property>
			<property-name>modelBean</property-name>
			<value>#{modelBean}</value>
		</managed-property>
	</managed-bean>
</faces-config>

 

 

Posted by neil.griffin at 2:38 PM in Entries by Neil Griffin

Thursday, 2 April 2009

Easy Ajax just got even easier - ICEfaces 1.8 is now available!

ICEfaces 1.8 is out!

If there is a theme to the ICEfaces 1.8 release, it is one of "refinement". Don't worry, we've added a bunch of new features too in the over 350 fixes and enhancements included in the release, but a lot of development time was spent looking at how we could make ICEfaces better, easier, and more robust than ever before. In that regard, we've made some impressive progress:

Richer & More Productive

  • All new confirmationPanel, dataExporter, and setEventPhase components.
  • Improved focus management via ice:outputBody value-binding.
  • Time entry is now supported by the selectInputDate component.
  • Keyboard and double-click support has been added to the rowSelector.
  • Popup components (menuBar, menuPopup, panelTooltip, selectInputDate) can now automatically position themselves to avoid displaying off the visible window.
  • The Input File component is now much easier to use, supports progress updates - even in synchronous mode.

Easy Robust Ajax Push

  • The new SessionRenderer API provides the simplest way to implement compelling Ajax Push features in any framework, and it's built on top of ICEfaces industry-leading push architecture.
  • The unique new Push Server provides a zero-configuration solution for deploying multiple asynchronous applications to the same server.
  • ICEfaces now supports deployment into clustered fail-over configurations for applications with high-availability requirements.
  • No other Ajax Push solution can approach this level of robustness, scalability, and ease-of use.

Faster & Leaner

  • Rendering performance has been improved up to 30%.
  • Java heap consumption has been reduced 30-50%.
Of course, there are many more improvements in the release. Check out the Release Notes for more details on what's new in 1.8.0.

In addition to all the great stuff that went into ICEfaces itself, we've been working hard to make it simpler than ever to get, install, and learn ICEfaces:

Many Thanks

Any release of this magnitude represents a massive effort to accomplish, and this one is no different. So thanks to the product team who invested the majority of their last 6 months into this release. A very special thanks to the ever-growing ICEfaces community for the large number of community contributions that went into 1.8. Everything from language translations for the components and Component Showcase, to countless smaller bug fixes, to complete new features, such as the new "Scatter Plot" chart type. In addition, community involvement in testing the development and release-candidate releases were invaluable in finding and eliminating bugs along the way.

Great job everyone - now go get 1.8!

Technorati Tags:

Posted by ken.fyten at 2:17 PM in Entries by Ken Fyten