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, 11 septembrie 2015

JSF and Observer design pattern - part IV (DeltaSpike event broadcasting)


Well, if you read the previous three parts of this article then you are pretty familiar with the observer pattern. In this final part we will discuss about the event broadcasting feature provided by the Apache DeltaSpike. More precisely, we will discuss about DeltaSpike support for:

·         Observe Faces-Requests
·         BeforePhase / AfterPhase
·         JSF SystemEvents

Observe Faces-Requests
DeltaSpike allows developers to observe the JSF requests (subject). More precisely, it allows developers to observe when a JSF request is initialized (before Restore View phase) and when the JSF request is destroyed (after Render Response phase). Technically speaking this can be accomplished via @Observes in combination with @org.apache.deltaspike.core.api.lifecycle.Initialized (shortly, @Initialized) or @org.apache.deltaspike.core.api.lifecycle.Destroyed (shortly, @Destroyed) as qualifier for javax.faces.context.FacesContext.

public void onBeforeFacesRequest(@Observes @Initialized FacesContext facesContext) {
 //...
}

public void onAfterFacesRequest(@Observes @Destroyed FacesContext facesContext) {
 //...
}

Note "In case of POST-Redirect-GET @Destroyed FacesContext is "different". The context gets destroyed twice (after: POST and GET)." thanks to DeltaSpike team for this explanation!

Let's suppose that we have a JSF application that represents a system used by fire stations to keep tracking of current fires. Each request to this system corresponds to a reported fire at a specific address. The time between a request-response lifespan may represent a complex business logic needed to designate the fire stations that will extinguish the reported fire (can be marked as extinguished fire).  So, if we keep tracking of the initialized and destroyed JSF requests then we can keep tracking of the current fires. This can be shaped via an application scoped bean, as below:

@Named
@ApplicationScoped
public class FiresTrackingBean implements Serializable {
   
 private final List<String> fires;
   
 public FiresTrackingBean(){
  fires = new ArrayList();
 }
          
 public void fireStarted(@Observes @Initialized FacesContext facesContext) {
  String address = facesContext.getExternalContext().getRequestParameterMap().get(address_placeholder);
  if (address != null) {
      System.out.println("Fire started at " + address);
      fires.add(address);
  }
 }
   
 public void fireExtinguished(@Observes @Destroyed FacesContext facesContext) {
  String address = facesContext.getExternalContext().getRequestParameterMap().get(address_placeholder);
  if (address != null) {
      System.out.println("Fire extinguished at " + address);
      fires.remove(address);
  }
 }

 public List<String> getFires() {
  return fires;
 }       
}

Since the fireStarted() is invoked before JSF lifecycle begins, we need to fetch the address value directly from the  request parameter map. For example, if you use <f:param name="address".../> then you can replace address_placeholder with address, but if you submit the address via an input component (e.g. input text) then you need to replace the address_placeholder with the corresponding clientId.

So, pay attention on this aspect!
@Initialized is a good choice for initializations stuff that are needed for the current request, but if those initializations needs data provided at current request via forms, view parameters, <f:param>, etc, you have to keep in mind that you cannot rely on data model at this moment, since the data model was not updated yet.

Well, there is a problem with the fireExtinguished()method. Practically, after a fire was extinguished, this method will remove the corresponding entry from the fires list. But, this method is invoked after the Render Response phase, when the markup was already prepared. This means that it is possible that the fire that follows to be deleted to be already rendered in the response.

So, pay attention on this aspect also!
@Destroyed is a good choice for cleaning/destroying stuff after the current request is over, but pay attention that when this take place the markup (response) was already generated and may contain values that follows to be cleaned/destroyed. This is happening because the cleaning process take place after the Render Response phase.

BeforePhase / AfterPhase
Cases as above can be fine tuned via DeltaSpike feature that allows developers to observe JSF request-lifecycle phase-events via @Observes in combination with @org.apache.deltaspike.jsf.api.listener.phase.BeforePhase (shortly @BeforePhase) or @org.apache.deltaspike.jsf.api.listener.phase.AfterPhase (shortly @AfterPhase) as qualifier for javax.faces.event.PhaseEvent.

Obviously, you can rely on JSF default API for writing phase listeners, but the DeltaSpike approach save us for configurations in faces-config.xml and is more elegant:

public void onPhaseStart(@Observes @BeforePhase(JsfPhaseId.ANY_PHASE) PhaseEvent event) {
 //...
}

public void onPhaseEnd(@Observes @AfterPhase(JsfPhaseId.ANY_PHASE) PhaseEvent event) {
 //...
}

So, we can easily shape our fire tracking system to take advantage of the data model and to ensure that a fire is removed before the markup is prepared, as below:

@Inject
// inject data from model

public void fireStarted(@Observes @AfterPhase(JsfPhaseId.UPDATE_MODEL_VALUES) PhaseEvent event) { 
 if (injected_address!= null) {
     System.out.println("Fire started at " + injected_address);
     fires.add(injected_address);
 }
}

public void fireExtinguished(@Observes @BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent event) {
 if (injected_address!= null) {
     System.out.println("Fire extinguished at " + injected_address);
     fires.remove(injected_address);
 }
}

Note "In case of POST-Redirect-GET @Destroyed FacesContext is "different". The context gets destroyed twice (after: POST and GET). Therefore only @AfterPhase(RENDER_RESPONSE) and @PostRenderView always fit for post-render logic." thanks to DeltaSpike team for this explanation!

JSF SystemEvents
Beside JSF requests and JSF phases, we can observe the following JSF system events via CDI:

·         javax.faces.event.PostConstructApplicationEvent
·         javax.faces.event.PreDestroyApplicationEvent
·         javax.faces.event.ExceptionQueuedEvent

The below example is provided in DeltaSpike documentation:

@ApplicationScoped
public class ApplicationConfig {
 public void init(@Observes PostConstructApplicationEvent event) {
  // ...
 }
}

As you probably know, exceptions that occurs during AJAX request are not treated as exceptions that occurs during non‐AJAX requests. By default, most of them are invisible to the client. Since the user does not receive a feedback about its AJAX request success, he will act as any confused user ‐ restart the application, resend the request, etc. Well, next to the OmniFaces FullAjaxExceptionHandler, the DeltaSpike @Observes ExceptionQueuedEvent can be also used as a starting point in developing a system to handle AJAX exceptions. Basically, you can rely on the fact that AJAX exceptions are queued (as unhandled, see ExceptionHandler#getUnhandledExceptionQueuedEvents()) and it is very easy to programmatically distinguish between AJAX and non-AJAX requests (see Faces#isAjaxRequest()).

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