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.
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 I, part 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:
·
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:
·
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
// OmniFaces 2.1
subscribeToApplicationEvent(PostAddToViewEvent.class,
new Callback.SerializableVoid() {
private static final long serialVersionUID = 1L;
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
// 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 invoke(SystemEvent event) {
System.out.println("..: PreRenderViewEvent event emitted by UIViewRoot :.."
//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 :.."
//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 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
// OmniFaces 2.0
// 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 ?!!";
}
}
}
});
});
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