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

Se afișează postările cu eticheta PrimeFaces. Afișați toate postările
Se afișează postările cu eticheta PrimeFaces. Afișați toate postările

duminică, 12 iunie 2016

PrimeFaces dynamic TabView and Hibernate lazy loading

The PrimeFaces TabView component supports a flag attribute named dynamic (defaults to false). When this attribute is set to true, PrimeFaces will load only the content of the initial opened tab, while the rest of content is loaded via AJAX only when the user clicks on tabs.

So, let's image that we have the following simple database with two tables:


Now, for each category, we want to create a tab, and each tab to be loaded dynamically. We can write something like below:

<h:form id="form">
 <p:tabView dynamic="true" cache="true">          
  <p:tab title="My Site">               
   Check out our categories
  </p:tab>
  <c:forEach items="#{dataBean.allCategories}" var="t">           
   <p:tab title="#{t.name}">
    <p:dataList value="#{t.productsCollection}" var="q" type="ordered">
     <f:facet name="header">
      Products
     </f:facet>
     #{q.product} 
    </p:dataList>
   </p:tab>          
  </c:forEach>
 </p:tabView>
</h:form>

Ok, so the first tab is just a dummy tab that doesn't contain data from the database. While the rest of tabs reflect the names and number of available categories. Notice that we have set dynamic="true", and moreover we have set cache="true". This means that caching only retrieves the tab contents
once and subsequent toggles of a cached tab does not communicate with server.

Now, let's take a quick look to our code used for querying database. We  can use Hibernate JPA, and the relevant part is:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "categories", fetch = FetchType.EAGER)
private Set<Products> productsCollection;

Notice that Hibernate is by default lazy, so we manually turned fetching to eager.

Now, if we run the application we see the following output:


Notice that our tab is not even containing data from database. Is just a dummy tab with some intros. But, since the rest of tab's names are actually our categories names, the application must hit the database. If we check the log we notice that even if load only the names of the categories, Hibernate will load the products from each category also. Obviously, this is the effect of eager loading.

Moreover, when we click on a tab of a category, this is happening again until all tabs are cached. Now, we may want to switch to the default Hibernate fetching style, which is LAZY (simply delete the fetch element, or manually set it):

@OneToMany(cascade = CascadeType.ALL, mappedBy = "categories", fetch = FetchType.LAZY)
private Set<Products> productsCollection;

When the application starts, everything looks fine. We query only the categories names. But, when we click on other tab, we get an error of type: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: javaee.entites.Categories.productsCollection. Well, this is a well-known Hibernate exception caused by the fact that Hibernate cannot hit the database to initialize the proxy objects since the connection is already closed.

There are a few approaches to solve this issue, like:

Use  PersistenceContextType.EXTENDED with @Stateful EJB - This works only in JEE and the container will manage the database transactions. But, you have to pay attention to the number of stateful beans because they may cause memory issues.  The N+1 issue is also a risk.

Load collection by join  - for example, in our case we can go for a left join fetch of type: SELECT c FROM Categories c LEFT JOIN FETCH c.productsCollection. But, this needs a new query to access each model class collection (lazy) attribute. Against this disadvantage, we have some advantages like the fact that we fire a single query in the database and will bring only the desired data. Moreover, the N+1 issue is not a risk.

Use the @NamedEntityGraph - provides a query independent way to define a graph of entities which will be fetched with the query.

EclipseLink - This is an alternative to Hibernate JPA that works via a LAZY strategy (hint) that can be set for the persistent provider. This way the persistent provider will know that you expect those data lazy.  Moreover, the N+1 issue is not a risk.

Load collection by Open Session in View - This is basically a solution that relies on keeping a database connection opened until the end of the user request. The implementation is based on a filter that handles the transactions. The N+1 is also a risk, and there are no really advantages of this approach.

We can chose here the first approach. So, we wrote a Stateful bean as below:

@Stateful
public class CategoriesAndProducts {

 @PersistenceContext(unitName = "javaee_PrimeFacesHibernateLazy_war_1.0PU", type=PersistenceContextType.EXTENDED)
 private EntityManager em;

 public List<Categories> getCategoriesAction() {
  TypedQuery<Categories> query = em.createNamedQuery("Categories.findAll", Categories.class);
  List<Categories> results = query.getResultList();

  return results;
 }
}

Now, when we click on a tab, Hibernate will query only the products from the selected category. You can try yourself an implementation via left join also.


The complete example is available here. You can easily run it with MySQL 5 and WildFly 10.

duminică, 15 mai 2016

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

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.xhtml page 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 ShoppingCart request 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.

sâmbătă, 23 aprilie 2016

Caching with PrimeFaces and Hazelcast


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 region and 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 region and 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 Refresh button) 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.

vineri, 22 aprilie 2016

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

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.xml to 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:\\cache must 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 region attribute which allows us to point to the cache region that we want to use, which is myCache in our case. Of course, this means that we can use <p:cache/> with different regions. Since, by default, the region defaults 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 JConsole management 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:\\cache folder and ensure that Payara is not running.
2. Start the application server. For Payara 4 simply start it via asadmin start-domain form /bin folder.
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:\\cache content) 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.

JSF BOOKS COLLECTION

Postări populare

Visitors Starting 4 September 2015

Locations of Site Visitors