Skip to content

Latest commit

 

History

History
62 lines (42 loc) · 2.88 KB

README.md

File metadata and controls

62 lines (42 loc) · 2.88 KB

caffeinated -- tiny multi-key caching layer based on caffeine

Build Status Code Coverage

The caffeinated library provides an asynchronous loading cache for a caching problem where multiple keys point to the same cached value (via same shared derived key) and are treated as a single entity for the purpose of expiration or eviction. In effect, it implements a caching cascade of K1,K2,K3->DK->V based on key mappers (Function<K,DK>) and value loaders (BiFunction<K,DK,V).

Given a cache instance one can retrieve values via the get methods, that exist in two variants:

  • with default loaders registered on the cached during construction (none are registered by default and the future will complete exceptionally): CompletableFuture<V> get(K key)

  • with explicit loaders: CompletableFuture<V> get(K key, Function<K,DK> keyMapper, BiFunction<K,DK,V> valueLoader)

The underlying cache is based on AsyncLoadingCache from caffeine and can be configured via the Caffeine builder, e.g.

Caffeine caffeine = Caffeine.newBuilder()
  .expireAfterAccess(5, TimeUnit.SECONDS);

AsyncMultikeyCache.<String, String, Session> sessionStore =
  AsyncMultikeyCache.<String, String, Session>newBuilder(caffeine)
	  .removalListener((keys, session, reason) -> session.expire())
		.buildAsync();

For this sort of session store the cache usage may look like this:

private final AuthenticationDAO authDao;

@Override
public CompletableFuture<String> authenticate(String username, String password) {
  String key = Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
  return sessionStore
    .get(key, $ -> {
      // make sure users with wrong passwords cannot hijack sessions of correctly 
      // authenticated users as shared key is just username
      authDao.validateUsernameAuth(username, password);
      return username;
    }, ($, $$) -> authDao.authByUsername(username, password))
    .thenCompose(session -> CompletableFuture.completedFuture(session.sessionId));
}

A complete example can be found in the SessionStoreExample test class.

License and copyright

Copyright (c) 2018. Oleg Sklyar and teris.io. All rights reserved. MIT license applies