Usage Documentation

This page is the usage documentation for FKache. If you want more usage examples, send me a mail request , and I'll get it added.

Group support/CacheAccess will be removed

I have started simplifying the interfaces of FKache. As a result, some of the features you are useing may be removed.

If you are using the group feature or the region feature of FKache, You must start thinking about changes to your code. In version beta 6 the group feature will be removed, with no planned replacement.

Some region features will be removed in beta 6. Details is in the javadocs.

Also starting with beta 5, features in CacheAccess will have equivalents in the MapAccess interface, and from beta 6 the CacheAccess class with most of the exceptions will be removed. If you are using the CacheAccess class instead of the Map Access, you can use the beta 5 for migrating over to the Map access.

Basic use

All access to the cache goes through the class javax.util.jcache.CacheAccess. IThere has also been added an alternative way to access the cache, you can use a regular Map interface, which is the recommended way to use FKache. most of the functionality is present in the Map interface. If you use the Map interface,you can use it as an replacement for custom Map-based caches, with the added features of FKache, such as disk-caching, distribution, cacheloaders, time/size/count based cache invalidation. This is accessible from the CacheAccessFactory. To instanciate a CacheAccess object, you use a CacheAccessFactory.

  
CacheAccessFactory factory = CacheAccessFactory.getInstance(); 
Map access = factory.getMapAccess(); 
						
					
These two lines will get a Map object to the default region. If the cache is not initialized, it will be auto-initialized.

Here's an example of the map interface use:

 
				 
//define your factory
CacheAccessFactory factory = CacheAccessFactory.getInstance();
/*Get the default region as a Map.
 * Its not neccessary to save this as an instance variable.
 */
Map cache = factory.getMapAccess();
//putting objects into the cache.
cache.put("key", "value");
//retrieveing objects.
Object obj = cache.get("key");
/*all methods in java.util.Map, java.util.Set
 * retrieveable from Map.keySet/Map.entrySet
 * and java.util.Iterator are available.
 * You can use both the Map access and the 
 * CacheAccess interfaces simultaneously.
 */
					

Distribution

There is nothing else you need to do than to mark the cache as "distributed", either in a property file, or in a custom CacheAttributes object. When a cache has been marked as distributed, it automatically joins any other distributed FKache inistances on your network. All updates/invalidates are automatically propagated to all the Caches on the network. if a local object cannot be found, a request is sent to the other FKache nodes.

CacheLoaders and StreamObjects

CacheLoaders are another way to use FKache, as all the attributes, invalidations, replacings etc are handled by one class, the CacheLoader. This is a good design principle.

StreamAccess objects are objects that are accessed as a stream. This means the object is loaded as an java.io.OutputStream and read as an java.io.InputStream. To create a stream for writing an object into FKache, you call the createStream() method from inside your implementation of load() in your cacheLoader object. Here is a short, simple example of a CacheLoader which uses streaming for reading and writing. This code snippet is the cacheloader class.

 
public class StreamingLoader extends CacheLoader { 
	public Object load(Object handle, Object arguments)throws CacheException { 
		OutputStream out = null; 
		try { 
			out = createStream(handle); 
			out.write(getHugeObject()); 
			return out; 
		} catch (IOException e) { 
			//wraps regular exceptions inside CacheExceptions. 
			throw exceptionHandler("Error in write.", e); 
		}finally { 
			if(out!=null) try { 
				out.close(); 
			} catch (IOException e1) { 
				throw exceptionHandler( 
				"Error in close of outputstream. Stream probably corrupted.", e1); 
			} 
		} 
	} 
 
	private byte[] getHugeObject() { 
		//here you write your code to retrieve your large object. 
 
	} 
} 

And here is the client code which uses the cacheloader. This code is a cut'n'paste from a JUnit test, so both the definition and the use of the CacheLoader is crammed into one method. The definition of an object should be separate from general usage, and done only once.

 
//this part prepares the object with the cacheloader.
CacheAccess access = CacheAccessFactory.getInstance().getAccess();
CacheLoader myLoader = new StreamingLoader();
Attributes attribs = Attributes.getDefaultAttributes();
attribs.setLoader(myLoader);
String objName = this.getClass().getName();
access.defineObject(objName, attribs);

//this part is the normal, regular use of a Streaming CacheLoader.
InputStream in = (InputStream)access.get(objName);

//now we have an inputstream, and use this to retrieve our
//object. 
byte[] buffer = new byte[1024]; 
//we know the object we want is a string.
ByteArrayOutputStream out = new ByteArrayOutputStream();
int amountRead=-1;
while((amountRead=in.read(buffer))!=-1) {
	out.write(buffer, 0, amountRead);
}
String result = new String(out.toByteArray());