Advertisement
Guest User

Untitled

a guest
Dec 9th, 2016
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.17 KB | None | 0 0
  1. import java.lang.reflect.Method;
  2. import java.util.concurrent.ConcurrentMap;
  3. import java.util.concurrent.TimeUnit;
  4.  
  5. import com.google.common.base.Ticker;
  6. import com.google.common.cache.CacheBuilder;
  7. import com.google.common.cache.CacheLoader;
  8. import com.google.common.cache.RemovalListener;
  9.  
  10. /**
  11. * Represents a Guava CacheBuilder that is compatible with both Guava 10 (Minecraft 1.7.X) and 13
  12. */
  13. public class CompatibleCacheBuilder<K, V> {
  14.  
  15. private static Method BUILD_METHOD;
  16. private static Method AS_MAP_METHOD;
  17.  
  18. /**
  19. * Construct a new safe cache builder.
  20. *
  21. * @param <K> Key type
  22. * @param <V> Value type
  23. *
  24. * @return A new cache builder.
  25. */
  26. public static <K, V> CompatibleCacheBuilder<K, V> newBuilder() {
  27. return new CompatibleCacheBuilder<>();
  28. }
  29.  
  30. private final CacheBuilder<K, V> builder;
  31.  
  32. @SuppressWarnings("unchecked")
  33. private CompatibleCacheBuilder() {
  34. builder = (CacheBuilder<K, V>) CacheBuilder.newBuilder();
  35. }
  36.  
  37. /**
  38. * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The table is
  39. * internally partitioned to try to permit the indicated number of concurrent updates without contention. Because
  40. * assignment of entries to these partitions is not necessarily uniform, the actual concurrency observed may vary.
  41. * Ideally, you should choose a value to accommodate as many threads as will ever concurrently modify the table.
  42. * Using a significantly higher value than you need can waste space and time, and a significantly lower value can
  43. * lead to thread contention. But overestimates and underestimates within an order of magnitude do not usually have
  44. * much noticeable impact. A value of one permits only one thread to modify the cache at a time, but since read
  45. * operations can proceed concurrently, this still yields higher concurrency than full synchronization. Defaults to
  46. * 4.
  47. *
  48. * <p>
  49. * <b>Note:</b>The default may change in the future. If you care about this value, you should always choose it
  50. * explicitly.
  51. *
  52. * @param concurrencyLevel New concurrency level
  53. * @return This for chaining
  54. *
  55. * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
  56. * @throws IllegalStateException if a concurrency level was already set
  57. */
  58. public CompatibleCacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) {
  59. builder.concurrencyLevel(concurrencyLevel);
  60. return this;
  61. }
  62.  
  63. /**
  64. * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
  65. * the entry's creation, or last access. Access time is reset by
  66. * {@link com.google.common.cache.Cache#get Cache.get()}, but not by operations on the view returned by
  67. * {@link com.google.common.cache.Cache#asMap() Cache.asMap()}.
  68. *
  69. * <p>
  70. * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
  71. * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
  72. * disable caching temporarily without a code change.
  73. *
  74. * <p>
  75. * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
  76. * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
  77. * occasional read operations in the absense of writes; though this behavior may change in the future.
  78. *
  79. * @param duration the length of time after an entry is last accessed that it should be automatically removed
  80. * @param unit the unit that {@code duration} is expressed in
  81. * @return This for chaining
  82. *
  83. * @throws IllegalArgumentException if {@code duration} is negative
  84. * @throws IllegalStateException if the time to idle or time to live was already set
  85. */
  86. public CompatibleCacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
  87. builder.expireAfterAccess(duration, unit);
  88. return this;
  89. }
  90.  
  91. /**
  92. * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
  93. * the entry's creation, or the most recent replacement of its value.
  94. *
  95. * <p>
  96. * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
  97. * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
  98. * disable caching temporarily without a code change.
  99. *
  100. * <p>
  101. * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
  102. * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
  103. * occasional read operations in the absense of writes; though this behavior may change in the future.
  104. *
  105. * @param duration the length of time after an entry is created that it should be automatically removed
  106. * @param unit the unit that {@code duration} is expressed in
  107. * @return This for chaining
  108. *
  109. * @throws IllegalArgumentException if {@code duration} is negative
  110. * @throws IllegalStateException if the time to live or time to idle was already set
  111. */
  112. public CompatibleCacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
  113. builder.expireAfterWrite(duration, unit);
  114. return this;
  115. }
  116.  
  117. /**
  118. * Sets the minimum total size for the internal hash tables. For example, if the initial capacity is {@code 60}, and
  119. * the concurrency level is {@code 8}, then eight segments are created, each having a hash table of size eight.
  120. * Providing a large enough estimate at construction time avoids the need for expensive resizing operations later,
  121. * but setting this value unnecessarily high wastes memory.
  122. *
  123. * @param initialCapacity - initial capacity
  124. * @return This for chaining
  125. *
  126. * @throws IllegalArgumentException if {@code initialCapacity} is negative
  127. * @throws IllegalStateException if an initial capacity was already set
  128. */
  129. public CompatibleCacheBuilder<K, V> initialCapacity(int initialCapacity) {
  130. builder.initialCapacity(initialCapacity);
  131. return this;
  132. }
  133.  
  134. /**
  135. * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict an entry before
  136. * this limit is exceeded</b>. As the cache size grows close to the maximum, the cache evicts entries that are less
  137. * likely to be used again. For example, the cache may evict an entry because it hasn't been used recently or very
  138. * often.
  139. *
  140. * <p>
  141. * When {@code size} is zero, elements will be evicted immediately after being loaded into the cache. This has the
  142. * same effect as invoking {@link #expireAfterWrite expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
  143. * unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
  144. *
  145. * @param size the maximum size of the cache
  146. * @return This for chaining
  147. *
  148. * @throws IllegalArgumentException if {@code size} is negative
  149. * @throws IllegalStateException if a maximum size was already set
  150. */
  151. public CompatibleCacheBuilder<K, V> maximumSize(int size) {
  152. builder.maximumSize(size);
  153. return this;
  154. }
  155.  
  156. /**
  157. * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will notify each time an
  158. * entry is removed from the cache by any means.
  159. *
  160. * <p>
  161. * Each cache built by this {@code CacheBuilder} after this method is called invokes the supplied listener after
  162. * removing an element for any reason (see removal causes in
  163. * {@link com.google.common.cache.RemovalCause RemovalCause}). It will invoke the listener during invocations of any
  164. * of that cache's public methods (even read-only methods).
  165. *
  166. * <p>
  167. * <b>Important note:</b> Instead of returning <em>this</em> as a {@code CacheBuilder} instance, this method returns
  168. * {@code CacheBuilder<K1, V1>}. From this point on, either the original reference or the returned reference may be
  169. * used to complete configuration and build the cache, but only the "generic" one is type-safe. That is, it will
  170. * properly prevent you from building caches whose key or value types are incompatible with the types accepted by
  171. * the listener already provided; the {@code CacheBuilder} type cannot do this. For best results, simply use the
  172. * standard method-chaining idiom, as illustrated in the documentation at top, configuring a {@code CacheBuilder}
  173. * and building your {@link com.google.common.cache.Cache Cache} all in a single statement.
  174. *
  175. * <p>
  176. * <b>Warning:</b> if you ignore the above advice, and use this {@code CacheBuilder} to build a cache whose key or
  177. * value type is incompatible with the listener, you will likely experience a {@link ClassCastException} at some
  178. * <i>undefined</i> point in the future.
  179. *
  180. * @param <K1> Key type
  181. * @param <V1> Value type
  182. * @param listener - removal listener
  183. * @return This for chaining
  184. *
  185. * @throws IllegalStateException if a removal listener was already set
  186. */
  187. @SuppressWarnings("unchecked")
  188. public <K1 extends K, V1 extends V> CompatibleCacheBuilder<K1, V1> removalListener(RemovalListener<? super K1, ? super V1> listener) {
  189. builder.removalListener(listener);
  190. return (CompatibleCacheBuilder<K1, V1>) this;
  191. }
  192.  
  193. /**
  194. * Specifies a nanosecond-precision time source for use in determining when entries should be expired. By default,
  195. * {@link System#nanoTime} is used.
  196. *
  197. * <p>
  198. * The primary intent of this method is to facilitate testing of caches which have been configured with
  199. * {@link #expireAfterWrite} or {@link #expireAfterAccess}.
  200. *
  201. * @param ticker - ticker
  202. * @return This for chaining
  203. *
  204. * @throws IllegalStateException if a ticker was already set
  205. */
  206. public CompatibleCacheBuilder<K, V> ticker(Ticker ticker) {
  207. builder.ticker(ticker);
  208. return this;
  209. }
  210.  
  211. /**
  212. * Specifies that each value (not key) stored in the cache should be wrapped in a
  213. * {@link java.lang.ref.SoftReference SoftReference} (by default, strong references are used). Softly-referenced
  214. * objects will be garbage-collected in a <i>globally</i>
  215. * least-recently-used manner, in response to memory demand.
  216. *
  217. * <p>
  218. * <b>Warning:</b> in most circumstances it is better to set a per-cache {@linkplain #maximumSize maximum size}
  219. * instead of using soft references. You should only use this method if you are well familiar with the practical
  220. * consequences of soft references.
  221. *
  222. * <p>
  223. * <b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
  224. * equality of values.
  225. *
  226. * @return This for chaining
  227. *
  228. * @throws IllegalStateException if the value strength was already set
  229. */
  230. public CompatibleCacheBuilder<K, V> softValues() {
  231. builder.softValues();
  232. return this;
  233. }
  234.  
  235. /**
  236. * Specifies that each key (not value) stored in the cache should be wrapped in a
  237. * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
  238. *
  239. * <p>
  240. * <b>Warning:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to
  241. * determine equality of keys.
  242. *
  243. * @return This for chaining
  244. *
  245. * @throws IllegalStateException if the key strength was already set
  246. */
  247. public CompatibleCacheBuilder<K, V> weakKeys() {
  248. builder.weakKeys();
  249. return this;
  250. }
  251.  
  252. /**
  253. * Specifies that each value (not key) stored in the cache should be wrapped in a
  254. * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
  255. *
  256. * <p>
  257. * Weak values will be garbage collected once they are weakly reachable. This makes them a poor candidate for
  258. * caching; consider {@link #softValues} instead.
  259. *
  260. * <p>
  261. * <b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
  262. * equality of values.
  263. *
  264. * @return This for chaining
  265. *
  266. * @throws IllegalStateException if the value strength was already set
  267. */
  268. public CompatibleCacheBuilder<K, V> weakValues() {
  269. builder.weakValues();
  270. return this;
  271. }
  272.  
  273. /**
  274. * Returns the cache wrapped as a ConcurrentMap.
  275. * <p>
  276. * We can't return the direct Cache instance as it changed in Guava 13.
  277. *
  278. * @param <K1> Key type
  279. * @param <V1> Value type
  280. * @param loader - cache loader
  281. * @return The cache as a a map.
  282. */
  283. @SuppressWarnings("unchecked")
  284. public <K1 extends K, V1 extends V> ConcurrentMap<K1, V1> build(CacheLoader<? super K1, V1> loader) {
  285. Object cache = null;
  286.  
  287. if (BUILD_METHOD == null) {
  288. try {
  289. BUILD_METHOD = builder.getClass().getDeclaredMethod("build", CacheLoader.class);
  290. BUILD_METHOD.setAccessible(true);
  291. } catch (Exception e) {
  292. throw new IllegalStateException("Unable to find CacheBuilder.build(CacheLoader)", e);
  293. }
  294. }
  295.  
  296. // Attempt to build the Cache
  297. try {
  298. cache = BUILD_METHOD.invoke(builder, loader);
  299. } catch (Exception e) {
  300. throw new IllegalStateException("Unable to invoke " + BUILD_METHOD + " on " + builder, e);
  301. }
  302.  
  303. if (AS_MAP_METHOD == null) {
  304. try {
  305. AS_MAP_METHOD = cache.getClass().getMethod("asMap");
  306. AS_MAP_METHOD.setAccessible(true);
  307. } catch (Exception e) {
  308. throw new IllegalStateException("Unable to find Cache.asMap() in " + cache, e);
  309. }
  310. }
  311.  
  312. // Retrieve it as a map
  313. try {
  314. return (ConcurrentMap<K1, V1>) AS_MAP_METHOD.invoke(cache);
  315. } catch (Exception e) {
  316. throw new IllegalStateException("Unable to invoke " + AS_MAP_METHOD + " on " + cache, e);
  317. }
  318. }
  319. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement