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

joi, 20 august 2015

JSF and Decorator pattern - part II (CDI @Decorator and @Delegate)

Is recommended to read first part I of this post (at least be familiar with the example from the Decorator pattern in plain code subsection).

Now, we will implement the decorator pattern from Java EE perspective. More precisely we will use CDI @Decorator and @Delegate to shape in CDI style the example from the first part of this post.

·         @Decorator annotates the decorator classes
·         @Delegate annotates the delegate injection point where the class to be decorated is injected

In order to correlate the decorator with the object that you want to decorate we start by reshaping the Hosting interface - the getHostingSubscription() is the method that will be implemented by decorators for adding the extra functionalities (extra items and prices):

public interface Hosting {

 public String getSubscriptionItems();
 public int getSubscriptionPeriod();
 public double getSubscriptionPrice();

 public void setSubscriptionItems(String items);
 public void setSubscriptionPeriod(int period);
 public void setSubscriptionPrice(double price);
   
 // the decorator will implement the below method
 public String getHostingSubscription();
}

First, this interface is implemented by the object that follows to be decorated. This is WebHosting:

public class WebHosting implements Hosting {

 private String items = "email account | unlimited traffic";
 private int period = 12;
 private double price = 25.0;

 @Override
 public String getSubscriptionItems() {
  return items;
 }

 @Override
 public int getSubscriptionPeriod() {
  return period;
 }

 @Override
 public double getSubscriptionPrice() {
  return price;
 }

 @Override
 public void setSubscriptionItems(String items) {
  this.items = items;
 }

 @Override
 public void setSubscriptionPeriod(int period) {
  this.period = period;
 }

 @Override
 public void setSubscriptionPrice(double price) {
  this.price = price;
 }

 @Override
 public String getHostingSubscription() {
  return items + "; " + period + " months" + "; $" + price;
 }
}

Further, we can create decorators! A CDI decorator is annotated with @Decorator and can be abstract. While the @Decorator will instruct the container that this class is a decorator, the instance that will be decorated (the delegate injection point) is annotated with @Delegate and must be:

·         an injected field
·         an initializer method parameter
·         a bean constructor method parameter

The delegate type must be the interface implemented by the classes that you want to be decorated, which in our case is Hosting - notice that there is no need to implement all the @Delegate methods. The container will inject any available instance of this interface into the corresponding member, as below - this is the SEOExtraHosting decorator:

@Decorator
public abstract class SEOExtraHosting implements Hosting {

 @Any
 @Inject
 @Delegate
 private Hosting hosting;

 @Override
 public String getHostingSubscription() {
  hosting.setSubscriptionItems(hosting.getSubscriptionItems() + " | " + "SEO");
  hosting.setSubscriptionPrice(hosting.getSubscriptionPrice() + (7 * 5.0));
  return hosting.getHostingSubscription();
 }
}

Another decorator may look like this - the SSHExtraHosting decorator:

@Decorator
public abstract class SSHExtraHosting implements Hosting {
   
 private final int EXTRA_SSH_TAX = 3;
   
 @Any
 @Inject
 @Delegate
 private Hosting hosting;

 @Override
 public String getHostingSubscription() {
  hosting.setSubscriptionItems(hosting.getSubscriptionItems() + " | " + "SSH");
  hosting.setSubscriptionPrice(hosting.getSubscriptionPrice() + (2 * 3.0) + EXTRA_SSH_TAX);
  return hosting.getHostingSubscription();
 }
}

Well, the job is almost done! Final step requires some configurations. The decorators should be declared in beans.xml in the same order that we want them to be chained and applied (the first declared decorator is first applied, and so on; e.g. in this case, the order is SEOExtraHosting, SSHExtraHosting), as below (in our case the order is not relevant, but this is not always the case):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
   
 <decorators>       
  <class>beans.SEOExtraHosting</class>       
  <class>beans.SSHExtraHosting</class>
 </decorators>
</beans>

Finally, we can use our decorators in a CDI managed bean, as below:

@Named
@RequestScoped
public class MyBean {

 @Any
 @Inject
 Hosting hosting;

 public void applyDecorators() {
  System.out.println(hosting.getHostingSubscription());
 }
}

This will output: email account | unlimited traffic | SEO | SSH; 12 months; $69.0

So, is important to keep in mind that decorators can be enabled/disabled at deployment time by editing the beans.xml configuration file and a decorator is automatically applied to classes that implement the same interface. This can be "fixed" by using qualifiers!

In order to skip the declarations in the beans.xml configuration file, you can use @Priority and an @Interceptor.Priority value, as below:

@Priority(Interceptor.Priority.APPLICATION)
@Decorator
public abstract class SEOExtraHosting implements Hosting {
...

@Priority(Interceptor.Priority.APPLICATION + 1)
@Decorator
public abstract class SSHExtraHosting implements Hosting {
...

The order of invocation is dictated by the value of  @Interceptor.Priority - lower value invoke first.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors