Quantcast
Channel: OmniFaces & JSF Fans
Viewing all 74 articles
Browse latest View live

JSF 2.3 - Conditionally open/close a websocket channel

$
0
0
Read also:


In this post, you will see how to conditionally open/close a channel. In order to accomplish this, we place the condition on the connected attribute via a ValueExpression. This attribute (condition) will be evaluated at each AJAX request, and if the value of this EL expression becomes false during an AJAX request then the push connection will explicitly be closed during oncompleteof that AJAX request.

In the JSF 2.3 - The WebSocket Quickstart under Payara post, we are pushing a message that indicates the current server time in format, hh:mm:ss. Let's re-write that example for limiting the pushing service only between 8-9 AM (PM).

The relevant part of the JSF page will look like this (notice the connected attribute at work):

<h:form>               
 <h:commandButton value="Clock" action="#{pushBean.clockAction()}">
  <f:ajax render="@form"/>
 </h:commandButton>
 Service status:
 <h:outputText value="#{pushBean.info}"/>
</h:form>

<f:websocket channel="clock"
             connected="#{pushBean.connected}"
             onopen="websocketOpenListener"
             onclose="websocketCloseListener"
             onmessage="socketListener" />     

On server-side we implement the condition logic as follows:

@Named
@ApplicationScoped
public class PushBean implements Serializable {

 private static final Logger LOG = Logger.getLogger(PushBean.class.getName());

 @Inject
 @Push(channel = "clock")
 private PushContext push;

 private boolean connected;
 private String info;
 private String time;

 private void pingClock() {
  Calendar now = Calendar.getInstance();

  int hour = now.get(Calendar.HOUR_OF_DAY);
  connected = (hour >= 8) && (hour < 9);

  if (connected) {
      time = now.get(Calendar.HOUR_OF_DAY) + ":"
              + now.get(Calendar.MINUTE) + ":" + now.get(Calendar.SECOND);
      info = "Service is available";
  } else {
      time = null;
      info = "Service is available only between 8-9 AM/PM";
  }
 }

 public void clockAction() {

  pingClock();

  if (time != null) {
      LOG.log(Level.INFO, "Time: {0}", time);
      push.send(time);
  }
 }

 public boolean isConnected() {
  return connected;
 }

 public void setConnected(boolean connected) {
  this.connected = connected;
 }

 public String getInfo() {
  return info;
 }
}

So, the connectedattribute will be set initially to false (default it is true meaning auto-connect). Furthermore, the attribute is evaluated to trueonly between the 8:00:00 - 8:59:59 server-time. This means that the first AJAX request that take place after 8:00:00 and before 8:59:59 will open the connection, while the first AJAX request that take place after 8:59:59 will close the connection.

The figures below shows a flow of usage:

-request fired before 8:00:00


-request fired after 8:00:00 opens the connection


- between 8:00:00 and 8:59:59 the connection is open

-after 8:59:59, the first request close the connection


The complete application is available here.

JSF VS Series: Forward VS Redirect

JSF VS Series: @ManagedBean VS @Named

JSF 2.3 - Firing one-time push when the web socket channel has been opened

$
0
0
Read also:


In this post, we want to write an application that uses a web socket to "say" Hello world! - pushes the Hello World! message to a channel named hello. This should take place automatically (when the channel has been opened) and one-time only.

Since a web socket channel is automatically opened, we don't need to put any effort in this step. We just define in page a simple web socket like below:

<f:websocket channel="hello" onmessage="socketListener" /> 

Note: In such cases, we should use this together with the optional user attribute of  <f:websocket/> to push the message to a specific user that it is login. Moreover, we can use the optional scope attribute set to session (push messages to all views in the current user session only) or view (push messages to  to the current view only). In such cases, the CDI managed bean should be annotated with the CDI @SessionScoped respectively @ViewScoped. Since we just want to show the technique of  firing one-time push when the web socket channel has been opened, we will not "pollute" the code and we will use the application scope.

Since this channel should "transport" a single message, we need to close the channel after receiving the first message, like below:

<div id="helloId"></div>

<script type="text/javascript">           
 function socketListener(message, channel, event) {               
  document.getElementById("helloId").innerHTML = message;           
  jsf.push.close("hello");
 }
</script>

Further, we have an application bean capable to push the message to hello channel:

@Named
@ApplicationScoped
public class PushBean implements Serializable {

 @Inject
 @Push(channel = "hello")
 private PushContext push;

 public void pushAction() {
  push.send("Hello world!");
 }
}

The only aspect that we didn't cover so far refers to pushing the message automatically when the channel has been opened. For this, we can use two server events:

CDI WebsocketEventwill be fired with @WebsocketEvent.Opened qualifier
This event is fired when a web socket channel has been opened.

CDI WebsocketEventwill be fired with @WebsocketEvent.Closed qualifier
This event is fired when a web socket channel has been closed.

Both events can be observed in an application scoped CDI bean as below. So, in our case we can take advantage of the event fired when the web socket channel has been opened and push the Hello world! message:

@ApplicationScoped
public class WebsocketObserver {
   
 private static final Logger LOG =  
                Logger.getLogger(WebsocketObserver.class.getName());       
   
 @Inject   
 private PushBean pushBean;

  public void onOpen(@Observes @Opened WebsocketEvent event) {        
  pushBean.pushAction();       
 }   
   
 public void onClose(@Observes @Closed WebsocketEvent event) {
  String channel = event.getChannel();
  LOG.log(Level.INFO, "Channel {0} was successfully closed!", channel);
 }
}

Notice that via the WebsocketEvent object we can obtain information such as:

Returns a string representing the <f:websocket/> channel name:
event.getChannel();         

Returns a string representing the <f:websocket/> user:
event.getUser();            


Returns a CloseCode instance representing the close reason code:
event.getCloseCode();      

Now, our application output will be like in figure below:


The complete application is available here.

JSF 2.3 Multiple File Upload with HTML 5, AJAX and upload progress bar via web sockets

$
0
0

The source code from the above article was modified to support a progress bar via the JSF 2.3 web sockets. The main modifications implies:

- add <f:websocket/>in page

Note: In production, this web socket should be adjusted to distinguish between users there are login  (in case that you have this feature) via the optional userattribute (e.g. you can use: user="#{request.remoteUser}") - this is needed for sending messages to a single login user, the one who initiated the upload. In the form below, JSF will push messages to  to the current view only. You can also set scope="session" and push messages to all views in the current user session only. But we don't take into account if the user is login or not!

<f:websocket channel="upload" onmessage="socketListener" scope="view" />

Notice that this web socket it is automatically open when you start the application and it is not explictly closed. If you want to accomplish such features please read further JSF 2.3 - Explicitly open/close a websocket channel.

- provide a divwhere the upload progress is displayed (we display the percent as: x%), but you can choose to implement a visual progress bar:

<div id="progressBarId">0 %</div>

- provide the JavaScript listener for processing the incoming messages:

function socketListener(message, channel, event) {               
 document.getElementById("progressBarId").innerHTML = message + "%";
}

- on server-side, in UploadBean, you have to inject the PushContextvia @Push annotation on the given channel name (upload):

@Inject
@Push(channel = "upload")
private PushContext push;

- and, finally, push the messages during upload:

push.send((totalReadSize * 100) / totalSize);

Below, you can see a possible output:


The complete application is available here.

What Is PrimeFaces? on developer.com

OmniFaces 2.3 released!

OmniFaces and WebSockets Quickstart

$
0
0
Starting with OmniFaces 2.3 we can take advantage of a brand new feature - register a web socket push connection in client side. Thanks to the OmniFaces team this feature is available in today OmniFaces 2.3-RC1 via <o:socket/> tag.

In this post, let's see a minimal usage of <o:socket/> tag.

First, ensure that you project contains the OmniFaces 2.3 dependency. Afterwards, in the JSF page, we need to add the <o:socket/> tag with its two required attributes:

·         channel - This is javax.el.ValueExpression that must be evaluated to String and it represents the name of the web socket channel. A channel name is restricted to alphanumeric characters, hyphens, underscores and periods. A channel can have multiple open web sockets, and each of these sockets will receive the same push notification from the server.
·         onmessage - This is javax.el.ValueExpression that must be evaluated to String and it represents the a JavaScript listener function that is automatically invoked when a push notification is received from the server.

The signature of the listener function for onmessage is of type:

function fooListener(message, channel, event) {                      
 // message - the message pushed by the server
 // channel - the channel name
 // event - the raw MessageEvent instance
}

So, a simple <o:socket/> tag usage will look like this:

<o:socket channel="clock" onmessage="socketListener" />

<div id="clockId"></div>

<script type="text/javascript">
 function socketListener(message, channel, event) {                      
  document.getElementById("clockId").innerHTML += message + "<br/>";
 }
</script>

By default, when we start the application, the web socket is automatically connected and open. As long as the document is open the web socket is open. When the document is unloaded the web socket is automatically closed. In the web socket is initially successfully connected but the connection is closed as a result of e.g. a network error or server restart, JSF will try to auto-reconnect it at increasing intervals.

Now, let's focus on the server side. Here we have to take into account the push messages mechanism. This mechanism is based on org.omnifaces.cdi.PushContext interface and org.omnifaces.cdi.Push API.

First, you need to know that by default the web socket is application scoped. This means that the managed bean that can push messages to this web socket must be in application scope (annotated with @ApplicationScope). In this case, the push message can be sent by all users and the application itself.

Furthermore, you have to inject PushContext via @Push annotation on the given channel name in any CDI/container managed artifact. For example:

@Inject
@Push(channel = "clock")
private PushContext push;

Finally, we need to write an action method capable to push messages to web socket via PushContext. For example:

public void clockAction(){
 Calendar now = Calendar.getInstance();
       
 String time = now.get(Calendar.HOUR_OF_DAY) + ":" +
               now.get(Calendar.MINUTE) + ":" +
               now.get(Calendar.SECOND);
 LOG.log(Level.INFO, "Time: {0}", time);
    
 push.send(time);
}

Let's glue everything together. First, the JSF page:

<h:body>        
 <h:form>           
  <h:commandButton value="Clock" action="#{pushBean.clockAction()}">
   <f:ajax />
  </h:commandButton>
 </h:form>

 <o:socket channel="clock" onmessage="socketListener" />       

 <hr/>
 <div id="clockId"></div>

 <script type="text/javascript">
  function socketListener(message, channel, event) {                      
   document.getElementById("clockId").innerHTML += message + "<br/>";
  }
 </script>   
</h:body>

Next, our simple CDI bean:

@Named
@ApplicationScoped
public class PushBean implements Serializable {
   
 private static final Logger LOG = Logger.getLogger(PushBean.class.getName());
       
 @Inject
 @Push(channel = "clock")
 private PushContext push;
   
 public void clockAction(){
  Calendar now = Calendar.getInstance();
       
  String time = now.get(Calendar.HOUR_OF_DAY) + ":" +
                now.get(Calendar.MINUTE) + ":" + now.get(Calendar.SECOND);
  LOG.log(Level.INFO, "Time: {0}", time);
       
  push.send(time);
 }
}

Finally, OmniFaces 2.3 requires the following settings in web.xml:

<context-param>
 <param-name>org.omnifaces.ENABLE_SOCKET_ENDPOINT</param-name>
 <param-value>true</param-value>
</context-param>


Done! The complete application was tested under Payara server and it is available here.

CHECK MORE EXAMPLES HERE.

Entirely skip validation via SkipValidators

$
0
0
OmniFaces 2.3 comes with a new tag handler named SkipValidators. As its name suggest, this tag handler allows us to entirely skip validation when executing an UICommandor ClientBehaviorHolderaction. Simply place the<o:skipValidators/> tag inside a UICommand or ClientBehaviorHolder component. For example, in the below code, the button labeled Hard Submit will take validation into account, while the button labeled Soft Submit will entirely skip validation and the submitted data end up in the data model:

<h:form>
 <h:messages/>
 <h:panelGrid columns="2">
  <h:outputLabel for="nameId" value="Name:"/>
  <h:inputText id="nameId" value="#{dataBean.name}" required="true"/>
  <h:outputLabel for="emailId" value="E-mail:"/>
  <h:inputText id="emailId" value="#{dataBean.email}" required="true" validator="emailValidator"/>
  <h:commandButton value="Hard Submit"/>
  <h:commandButton value="Soft Submit">
   <o:skipValidators />
  </h:commandButton>
 </h:panelGrid>
 Name: #{dataBean.name} | E-mail: #{dataBean.email}
</h:form>

Note Even if the validation is disabled conversion errors could still occur.

This can be useful in different scenarios including debugging, testing, dynamically adding/removing items from a form, etc. You can temporary disable the validation for large forms and perform different checks with respect to data model. Instead of removing validators one by one, you simply add this tag handler.  The complete application is available here.

[OmniFaces utilities 2.3] Load given script resource on complete of the current ajax response

$
0
0

[OmniFaces utilities] The load() method loads the given script resource on complete of the current ajax response. Basically, it loads the script resource as String and then delegates it to #oncomplete(String...).

Method:
Usage:

Let's suppose that we have a script file named foo.js in the default library. Now, programmatically we can load this file at the end of the current AJAX request (at on complete) as below:

import org.omnifaces.util.Ajax;
...
Ajax.load("default","foo.js");

What's new in OmniFaces 2.3

$
0
0

JSF Navigation Tutorial - Conditional Navigation

$
0
0
Check also:
The three golden rules of use
JSF Navigation Tutorial - Implicit Navigation
JSF Navigation Tutorial - Declarative Navigation
JSF Navigation Tutorial - Preemptive Navigation
JSF Navigation Tutorial - Programmatic Navigation
JSF VS Series: Implicit Navigation VS Declarative (explicit) Navigation

Conditional navigation allows us to specify preconditions for choosing the desired navigation case; a precondition must be met in order for the navigation case to be accepted. For this, we use the <if/>tag as a child of the <navigation-case/>tag and use an EL expression that can be evaluated to a boolean value; here the true value matches the navigation case. If you don't prefer the declarative approach, then you can simply add the conditions in action methods.

Let's see some examples of using implicit navigation. The managed bean used in the next examples is listed first and the application is named ConditionalNavigation:

@Named
@RequestScoped
public class TheBean {

 private static final Logger LOG = Logger.getLogger(TheBean.class.getName());

 private int rnd = new Random().nextInt(100);

 public int getRnd() {
  return rnd;
 }

 public String theActionWithDoneOutcome() {
  LOG.info("TheBean#theActionWithDoneOutcome() called ...");
  return rnd > 50 ? "success" : "failure";
 }
   
 public String theActionWithDoneOutcomeAndRedirect() {
  LOG.info("TheBean#theActionWithDoneOutcome() called ...");
  return rnd > 50 ? "success?faces-redirect=true" : "failure?faces-redirect=true";
 }
}

FIRE A JSF GET REQUEST AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
JSF will interpret the outcome value of <h:link/>/<h:button/> as the targeted page name (done becomes success.xhtml/failure.xhtml via conditional navigation)

<h:link value="Click me! (h:link)" outcome="done"/>
<h:button value="Click me! (h:button)" outcome="done"/>

JSF will render the right view by evaluating the following declarative condition:

<navigation-rule>
 <from-view-id>index.xhtml</from-view-id>
 <navigation-case>
  <from-outcome>done</from-outcome>
  <if>#{theBean.rnd gt 50}</if>
  <to-view-id>/success.xhtml</to-view-id>
 </navigation-case>
 <navigation-case>
  <from-outcome>done</from-outcome>
  <if>#{theBean.rnd le 50}</if>
  <to-view-id>/failure.xhtml</to-view-id>
 </navigation-case>
</navigation-rule>

FIRE A JSF GET REQUEST. PROVIDE THE NAVIGATION OUTCOME VIA A SERVER-SIDE METHOD CALLED DURING COMPUTING THE VIEW ID (AT RENDERING TIME)
JSF will interpret the outcome value of <h:link/>/<h:button/> as the targeted page name (done returned by theActionWithDoneOutcome() becomes success.xhtml/failure.xhtml via conditional navigation)

<h:link value="Click me! (h:link)" outcome="#{theBean.theActionWithDoneOutcome()}"/>
<h:button value="Click me! (h:button)" outcome="#{theBean.theActionWithDoneOutcome()}"/>

JSF will render the right view by evaluating the following programmatic condition:

public String theActionWithDoneOutcome() {
 return rnd > 50 ? "success" : "failure";
}

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
JSF will interpret the action value of <h:commandLink/Button/> as the targeted page name (done becomes success.xhtml/failure.xhtml via conditional navigation)

<h:commandLink value="Click Me! (h:commandLink)" action="done"/>
<h:commandButton value="Click Me! (h:commandButton)" action="done"/>

JSF will render the right view by evaluating the same declarative condition from above:

<navigation-rule>
 <from-view-id>index.xhtml</from-view-id>
 <navigation-case>
  <from-outcome>done</from-outcome>
  <if>#{theBean.rnd gt 50}</if>
  <to-view-id>/success.xhtml</to-view-id>
 </navigation-case>
 <navigation-case>
  <from-outcome>done</from-outcome>
  <if>#{theBean.rnd le 50}</if>
  <to-view-id>/failure.xhtml</to-view-id>
 </navigation-case>
</navigation-rule>

FIRE (SUBMIT) A POST REQUEST VIA REDIRECT MECHANISM AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
The presence of <redirect/> in navigation case will instruct JSF to rely on POST-redirect-GET (PRG) navigation pattern

<h:commandLink value="Click Me! (h:commandLink)" action="doneredirect"/>
<h:commandButton value="Click Me! (h:commandButton)" action="doneredirect"/>

JSF will render the right view by evaluating the following declarative condition:

<navigation-rule>
 <from-view-id>index.xhtml</from-view-id>
 <navigation-case>
  <from-outcome>doneredirect</from-outcome>
  <if>#{theBean.rnd gt 50}</if>
  <to-view-id>/success.xhtml</to-view-id>
  <redirect/>
 </navigation-case>
 <navigation-case>
  <from-outcome>doneredirect</from-outcome>
  <if>#{theBean.rnd le 50}</if>
  <to-view-id>/failure.xhtml</to-view-id>
  <redirect/>
 </navigation-case>
</navigation-rule>

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM. INVOKE AN ACTION METHOD AND NAVIGATE TO THE VIEW ID COMPUTED BASED ON THE OUTCOME RETURNED BY THIS METHOD
The action can point to an action method that returns a String. This string is considered the outcome and it will be interpreted as the targeted page name.

<h:commandLink value="Click Me! (h:commandLink)" action="#{theBean.theActionWithDoneOutcome()}"/>
<h:commandButton value="Click Me! (h:commandButton)" action="#{theBean.theActionWithDoneOutcome()}"/>           

JSF will render the right view by evaluating the following programmatic condition:

public String theActionWithDoneOutcome() {
 return rnd > 50 ? "success" : "failure";
}

FIRE (SUBMIT) A POST REQUEST VIA REDIRECT MECHANISM. INVOKE AN ACTION METHOD AND NAVIGATE TO THE VIEW ID COMPUTED BASED ON THE OUTCOME RETURNED BY THIS METHOD
The action can point to an action method that returns a String. This string is considered the outcome and it will be interpreted as the targeted page name. The presence of ?faces-redirect=true will instruct JSF to rely on POST-redirect-GET (PRG) navigation pattern.

<h:commandLink value="Click Me! (h:commandLink)" action="#{theBean.theActionWithDoneOutcomeAndRedirect()}"/>
<h:commandButton value="Click Me! (h:commandButton)" action="#{theBean.theActionWithDoneOutcomeAndRedirect()}"/>          

JSF will render the right view by evaluating the following programmatic condition:

public String theActionWithDoneOutcomeAndRedirect() {
 return rnd > 50 ? "success?faces-redirect=true" : "failure?faces-redirect=true";
}

Note
In conditional navigation, the navigation cases are evaluated even when the outcome is null or void. Notice that there is no <else/>tag or multiple conditional checking; therefore, in such cases, you have to emulate a switchstatement. If you want to simply match the null outcome in any case, then you can use a condition of type: <if>#{true}</if>. Moreover, the sequence of the navigation rule affects the navigation flow; therefore, it is a good practice to prioritize conditions.

The complete application is available here.

[OmniFaces utilities 2.4] URI-encode the given string using UTF-8

$
0
0

[OmniFaces utilities] The encodeURI() method encodes the given string using UTF-8. URIs (paths and filenames) have different encoding rules as compared to URLs. URLEncoder is actually only for www (HTML) form based query string parameter values. URI encoding has a lot in common with URL encoding, but the space has to be %20 and some chars doesn't necessarily need to be encoded.

Method
Usage

import org.omnifaces.util.Utils;
...
// http%3A%2F%2Fwww.names.org%3Fname%3DAnghel%20Leonard
String encode_uri = Utils.encodeURI("http://www.names.org?name=Anghel Leonard");

// check #encodeURL() also
// http%3A%2F%2Fwww.names.org%3Fname%3DAnghel+Leonard
String encode_url = Utils.encodeURL("http://www.names.org?name=Anghel Leonard");

Notice how the empty space was encoded by #encodeURI() as %20, while #encodeURL() as +.

JSF Navigation Tutorial - Preemptive Navigation

$
0
0
Check also:
The three golden rules of use
JSF Navigation Tutorial - Implicit Navigation
JSF Navigation Tutorial - Declarative Navigation
JSF Navigation Tutorial - Conditional Navigation
JSF Navigation Tutorial - Programmatic Navigation
JSF VS Series: Implicit Navigation VS Declarative (explicit) Navigation

Preemptive navigation is available starting with JSF 2.0. The navigation rules are more permissive and they are evaluated during the Render Response phase instead of the Invoke Application phase.

This is known as predetermined navigation or preemptive navigation. The current view ID and specified outcome are used to determine the target view ID. Afterwards, the target view ID is translated into a bookmarkable URL and used as the hyperlink's target. Practically, the URL is prepared without user interaction.

The main usage of preemptive navigation appears in bookmarkable component tags, <h:link/> and <h:button/>. For example, the following are two classical examples of preemptive navigation:

<h:link value="Success" outcome="success"/>
<h:button value="Success" outcome="success"/>

When the application starts, you can check the source code of the page to see how the corresponding URLs were mapped in the HTML tag <a/> in case of <h:link/>, and the HTML tag <input type="button"/> in case of <h:button>. Even if you never use those URLs, they are ready to serve.  Well, before JSF 2.0, navigation rules were explicitly the domain of POST requests (NavigationHandler.handleNavigation()was doing the dirty job behind the scene), but the new support for GET-based navigation and bookmarkability takes navigation to another level of flexibility and transparency (for example, the ConfigurableNavigationHandler API).

The interesting part here is how the query string of a URL is assembled. The simplest case consists of the implicit query string parameter as shown in the following code:

<h:link value="Done" outcome="done?id=done"/>.

But, you can also use <f:param/>and/or <f:viewParam/>.

Another way consists in using the <view-param/> tag nested in a <redirect/> tag in a navigation case. For example, we can add query string parameters to a redirect URL in the navigation rules. Let's create the following button:

<h:commandButton value="Success" action="#{playerBean.playerDone()}"/>

Also, a silly method named playerDone is as follows:

private String player;

public String getPlayer() {
 return player;
}

public void setPlayer(String player) {
 this.player = player;
}

public String playerDone() {
 player = "Rafael Nadal";
 return "done";
}

Now, we can add the playerproperty value (of course, you can add any other value) as a parameter in the query string of the redirection navigation URL:

<navigation-rule>
 <from-view-id>/index.xhtml</from-view-id>
 <navigation-case>
  <from-action>#{playerBean.playerDone()}</from-action>
  <from-outcome>done</from-outcome>
  <to-view-id>/success.xhtml</to-view-id>
  <redirect>
   <view-param>
    <name>playerparam</name>
    <value>#{playerBean.player}</value>
   </view-param>
  </redirect>
 </navigation-case>
</navigation-rule>

A URL like this will be of the format (notice how the request parameter was attached based on the navigation rule) http://host:port/app-name/faces/success.xhtml?playerparam=Rafael+Nadal.

The playerparamvalue will be available through the param implicit object:

#{param['playerparam']}

The complete application is available here.

JSF Navigation Tutorial - Programmatic Navigation

$
0
0
JSF provides the NavigationHandlerand ConfigurableNavigationHandlerAPIs that can be used for tasks such as accessing navigation cases, customizing navigation handlers, conditional navigations, and so on. It is good to know that, programmatically speaking, we can do the following:

1. Obtain access to navigation handler (NavigationHandler) using the following code:

FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
NavigationHandler nh = application.getNavigationHandler();

2.Invoke navigation case using NavigationHandleras follows:

nh.handleNavigation(context, fromAction, outcome);
nh.handleNavigation(context, fromAction, outcome, toFlowDocumentId);

3.Access the ConfigurableNavigationHandlerAPI using the following code:

ConfigurableNavigationHandler cnh = (ConfigurableNavigationHandler) FacesContext.
getCurrentInstance().getApplication().getNavigationHandler();

4.Invoke navigation case using ConfigurableNavigationHandleras follows:

cnh.handleNavigation(context, fromAction, outcome);
cnh.handleNavigation(context, fromAction, outcome, toFlowDocumentId);

5.Retrieve one NavigationCase object by the action expression signature and outcome as shown in the following code:

NavigationCase case = cnh.getNavigationCase(context, fromAction, outcome);
NavigationCase case = cnh.getNavigationCase(context, fromAction, outcome, toFlowDocumentId);

6. Access all navigation rules into Map<String, Set<NavigationCase>>, where the keys are the <from-view-id/>values as follows:

Map<String, Set<NavigationCase>> cases = cnh.getNavigationCases();

Starting with JSF 2.2, we have wrappers for many classes that provide basic implementations and help developers to extend those classes and override only the necessary methods. Among them, we have a wrapper class for NavigationHandler, named NavigationHandlerWrapper, one for ConfigurableNavigationHandler, named ConfigurableNavigationHandlerWrapper, and one for NavigationCase, named NavigationCaseWrapper.

Caching via PrimeFaces and EHCache (register MBeans in JConsole via OmniFaces @Eager)

$
0
0
PrimeFaces supports cache at rendering time. Basically, at initial request, PrimeFaces will cache the HTML markup that corresponds to the content delimited by <p:cache/>tag. This means that the initial request doesn't take advantage of caching, and even more it will take longer than usually since at this moment PrimeFaces caches the corresponding markup. But, at postbacks the cache will serve the cached HTML instead of rendering it again via specific renderers. This will reduce the time for loading page at postbacks.

PrimeFaces supports two different providers of cache implementation; EHCache and Hazelcast. In this post, we will take a look on the EHCache provider.

Let's suppose that we have a static table that list the tennis players from ATP. Something like in figure below (this table is produced via a simple usage of the <p:dataTable/>tag):

Rendering a table (<p:dataTable/>) is a time-consuming task, especially if the table contains many rows. So, instead of re-rendering this static table, we better cache it. In order to accomplish that via PrimeFaces and EHCache, we need to follow these steps:

1. Configure the pom.xmlto contain the needed dependencies as below:

<dependencies>
 <dependency> 
  <groupId>org.primefaces</groupId> 
  <artifactId>primefaces</artifactId> 
  <version>5.3</version> 
 </dependency>
 <dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>3.0.0</version>
 </dependency>  
 <dependency>
  <groupId>net.sf.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>2.10.1</version>
 </dependency>
 ...
</dependencies>

2.Configure the cache provider in web.xml via the primefaces.CACHE_PROVIDER context parameter:

<context-param>
  <param-name>primefaces.CACHE_PROVIDER</param-name>
  <param-value>org.primefaces.cache.EHCacheProvider</param-value>
</context-param>

3. Configure EHCache. There are multiple ways to accomplish this, and one of these consist in providing the ehcache.xml file in /src/main/resources folder of your application. The content of this file calibrates cache as you want (more details are available here):

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
  monitoring="autodetect" dynamicConfig="true">

  <!-- By default, Ehcache stored the cached files in temp folder. -->
  <!-- <diskStore path="java.io.tmpdir" /> -->
      
  <!-- Ask Ehcache to store cache in this path -->
  <diskStore path="D:\\cache" />
       
  <!-- Sample cache named myCache
       This cache contains a maximum in memory of 10000 elements, and will expire
       an element if it is idle for more than 5 minutes and lives for more than
       10 minutes. If there are more than 10000 elements it will overflow to the
       disk cache -->   
  <cache name="myCache"
         statistics="true"
         maxEntriesLocalHeap="10000"
         maxEntriesLocalDisk="1000"
         eternal="false"
         diskSpoolBufferSizeMB="20"
         timeToIdleSeconds="300" timeToLiveSeconds="600"
         memoryStoreEvictionPolicy="LFU"
         transactionalMode="off">
          <persistence strategy="localTempSwap" />
 </cache>
</ehcache>

The path D:\\cachemust be manually created, or simply modify this entry to reflect a convenient path for you.

4. Use the <p:cache/>tag to point out the content that should be cached. As you can see in the official documentation this tag support a bunch of optional attributes. We are especially interested in the regionattribute which allows us to point to the cache region that we want to use, which is myCachein our case. Of course, this means that we can use <p:cache/> with different regions. Since, by default, the regiondefaults to view id (if you want to use it like this simply add a <defaultCache/>region), we need to explicitly set it as below:

<p:cache region="myCache">
 <p:dataTable var="t" value="#{playersBean.data}">
  <p:column headerText="Player">
   <h:panelGroup id="playerId">#{t.player}</h:panelGroup>
  </p:column>

  <p:column headerText="Age">
   <h:panelGroup id="ageId">#{t.age}</h:panelGroup>
  </p:column>

  <p:column headerText="Birthplace">
   <h:panelGroup id="birthplaceId">#{t.birthplace}</h:panelGroup>
  </p:column>

  <p:column headerText="Residence">
   <h:panelGroup id="residenceId">#{t.residence}</h:panelGroup>
  </p:column>

  <p:column headerText="Height">
   <h:panelGroup id="heightId">#{t.height} cm</h:panelGroup>
  </p:column>

  <p:column headerText="Weight">
   <h:panelGroup id="weightId">#{t.weight} kg</h:panelGroup>
  </p:column>
 </p:dataTable>
</p:cache>

Done! If you run the application at this point then everything should work as expected. You will notice that initial request take some time to load, while postbacks will work very fast. This is a sign that, at postbacks, the table markup comes from cache.

But, how can we be sure that this is working? Well, EHCache provides management and monitoring using JMX. A simple approach consist in registering the cache statistics in the JDK platform MBeanServer, which works with the JConsolemanagement agent. The needed code is listed below:

CacheManager manager = CacheManager.create();
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(manager, mBeanServer, true, true, true, true);

We can easily slip this code in an application scoped bean that is eagerly loaded via OmniFaces @Eager.

@Eager
@ApplicationScoped
public class CacheStatisticsBean {

 private static final Logger LOG = Logger.getLogger(CacheStatisticsBean.class.getName());
 private static final String CACHE_MANAGER = "net.sf.ehcache:type=CacheManager,name=__DEFAULT__";
 private static final String CACHE = "net.sf.ehcache:type=Cache,CacheManager=__DEFAULT__,name=myCache";
 private static final String CACHE_STATISTICS = "net.sf.ehcache:type=CacheStatistics,CacheManager=__DEFAULT__,name=myCache";
 private static final String CACHE_CONFIGURATION = "net.sf.ehcache:type=CacheConfiguration,CacheManager=__DEFAULT__,name=myCache";
 private static final ArrayList<ObjectName> objectNames = new ArrayList<ObjectName>() {
  {
  try {
      add(new ObjectName(CACHE_MANAGER));
      add(new ObjectName(CACHE));
      add(new ObjectName(CACHE_STATISTICS));
      add(new ObjectName(CACHE_CONFIGURATION));
  } catch (MalformedObjectNameException ex) {
                Logger.getLogger(CacheStatisticsBean.class.getName()).log(Level.SEVERE, null, ex);
  }
 }
 };

 @PostConstruct
 public void init() {
  try {
      LOG.info("------------ Configure JConsole MBeans ------------");
      MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
      LOG.info("----------------- Unregister MBeans ---------------");
      for (ObjectName name : objectNames) {
           if (mBeanServer.isRegistered(name)) {
               mBeanServer.unregisterMBean(name);
           }
      }

      LOG.info("------------------ Register MBeans ----------------");
      CacheManager manager = CacheManager.create();
      ManagementService.registerMBeans(manager, mBeanServer, true, true, true, true);

      LOG.info("------------ ------------------------  ------------");
  } catch (NullPointerException | InstanceNotFoundException | MBeanRegistrationException ex) {
    Logger.getLogger(CacheStatisticsBean.class.getName()).log(Level.SEVERE, null, ex);
  }
 }
}

Now we can perform a quick test to see if cache is working. For this, we have run the application on Payara 4. The steps of the test are:

1. Delete the content of D:\\cachefolder and ensure that Payara is not running.
2. Start the application server. For Payara 4 simply start it via asadmin start-domainform /binfolder.
3. Start JConsole. Simply navigate to your Java home and double-click on jconsole.exe in the /bin folder.
4. Connect to Payara domain as in figure below:
5. After the connection is successfully accomplished navigate to the MBeans tab. Notice there the entry named net.sf.ehcache. This entry was added via the CacheStatisticsBean from above and it is what we are looking for.

At this moment, there is nothing in the cache. For checking this, simply expose some attributes under CacheStatistics as DiskStoreObjectCount, MemoryStoreObjectCount, CacheHits, etc:
 6. Now, deploy and run the application. After the application starts, let's point out that at this moment we have 1 object stored in memory and on disk (check also the D:\\cachecontent) and nothing was read from cache yet:
7. Now, refresh the browser few times or open the application in multiple tabs or even other browsers. After that refresh the indicators from figure above and you should notice something like below (pay attention to a few more also):
Well, now it is obvious that our cache is working fine.

Programmatically, you can clean cache content like this:
RequestContext.getCurrentInstance().getApplicationContext().getCacheProvider().clear();

The complete application is named PFAndECache.

Caching with PrimeFaces and Hazelcast

$
0
0

PrimeFaces supports two different providers of cache implementation: EHCache and Hazelcast. In this post, we will take a look on the Hazelcast provider based on the same scenario described in the Caching via PrimeFaces and EHCache (register MBeans in JConsole via OmniFaces @Eager).

So, instead of re-rendering this static table, we better cache it. In order to accomplish that via PrimeFaces and Hazelcast, we need to follow these steps:

1.Configure the cache provider in web.xml via the primefaces.CACHE_PROVIDER context parameter:

<context-param>
  <param-name>primefaces.CACHE_PROVIDER</param-name>
  <param-value>org.primefaces.cache.HazelcastCacheProvider</param-value>
</context-param>

2. Use the <p:cache/>tag to point out the content that should be cached. As you can see in the official documentation this tag support a bunch of optional attributes. We are especially interested in the regionand key attributes. The region attribute allows us to point to the cache region that we want to use, which is myCache in our case. The key attribute represents an unique id of the cache entry in regionand defaults to client id of component. We set it as myTable. Of course, this means that we can use <p:cache/>with different regions and keys:

<p:cache region="myCache" key="myTable">
 <p:dataTable var="t" value="#{playersBean.data}">
  <p:column headerText="Player">
   <h:panelGroup id="playerId">#{t.player}</h:panelGroup>
  </p:column>

  <p:column headerText="Age">
   <h:panelGroup id="ageId">#{t.age}</h:panelGroup>
  </p:column>

  <p:column headerText="Birthplace">
   <h:panelGroup id="birthplaceId">#{t.birthplace}</h:panelGroup>
  </p:column>

  <p:column headerText="Residence">
   <h:panelGroup id="residenceId">#{t.residence}</h:panelGroup>
  </p:column>

  <p:column headerText="Height">
   <h:panelGroup id="heightId">#{t.height} cm</h:panelGroup>
  </p:column>

  <p:column headerText="Weight">
   <h:panelGroup id="weightId">#{t.weight} kg</h:panelGroup>
  </p:column>
 </p:dataTable>
</p:cache>

Done! If you run the application at this point then everything should work as expected. You will notice that initial request take some time to load, while postbacks will work very fast. This is a sign that, at postbacks, the table markup comes from cache. Moreover, you can see that Hazelcast is at work:
But, let's add some code to check the cache content. First, let's display the cache content in page:

Cache content:
<hr/>       
 <p>
  <code>
   #{playersBean.showCache()}
  </code>
 </p>
<hr/>

public Object showCache() {
 HazelcastCacheProvider cacheProvider = (HazelcastCacheProvider)
  RequestContext.getCurrentInstance().getApplicationContext().getCacheProvider();
 return cacheProvider.get("myCache", "myTable");
}

We also may want to programmatically remove our entry from cache. For this we can simply use an action method as below:

public void clearCache() {
 HazelcastCacheProvider cacheProvider = (HazelcastCacheProvider)
  RequestContext.getCurrentInstance().getApplicationContext().getCacheProvider();
 cacheProvider.remove("myCache", "myTable");
}

At initial request there is nothing in the cache:
At postback (click the Refreshbutton) the cache content shows the HTML markup corresponding to our data table:
Further, if you click the Clear Cache button, the cache entry will be removed.

The complete application is available here.

Stateless JSF application via PrimeFaces, OmniFaces, Hazelcast and Payara Server

$
0
0
This is a simple post about writing a stateless JSF application for holding a dummy shopping cart using Hazelcast. The application uses PrimeFaces, OmniFaces and it is deployed on Payara Server 4.1.1.162, which provide a very nice support for Hazelcast.

Notice that this application is far away for being a good example to follow in production, being more a proof of concept meant to show an example of how we can develop JSF stateless (easy to scale out) application and keep user data intact over multiple requests.

For those who don't know, JSF is by default stateful. This refers to the fact that JSF works as expected only in presence of a view state (component tree) which is restored at each postback request. Starting with version 2.2, JSF provides support for stateless mode. This means that there is no view state saved and we have to use only request scoped beans. The advantage of this approach consist in the fact that we can easily scale out the application without taking care of aspects as sessions replication or sticky sessions.

Some dependencies:

<dependencies>
 <dependency>
  <groupId>org.omnifaces</groupId>
  <artifactId>omnifaces</artifactId>
  <version>2.3</version>
 </dependency>
 <dependency> 
  <groupId>org.primefaces</groupId> 
  <artifactId>primefaces</artifactId> 
  <version>5.3</version> 
 </dependency>
 <dependency>
  <groupId>com.hazelcast</groupId>
  <artifactId>hazelcast</artifactId>
  <version>3.6.2</version>
 </dependency>
 <dependency>
  <groupId>javax</groupId>
  <artifactId>javaee-web-api</artifactId>
  <version>7.0</version>
  <scope>provided</scope>
 </dependency>
</dependencies>

Ok, let's see the steps for developing this proof of concept:

1. First, we need to activate stateless mode for JSF like below:

<f:view transient="true">  
 ...
</f:view>

2. Therefore, the index.xhtmlpage that displays the shopping cart is pretty simple and you can easily understand it by following the code line by line:

<f:view transient="true">           
 <h:form id="cartId">
  <p:dataList value="#{shoppingCart.viewCart()}" var="t" type="ordered">
   <f:facet name="header">
    Your Shopping Cart
   </f:facet>
   #{t.name}, #{t.price}
   <p:commandButton value="Remove" action="#{shoppingCart.removeItemFromCart(t)}" update="@form"/>
  </p:dataList>                       
  <p:commandButton value="Add random item" action="#{shoppingCart.addItemToCart()}" update="@form" />
 </h:form>
</f:view>

3. The shopping cart content is stored in a Hazelcast IList, therefore we need to activate Hazelcast. Commonly this is accomplished via something like below:

Config cfg = new Config();
HazelcastInstance instance = Hazelcast.newHazelcastInstance(cfg);

But, in this case we don't need to do that because Payara already provide Hazelcast support, and all we need to do is to activate it. For example, we have created a cluster named TestCluster with two instances, test1 and test2. As you can see in figure below, all we have to do for having a Hazelcast instance is to enable Hazelcast for our cluster and click Save (by default Payara Server admin console is available at localhost:4848):


As a note not related to this app (we don't need sessions), is good to know that Payara also provide session persistence via Hazelcast. Check the below screen-shot:


4. Now, we have a Hazelcast instance available for our cluster. Payara expose the Hazelcast instance via JNDI under the name payara/Hazelcast:


This means that we can easy obtain the Hazelcast instance in the application via @Resource as below:

@Resource(name = "payara/Hazelcast")
HazelcastInstance hazelcast;

5. In order to configure Hazelcast data structures we can use an XML file. Payara recognize the hazelcast-config.xml (it doesn't exist by default):


But, Hazelcast also supports programmatic configuration. For example, let's suppose that each time we add a new instance in cluster, we want to add a dummy item in the shopping cart (I know, this is a pretty useless use case, but that not important here). This item is added only once or under certain circumnstances, so ideally we will run that code only once or only under certain conditions. There are many ways to accomplish this and different moments in application flow where to do it, but let's do this via a request scoped managed bean instantiated eagerly. For this we can assign a requestURI to a managed bean annotated with the OmniFaces @Eager. The following bean will be instantiated whenever the URI /faces/start.xhtml (relatively to the application root) is requested:

@Eager(requestURI = "/faces/start.xhtml")
@RequestScoped
public class HazelcastInit {

 @Resource(name = "payara/Hazelcast")
 HazelcastInstance hazelcast;

 private static final Logger LOG = Logger.getLogger(HazelcastInit.class.getName());

 @PostConstruct
 public void init() {
  LOG.info("Initialize list of products started ...");

  // since this is a default config we can skip the following 4 lines
  Config config = new XmlConfigBuilder().build();
  ListConfig listConfig = config.getListConfig("cart");
  listConfig.setName("cart");
  hazelcast.getConfig().addListConfig(listConfig);
       
  IList<Item> cartList = hazelcast.getList("cart");
  cartList.add(new Item("Dummy Product", 0));
     
  LOG.info("Initialize list of products successfully done ...");
 }
}

In our case, we have set the start.xhtml as the start page of the application, so the above code is executed at least once (and each time to navigate to the specified URI):

<f:view transient="true">           
 Hazelcast was successfully initialized ...
 <p:link outcome="index">Go to app ...</p:link>
</f:view>

Note that when Hazelcast "meets" a data structure (e.g. IList, IMap, etc) usage, it is smart enough to create that data structure when it doesn't exist and to not re-create it when exists, so if you don't need some specific tasks or configuration then is no need to define that data structure in XML or programmatic. At first use, Hazelcast will create it for you with the default configurations.

6. Finally, we write the ShoppingCartrequest managed bean a below:

@Named
@RequestScoped
public class ShoppingCart implements Serializable {

 @Resource(name = "payara/Hazelcast")
 HazelcastInstance hazelcast;

 private static final Logger LOG = Logger.getLogger(ShoppingCart.class.getName());

 // the available items
 private static final List<Item> AVAILABLE_PRODUCTS = new ArrayList<Item>() {
  {
  add(new Item("product_1", 23));
  add(new Item("product_2", 53));
  add(new Item("product_3", 13));
  add(new Item("product_4", 58));
  add(new Item("product_5", 21));
  }
 };

 public void addItemToCart() {
  LOG.info("Adding a product to shopping cart ...");
  IList<Item> cartList = hazelcast.getList("cart");
  cartList.add(AVAILABLE_PRODUCTS.get(new Random().nextInt(5)));
  LOG.info("Product successfully added ...");
  viewCart();
 }

 public void removeItemFromCart(Item item) {
  LOG.info("Removing a product to shopping cart ...");
  IList<Item> cartList = hazelcast.getList("cart");
  cartList.remove(item);       
  LOG.info("Product successfully remove ...");
  viewCart();
 }

 public List<Item> viewCart() {
  List<Item> cart = new ArrayList<>();
  LOG.info("View cart ...");
     
  IList<Item> cartList = hazelcast.getList("cart");
  for (int i = 0; i < cartList.size(); i++) {
       cart.add(cartList.get(i));
  }
  return cart;
 }
}

7. Let's test the app. Ensure that you have the WAR of the application and follow these steps:
   
7.1 Start the TestCluster:

           
  7.2 Ensure that the cluster was successfully started and that Hazelcast contains the members:

           
  7.3 Deploy the WAR application in cluster:

         
    7.4 Launch the application

             
 7.5 Click the link for test1 (notice the log below):

           
  7.6 Click the Go to app link (notice the dummy item added at initialization):

     
        7.7 Add few more random items by clicking the button labeled Add random item:

       
      7.8 Start test2 (notice the log below):

           
  7.9 Click the Go to app link (notice the dummy item added at initialization and the rest of items added eariler):


Done! You try further to play by removing and adding items and notice how the shopping cart is maintained by Hazelcast in a JSF stateless application. Of course, if you want to take into account the login part, you can easily go for JWT authentication mechanism.

Notice that we have accomplished many of our tasks (e.g. cluster creation, deploy app, etc) via the visual admin console of Payara. But, you can also accomplish all these steps from CLI. Payara comes with a very handy tool named Asadmin Recorder which is capable to record the actions from visual console and output it in a text file as commands:


Well, I have used this feature and here it is the commands:

copy-config default-config TestCluster-config
create-cluster --config=TestCluster-config TestCluster
create-instance --cluster=TestCluster --node=localhost-domain1 test2
create-instance --cluster=TestCluster --node=localhost-domain1 test1
set-hazelcast-configuration --startPort=5900 --hazelcastConfigurationFile=hazelcast-config.xml --clusterName=development --clusterPassword=D3v3l0pm3nt --dynamic=true --multicastPort=54327 --enabled=true --multicastGroup=224.2.2.3 --jndiName=payara/Hazelcast --target=TestCluster
start-cluster TestCluster
deploy --keepState=false --precompilejsp=false --availabilityEnabled=false --name=JSFStatelessSC-1.0 --verify=false --force=false --contextroot=JSFStatelessSC-1.0 --enabled=true --properties=implicitCdiEnabled=true:preserveAppScopedResources=false --target=TestCluster C:\Users\Leonard\AppData\Local\Temp\JSFStatelessSC-13447695818088979490.0.war

The complete application is available here.

CDI - JSF: Bean constructor annotated with @Inject example

$
0
0
Generally speaking, any Java class that has a constructor without parameters or a constructor annotated with @Inject is a bean. This means that we can write a bean like this:

@Named
@RequestScoped
public class TheBean {

 private Foo foo;
 private Buzz buzz;
 private Bizz bizz;

 @Inject
 public TheBean(Foo foo, Buzz buzz, Bizz bizz) {
  this.foo = foo;
  this.buzz = buzz;
  this.bizz = bizz;
 }

 public void callFooBuzzBizz() {
  // do something with foo, buzz and bizz
 }
}

A complete example is available here.

CDI-JSF: Use @Inject to annotate a common method of a bean

$
0
0
As you probably know, when a bean is instantiated the first called method is the corresponding constructor. Afterwards, we have the method annotated with @PostConstruct. When this method is called we say that the dependency injections is done and we can exploit the injected artifacts. By annotating a common method with @Inject, we basically instruct CDI to call this method also when the bean in instantiated. For example, the below initFooBuzzBizz() is called after the constructor, but before the @PostConstruct:

@Named
@RequestScoped
public class TheBean {

 private static final Logger LOG = Logger.getLogger(TheBean.class.getName());

 public TheBean() {
  LOG.info("TheBean#constructor called ...");
  Messages.addGlobalInfo("TheBean#constructor called ...");
 }

 @PostConstruct
 public void init() {
  LOG.info("TheBean#init() called ...");
  Messages.addGlobalInfo("TheBean#init() called ...");
 }

 public void callFooBuzzBizzAction() {
  LOG.info("TheBean#callFooBuzzBizz() called ...");
  Messages.addGlobalInfo("TheBean#callFooBuzzBizz() called ...");
 }

 @Inject
 private void initFooBuzzBizz(Foo foo, Buzz buzz, Bizz bizz) {
  LOG.info("TheBean#initFooBuzzBizz() called ...");
  Messages.addGlobalInfo("TheBean#initFooBuzzBizz() called ...");

  foo.fooify();
  buzz.buzzify();
  bizz.bizzify();
 }
}

The output will be:
  • TheBean#constructor called ...
  • TheBean#initFooBuzzBizz() called ...
  • Foo#fooify() called ...
  • Buzz#buzzify() called ...
  • Bizz#bizzify() called ...
  • TheBean#init() called ...
  • TheBean#callFooBuzzBizz() called ...
The complete example is available here,
Viewing all 74 articles
Browse latest View live