org.babyfish.jimmer.sql.cache.chain.ParameterizedChainCacheImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jimmer-sql Show documentation
Show all versions of jimmer-sql Show documentation
A revolutionary ORM framework for both java and kotlin
package org.babyfish.jimmer.sql.cache.chain;
import org.babyfish.jimmer.sql.cache.Cache;
import org.babyfish.jimmer.sql.cache.CacheEnvironment;
import org.babyfish.jimmer.sql.cache.CacheLoader;
import org.babyfish.jimmer.sql.runtime.ExecutionException;
import org.jetbrains.annotations.NotNull;
import java.util.*;
class ParameterizedChainCacheImpl extends ChainCacheImpl implements Cache.Parameterized {
public ParameterizedChainCacheImpl(List> binders) {
super(binders);
boolean hasParameterizedBinder = false;
for (Object binder : binders) {
boolean isParameterizedBinder =
binder instanceof LoadingBinder.Parameterized, ?> ||
binder instanceof SimpleBinder.Parameterized, ?>;
if (hasParameterizedBinder && !isParameterizedBinder) {
throw new IllegalArgumentException(
"Parameterized binder must be after other binders"
);
}
hasParameterizedBinder = isParameterizedBinder;
}
if (!hasParameterizedBinder) {
throw new IllegalArgumentException("No parameterized binders");
}
}
@Override
@NotNull
public Map getAll(
@NotNull Collection keys,
@NotNull SortedMap parameterMap,
@NotNull CacheEnvironment env
) {
return usingCacheLoading(
env.getLoader(), () -> ((ParameterizedNode)node).loadAll(keys, parameterMap)
);
}
@SuppressWarnings("unchecked")
@Override
protected Node createNode(Object binder, Node next) {
if (binder instanceof LoadingBinder.Parameterized, ?>) {
return new ParameterizedLoadingNode(
(LoadingBinder.Parameterized) binder,
(ParameterizedNode) next
);
}
if (binder instanceof SimpleBinder.Parameterized, ?>) {
return new ParameterizedSimpleNode(
(SimpleBinder.Parameterized) binder,
next
);
}
return super.createNode(binder, next);
}
@Override
protected TailNode createTailNode() {
return new TailNode<>();
}
protected interface ParameterizedNode extends Node, CacheChain.Parameterized {}
private static class TailNode extends ChainCacheImpl.TailNode implements ParameterizedNode {
@Override
public @NotNull Map loadAll(@NotNull Collection keys, @NotNull SortedMap parameterMap) {
CacheLoader loader = currentCacheLoader();
return loader.loadAll(keys);
}
}
private static class ParameterizedLoadingNode implements ParameterizedNode {
private final LoadingBinder.Parameterized binder;
private final ParameterizedNode next;
ParameterizedLoadingNode(LoadingBinder.Parameterized binder, ParameterizedNode next) {
this.binder = binder;
this.next = next;
binder.initialize(next);
}
@NotNull
@Override
public Map loadAll(@NotNull Collection keys) {
return binder.getAll(keys);
}
@Override
@NotNull
public Map loadAll(
@NotNull Collection keys,
@NotNull SortedMap parameterMap
) {
return binder.getAll(keys, parameterMap);
}
@Override
public void deleteAll(@NotNull Collection keys, Object reason) {
next.deleteAll(keys, reason);
binder.deleteAll(keys, reason);
}
}
protected static class ParameterizedSimpleNode extends SimpleNode implements ParameterizedNode {
protected ParameterizedSimpleNode(SimpleBinder.Parameterized binder, Node next) {
super(binder, next);
}
@Override
public @NotNull Map loadAll(
@NotNull Collection keys,
@NotNull SortedMap parameterMap
) {
SimpleBinder.Parameterized parameterizedBinder =
(SimpleBinder.Parameterized) binder;
Map map = parameterizedBinder.getAll(keys, parameterMap);
if (map.size() < keys.size()) {
if (binder instanceof LockedBinder, ?>) {
Set missedKeys = missedKeys(keys, map);
LockedBinder, ?> lockedBinder = (LockedBinder, ?>) binder;
try {
lockedBinder.locker().locking(
((LockedBinder, ?>) binder).unwrap(),
missedKeys,
lockedBinder.waitDuration(),
lockedBinder.leaseDuration(),
lock -> {
loadAllFromNext(missedKeys, parameterMap, map,false);
}
);
} catch (ExecutionException ex) {
throw ex;
} catch (Exception ex) {
throw new ExecutionException(
"Failed to load missed data and update cache",
ex
);
}
} else {
loadAllFromNext(missedKeys(keys, map), parameterMap, map, true);
}
}
return map;
}
private static Set missedKeys(Collection keys, Map loadedMap) {
Set missedKeys = new LinkedHashSet<>();
for (K key : keys) {
if (!loadedMap.containsKey(key)) {
missedKeys.add(key);
}
}
return missedKeys;
}
private void loadAllFromNext(
Set missedKeys,
SortedMap parameterMap,
Map loadedMap,
boolean updateBinder
) {
Map mapFromNext = next.loadAll(missedKeys);
if (mapFromNext.size() < missedKeys.size()) {
mapFromNext = new HashMap<>(mapFromNext);
if (updateBinder) {
for (K missedKey : missedKeys) {
if (!mapFromNext.containsKey(missedKey)) {
mapFromNext.put(missedKey, null);
}
}
}
}
if (updateBinder) {
((SimpleBinder.Parameterized)binder).setAll(mapFromNext, parameterMap);
}
loadedMap.putAll(mapFromNext);
}
}
}