package fr.openwide.core.wicket.more.model; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Iterator; import java.util.List; import org.apache.wicket.markup.repeater.data.IDataProvider; import org.apache.wicket.model.IModel; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; public class CacheDataProvider<T> implements IDataProvider<T>, IBindableDataProvider { private static final long serialVersionUID = 6701302381473177093L; private boolean cached = false; private boolean cachedSize = false; private final IDataProvider<T> reference; private final List<IModel<T>> cache = Lists.newArrayList(); private long cacheSize = 0; private Long lastFirst; private Long lastCount; public static <T> CacheDataProvider<T> of(IDataProvider<T> reference) { return new CacheDataProvider<>(reference); } public CacheDataProvider(IDataProvider<T> reference) { super(); this.reference = checkNotNull(reference); } @Override public IModel<T> model(T object) { return reference.model(object); } @Override public void detach() { reference.detach(); for (IModel<T> model : cache) { model.detach(); } } @Override public Iterator<? extends T> iterator(long first, long count) { long realCount = Math.min(count, size() - first); if (!cached || !Long.valueOf(first).equals(lastFirst) || !Long.valueOf(realCount).equals(lastCount)) { read(first, count); } lastFirst = first; lastCount = realCount; return Iterables.transform(cache, new ModelToObjectFunction()).iterator(); } @Override public long size() { if (!cachedSize) { cacheSize = reference.size(); cachedSize = true; } return cacheSize; } public void read(long first, long count) { cacheSize = size(); cache.clear(); cache.addAll(Lists.newArrayList(Iterables.transform(Lists.newArrayList(reference.iterator(first, count)), new ObjectToModelFunction()))); cached = true; cachedSize = true; } public void reset() { cached = false; cachedSize = false; cache.clear(); cacheSize = 0; } public IDataProvider<T> getReference() { return reference; } private class ObjectToModelFunction implements Function<T, IModel<T>> { @Override public IModel<T> apply(T input) { return input != null ? model(input) : null; } } private class ModelToObjectFunction implements Function<IModel<T>, T> { @Override public T apply(IModel<T> input) { return input != null ? input.getObject() : null; } } }