My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

luni, 21 septembrie 2015

JSF and Composite design pattern - part II (JSF+CDI)

Read also:
JSF and Composite design pattern - part I (plain code)

In the first part of this article you saw an example of implementing the composite design pattern in plain Java code. Further, we will re-write that example in order to provide a JSF+CDI implementation. Keep in mind that this is just an approach, not the only approach! The interface of our application will look like in figure below:
So, let's consider each artifact of the plain code example and let's see how we will modify it.

Implement Base Component
In our example, the base component is represented by the Car interface. This remains unchanged, since we need to define the same contract:

public interface Car {

 public void paint(String color);
}

Implement Leaf Objects
Our leaf objects, Logan, Volvo and Mazda will be modified as follow:
·         we annotate them as request scoped CDI beans;
·         we provide a toString() method ;
·         we rename them as LoganBean, VolvoBean and MazdaBean (this is just to look nice)

Since we need to expose the leaf objects in page via EL, we need to transform them in CDI managed beans. Further, the list with cars to paint (instances of LoganBean, VolvoBean and MazdaBean) should be displayed in the client interface. In order to accomplish this, we override the toString() method, which will provide a human readable string for the leaf instances. Moreover, when we click on a car from the list, we want to be removed from the paint list, and for this, we need a converter to convert the submitted strings into a Car instances. A convenient approach will consist in using the OmniFaces, SelectItemsConverter which also requires a good toString() implementation. Is true that our implementation is not a good/real one, since we simply replace the default fqn@hashcode with car_name{hashcode}, but it will do the job in our example - suppose that the hashcode is some kind of car ID. So, we will obtain:

@Named
@RequestScoped
public class LoganBean implements Car, Serializable {

 @Override
 public void paint(String color) {
  System.out.println("Logan (" + this + ") paint color: " + color);
 }

 @Override
 public String toString() {
  return "Logan {" + this.hashCode() + "}";
 }
}

@Named
@RequestScoped
public class VolvoBean implements Car, Serializable {

 @Override
 public void paint(String color) {
  System.out.println("Volvo (" + this + ") paint color: " + color);
 }

 @Override
 public String toString() {
  return "Volvo {" + this.hashCode() + "}";
 }
}

@Named
@RequestScoped
public class MazdaBean implements Car, Serializable {

 @Override
 public void paint(String color) {
  System.out.println("Mazda (" + this + ")  paint color: " + color);
 }

 @Override
 public String toString() {
  return "Mazda {" + this.hashCode() + "}";
 }
}

Implement Composite
The composite object will be modified as follows:
·         we annotate it as a view scoped CDI beans;
·         we provide getter and setter methods for the Car list;
·         we adjust the remove() helper method to work with valueChangeListener;
·         rename the PaintCar as PaintCarBean (just to look nice).

The composite object contains group of leaf objects (Car) that should be visible in the end-user interface. Moreover, the end-user should be able to add/remove leaf objects from the list, so we need to transform the composite object into a CDI managed bean. Since the list should be maintained during multiple request in the same view, we need a view scoped managed bean. In order to expose the list of cars, which is private, we need the corresponding getter and setter. Finally, since we choose to use a <h:selectOneListbox> with valueChangeListener for removing the clicked cars, we need to re-write the remove() helper method accordingly:

@Named
@ViewScoped
public class PaintCarBean implements Car, Serializable {

 //collection of cars
 private List<Car> cars = new ArrayList<>();

 @Override
 public void paint(String color) {
  System.out.println("Color: " + color);
  for (Car car : cars) {
       car.paint(color);
  }
 }

 //adding car
 public void add(Car car) {
  System.out.println("Adding car: " + car);
  this.cars.add(car);
 }

 //removing car
 public void remove(ValueChangeEvent event) {
  System.out.println("Removing car: " + event.getNewValue());
  this.cars.remove((Car)event.getNewValue());       
 }

 //removing all the cars
 public void clear() {
  System.out.println("Clearing all the cars!");
  this.cars.clear();
 }

 public List<Car> getCars() {
  return cars;
 }

 public void setCars(List<Car> cars) {
  this.cars = cars;
 }     
}

Now, we can shape the interface from figure above as:

<h:body>  
 Available cars:
 <h:form>
  <h:selectOneListbox converter="omnifaces.SelectItemsConverter" 
                      onchange="this.form.submit();" valueChangeListener="#{paintCarBean.remove}">              
   <f:selectItem itemLabel="Click on the car to remove ..." noSelectionOption="true"/>
   <f:selectItems value="#{paintCarBean.cars}"  var="t" itemLabel="#{t}" itemValue="#{t}"/>                
  </h:selectOneListbox>          
 </h:form>
 <hr/>      
 <h:form>
  Add car:<br/>
  <h:commandButton value="Add Logan Car" action="#{paintCarBean.add(loganBean)}"/>                
  <h:commandButton value="Add Mazda Car" action="#{paintCarBean.add(mazdaBean)}"/> 
  <h:commandButton value="Add Volvo Car" action="#{paintCarBean.add(volvoBean)}"/>           
  <hr/>
  Paint cars:<br/>
  <h:commandButton value="Paint cars red" action="#{paintCarBean.paint('red')}"/> 
  <h:commandButton value="Paint cars blue" action="#{paintCarBean.paint('blue')}"/> 
 </h:form>
</h:body>

After adding/removing some cars and pressing the Paint cars red/blue buttons, you will see an output as in the below sample:

Adding car: Logan {920499440}
Adding car: Mazda {686360510}
Adding car: Mazda {784544289}
Adding car: Volvo {2043446353}
Adding car: Logan {480920299}
Removing car: Mazda {784544289}
Removing car: Logan {920499440}
Color: red
Mazda (Mazda {686360510})  paint color: red
Volvo (Volvo {2043446353}) paint color: red
Logan (Logan {480920299}) paint color: red
Adding car: Mazda {534814168}
Adding car: Mazda {1979975711}
Color: blue
Mazda (Mazda {686360510})  paint color: blue
Volvo (Volvo {2043446353}) paint color: blue
Logan (Logan {480920299}) paint color: blue
Mazda (Mazda {534814168})  paint color: blue
Mazda (Mazda {1979975711})  paint color: blue

Of course, you can think to shape the interface differently. You just have to keep in mind to not alter the composite design pattern meaning.

In the final part of this post, we will discuss about how the composite pattern is used internally in JSF source code.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors