com.fnklabs.draenei.orm.CacheableDataProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fnklabs-draenei Show documentation
Show all versions of fnklabs-draenei Show documentation
ORM for Cassandra but with distributed cache and analytics utils from package
package com.fnklabs.draenei.orm;
import com.codahale.metrics.Timer;
import com.fnklabs.draenei.CassandraClient;
import com.fnklabs.draenei.MetricsFactory;
import com.fnklabs.draenei.orm.exception.CanNotBuildEntryCacheKey;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.util.concurrent.*;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.core.IMap;
import com.hazelcast.map.EntryProcessor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public abstract class CacheableDataProvider extends DataProvider {
/**
* hashing function to build Entity cache id
*/
private static final HashFunction HASH_FUNCTION = Hashing.murmur3_128();
/**
* Distributed object dataGrid
*/
private final IMap dataGrid;
private final EventListener eventListener;
public CacheableDataProvider(Class clazz,
CassandraClient cassandraClient,
HazelcastInstance hazelcastClient,
MetricsFactory metricsFactory,
EventListener eventListener,
ListeningExecutorService executorService) {
super(clazz, cassandraClient, metricsFactory, executorService);
this.eventListener = eventListener;
/**
* Initialize dataGrid
*/
dataGrid = hazelcastClient.getMap(getMapName(clazz));
}
public CacheableDataProvider(Class clazz,
CassandraClient cassandraClient,
HazelcastInstance hazelcastClient,
MetricsFactory metricsFactory,
ListeningExecutorService executorService) {
super(clazz, cassandraClient, metricsFactory, executorService);
this.eventListener = new EventListener() {
@Override
public void onEntrySave(T entry) {
}
@Override
public void onEntryRemove(T entry) {
}
};
/**
* Initialize dataGrid
*/
dataGrid = hazelcastClient.getMap(getMapName(clazz));
}
@Override
public ListenableFuture findOneAsync(Object... keys) {
Timer.Context time = getMetricsFactory().getTimer(MetricsType.CACHEABLE_DATA_PROVIDER_FIND).time();
long cacheKey = buildCacheKey(keys);
ListenableFuture getFromDataGridFuture = getFromDataGrid(cacheKey);
ListenableFuture findEntityFuture = Futures.transform(getFromDataGridFuture, (T result) -> {
if (result != null) {
getMetricsFactory().getCounter(MetricsType.CACHEABLE_DATA_PROVIDER_HITS).inc();
return getFromDataGridFuture;
}
// try to load entity from DB
ListenableFuture findFuture = super.findOneAsync(keys);
Futures.addCallback(findFuture, new FutureCallback() {
@Override
public void onSuccess(T result) {
if (result != null) {
result.setCacheKey(cacheKey);
getMap().putAsync(cacheKey, result);
}
}
@Override
public void onFailure(Throwable t) {
LOGGER.warn("Can't put to cache", t);
}
}, getExecutorService());
return findFuture;
}, getExecutorService());
monitorFuture(time, findEntityFuture);
return findEntityFuture;
}
@Override
public ListenableFuture saveAsync(@NotNull T entity) {
Timer.Context time = getMetricsFactory().getTimer(MetricsType.CACHEABLE_DATA_PROVIDER_SAVE).time();
Long cacheKey = entity.getCacheKey() == null ? buildCacheKey(entity) : entity.getCacheKey();
ICompletableFuture future = (ICompletableFuture) getMap().putAsync(cacheKey, entity);
SettableFuture saveFuture = SettableFuture.create();
future.andThen(new ExecutionCallback() {
@Override
public void onResponse(T response) {
saveFuture.set(true);
}
@Override
public void onFailure(Throwable t) {
saveFuture.setException(t);
}
}, getExecutorService());
monitorFuture(time, saveFuture, result -> {
ListenableFuture saveAsyncFuture = super.saveAsync(entity);
getExecutorService().submit(() -> eventListener.onEntrySave(entity));
return saveAsyncFuture;
});
return saveFuture;
}
@Override
public ListenableFuture removeAsync(@NotNull T entity) {
Timer.Context timer = getMetricsFactory().getTimer(MetricsType.CACHEABLE_DATA_PROVIDER_REMOVE).time();
long key = entity.getCacheKey() == null ? buildCacheKey(entity) : entity.getCacheKey();
SettableFuture deleteFuture = SettableFuture.create();
ICompletableFuture removeFromDataGridFuture = (ICompletableFuture) getMap().removeAsync(key);
removeFromDataGridFuture.andThen(new ExecutionCallback() {
@Override
public void onResponse(T response) {
deleteFuture.set(true);
}
@Override
public void onFailure(Throwable t) {
deleteFuture.setException(t);
}
});
monitorFuture(timer, deleteFuture, result -> {
ListenableFuture removeFuture = super.removeAsync(entity);
getExecutorService().submit(() -> eventListener.onEntryRemove(entity));
return removeFuture;
});
return deleteFuture;
}
/**
* Execute function on entry
*
* @param entry Entry
* @param entryProcessor User Function
*
* @return Future for current operation
*/
protected ListenableFuture executeOnEntry(@NotNull T entry, @NotNull EntryProcessor entryProcessor) {
Long entityId = entry.getCacheKey() == null ? buildCacheKey(entry) : entry.getCacheKey();
ICompletableFuture completableFuture = (ICompletableFuture) getMap().submitToKey(entityId, entryProcessor);
SettableFuture responseFuture = SettableFuture.create();
completableFuture.andThen(new ExecutionCallback() {
@Override
public void onResponse(Boolean response) {
responseFuture.set(response);
}
@Override
public void onFailure(Throwable t) {
responseFuture.setException(t);
}
});
return responseFuture;
}
@NotNull
protected String getMapName() {
return getMap().getName();
}
protected IMap getMap() {
return dataGrid;
}
protected final long buildCacheKey(@NotNull T entity) {
Timer.Context time = getMetricsFactory().getTimer(MetricsType.CACHEABLE_DATA_PROVIDER_CREATE_KEY).time();
int primaryKeysSize = getEntityMetadata().getPrimaryKeysSize();
List