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

duminică, 11 ianuarie 2015

JSF-Working with @ListenerFor, ComponentSystemEventListener and SystemEventListener-part III

Check first:
JSF-Working with @ListenerFor, ComponentSystemEventListener and SystemEventListener - part I
JSF-Working with @ListenerFor, ComponentSystemEventListener and SystemEventListener - part II

Sometimes you need to install the listener instance referenced by argument listener into the UIViewRoot as a listener for events of type systemEventClass, as in the case of PreRenderViewEvent.

Below you can see the UIViewRoot.subscribeToViewEvent() provided by JSF and some alternatives provided by OmniFaces 2.1 and 2.0:
In such cases, you cannot use @ListenerFor, do not try: @ListenerFor(systemEventClass = PreRenderViewEvent.class), consider this as another bad practice!!!. You need the UIViewRoot.subscribeToViewEvent() method, as below:

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

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

 @PostConstruct
 public void tomSubscribeToViewEvent() {
  FacesContext.getCurrentInstance().getViewRoot().
      subscribeToViewEvent(PreRenderViewEvent.class, this);
 }

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  System.out.println("EVENT EMITTED: " + event);       
 }

 @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;
 }

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

Sometimes, you need to combine an event like PostAddToViewEvent with PreRenderViewEvent. Per example, OmniFaces does this in the OnloadScript component. The next example is inspired by the source code of OnloadScript component:

@ListenerFor and UIViewRoot.subscribeToViewEvent()  used with an UIComponent that implements the ComponentSystemEventListener and SystemEventListener interfaces
§  the UIComponent is annotated with @ListenerFor and listen the PostAddToViewEvent event emitted by instances of this UIComponent
§  if the request (initial/postback) is an AJAX request then the component register as a listener for the PreRenderViewEvent emitted by the UIViewRoot.

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

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

 @Override
 public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
  System.out.println("EVENT EMITTED (ComponentSystemEvent): " + event);
  FacesContext context = FacesContext.getCurrentInstance();
  boolean ajaxRequest = context.getPartialViewContext().isAjaxRequest();
  if (ajaxRequest) {
      context.getViewRoot().subscribeToViewEvent(PreRenderViewEvent.class, this);
  }
 }

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  System.out.println("EVENT EMITTED (SystemEvent): " + event);
 }

 @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;
 }

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

Output at initial request (AJAX reqest):

EVENT EMITTED (ComponentSystemEvent): javax.faces.event.PostAddToViewEvent[source=jsf.listenerforanduicomponent.TomComponent]

Output at postback (AJAX request):

EVENT EMITTED (ComponentSystemEvent): javax.faces.event.PostAddToViewEvent[source=jsf.listenerforanduicomponent.TomComponent]
EVENT EMITTED (ComponentSystemEvent): javax.faces.event.PostRestoreStateEvent[source=jsf.listenerforanduicomponent.TomComponent]
EVENT EMITTED (SystemEvent): javax.faces.event.PreRenderViewEvent[source=javax.faces.component.UIViewRoot]

System events can be configured in faces-config.xml also. If you need to register as listener for a built-in JSF component then this can be the right approach. Per example, we can write a system event for looping through the CSS resources and remove some of them (or, all of them). The code of our listener is pretty simple, as you can see in the following code:

public class ResourcesListener implements SystemEventListener {

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

  FacesContext context = FacesContext.getCurrentInstance();
     
  int i = context.getViewRoot().getComponentResources(context, "HEAD").size() - 1;

  while (i >= 0) {
   UIComponent resource = context.getViewRoot().getComponentResources(context, "HEAD").get(i);

   String resourceLibrary = (String) resource.getAttributes().get("library");
   String resourceName = (String) resource.getAttributes().get("name");

   if ((resourceLibrary.equals("default")) && (resourceName.equals("css/jerry.css"))) {
        context.getViewRoot().removeComponentResource(context, resource, "HEAD");
   }

   i--;
  }
 }

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

The listener should be configured in faces-config.xml, as follows (the tags names reveals their goal):

...
<application>       
 <system-event-listener>
   <system-event-listener-class>
     tom.jerry.ResourcesListener
   </system-event-listener-class>
   <system-event-class>
     javax.faces.event.PreRenderViewEvent
   </system-event-class>
   <source-class>
     javax.faces.component.UIViewRoot
   </source-class>
 </system-event-listener>
</application>
...

So, even if initially we write the following code:
...
<h:head>
 <h:outputStylesheet library="default" name="css/tom.css"/>
 <h:outputStylesheet library="default" name="css/jerry.css"/>
</h:head>
...

JSF will render the following code:

...
<head>
 <link type="text/css" rel="stylesheet"  
       href="/tomandjerry/faces/javax.faces.resource/css/tom.css?ln=default" />
</head>
...

Note: Programmatically, you can unsubscribe from an event using the UIComponent/Application.unsubscribeFromEvent() methods:

//UIComponent
public void unsubscribeFromEvent(java.lang.Class<? extends SystemEvent> eventClass,
                                 ComponentSystemEventListener componentListener)

//Application
public void unsubscribeFromEvent(java.lang.Class<? extends SystemEvent> systemEventClass,
                                 java.lang.Class<?> sourceClass,
                                 SystemEventListener listener)
public void unsubscribeFromEvent(java.lang.Class<? extends SystemEvent> systemEventClass,
                                 SystemEventListener listener)

Useful links: JSF ZEEF
                  OmniFaces Custom Components Approach

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