|
![]() ![]() ![]() |
Search on blog
Petition by Java EE Guardians
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ă, 21 august 2016
luni, 18 iulie 2016
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.
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
// 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
Recommended to read before: Caching
via PrimeFaces and EHCache (register MBeans in JConsole via OmniFaces @Eager)
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:
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.
Abonați-vă la:
Postări
(
Atom
)
|
[JSF Page Author Beginner's Guide] |
Postări populare
-
If you like this article, I think you are going to like JSF 2.3 Tutorial as well.
-
Starting with JSF 2.3 the JSF "native" managed bean annotations are officially deprecated. So, there is no doubt now that CDI is ...
-
[OmniFaces utilities] The getRequestURL() method returns the HTTP request URL with query string, regardless of any forward. This is the f...
-
[OmniFaces utilities] The getCurrentActionSource() method returns the source of the currently invoked action, or null if there is none, ...
-
Starting with JSF 2.3, more exactly with m07 , we can take advantage of using the auto detection of convertors based on 1st UISelectMany it...
-
Before you read this post please read: Use a CDI alternative as a mock implementation for a stateless session bean So, since you are fa...
-
[OmniFaces utilities] The getActionExpressionsAndListeners() method returns a list of all action expressions and listeners associated wit...
-
[OmniFaces utilities] The isSerializable() method returns true if the given object is serializable. Method: Usage: Example 1 - te...
-
[OmniFaces utilities] The reverseArray() function returns a copy of the array with items in reversed order. Function: Usage: Let...
-
Let's checkout a common practice for declaring constants in Java using the public static final declaration: public class Circle { ...
JSF/OmniFaces Resources |