Mediator Pattern: Reducing Page Dependencies in JSF
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
| Attachment | Size |
|---|---|
| bd_sts_top10.jpg | 56.83 KB |
| 1.PNG | 8.8 KB |
| 2.PNG | 7.22 KB |
| 3.PNG | 7.11 KB |
| 4.PNG | 7.55 KB |
| 5.PNG | 6.17 KB |
| 6.PNG | 9.52 KB |
- Login or register to post comments
- 7417 reads
- Printer-friendly version
(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
Dab Snooper replied on Tue, 2008/10/28 - 12:54pm