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


luni, 28 septembrie 2015

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

Read also:

In this part, we will re-write the application from first part with respect to JSF+CDI style. Basically, we try to keep the strategy pattern, and adjust the code to "support" the user interface from figure below:
Before we can shape this user interface, we need to adjust the source code of the strategy interface (ArchiverStrategy), concrete strategy implementations (FastArchiverStrategy, SlowArchiverStrategy) and  context (Archiver) accordingly.

Implement Strategy Interface
In our example, the strategy interface is represented by the ArchiverStrategy interface. This remains unchanged, since we need to define the same contract:

public interface ArchiverStrategy {

 public void archive(String path, List<String> files);

Implement Concrete Strategies
Our concrete strategies, FastArchiverStrategy and SlowArchiverStrategy will be modified as follows:

·           we annotate them as request scoped CDI beans;
·         for FastArchiverStrategy, we remove the constructor with arguments and we expose the compression field via getter and setter;
·         for SlowArchiverStrategy, we remove the constructor with arguments and we expose the compression, numFastBytes and numPasses fields via getters and setters;

Once we accomplish  these adjustments, the user will be able to configure the archiver parameters:

public class FastArchiverStrategy implements ArchiverStrategy {

 private int compression;
 public int getCompression() {
  return compression;

 public void setCompression(int compression) {
  this.compression = compression;

 public void archive(String path, List<String> files) {
  System.out.println("Fast archiver for " + files + " at compression level " + compression);

public class SlowArchiverStrategy implements ArchiverStrategy {

 private int compression;
 private int numFastBytes;
 private int numPasses;      

 public int getCompression() {
  return compression;

 public void setCompression(int compression) {
  this.compression = compression;

 public int getNumFastBytes() {
  return numFastBytes;

 public void setNumFastBytes(int numFastBytes) {
  this.numFastBytes = numFastBytes;

 public int getNumPasses() {
  return numPasses;

 public void setNumPasses(int numPasses) {
  this.numPasses = numPasses;

 public void archive(String path, List<String> files) {
  System.out.println("Slow archiver for " + files + " at compression level " + compression + " (Fast Bytes: " + numFastBytes + ", Passes: " + numPasses + ")");

Notice that these CDI managed beans represents now our algorithms implementations. By their nature, managed beans are not meant for business logic, while algorithms code may be considered business logic and may be really complex and may rely on possibly expensive service/DAO operations, so, if you are in such cases, take care of separating the business logic (maybe in a EJB bean).

Implement Context
Our context, Archiver, will be modified as follows:

·         we annotate it as request scoped CDI bean;
·         we replace the helper methods (addFile() and removeFile()) with getter and setter for the files field;

Via these adjustments, the user will be able to select the files that will be part of the archive. Of course, if you need to add the files one by one, or need to be able to remove files, then you can rely on the helper methods combined with a view scoped bean and the desired interface.

public class Archiver {
 private List<String> files;  

 public Archiver() {
  this.files = new ArrayList<>();

 public List<String> getFiles() {
  return files;

 public void setFiles(List<String> files) {
  this.files = files;
 public void archive(String path, ArchiverStrategy archiverStrategy){
  archiverStrategy.archive(path, files);

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

 Select files to archive:
 <h:selectManyListbox value="#{archiver.files}">
  <f:selectItem itemValue="foo.txt" itemLabel="foo.txt"/>
  <f:selectItem itemValue="buzz.txt" itemLabel="buzz.txt"/>
  <f:selectItem itemValue="fizz.txt" itemLabel="fizz.txt"/>

 Compression: <h:inputText value="#{slowArchiverStrategy.compression}"/>
 Number Fast Bytes: <h:inputText value="#{slowArchiverStrategy.numFastBytes}"/>
 Number Passes: <h:inputText value="#{slowArchiverStrategy.numPasses}"/>
 <h:commandButton value="Slow" action="#{archiver.archive('SOME_PATH', slowArchiverStrategy)}"/>

 Compression: <h:inputText value="#{fastArchiverStrategy.compression}"/>
 <h:commandButton value="Fast" action="#{archiver.archive('SOME_PATH', fastArchiverStrategy)}"/>

Supposing that we have select the foo.txt and fizz.txt files, set compression to 9, fast bytes to 128, passes to 10,  and we pressed on the Slow button:

Slow archiver for [foo.txt, fizz.txt] at compression level 9 (Fast Bytes: 128, Passes: 10)

Or, if we select all three files, set compression to 0 and press the Fast button:

Fast archiver for [foo.txt, buzz.txt, fizz.txt] at compression level 0

In the next part of this post we will discuss about strategy pattern in JSF source code.

Niciun comentariu :

Trimiteți un comentariu


Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors