ReferenceCountingCachingFactory

class ReferenceCountingCachingFactory<K, V : ReferenceCounted>(constructorParamType: Class<K>, objType: Class<V>)

This class defines a special type of cache that either return or constructs a new instance of objects of type V, given.

Description

The gist of this cache is that it will create a new instance of an object only if there is not already a satisfying instance in the it, hence avoiding duplicates. A couple of requirements have to be met :

  • the "Value Type" V (the type of objects that are sored in the cache) must implement the ReferenceCounted interface,

  • the "Value Type" must provide a 1-argument constructor, of type K, a.k.a the "Key Type",

  • the cache is using a hash table internally to memorize the active instances. The keys of this map are instances of the "Key Type" K, so be careful of the correctness of the hashCode and equals for K. Kotlin data classes will work out of the box.

Usage

Define a "Key type":

data class ConnectionInfo(val host: String, val port: Int)

Then define a "Value type", that implements the ReferenceCounted interface, and with a 1-arg of the former type constructor. For example if you'd like to implement a database connection pool, you can wrap it in such a class, like in the example below:

class PooledDatabaseConnection(info: ConnectionInfo): ReferenceCounted {
init { ... }

companion object {
private val pool = ReferenceCountingCachingFactory(ConnectionInfo::class.java, PooledDatabaseConnection::class.java)

fun get(val host: String, val port: Int): PooledDatabaseConnection {
return pool.get(ConnectionInfo(host, port))
}
}

var connected = false

private fun connect() { ... }
private fun disconnect() { ... }

fun onReferenceReleased(remainingRefs: Int) {
if (remainingRefs == 0 && connected) { disconnect() }
}

fun onReferenceAcquired(currentRefCount: Int) {
if (!connected) { connect() }
}

fun close() { pool.release(this) }
}

To obtain a connection, you would use PooledDatabaseConnection.get("host.example", 1234). If such a connection is already existing, it will be reused, otherwise it will be created. To give a chance to the garbage collector to dispose of useless objects, you should release it from the pool (e.g. the close() function above), it will decrease the internal reference counter by one. Once the reference count reaches 0, the object will be removed from the cache.

Note

As type parameters cannot be reified, their runtime class must be passed in the constructor. The type inferer can infer the type parameters from the constructor parameters, so a new instance can be created without code redundancy:

val myCache = ReferenceCountingCachingFactory(MyKeyType::class.java, MyCachedType::class.java)

Constructors

ReferenceCountingCachingFactory
Link copied to clipboard
fun <K, V : ReferenceCounted> ReferenceCountingCachingFactory(constructorParamType: Class<K>, objType: Class<V>)

Functions

get
Link copied to clipboard
fun get(key: K): V

Returns an object of type V given its key of type K.

ref
Link copied to clipboard
fun ref(key: K): Int?

Increments the reference counter of the cached object associated to key.

release
Link copied to clipboard
fun release(key: K)

Decrements the cache's reference counter by one for the object associated to key

tryGet
Link copied to clipboard
fun tryGet(key: K): V?

Returns an object of type V given its key of type K, if it is present in the cache, or null if no entry was found.

Properties

constructor
Link copied to clipboard
val constructor: Constructor<V>