Java tutorial
/* * Copyright 2015 Samppa Saarela * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.javersion.store.jdbc; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.ListenableFuture; import org.javersion.core.Revision; import org.javersion.core.VersionNotFoundException; import org.javersion.object.ObjectVersion; import org.javersion.object.ObjectVersionGraph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.function.Function; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.util.concurrent.Futures.immediateFuture; public class GuavaGraphCache<Id, M> implements GraphCache<Id, M> { public static <Id, M> Function<VersionStore<Id, M>, GraphCache<Id, M>> guavaCacheBuilder( CacheBuilder<Object, Object> cacheBuilder) { return guavaCacheBuilder(cacheBuilder, null); } public static <Id, M> Function<VersionStore<Id, M>, GraphCache<Id, M>> guavaCacheBuilder( CacheBuilder<Object, Object> cacheBuilder, GraphOptions<Id, M> graphOptions) { return versionStore -> new GuavaGraphCache<>(versionStore, cacheBuilder, graphOptions); } private final Logger log = LoggerFactory.getLogger(GuavaGraphCache.class); @SuppressWarnings("unchecked") private static final GraphOptions DEFAULT_CACHE_OPTIONS = new GraphOptions(); protected final LoadingCache<Id, ObjectVersionGraph<M>> cache; private final GraphOptions<Id, M> graphOptions; protected final Set<Id> cachedDocIds; public GuavaGraphCache(VersionStore<Id, M> versionStore, CacheBuilder<Object, Object> cacheBuilder) { this(versionStore, cacheBuilder, null); } // About CacheBuilder generics: https://code.google.com/p/guava-libraries/issues/detail?id=738 @SuppressWarnings("unchecked") public GuavaGraphCache(VersionStore<Id, M> versionStore, CacheBuilder<Object, Object> cacheBuilder, GraphOptions<Id, M> graphOptions) { this.cache = cacheBuilder.build(newCacheLoader(versionStore)); this.cachedDocIds = cache.asMap().keySet(); this.graphOptions = firstNonNull(graphOptions, DEFAULT_CACHE_OPTIONS); } @Override public ObjectVersionGraph<M> load(Id docId) { try { return cache.get(docId); } catch (ExecutionException e) { throw new RuntimeException(e); } } @Override public void refresh(Id docId) { if (cachedDocIds.contains(docId)) { cache.refresh(docId); } } @Override public void evict(Id docId) { cache.invalidate(docId); } @Override public void evict(Iterator<Id> docIds) { cache.invalidate(docIds); } @Override public void evictAll() { cache.invalidateAll(); } protected CacheLoader<Id, ObjectVersionGraph<M>> newCacheLoader(final VersionStore<Id, M> versionStore) { return new CacheLoader<Id, ObjectVersionGraph<M>>() { @Override public ObjectVersionGraph<M> load(Id docId) throws Exception { log.debug("load({})", docId); return compactIfRequired(versionStore.getOptimizedGraph(docId)); } @Override public ListenableFuture<ObjectVersionGraph<M>> reload(Id docId, ObjectVersionGraph<M> oldValue) throws Exception { if (!oldValue.isEmpty()) { ObjectVersionGraph<M> newValue = oldValue; Revision since = oldValue.getTip().getRevision(); try { List<ObjectVersion<M>> updates = versionStore.fetchUpdates(docId, since); log.debug("refresh({}): {})", docId, updates.size()); if (!updates.isEmpty()) { newValue = oldValue.commit(updates); } return immediateFuture(compactIfRequired(newValue)); } catch (VersionNotFoundException e) { // since revision is deleted - reload graph } } return immediateFuture(load(docId)); } private ObjectVersionGraph<M> compactIfRequired(ObjectVersionGraph<M> graph) { if (graphOptions.optimizeWhen.test(graph)) { return graph.optimize(graphOptions.optimizeKeep.apply(graph)).getGraph(); } else { return graph; } } }; } }