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

Se încarcă...

Petition by Java EE Guardians

Twitter

miercuri, 14 ianuarie 2015

Subscribe With OmniFaces 2.1 (serializable) /2.0 (un-serializable) Callback-listeners to JSF System Events


In this post we will discuss about how to:

- subscribe the given callback to the current app that get invoked every time when the given system event type is published in the current application (detailed here)
- subscribe the given callback to the current view that get invoked every time when the given system event type is published on the current view (detailed here)

In case you don't know, OmniFaces 2.0 comes with a set of un-serializable callback interfaces useful in (mini) visitor and strategy patterns. In OmniFaces 2.1 we have Serializable callbacks also. Further, we suppose that you are familiar with the Callback interfaces.

So, speaking from JSF angle, what we can do with these interfaces ? Well, OmniFaces uses internally for several tasks, but, in this post we want to focus on using the first two interfaces listed above in conjunction with JSF system events.

Note If you are not very familiar with JSF system events (@ListenerFor, ComponentSystemEventListener and SystemEventListener) then please check this: JSF-Working with @ListenerFor,ComponentSystemEventListener and SystemEventListener - part Ipart II and part III.

In case you didn't know OmniFaces provides two "shortcuts" for programmatically subscribe to system events. First, we have the case when we need to subscribe the given system event listener to the current application that get invoked every time when the given system event type is published in the current application. This is accomplish via JSF, like this:

FacesContext.getCurrentInstance().getApplication().
     subscribeToEvent(Class<? extends SystemEvent> type, SystemEventListener listener);

Starting with OmniFaces 2.0, you should know that this is possible via org.omnifaces.util.Events.subscribeToApplicationEvent() method. You can use it as:

org.omnifaces.util.Events.subscribeToApplicationEvent
      (Class<? extends SystemEvent> type, SystemEventListener listener)

Secondly, we have the case when we need to subscribe the given system event listener to the current view that get invoked every time when the given system event type is published on the current view. This is commonly accomplish in JSF via:

FacesContext.getCurrentInstance().getViewRoot().subscribeToViewEvent
      (java.lang.Class<? extends SystemEvent> systemEvent, SystemEventListener listener)

Using OmniFaces, you can do this instead:

org.omnifaces.util.Events.subscribeToViewEvent
      (java.lang.Class<? extends SystemEvent> systemEvent, SystemEventListener listener)

Beside these two "shortcuts", starting with version 2.0, OmniFaces has seriously increased the combinations of callback interfaces and system events. Based on the first shortcut, OmniFaces allows us to subscribe a callback to the current application that get invoked every time when the given system event type is published in the current application. This is possible via the next Events methods:

·         serializable void callback subscribes to application event (since 2.1)

·         void callback subscribes to application event (since 2.0) - serializable in 2.1

·        serializable callback which takes an argument subscribes to application event (since 2.1) 

·         callback which takes an argument subscribes to application event (since 2.0) - serializable in 2.1

Based on the second shortcut, OmniFaces allows us to subscribe a callback to the current view that get invoked every time when the given system event type is published on the current view. This is possible via the next Events methods:

·         serializable void callback subscribes to view event (since 2.1)

·         void callback subscribes to view event (since 1.2) - serializable in 2.1

·         serializable callback which takes an argument subscribes to view event (since 2.1)

·         callback which takes an argument subscribes to view event (since 2.0) - serializable in 2.1

Note Is important to know that these methods are based on an implementation of the JSF SystemEventListener, named DefaultViewEventListener. This OmniFaces implementation is used for the subset of system events that are registered as "view event" on the component tree's view root:

public abstract class DefaultViewEventListener implements SystemEventListener {

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  // NOOP
 }

 @Override
 public boolean isListenerForSource(Object source) {
  return source instanceof UIViewRoot;
 }
}

Note As you can see, this implementation suppress the effect of the processEvents() method and restrict the event emitters to instances of UIViewRoot. Before using these methods, is major to be aware of this behavior.

Now, that you know this, let's see how to use each of these methods is custom component sample (you can use them in any artifact that fits properly):

·         serializable/un-serializable void callback subscribes to application event

import org.omnifaces.util.Callback;
import static org.omnifaces.util.Events.subscribeToApplicationEvent;
...

@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase {

 public static final String COMPONENT_FAMILY = "jsf.callback.void";
 public static final String COMPONENT_TYPE = "jsf.callback.void.TomComponent";

 public TomComponent() {

  // OmniFaces 2.1
  subscribeToApplicationEvent(PostAddToViewEvent.class, new Callback.SerializableVoid()  {

   private static final long serialVersionUID = 1L;


   @Override
   public void invoke() {
    System.out.println("..: PostAddToViewEvent event emitted by UIViewRoot :..");
    //do something ...
   }
  });

  // OmniFaces 2.0
  subscribeToApplicationEvent(PostAddToViewEvent.class, new Callback.Void() {
   @Override
   public void invoke() {
    System.out.println("..: PostAddToViewEvent event emitted by UIViewRoot :..");
    //do something ...
   }
  });
 }

 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

·         serializable/un-serializable callback which takes an argument subscribes to application event

import javax.faces.event.SystemEvent;
import org.omnifaces.util.Callback;
import static org.omnifaces.util.Events.subscribeToApplicationEvent;
...
@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase {

 public static final String COMPONENT_FAMILY = "jsf.callback.with.argument";
 public static final String COMPONENT_TYPE = "jsf.callback.with.argument.TomComponent";

 public TomComponent() {

  // OmniFaces 2.1
  subscribeToApplicationEvent(PostAddToViewEvent.class, new Callback.SerializableWithArgument<SystemEvent>() {

   private static final long serialVersionUID = 1L;

   @Override
   public void invoke(SystemEvent event) {
    System.out.println("..: PostAddToViewEvent event emitted by UIViewRoot :.." + event.getSource());
    //do something ...
   }
  });

  // OmniFaces 2.0
  subscribeToApplicationEvent(PostAddToViewEvent.class, new Callback.WithArgument<SystemEvent>() {
   @Override
   public void invoke(SystemEvent event) {
    System.out.println("..: PostAddToViewEvent event emitted by UIViewRoot :.." + event.getSource());
    //do something ...
   }
  });
 }

 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

The pure JSF "equivalent":

@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase implements SystemEventListener{

 public static final String COMPONENT_FAMILY = "jsf.equivalent";
 public static final String COMPONENT_TYPE = "jsf.equivalent.TomComponent";

 public TomComponent() {

  FacesContext.getCurrentInstance().getApplication().
   subscribeToEvent(PostAddToViewEvent.class, this);
 }

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  System.out.println("..: PostAddToViewEvent event emitted by UIViewRoot :.." +  
                                                                   event.getSource());
  //do something ...
 }

 @Override
 public boolean isListenerForSource(Object source) {        
  return source instanceof UIViewRoot;
 }
   
 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
  public String getFamily() {
  return COMPONENT_FAMILY;
 }   
}

·         serializable/un-serializable void callback subscribes to view event

import org.omnifaces.util.Callback;
import static org.omnifaces.util.Events.subscribeToViewEvent;
...
@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase {

 public static final String COMPONENT_FAMILY = "jsf.callback.void";
 public static final String COMPONENT_TYPE = "jsf.callback.void.TomComponent";

 public TomComponent() {

  // OmniFaces 2.1
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.SerializableVoid() {

   private static final long serialVersionUID = 1L;

   @Override
   public void invoke() {
    System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :..");
    //do something ...
   }
  });

  // OmniFaces 2.0
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.Void() {
   @Override
   public void invoke() {
    System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :..");
    //do something ...
   }
  });
 }

 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

·        serializable/un-serializable callback which takes an argument subscribes to application event

import javax.faces.event.SystemEvent;
import org.omnifaces.util.Callback;
import static org.omnifaces.util.Events.subscribeToViewEvent;

@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase {

 public static final String COMPONENT_FAMILY = "jsf.callback.with.argument";
 public static final String COMPONENT_TYPE = "jsf.callback.with.argument.TomComponent";

 public TomComponent() {

  // OmniFaces 2.1
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.SerializableWithArgument <SystemEvent>() {

   private static final long serialVersionUID = 1L;

   @Override
   public void invoke(SystemEvent event) {
    System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :.." + event.getSource());
    //do something ...
   }
  });

  // OmniFaces 2.0
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.WithArgument<SystemEvent>() {
   @Override
   public void invoke(SystemEvent event) {
    System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :.." + event.getSource());
    //do something ...
   }
  });
 }

 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

The pure JSF "equivalent":

@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
public class TomComponent extends UIComponentBase implements SystemEventListener {

 public static final String COMPONENT_FAMILY = "jsf.equivalent";
 public static final String COMPONENT_TYPE = "jsf.equivalent.TomComponent";

 public TomComponent() {

  FacesContext.getCurrentInstance().getViewRoot().
     subscribeToViewEvent(PreRenderViewEvent.class, this);
 }

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :.."
                                                               + event.getSource());
  //do something ...
 }

 @Override
 public boolean isListenerForSource(Object source) {
  return source instanceof UIViewRoot;
 }

 @Override
 public void encodeEnd(FacesContext context) throws IOException {
  ResponseWriter responseWriter = context.getResponseWriter();
  responseWriter.write("I'm Tom the cat!");
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

Finally, let's have an example that uses the OmniFaces technique in a JSF managed bean. First,let's have a simple JSF page:

<h:body>                
 <h:form>
  <o:outputLabel for="tomId" value="Tom Enemy:"/>
  <h:inputText id="tomId" value="#{tomBean.enemy}"/>
  <h:commandButton value="Get Advice"/>
 </h:form>
 <h:outputText rendered="#{facesContext.postback}" value="#{tomBean.advice}"/>
</h:body>

Tom enters the name of its enemy (jerry, or the dog) and it gets some advice that helps him to survive. This is happening in a managed bean, like this:

@Named
@RequestScoped
public class TomBean implements Serializable {

 private static final long serialVersionUID = 1L; 

 private String enemy;
 private String advice;

 @PostConstruct
 public void adviceForTom() {
  //the enemy value is not available in @PostConstruct, but we can
  //subscribe with a callback to PreRenderViewEvent, when the enemy is available

  // OmniFaces 2.1
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.SerializableWithArgument<SystemEvent>() {

   private static final long serialVersionUID = 1L;

   @Override
   public void invoke(SystemEvent event) {               
    if (enemy != null) {
        if (enemy.equals("jerry")) {
            advice = "Tom, watch the dog while you are chasing Jerry!";
        } else if (enemy.equals("dog")) {
            advice = "Tom, be careful to Jerry traps!";
        } else {
            advice = "Tom, you have a new enemy ?!!";
        }
    }
   }
  });

  // OmniFaces 2.0
  subscribeToViewEvent(PreRenderViewEvent.class, new Callback.WithArgument<SystemEvent>() {
   @Override
   public void invoke(SystemEvent event) {               
    if (enemy != null) {
        if (enemy.equals("jerry")) {
            advice = "Tom, watch the dog while you are chasing Jerry!";
        } else if (enemy.equals("dog")) {
            advice = "Tom, be careful to Jerry traps!";
        } else {
            advice = "Tom, you have a new enemy ?!!";
        }
    }
   }
  });
 }

 public String getEnemy() {
  return enemy;
 }

 public void setEnemy(String enemy) {
  this.enemy = enemy;
 }

 public String getAdvice() {
  return advice;
 }

 public void setAdvice(String advice) {
  this.advice = advice;
 }
}

When Tom submits the form and the application flow reaches in the @PostConstruct method, the enemy value was not set yet. But, we register a callback as a listener for the PreRenderViewEvent which means that right before the UIViewRoot is about to be rendered the invoke() method is called, and the enemy value is set and can be used to choose the right advice for Tom. Nice!

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