How do I implement Guava Caching in Dropwizard? - java

I'm trying to setup a cache using guava, with the following code:
private List<Profile> buildCache() {
LoadingCache cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(40)
.build(
new CacheLoader<Profile, List<Profile>>() {
#Override
public List<Profile> load(Profile profile) throws Exception {
Profile profile1 = new Profile();
Profile.setEmployed(true);
return profileDAO.getAllProfiles(Profile1, null);
}
}
);
return (List<Profile>) cache;
}
public List<Profile> getAllProfiles(Profile profile, Integer size) throws Exception {
return profileDAO.getAllProfiles(profile, size);
}
The idea here is that this will create a cache using get all profile. The method for that uses a new profile object to set a boolean on whether that employee is employed or not. The size variable means that the method will return however many indicated. When null, it defaults to top 10.
I have two issues:
1. This is the first time I have ever used a cache, so I really do not know if I am doing this correctly.
2. I cannot find anything in the documentation on how to implement this within my app. How am I supposed to call this? I tried modifying the getAllProfiles method to return it:
public List<Profile> getAllProfiles(Profile profile, Integer size) throws Exception {
return buildCache();
}
But that simply returns an exception that I cannot cast the cache into a java list:
Exception occurred: java.lang.ClassCastException: com.google.common.cache.LocalCache$LocalLoadingCache cannot be cast to java.util.List
If its any help, my app is also using spring, so I've also been doing research into that. Is there any difference between springframework.cache.guava and google.common.cache, or is it just Spring's inbuilt guava cache?

Ok, I think I managed to figure it out:
private LoadingCache<Integer, List<Profile>> loadingCache = CacheBuilder.newBuilder()
.refreshAfterWrite(10,TimeUnit.MINUTES)
.maximumSize(100).build(
new CacheLoader<Integer, List<Profile>>() {
#Override
public List<Profile> load(Integer integer) throws Exception {
Profile profile= new Profile();
if (integer == null) {
integer = 10;
}
return profileDAO.getAllProfiles(profile, integer);
}
}
);
First, I should have specified the key and value being passed into LoadingCache, in this case, an Integer and a List of Profile. Also, when I declared the new CacheLoader in the build function, I should have kept that layout of key and value. Finlly, when calling the getAll method, I should have loaded using the key Integer, not a profile object.
As for calling the function:
public List<Profile> getAllProfiles(Profile profile, Integer size) throws Exception {
return loadingCache.get(size);
}
This serves to get lists of certain legnths that are stored in the cache. If the list of that length is not in the cache, the getAll method will run, using the size varaible you pass to it.
#Eugene, Thank you for your help. Your explanation on the load method really helped put the cache into perspective for me.

Related

Java class method with Class and Field as parameters

How can i create a method that accepts Class and Field as parameters? Like this:
List<SomeClassEntity> list = ...;
// Service to make useful things around a list of objects
UsefulThingsService<SomeClassEntity> usefulThingsService = new UsefulThingsService<>();
// Maybe invoke like this. Did't work
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, SomeClassEntity::getFieldOne);
// or like this. Will cause delayed runtime erros
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, "fieldTwo");
public class SomeClassEntity {
Integer fieldOne = 10;
Double fieldThree = 0.123;
public Integer getFieldOne() {
return fieldOne;
}
public void setFieldOne(Integer fieldOne) {
this.fieldOne = fieldOne;
}
public Double getFieldThree() {
return fieldThree;
}
public void setFieldThree(Double fieldThree) {
this.fieldThree = fieldThree;
}
}
public class UsefulThingsService<T> {
public void makeUsefulThings(Class<T> someClassBClass, String fieldName) {
// there is some code
}
}
Want to have correct references on compile stage, not at runtime.
Update:
I need code that would look more convenient than this:
Field fieldOne = null;
try {
fieldOne = SomeClassEntity.class.getDeclaredField("fieldOne");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
usefulThingsService.makeUsefulThings(SomeClassEntity.class, fieldOne);
I apologize for the next clarification.
Update 2:
- The service compares the list with the previous list, reveals only the changed fields of objects (list items) and updates these fields in the objects in the original list.
- Currently i use annotation on entity's field that is actually ID of the entity and that ID is used to detect identically entities (old and new) when i need to update field of entity in source list.
- Service detect annotated field and use it for next update process.
- I want to refuse to use annotations and provide an Field directly in constructor of service. Or use something other that could establish a relationship between class and field on compilation stage.
Assuming that you want field access because you want to get and set the value, you’d need two functions:
public class UsefulThingsService<T> {
public <V> void makeUsefulThings(List<T> list, Function<T,V> get, BiConsumer<T,V> set) {
for(T object: list) {
V v = get.apply(object);
// there is some code
set.accept(object, v);
}
}
}
and
usefulThingsService.makeUsefulThings(
list, SomeClassEntity::getFieldOne, SomeClassEntity::setFieldOne);
usefulThingsService.makeUsefulThings(
list, SomeClassEntity::getFieldThree, SomeClassEntity::setFieldThree);
There are, however, some things open. E.g., how is this service supposed to do something useful with the field resp. property, without even knowing its actual type. In your example, both are subtypes of Number, so you could declare <V extends Number>, so the method knows how to extract numerical values, however, constructing an appropriate result object would require specifying another function argument.

How to create a write-behind cache from inmemory to database?

My goal is to cache data inmemory for 60s. As soon as the entry is read again from cache, I want to remove it from cache (permit single reads only).
If those 60s expired in the meantime and the entry is still available in cache, I want to writebehind the entry into a database.
Is there any existing technology/spring/apache framework that already offers such a cache?
(sidenote: I don't want to use complex libraries like redis, ehcache etc for such a simple usecase).
If set up manually, I'd be doing as follows. But probably there are better options?
#Service
public class WriteBehindCache {
static class ObjectEntry {
Object data;
LocalDateTime timestamp;
public ObjectEntry(Object data) {
this.data = data;
timestamp = LocalDateTime.now();
}
}
Map<String, ObjectEntry> cache = new ConcurrentHashMap<>();
//batch every minute
#Scheduled(fixedRate = 60000)
public void writeBehind() {
LocalDateTime now = LocalDateTime.now();
List<ObjectEntry> outdated = cache.values()
.filter(entry -> entry.getValue().timestamp.plusSeconds(60).isBefore(now))
.collect(Collectors.toList());
databaseService.persist(outdated);
cache.removeAll(outdated); //pseudocode
}
//always keep most recent entry
public void add(String key, Object data) {
cache.put(key, new ObjectEntry(data));
}
//fallback lookup to database if cache is empty
public Object get(String key) {
ObjectEntry entry = cache.remove(key);
if (entry == null) {
entry = databaseService.query(key);
if (entry != null) databaseService.remove(entry);
}
return entry;
}
}
Your solution has two problems:
You are doing a sequential scan for persisting, which will get costly when there are a lot of entries
The code has race conditions
Due to the race conditions the code does not satisfy your requirements. Its possible to construct a concurrent access sequence where an entry is removed from the cache but as well was written to the database
Is there any existing technology/spring/apache framework that already offers such a cache? (sidenote: I don't want to use complex libraries like redis, ehcache etc for such a simple usecase).
I think you can solve the concurrency issues based on the ConcurrentHashMap. But I don't know an elegant way for the timeout. Still, a possible solution is to use a caching library. I'd like to offer an example based on cache2k which is not heavy (about a 400k jar) and has other nice use cases as well. As an extra there is also good support for the Spring caching abstraction.
public static class WriteBehindCache {
Cache<String, Object> cache = Cache2kBuilder.of(String.class, Object.class)
.addListener((CacheEntryExpiredListener<String, Object>) (cache, entry)
-> persist(entry.getKey(), entry.getValue()))
.expireAfterWrite(60, TimeUnit.SECONDS)
.build();
public void add(String key, Object data) {
cache.put(key, data);
}
public Object get(String key) {
return cache.invoke(key, e -> {
if (e.exists()) {
Object v = e.getValue();
e.remove();
return v;
}
return loadAndRemove(e.getKey());
});
}
// stubs
protected void persist(String key, Object value) {
}
protected Object loadAndRemove(String key) {
return null;
}
}
With this wiring the cache blocks out concurrent operation on one entry, so it is certain that only one database operation runs for one entry at a time.
You can do it in similar ways with other caching libraries. Using the JCache/JSR107 API the code would look almost identical.
A more "lighter" approach is to use jhalterman's expiringmap
Personally, I believe a cache should be in every developers toolbox. However, I am the author of cache2k. Of course, I need to say that.

Batch delete all entities with given property (or properties)

This code below is our code to delete property for a given Entity type:
#Override
public boolean deleteProperty(String instance, String storeName, String propertyName) {
final boolean[] success = {false};
final PersistentEntityStore entityStore = manager.getPersistentEntityStore(xodusRoot, instance);
try {
entityStore.executeInTransaction(new StoreTransactionalExecutable() {
#Override
public void execute(#NotNull final StoreTransaction txn) {
EntityIterable entities = txn.findWithProp(storeName, propertyName);
final boolean[] hasError = {false};
entities.forEach(entity -> {
if(!entity.deleteProperty(propertyName)) {
hasError[0] = true;
}
});
success[0] = hasError[0];
}
});
} finally {
//entityStore.close();
}
return success[0];
}
I understand that Xodus is transactional and that if one of the deleteProperty operation here fails it will roll back (I may need to know if this is confirmed).
Still, is there a official way to delete a property for all existing entities of a given type?
I understand that Xodus is transactional and that if one of the deleteProperty operation here fails it will roll back (I may need to know if this is confirmed).
Yes, it's true. Here transaction will be flushed after StoreTransactionalExecutable performs there job. But you can split EntityIterable into batches (of size 100 for example) and after processing each batch execute txn.flush() method. Do not forget to check flush result since it returns boolean.
Still, is there a official way to delete a property for all existing entities of a given type?
No, there isn't. Only manually like I described above.

HashMap with weak values

I'm implementing a cache for Objects stored persistently. The idea is:
Method getObjectFromPersistence(long id); ///Takes about 3 seconds
Method getObjectFromCache(long id) //Instantly
And have a method: getObject(long id) with the following pseudocode:
synchronized(this){
CustomObject result= getObjectFromCache(id)
if (result==null){
result=getObjectFromPersistence(id);
addToCache(result);
}
return result;
}
But I need to allow the CustomObject to be collected by the garbage collector. Until now I was using an HashMap<Long,WeakReference<CustomObject> for the implementation. The problem is that over the time the HashMap becomes filled of empty WeakReferences.
I've checked WeakHashMap but there the keys are weak (and the values are still strong references) so having the longs with WeakReferences have no sense.
Whats the best solution for solving this problem? Is there some "inverse WeakHashMap" or something similar?
Thanks
You can use the Guava MapMaker for this:
ConcurrentMap<Long, CustomObject> graphs = new MapMaker()
.weakValues()
.makeMap();
You can even include the computation part by replacing makeMap() with this:
.makeComputingMap(
new Function<Long, CustomObject>() {
public CustomObject apply(Long id) {
return getObjectFromPersistence(id);
}
});
Since what you are writing looks a lot like a cache, the newer, more specialized Cache (built via a CacheBuilder) might be even more relevant to you. It doesn't implement the Map interface directly, but provides even more controls that you might want for a cache.
You can refer to this for a detailed how to work for CacheBuilder and here is an example for fast access:
LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<Integer, String>() {
#Override
public String load(Integer id) throws Exception {
return "value";
}
}
);
A WeakReference is added to its ReferenceQueue supplied at the construction time when its reference is collected.
You could poll the ReferenceQueue whenever you access the cache, and hold a HashMap<WeakReference<CustomObject>,Long> to know which entry to remove if a reference is found in the queue.
Alternatively, if the cache is not frequently used, you can watch the queue in a separate thread.
Have you tried android.util.LruCache (its a SDK11 class but it's also in the compatibility package as android.support.v4.util.LruCache). It does not implement java.util.Map but works like a Map and you can define how much memory will it take and it will flush old (unused cached objects by itself).
You could start a "cleanup" - Thread every once in a while. Perhaps if your map size exceeds a threshold but at most every 5 minutes .... something like that.
Keep the cleanup cycles short to not block the main functionality.
You can also test WeakValueHashMap from jboss-common http://docs.jboss.org/jbossas/javadoc/4.0.2/org/jboss/util/collection/WeakValueHashMap.java.html
I think the best option (if a dependency on Guava is undesirable) would be to use a custom subclass of WeakReference that remembers its ID, so that your cleanup thread can remove the weak values during cleanup of the WeakReferences.
The implementation of the weak reference, with the necessary ReferenceQueue and cleanup thread would look something like this:
class CustomObjectAccess {
private static final ReferenceQueue<CustomObject> releasedCustomObjects =
new ReferenceQueue<>();
static {
Thread cleanupThread = new Thread("CustomObject cleanup thread")
while (true) {
CustomObjectWeakReference freed = (CustomObjectWeakReference)
CustomObjectWeakReference.releasedCustomObjects.remove();
cache.remove(freed.id);
}
};
cleanupThread.start();
}
private Map<CustomObjectID, CustomObjectWeakReference> cache;
public CustomObject get(CustomObjectID id) {
synchronized(this){
CustomObject result= getFromCache(id);
if (result==null) {
result=getObjectFromPersistence(id);
addToCache(result);
}
}
return result;
}
private addToCache(CustomObject co) {
cache.put(CustomObject.getID(), new CustomObjectWeakReference(co));
}
private getFromCache(CustomObjectID id) {
WeakReference<CustomObject> weak = cache.get(id);
if (weak != null) {
return weak.get();
}
return null;
}
class CustomObjectWeakReference extends WeakReference<CustomObject> {
private final CustomObjectID id;
CustomObjectWeakReference(CustomObject co) {
super(co, releasedCustomObjects);
this.id = co.getID();
}
}
}
I had the need to store tagged weak objects and figured instead of using WeakHashMap<String, T>, I could just use WeakHashMap<T, String> instead.
This is Kotlin, but should apply to Java equally:
abstract class InstanceFactory<T> {
#Volatile
private var instances: MutableMap<T, String> = WeakHashMap<T, String>()
protected fun getOrCreate(tag: String = SINGLETON, creator: () -> T): T =
findByTag(tag)?.let {
it
} ?: synchronized(this) {
findByTag(tag)?.let {
it
} ?: run {
creator().also {
instances[it] = tag
}
}
}
private fun findByTag(tag: String): T? = instances.entries.find { it.value == tag }?.key
companion object {
const val SINGLETON = "singleton"
}
}
This can be used as follows:
class Thing(private val dependency: Dep) { ... }
class ThingFactory(private val dependency: Dep) : InstanceFactory<Thing>() {
createInstance(tag: String): Thing = getOrCreate(tag) { Thing(dependency) }
}
Simple singletons can be done like this:
object ThingFactory {
getInstance(dependency: Dependency): Thing = getOrCreate { Thing(dependency) }
}
There is ReferenceMap in Apache Commons Collections, this is a map implementation with hard keys and soft values (the opposite of WeakHashMap).

How build my own Application Setting

I want to build a ApplicationSetting for my application. The ApplicationSetting can be stored in a properties file or in a database table. The settings are stored in key-value pairs. E.g.
ftp.host = blade
ftp.username = dummy
ftp.pass = pass
content.row_pagination = 20
content.title = How to train your dragon.
I have designed it as follows:
Application settings reader:
interface IApplicationSettingReader {
Map read();
}
DatabaseApplicationSettingReader implements IApplicationSettingReader {
dao appSettingDao;
Map read() {
List<AppSettingEntity> listEntity = appSettingsDao.findAll();
Map<String, String> map = new HaspMap<String, String>();
foreach (AppSettingEntity entity : listEntity) {
map.put(entity.getConfigName(), entity.getConfigValue());
}
return new AppSettings(map);
}
}
DatabaseApplicationSettingReader implements IApplicationSettingReader {
dao appSettingDao;
Map read() {
//read from some properties file
return new AppSettings(map);
}
}
Application settings class:
AppSettings {
private static AppSettings instance = new AppSettings();
private Map map;
private AppSettings() {
}
public static AppSettings getInstance() {
if (instance == null) {
throw new RuntimeException("Object not configure yet");
}
return instance;
}
public static configure(IApplicationSettingReader reader) {
this.map = reader.read();
}
public String getFtpSetting(String param) {
return map.get("ftp." + param);
}
public String getContentSetting(String param) {
return map.get("content." + param);
}
}
Test class:
AppSettingsTest {
IApplicationSettingReader reader;
#Before
public void setUp() throws Exception {
reader = new DatabaseApplicationSettingReader();
}
#Test
public void getContentSetting_should_get_content_title() {
AppSettings.configure(reader);
Instance settings = AppSettings.getInstance();
String title = settings.getContentSetting("title");
assertNotNull(title);
Sysout(title);
}
}
My questions are:
Can you give your opinion about my code, is there something wrong ?????
I configure my application setting once, while the application start, I configure the application setting with appropriate reader (DbReader or PropertiesReader), I make it singleton because the application just have one instance of ApplicationSettngs. The problem is, when some user edit the database or file directly to database or file, I can't get the changed values. Now, I want to implement something like ApplicationSettingChangeListener. So if the data changes, I will refresh my application settings. Do you have any suggestions how this can be implementedb ????
I haven't throughly inspected your code, but there seems to be a concurrency issue. The map is thread-unsafe (HashMap), so if you mutate it through config() and have other threads access map, you have a problem.
Though you could use a ConcurrentHashMap instead HashMap, a batch operation on ConcurrentHashMap is not atomic. Meaning that, if you use it, you will see a "half-way" modified config. That could not be okay depending on your app.
So, the solution for this is to use this:
private volatile ImmutableMap map;
public config(){
ImmutableMap newMap = createNewMap();
this.map = newMap;
}
This will change your configs atomically (no intermediate state is visible).
As for updating your config on the fly, log4j does it using a background thread that monitors the config file. You could of course monitor a db table instead by polling it periodically.
In that case, your Config class will have preferably a ScheduledExecutor with a task that will monitor files/db and call config() periodically.
The answer to question #2 is to use a thread and check periodically if the file has been changed or to simply reinitialize your settings with the file contents.

Categories

Resources