Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.lang.reflect.Method;
- import java.util.concurrent.ConcurrentMap;
- import java.util.concurrent.TimeUnit;
- import com.google.common.base.Ticker;
- import com.google.common.cache.CacheBuilder;
- import com.google.common.cache.CacheLoader;
- import com.google.common.cache.RemovalListener;
- /**
- * Represents a Guava CacheBuilder that is compatible with both Guava 10 (Minecraft 1.7.X) and 13
- */
- public class CompatibleCacheBuilder<K, V> {
- private static Method BUILD_METHOD;
- private static Method AS_MAP_METHOD;
- /**
- * Construct a new safe cache builder.
- *
- * @param <K> Key type
- * @param <V> Value type
- *
- * @return A new cache builder.
- */
- public static <K, V> CompatibleCacheBuilder<K, V> newBuilder() {
- return new CompatibleCacheBuilder<>();
- }
- private final CacheBuilder<K, V> builder;
- @SuppressWarnings("unchecked")
- private CompatibleCacheBuilder() {
- builder = (CacheBuilder<K, V>) CacheBuilder.newBuilder();
- }
- /**
- * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The table is
- * internally partitioned to try to permit the indicated number of concurrent updates without contention. Because
- * assignment of entries to these partitions is not necessarily uniform, the actual concurrency observed may vary.
- * Ideally, you should choose a value to accommodate as many threads as will ever concurrently modify the table.
- * Using a significantly higher value than you need can waste space and time, and a significantly lower value can
- * lead to thread contention. But overestimates and underestimates within an order of magnitude do not usually have
- * much noticeable impact. A value of one permits only one thread to modify the cache at a time, but since read
- * operations can proceed concurrently, this still yields higher concurrency than full synchronization. Defaults to
- * 4.
- *
- * <p>
- * <b>Note:</b>The default may change in the future. If you care about this value, you should always choose it
- * explicitly.
- *
- * @param concurrencyLevel New concurrency level
- * @return This for chaining
- *
- * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
- * @throws IllegalStateException if a concurrency level was already set
- */
- public CompatibleCacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) {
- builder.concurrencyLevel(concurrencyLevel);
- return this;
- }
- /**
- * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
- * the entry's creation, or last access. Access time is reset by
- * {@link com.google.common.cache.Cache#get Cache.get()}, but not by operations on the view returned by
- * {@link com.google.common.cache.Cache#asMap() Cache.asMap()}.
- *
- * <p>
- * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
- * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
- * disable caching temporarily without a code change.
- *
- * <p>
- * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
- * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
- * occasional read operations in the absense of writes; though this behavior may change in the future.
- *
- * @param duration the length of time after an entry is last accessed that it should be automatically removed
- * @param unit the unit that {@code duration} is expressed in
- * @return This for chaining
- *
- * @throws IllegalArgumentException if {@code duration} is negative
- * @throws IllegalStateException if the time to idle or time to live was already set
- */
- public CompatibleCacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
- builder.expireAfterAccess(duration, unit);
- return this;
- }
- /**
- * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
- * the entry's creation, or the most recent replacement of its value.
- *
- * <p>
- * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
- * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
- * disable caching temporarily without a code change.
- *
- * <p>
- * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
- * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
- * occasional read operations in the absense of writes; though this behavior may change in the future.
- *
- * @param duration the length of time after an entry is created that it should be automatically removed
- * @param unit the unit that {@code duration} is expressed in
- * @return This for chaining
- *
- * @throws IllegalArgumentException if {@code duration} is negative
- * @throws IllegalStateException if the time to live or time to idle was already set
- */
- public CompatibleCacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
- builder.expireAfterWrite(duration, unit);
- return this;
- }
- /**
- * Sets the minimum total size for the internal hash tables. For example, if the initial capacity is {@code 60}, and
- * the concurrency level is {@code 8}, then eight segments are created, each having a hash table of size eight.
- * Providing a large enough estimate at construction time avoids the need for expensive resizing operations later,
- * but setting this value unnecessarily high wastes memory.
- *
- * @param initialCapacity - initial capacity
- * @return This for chaining
- *
- * @throws IllegalArgumentException if {@code initialCapacity} is negative
- * @throws IllegalStateException if an initial capacity was already set
- */
- public CompatibleCacheBuilder<K, V> initialCapacity(int initialCapacity) {
- builder.initialCapacity(initialCapacity);
- return this;
- }
- /**
- * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict an entry before
- * this limit is exceeded</b>. As the cache size grows close to the maximum, the cache evicts entries that are less
- * likely to be used again. For example, the cache may evict an entry because it hasn't been used recently or very
- * often.
- *
- * <p>
- * When {@code size} is zero, elements will be evicted immediately after being loaded into the cache. This has the
- * same effect as invoking {@link #expireAfterWrite expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
- * unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
- *
- * @param size the maximum size of the cache
- * @return This for chaining
- *
- * @throws IllegalArgumentException if {@code size} is negative
- * @throws IllegalStateException if a maximum size was already set
- */
- public CompatibleCacheBuilder<K, V> maximumSize(int size) {
- builder.maximumSize(size);
- return this;
- }
- /**
- * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will notify each time an
- * entry is removed from the cache by any means.
- *
- * <p>
- * Each cache built by this {@code CacheBuilder} after this method is called invokes the supplied listener after
- * removing an element for any reason (see removal causes in
- * {@link com.google.common.cache.RemovalCause RemovalCause}). It will invoke the listener during invocations of any
- * of that cache's public methods (even read-only methods).
- *
- * <p>
- * <b>Important note:</b> Instead of returning <em>this</em> as a {@code CacheBuilder} instance, this method returns
- * {@code CacheBuilder<K1, V1>}. From this point on, either the original reference or the returned reference may be
- * used to complete configuration and build the cache, but only the "generic" one is type-safe. That is, it will
- * properly prevent you from building caches whose key or value types are incompatible with the types accepted by
- * the listener already provided; the {@code CacheBuilder} type cannot do this. For best results, simply use the
- * standard method-chaining idiom, as illustrated in the documentation at top, configuring a {@code CacheBuilder}
- * and building your {@link com.google.common.cache.Cache Cache} all in a single statement.
- *
- * <p>
- * <b>Warning:</b> if you ignore the above advice, and use this {@code CacheBuilder} to build a cache whose key or
- * value type is incompatible with the listener, you will likely experience a {@link ClassCastException} at some
- * <i>undefined</i> point in the future.
- *
- * @param <K1> Key type
- * @param <V1> Value type
- * @param listener - removal listener
- * @return This for chaining
- *
- * @throws IllegalStateException if a removal listener was already set
- */
- @SuppressWarnings("unchecked")
- public <K1 extends K, V1 extends V> CompatibleCacheBuilder<K1, V1> removalListener(RemovalListener<? super K1, ? super V1> listener) {
- builder.removalListener(listener);
- return (CompatibleCacheBuilder<K1, V1>) this;
- }
- /**
- * Specifies a nanosecond-precision time source for use in determining when entries should be expired. By default,
- * {@link System#nanoTime} is used.
- *
- * <p>
- * The primary intent of this method is to facilitate testing of caches which have been configured with
- * {@link #expireAfterWrite} or {@link #expireAfterAccess}.
- *
- * @param ticker - ticker
- * @return This for chaining
- *
- * @throws IllegalStateException if a ticker was already set
- */
- public CompatibleCacheBuilder<K, V> ticker(Ticker ticker) {
- builder.ticker(ticker);
- return this;
- }
- /**
- * Specifies that each value (not key) stored in the cache should be wrapped in a
- * {@link java.lang.ref.SoftReference SoftReference} (by default, strong references are used). Softly-referenced
- * objects will be garbage-collected in a <i>globally</i>
- * least-recently-used manner, in response to memory demand.
- *
- * <p>
- * <b>Warning:</b> in most circumstances it is better to set a per-cache {@linkplain #maximumSize maximum size}
- * instead of using soft references. You should only use this method if you are well familiar with the practical
- * consequences of soft references.
- *
- * <p>
- * <b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
- * equality of values.
- *
- * @return This for chaining
- *
- * @throws IllegalStateException if the value strength was already set
- */
- public CompatibleCacheBuilder<K, V> softValues() {
- builder.softValues();
- return this;
- }
- /**
- * Specifies that each key (not value) stored in the cache should be wrapped in a
- * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
- *
- * <p>
- * <b>Warning:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to
- * determine equality of keys.
- *
- * @return This for chaining
- *
- * @throws IllegalStateException if the key strength was already set
- */
- public CompatibleCacheBuilder<K, V> weakKeys() {
- builder.weakKeys();
- return this;
- }
- /**
- * Specifies that each value (not key) stored in the cache should be wrapped in a
- * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
- *
- * <p>
- * Weak values will be garbage collected once they are weakly reachable. This makes them a poor candidate for
- * caching; consider {@link #softValues} instead.
- *
- * <p>
- * <b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
- * equality of values.
- *
- * @return This for chaining
- *
- * @throws IllegalStateException if the value strength was already set
- */
- public CompatibleCacheBuilder<K, V> weakValues() {
- builder.weakValues();
- return this;
- }
- /**
- * Returns the cache wrapped as a ConcurrentMap.
- * <p>
- * We can't return the direct Cache instance as it changed in Guava 13.
- *
- * @param <K1> Key type
- * @param <V1> Value type
- * @param loader - cache loader
- * @return The cache as a a map.
- */
- @SuppressWarnings("unchecked")
- public <K1 extends K, V1 extends V> ConcurrentMap<K1, V1> build(CacheLoader<? super K1, V1> loader) {
- Object cache = null;
- if (BUILD_METHOD == null) {
- try {
- BUILD_METHOD = builder.getClass().getDeclaredMethod("build", CacheLoader.class);
- BUILD_METHOD.setAccessible(true);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to find CacheBuilder.build(CacheLoader)", e);
- }
- }
- // Attempt to build the Cache
- try {
- cache = BUILD_METHOD.invoke(builder, loader);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to invoke " + BUILD_METHOD + " on " + builder, e);
- }
- if (AS_MAP_METHOD == null) {
- try {
- AS_MAP_METHOD = cache.getClass().getMethod("asMap");
- AS_MAP_METHOD.setAccessible(true);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to find Cache.asMap() in " + cache, e);
- }
- }
- // Retrieve it as a map
- try {
- return (ConcurrentMap<K1, V1>) AS_MAP_METHOD.invoke(cache);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to invoke " + AS_MAP_METHOD + " on " + cache, e);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement