Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Simple Caching Library

DZone's Guide to

Simple Caching Library

Here's a simple caching library, which is a powerful but easy to use LRUCachingMap implementation. Here's a look at the various performance-enhancing features, like in-memory caching, file reference caching, and xml file caching.

· Performance Zone
Free Resource

Evolve your approach to Application Performance Monitoring by adopting five best practices that are outlined and explored in this e-book, brought to you in partnership with BMC.

I have created an easy to use a caching library.

This is a powerful yet simple LRUCachingMap implementation. 

Short definition: Caches key/values for a certain amount of time, whenever a key is "get" the expiration time can be extended.

http://jhcaching.sourceforge.net/

It is all POJO classes, so NO external setup of configuration files, facets, metadata properties etc.

It makes heavy use of generics and is therefore highly extendable.
It supports persistences of your cache.
It can come with the 1 default implementation and 6 versatile versions of that

  • Caching in memory.
  • Caching file references.
  • Caching as xml files - with 3 variations.
  • Caching as serialized files - with 3 variations.
  • Caching in a JPA table.
  • Caching in a grouped JPA table. Where many caching instances share the same table.

Here are three examples

Memory

DefaultLRUCachingMap<Long,String> cache = 
  LRUCachingMapFactory.createMemoryCache(DefaultLRUCachingMapConfiguration.ONE_DAY());

You will have a "memory" cache where:

  • The key is of type "Long".
  • The value is of type "String".
  • The keys are stored for one day (24 hours).
  • Every time a "key" is "get" the expiration datetime for the key is extended by 1 hour.
  • A key can maximum be extended 5 times.
  • There can maximum be 10000 keys in the cache.
  • A cleanup thread runs every 15 minutes.

 File

CachingDirectory cachingDirectory = 
  new CachingDirectory(Files.createTempDirectory("storage").toFile());
LRUCachingMapConfiguration configuration = 
  DefaultLRUCachingMapConfiguration.ONE_DAY();

DefaultFileLRUCachingMap<String,Book> cache = 
  LRUCachingMapFactory.createFilenameSerializedCache(configuration, cachingDirectory,PersistencesRestoreMethod.NOTHING);

You will have a file persisted cache

  • The key is of type "Long".
  • The value is of type "Book".
  • The keys are stored for one day (24 hours).
  • Every time a "key" is "get" the expiration datetime for the key is extended by 1 hour.
  • A key can maximum be extended 5 times.
  • There can maximum be 10000 keys in the cache.
  • A cleanup thread runs every 15 minutes.

JPA

DefaultCachedJPALRUCachingMap<String,Book> cache = 
     LRUCachingMapFactory.createJPACache(
        DefaultLRUCachingMapConfiguration.ONE_DAY(),
        MyCachedBookJPAEntity.class,
        entityManagerFactory,
        PersistencesRestoreMethod.LOAD_ALL);

You will have JPA persisted cache.

  • The key is of type "Long".
  • The value is of type "Book".
  • The keys are stored for one day (24 hours).
  • Everytime a "key" is "get" the expiration datetime for the key is extended by 1 hour.
  • A key can maximum be extended 5 times.
  • There can maximum be 10000 keys in the cache.
  • A cleanup thread runs every 15 minutes.

You will need to create an entity

@Entity(name="MyCachedBookTable")
@Access(AccessType.FIELD)
public class MyCachedBookJPAEntity implements CachedJPAEntity<String,Book> {

@Id
@Column(name="bookkey",length=1000,nullable=false,updatable=false)
private String key;

@Column(name="bookstoretime",nullable=false,updatable=false)
private Date storeDateTime;

@Column(name="bookexpiretime",nullable=false,updatable=true)
private Date expireDateTime;

@Lob 
@Column(name="bookvalue",nullable=false,updatable=true,length=10000)
private Book value;

    //getters and setters
}

Interface

The interface is defined as this, and it has a default implementation.

public interface LRUCachingMap<K,V> {
  public Logger getLogger();
  public int removeAll();
  public int cleanup();
  public boolean exists(K key) throws NullPointerException;
  public void extend(K key) throws NullPointerException;
  public void extend(K key,long extendTime) throws NullPointerException;
  public boolean isExpired(K key) throws NullPointerException;
  public V get(K key) throws NullPointerException;
  public V get(K... keys) throws NullPointerException;
  public LRUCachingMapConfiguration getConfiguration();
  public Date getExpirationDateTime(K key) throws NullPointerException;
  public TimeSpan getExpirationTimeSpan();
  public Iterator<K> getKeys();
  public K getNextToExpire();
  public Date getStoreDateTime(K key) throws NullPointerException;
  public ValueManager<K,V> getValueManager();
  public V put(K key,V value) throws NullPointerException;
  public V remove(K key) throws NullPointerException;
  public void restoreCacheElement(K key, AbstractValueWrapper<K,V> valueWrapper,Date expireDateTime);
  public int reload();
  public int size();
  public boolean isPersisted();
  public Date getLastCleanupDateTime();
}

Configuration

In the "LRUCachingMapConfiguration" you can set the following values

Name Description

ExpireTime

The number of milliseconds which the key lives in the cache. Has to be greater than zero.

ExtendTime

The number of milliseconds which the key expireTime is extended which each "get" of the "key". If less than one, then no extend of expiration time and it will behave like a "normal" cache with fix time.

MaxExtendCount

The maximum number of times a "key" expireTime" can be extended. If less than one than "no limit" to the extended count.

MaxSize

The maximum number of keys in the cache. Has to greather than zero.

CleanupIntervalTime

The number of milliseconds between the cache is cleanup up, if greater than zero the Internal thread is used (CleanupTimerRunnable),otherwise you must handle the cleanup yourself.

PersistedValuesInMemory

This configuration will only work for LRUCachingMaps which persists its values.

It tells if the values should be is stored in memory as well as getting persisted, this is a fast way to get the Value(V) instead of having to load it from persisted storage.

If  "false," then none will be stored in memory.

This will increase the speed you are getting the values from persisted implementations, but it will increase the memory footprint.

So when the LRUCachingMap gets a Value(V) by the Key(K) it will first ask if the value is in memory otherwise retrieve it from persisted storage and put it in memory. 

This is relevant if it's after a restore.

Usage

Personally, I use it for

  • Caching cookies key to a user instance, which defines how long I want to remember users, without the need for the user to reenter their logins credentials.
  • Caching blocked users and IP addresses, to "many bad logins attempts"
  • Geo data to use in a google map display
  • List of possible users, which is updated on a regular basis.
  • Selected queries results which execution time took a bit to long.
DefaultCachedJPALRUCachingMap<String,Book> cache = 
     LRUCachingMapFactory.createJPACache(
           DefaultLRUCachingMapConfiguration.ONE_DAY(),
           MyCachedJPAEntity.class,
           entityManagerFactory,
           PersistencesRestoreMethod.DELETE_ALL);

The library is fully documented and comes with a lot of examples.
The source is free under LGPL 3.0
You can find the library here - http://jhcaching.sourceforge.net/

I hope you will find this useful, a give me some feedback.

Learn tips and best practices for optimizing your capacity management strategy with the Market Guide for Capacity Management, brought to you in partnership with BMC.

Topics:
java ,caching ,pojo ,library ,persistence ,extendable

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}