Guava Cache basic demo

25 07 2015

Here I go with the caching! Caching (and cache invalidation) is second one of the most difficult thing to do while programming (the first one is the naming things problem :P ). I’ll show the demo with Guava Cache (18.0). Source Code for this tutorial is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo

Caches Explained

You may want to get familiar with this article to get the idea of how cache works: https://code.google.com/p/guava-libraries/wiki/CachesExplained.

The Demo Introduction

Here I explain the basic app that accesses data via DAO. Let’s assume that data access is costly so the cache is needed. I want cache entries to expire after specified amount of time. Pretty simple.

Build Cache

Guava provides the cache builder. In my case I make use of it is as follows:

cache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.SECONDS)
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                return dataDao.getValueForKey(key);
            }
        });

I do two things here:

  1. set the desired expiration algorithm and time – entry will become invalid in 5 seconds after it was created or updated
  2. provide the method to load entry – Guava Cache will call this method when you will try to retrieve the value from the cache for the first time (when entry was not found in it yet) or if requested entry has expired. Here that method makes call to my DAO.

Expiration

Among few types of eviction (Size-based, timed, Reference-based) I use Timed eviction, There are two algorythms of expiration in that case. From guava doc:

  • expireAfterAccess(long, TimeUnit) Only expire entries after the specified duration has passed since the entry was last accessed by a read or a write.
  • expireAfterWrite(long, TimeUnit) Expire entries after the specified duration has passed since the entry was created, or the most recent replacement of the value. This could be desirable if cached data grows stale after a certain amount of time.

expireAfterAccess works different. In opposed to expireAfterWrite, it expires entry if it was not accessed in cache in specified time. So if you constatly read that value within its expiration time, it will not get refreshed. expireAfterWrite expires entries based on its age in cache. So it will be refreshed if validity period passed, no matter how freqently you access it (it is done in lazy way, so if time passed, the value will be refreshed only when requested from cache).

Expiration details

In this StackOverflow answer the details are explained by Guava team member:

The Guava Cache implementation expires entries in the course of normal maintenance operations, which occur on a per-segment basis during cache write operations and occasionally during cache read operations. Entries usually aren’t expired at exactly their expiration time, just because Cache makes the deliberate decision not to create its own maintenance thread, but rather to let the user decide whether continuous maintenance is required.

I’m going to focus on expireAfterAccess, but the procedure for expireAfterWrite is almost identical. In terms of the mechanics, when you specify expireAfterAccess in the CacheBuilder, then each segment of the cache maintains a linked list access queue for entries in order from least-recent-access to most-recent-access. The cache entries are actually themselves nodes in the linked list, so when an entry is accessed, it removes itself from its old position in the access queue, and moves itself to the end of the queue.

When cache maintenance is performed, all the cache has to do is to expire every entry at the front of the queue until it finds an unexpired entry. This is straightforward and requires relatively little overhead, and it occurs in the course of normal cache maintenance. (Additionally, the cache deliberately limits the amount of work done in a single cleanup, minimizing the expense to any single cache operation.) Typically, the cost of cache maintenance is dominated by the expense of computing the actual entries in the cache.

The demo and the test

Test mechanism is simple. I set the cache entry expiration time to 5 seconds, and set up a loop to retrieve value from cache each second.

for (int i = 0; i < 20; i++) {
    cacheDemo.getValue("Blue");
    Thread.sleep(1000);
}

I have also added the log line in DAO on each data retrieval and a log line on cache value request. One in five log lines is a log by DAO data retrieval method. The cache value is a string with a timestamp. Notice that it gets updated each time the data is retrieved. This is how console output look like (bold lines are logged by DAO on data request):

Hello, Cache!
returning value from dao: value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
returning value from dao: value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
returning value from dao: value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
...

Get the source code

Source code for this demo is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo

Advertisements




“5 reasons to use Guava”

6 12 2014

Easier use of java collections, functional programming, method arguments validations, caches, rate limiters and more – this is why Google’s Guava library may be useful for you.

Read concise description of five sample features in Guava that you may find helpful:

http://www.javacodegeeks.com/2013/06/5-reasons-to-use-guava.html





HTML 5 Offline Web Application with Spring Boot

30 11 2014

Think of users using your web application from mobile phones when their internet connection breaks down. Native mobile app would still work and cache all user actions, synchronizing them afterwards. HTML5 web apps can also work offline.

Basically it is done by listing the resource files (html, js, images) that browser should cache immadietly and use the cached version when user redirects to it. If internet connection is working, the browser will return the online server version, else, if user is offline the cached version will be used.

Resources to cache can be defined in html headers or in .manifest file. These two locations are interpreted by all modern browsers.

1. Download the code base

This tutorial is based on the source code from SpringBoot MVC Hello World tutorial. All instructions are performed on this code.

2. Create offline.manifest file

In this file you can select the files and resources that will be cached by the browser and used if user requests to connect with server while being disconnected from the Internet. I will create new html file: offline.html and redirect to it if user is offline. My offline.manifest looks as follows:

CACHE MANIFEST
#v1

CACHE:
offline.html

NETWORK:
*

FALLBACK:
/ /offline.html

And is located under the /src/main/resources/static/offline.manifest.

3. Manifest file explained

The manifest file must begin with CACHE MANIFEST. The CACHE: section lists the files that we need for offline use. The NETWORK: section lists any resources that should not be cached. The FALLBACK: section uses the / character to define a URL pattern. It basically asks “is this page in the cache?” If it finds the page there, it displays it. If not, it shows the user the file specified – offline.html.

4. Create the offline.html page

This page will be displayed when user requests any page while being offline. This is static page – not the Spring template, so i simply put it in the /src/main/resources/static folder, next to the offfline.manifest file. The offline.html page content is basic one:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:th="http://www.thymeleaf.org" >
    <head>
        <title>Offline Web Application</title>
    </head>
    <body>
        <h1>You are offline</h1>
    </body>
</html>

5. Request to cache resources

To make use of offline.manifest file I point it in my hello.html and greeting.html page head:

<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:th="http://www.thymeleaf.org" 
  manifest="offline.manifest">

This way the browser will download the manifest and cache specified resources. Moreover it will add the hello.html and greeting.html to the cache as well

6. Test it

Run spring boot app, and open the url in the browser. When you are on hello page, the browser will cache files for offline use. In Chrome console this is indicated as:

hello:1 Creating Application Cache with manifest http://localhost:8080/offline.manifest
hello:1 Application Cache Checking event
hello:1 Application Cache Downloading event
hello:1 Application Cache Progress event (0 of 1) http://localhost:8080/offline.html
hello:1 Application Cache Progress event (1 of 1) 
hello:1 Application Cache Cached event

Now stop the Spring Boot app and click the url on th page. Since the server is offline, you will be redirected to cached offline.html page (or the greeting.html if it was previously cached). If you try tu go to any other url, for example: http://localhost:8080/someInvalidUrl – then the offline html page will be displayed.

Note: best to be tested in private / incognito browser mode to prevent unwanted cache.

Get the source Code

Full source code for this tutorial you can get at my GitHub under the SpringBootOfflineWebApp tag: https://github.com/yacekmm/looksok/tree/SpringBootOfflineWebApp.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Refresh JSF page programmatically from JavaBean

4 08 2012

When business logic in JavaBean decides that forced jsf page refresh is needed, it can be done from logic’s level. Add this code to your logic (prefereably put it in some refresh() method):

FacesContext context = FacesContext.getCurrentInstance();
String viewId = context.getViewRoot().getViewId();
ViewHandler handler = context.getApplication().getViewHandler();
UIViewRoot root = handler.createView(context, viewId);
root.setViewId(viewId);
context.setViewRoot(root);

Browsers may have cache enabled, so some cached elements may not be refreshed. If this is your case, you should also add header to Http response, that will force browser not to use cache:

response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);

Cached elements were not my problem, so the second snippet is not tested by me. For more info, please see following sources: OTN Discussion Forum, Refresh current JSF page and caching on StackOverflow.

Note: page refresh done that way means sending Http Response – one Http Request can have only one Http Response. You can’t use this code if you have already sent your response earlier for this particular Http Request.

For example – while performing file download. The file download data is sent in Http Response, so unfortunately there is no way to refresh page programmaticaly. Probably Ajax refresh could help you, if just some of the components should be rerendered. This problem is described in threads: StackOverflow thread 1Coderanch question, another Coderanch problem, refresh after response is commited, and the last one Coderanch – so.. just impossible…

 

.. so maybe better to use this JavaScript delayed reload – give it a try!

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: