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

vineri, 2 octombrie 2015

JSF and Template Method design pattern - part II (JSF+CDI)

Read also:

In this part, we will transform the application from first part from plain code into a JSF+CDI application. The biggest issue of this case is represented by the final method, PrinterTemplate#print(). For example, we may try to transform the concrete implementations (A1Printing and A4Printing) into CDI managed beans and invoke the print() method, as below:

@Named
@RequestScoped
public class A1Printing extends PrinterTemplate {

 @Override
 public void feedWithPaper() {
  System.out.println("Feed with paper A1 format.");
 }

 @Override
 public void alignMargins() {
  System.out.println("A1 margins top/0.5in, bottom/0.5in, left/0.2in, right/0.2in.");
 }

 @Override
 public void printStyle() {
  System.out.println("A1 print in grayscale.");
 }   
}

@Named
@RequestScoped
public class A4Printing extends PrinterTemplate {

 @Override
 public void feedWithPaper() {
  System.out.println("Feed with paper A4 format.");
 }

 @Override
 public void alignMargins() {
  System.out.println("A4 margins: top/1.0in, bottom/0.75in, left/0.75in, right/0.75in.");
 }

 @Override
 public void printStyle() {
  System.out.println("A4 print in colors.");
 }   
}

<h:form>
 <h:commandButton value="Print A4" action="#{a4Printing.print()}"/>                              
 <h:commandButton value="Print A1" action="#{a1Printing.print()}"/>                              
</h:form>

Or, we can try to use a separate CDI managed bean and pass the A1Printing/A4Printing instance via <f:setPropertyActionListener/>:

@Named
@RequestScoped
public class MyBean {

 private PrinterTemplate printer;

 public PrinterTemplate getPrinter() {
  return printer;
 }

 public void setPrinter(PrinterTemplate printer) {
  this.printer = printer;
 }

 public void printAction() {
  printer.print();
 }
}

<h:form>
 <h:commandButton value="Print A1" action="#{myBean.printAction()}">              
  <f:setPropertyActionListener target="#{myBean.printer}" value="#{a1Printing}" />
 </h:commandButton>
 <h:commandButton value="Print A4" action="#{myBean.printAction()}">              
  <f:setPropertyActionListener target="#{myBean.printer}" value="#{a4Printing}" />
 </h:commandButton>
</h:form>   

But, these approaches will not work because they will cause an error as:  WELD-001437: Normal scoped bean class template.method.PrinterTemplate is not proxyable because the type is final or it contains a final method public final void template.method.PrinterTemplate.print().

Practically, the CDI container will create proxy objects for injected classes. In order to provide a proxy object of the same type as the original object, CDI extends the original object (extend the class you want to inject). This is happening internally, so we may find "strange" the above exception. Since CDI provides us a proxy subclass of the bean, is pretty easy to intuit that this doesn't work very well with final methods/classes and private constructors (e.g. public final void template.method.PrinterTemplate.print()).If the class is not final (e.g. PrinterTemplate), the proxy can extend it, but cannot easily overwrite the final method PrinterTemplate#print().

Now, we can remove the final keyword from PrinterTemplate#print() method, but this will violate the template method design pattern concept, since subclasses will be able to override the print() method and alter the steps order.

So, a simple approach will consist in instantiating A1Printing/A4Printing in bean (MyBean):

@Named
@RequestScoped
public class MyBean {

 public void printA1Action() {
  PrinterTemplate printerA1 = new A1Printing();
  printerA1.print();
 }

 public void printA4Action() {
  PrinterTemplate printerA4 = new A4Printing();
  printerA4.print();
 }
}

<h:form>
 <h:commandButton value="Print A1" action="#{myBean.printA1Action()}"/>
 <h:commandButton value="Print A4" action="#{myBean.printA4Action()}"/>              
</h:form>

Obviously, this is not a very elegant approach! In order to keep everything in a single method, we can pass the printing type as argument:

@Named
@RequestScoped
public class MyBean {
  
 public void printAction(String type) {
  PrinterTemplate printer;
  if (type.equals("a1")) {
      printer = new A1Printing();
  } else {
      printer = new A4Printing();
  }
  printer.print();
 }
}

<h:form>
 <h:commandButton value="Print A1" action="#{myBean.printAction('a1')}"/>
 <h:commandButton value="Print A4" action="#{myBean.printAction('a4')}"/>              
</h:form>  

In the next part we will discuss about template method pattern in JSF implementation.

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