Mediator Pattern: Reducing Page Dependencies in JSF

Tags:
Mediator

In order to use “Select Address” page for both “Add Person” and “Add Company” pages it is desirable to keep it independent on the latter ones. Also if assume using another page (strategy) for selecting address it is desirable to keep “Add Person” and “Add Company” pages independent on this “Select Address” page. This is where the Mediator pattern comes up. The next diagrams show the role of the mediator object:

 

Mediator object is implemented as managed-bean. “Select address” button has an attached action listener that points to method of the Mediator object. This method tunes up “Select Address” page behavior using the Service which stores preferences data in session. Mediator also adds listener that should be fired when address is selected. The code below will help better understanding of the action flow.

The “select address” button is defined inside of the page as follows:


<h:commandButton immediate="true"
action="#{selectAddressForPersonBB.selectAddress}"
value="Select Address"/>
 

Below is the code of the Mediator class:


public class SelectAddressForPersonBB {
private SelectAddressService selectAddressService;
public String selectAddress() {
// Reset selection for "select address page"
selectAddressService.setSelectedAddress(null);
// Set navigation outcome
selectAddressService.setSuccessNavigationOutcome("personAddressSelected");
// Add listener
selectAddressService.setAddressSelectedListener(new Listener() {
public void fire(FacesContext facesContext) {
Application app = facesContext.getApplication();
SelectAddressService selectAddressService =
(SelectAddressService) app.evaluateExpressionGet(facesContext, "#{selectAddressService}", SelectAddressService.class);
PersonService personService =
(PersonService) app.evaluateExpressionGet(facesContext, "#{personService}", PersonService.class);
Address address = selectAddressService.getSelectedAddress();
// Set person's address
personService.setPersonAddress(address);
// Remove listener
selectAddressService.setAddressSelectedListener(null);
}
});
return "selectAddress";
}
public void setSelectAddressService(final SelectAddressService selectAddressService) {
this.selectAddressService = selectAddressService;
}
}

It is configured as a backing bean (note: all managed beans, except for the userSession, are defined with the request scope):


 <managed-bean>
<managed-bean-name>selectAddressForPersonBB</managed-bean-name>
<managed-bean-class>example.backingbean.SelectAddressForPersonBB</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>selectAddressService</property-name>
<value>#{selectAddressService}</value>
</managed-property>
</managed-bean>
 

The Service of the “Select Address” page stores preferences and listener in session. The service itself defines interface for tuning the page’s behavior (e.g. it gives the ability to set the success navigation outcome).


public class SelectAddressService {
private static final String SELECTED_ADDRESS = "selected_address";
private static final String SUCCESS_OUTCOME = "success_outcome";
private static final String SELECTED_ LISTENER = "address_selected_listener";
private UserSession userSession;
public List<Address> getAddresses() {
return DataSource.getAddresses();
}
public void setAddressSelectedListener(Listener listener) {
userSession.setAttribute(SELECTED_LISTENER, listener);
}
public void setSelectedAddress(Address address) {
userSession.setAttribute(SELECTED_ADDRESS, address);
Object listener = userSession.getAttribute(SELECTED_LISTENER);
if(listener != null) {
((Listener) listener).fire(FacesContext.getCurrentInstance());
}
}
public Address getSelectedAddress() {
Object address = userSession.getAttribute(SELECTED_ADDRESS);
return address == null ? null : (Address) address;
}
public void setSuccessNavigationOutcome(String navigationOutcome) {
userSession.setAttribute(SUCCESS_OUTCOME, navigationOutcome);
}
public String getSuccessNavigationOutcome() {
Object navigationOutcome = userSession.getAttribute(SUCCESS_OUTCOME);
return navigationOutcome == null ? null : (String) navigationOutcome;
}
public void setUserSession(final UserSession userSession) {
this.userSession = userSession;
}
}

The diagram below explains what happens when user selects address on the “Select Address” page:

 

After address is selected it is stored and listener that was added by mediator is invoked. This listener retrieves selected address and sets it to the person using the corresponding Service:


public void fire(FacesContext facesContext) {
Application app = facesContext.getApplication();
SelectAddressService selectAddressService =
(SelectAddressService) app.evaluateExpressionGet(facesContext, "#{selectAddressService}", SelectAddressService.class);
CompanyService companyService =
(CompanyService) app.evaluateExpressionGet(facesContext, "#{companyService}", CompanyService.class);
Address address = selectAddressService.getSelectedAddress();
// Set company's address
companyService.setCompanyAddress(address);
// Remove listener
selectAddressService.setAddressSelectedListener(null);
}

Conclusion

The article explored an example of applying the well-known Mediator pattern for Web application development. The examples provided in this article, along with the source code, can help you implement this pattern in almost any JSF-based application.

You are free to download sources  http://java.dzone.com/sites/all/files/mediator_in_jsf_app-src.zip

AttachmentSize
bd_sts_top10.jpg56.83 KB
1.PNG8.8 KB
2.PNG7.22 KB
3.PNG7.11 KB
4.PNG7.55 KB
5.PNG6.17 KB
6.PNG9.52 KB
0
Average: 3 (3 votes)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Barry Stevenson replied on Mon, 2008/10/20 - 12:57pm

Please post the source code for your JSPs and your faces-config.xml file.  Thanks.

Dab Snooper replied on Tue, 2008/10/28 - 12:54pm

Please see the link at the end of the article for downloading the sources.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.