Bukkit-API  1.7.9-R0.2
The inofficial Bukkit-API
LazyMetadataValue.java
1 package org.bukkit.metadata;
2 
3 import java.lang.ref.SoftReference;
4 import java.util.concurrent.Callable;
5 
6 import org.apache.commons.lang.Validate;
7 import org.bukkit.plugin.Plugin;
8 
9 /**
10  * The LazyMetadataValue class implements a type of metadata that is not
11  * computed until another plugin asks for it.
12  * <p>
13  * By making metadata values lazy, no computation is done by the providing
14  * plugin until absolutely necessary (if ever). Additionally,
15  * LazyMetadataValue objects cache their values internally unless overridden
16  * by a {@link CacheStrategy} or invalidated at the individual or plugin
17  * level. Once invalidated, the LazyMetadataValue will recompute its value
18  * when asked.
19  */
20 public class LazyMetadataValue extends MetadataValueAdapter implements MetadataValue {
21  private Callable<Object> lazyValue;
22  private CacheStrategy cacheStrategy;
23  private SoftReference<Object> internalValue;
24  private static final Object ACTUALLY_NULL = new Object();
25 
26  /**
27  * Initialized a LazyMetadataValue object with the default
28  * CACHE_AFTER_FIRST_EVAL cache strategy.
29  *
30  * @param owningPlugin the {@link Plugin} that created this metadata
31  * value.
32  * @param lazyValue the lazy value assigned to this metadata value.
33  */
34  public LazyMetadataValue(Plugin owningPlugin, Callable<Object> lazyValue) {
35  this(owningPlugin, CacheStrategy.CACHE_AFTER_FIRST_EVAL, lazyValue);
36  }
37 
38  /**
39  * Initializes a LazyMetadataValue object with a specific cache strategy.
40  *
41  * @param owningPlugin the {@link Plugin} that created this metadata
42  * value.
43  * @param cacheStrategy determines the rules for caching this metadata
44  * value.
45  * @param lazyValue the lazy value assigned to this metadata value.
46  */
47  public LazyMetadataValue(Plugin owningPlugin, CacheStrategy cacheStrategy, Callable<Object> lazyValue) {
48  super(owningPlugin);
49  Validate.notNull(cacheStrategy, "cacheStrategy cannot be null");
50  Validate.notNull(lazyValue, "lazyValue cannot be null");
51  this.internalValue = new SoftReference<Object>(null);
52  this.lazyValue = lazyValue;
53  this.cacheStrategy = cacheStrategy;
54  }
55 
56  /**
57  * Protected special constructor used by FixedMetadataValue to bypass
58  * standard setup.
59  */
60  protected LazyMetadataValue(Plugin owningPlugin) {
61  super(owningPlugin);
62  }
63 
64  public Object value() {
65  eval();
66  Object value = internalValue.get();
67  if (value == ACTUALLY_NULL) {
68  return null;
69  }
70  return value;
71  }
72 
73  /**
74  * Lazily evaluates the value of this metadata item.
75  *
76  * @throws MetadataEvaluationException if computing the metadata value
77  * fails.
78  */
79  private synchronized void eval() throws MetadataEvaluationException {
80  if (cacheStrategy == CacheStrategy.NEVER_CACHE || internalValue.get() == null) {
81  try {
82  Object value = lazyValue.call();
83  if (value == null) {
84  value = ACTUALLY_NULL;
85  }
86  internalValue = new SoftReference<Object>(value);
87  } catch (Exception e) {
88  throw new MetadataEvaluationException(e);
89  }
90  }
91  }
92 
93  public synchronized void invalidate() {
94  if (cacheStrategy != CacheStrategy.CACHE_ETERNALLY) {
95  internalValue.clear();
96  }
97  }
98 
99  /**
100  * Describes possible caching strategies for metadata.
101  */
102  public enum CacheStrategy {
103  /**
104  * Once the metadata value has been evaluated, do not re-evaluate the
105  * value until it is manually invalidated.
106  */
108 
109  /**
110  * Re-evaluate the metadata item every time it is requested
111  */
113 
114  /**
115  * Once the metadata value has been evaluated, do not re-evaluate the
116  * value in spite of manual invalidation.
117  */
118  CACHE_ETERNALLY
119  }
120 }
LazyMetadataValue(Plugin owningPlugin, CacheStrategy cacheStrategy, Callable< Object > lazyValue)
LazyMetadataValue(Plugin owningPlugin, Callable< Object > lazyValue)