001: package javolution.util;
002:
003: import j2me.util.Collection;
004: import j2me.util.Map;
005: import j2me.util.Set;
006: import javolution.context.LocalContext;
007:
008: /**
009: * <p> This class represents a map which can be temporarily modified
010: * without impacting other threads ({@link LocalContext locally}
011: * scoped changes).</p>
012: *
013: * <p> Operation on instances of this class are completely thread-safe.
014: * For example:
015: * public class XMLFormat {
016: * static LocalMap<Class, XMLFormat> CLASS_TO_FORMAT = new LocalMap<Class, XMLFormat>();
017: * public static void setFormat(Class forClass, XMLFormat that) {
018: * CLASS_TO_FORMAT.put(forClass, that); // No synchronization required.
019: * }
020: * public static XMLFormat getInstance(Class forClass) {
021: * return CLASS_TO_FORMAT.get(forClass); // No synchronization required.
022: * }
023: * }
024: * public void main(String[] args) {
025: * // Sets default (global settings).
026: * XMLFormat.setFormat(Foo.class, xFormat);
027: * XMLFormat.setFormat(Bar.class, yFormat);
028: * }
029: * ... // Another thread.
030: * LocalContext.enter();
031: * try { // Use of local context to avoid impacting other threads.
032: * XMLFormat.setFormat(Foo.class, zFormat);
033: * XMLFormat.getInstance(Foo.class); // Returns zFormat
034: * XMLFormat.getInstance(Bar.class); // Returns yFormat (inherited)
035: * } finally {
036: * LocalContext.exit();
037: * }
038: * getInstance(Foo.class); // Returns xFormat
039: * [/code]</p>
040: *
041: * <p> <b>Note:</b> Because key-value mappings are inherited, the semantic of
042: * {@link #remove} and {@link #clear} is slightly modified (associate
043: * <code>null</code> values instead of removing the entries).</p>
044: *
045: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
046: * @version 3.7, January 27, 2005
047: */
048: public final class LocalMap/*<K,V>*/implements Map/*<K,V>*/{
049:
050: /**
051: * Holds the fast map reference (shared map).
052: */
053: private final LocalContext.Reference _mapRef = new LocalContext.Reference(
054: new FastMap().setShared(true));
055:
056: /**
057: * Default constructor.
058: */
059: public LocalMap() {
060: }
061:
062: /**
063: * Sets the key comparator for this local map.
064: *
065: * @param keyComparator the key comparator.
066: * @return <code>this</code>
067: */
068: public LocalMap /*<K,V>*/setKeyComparator(
069: FastComparator/*<? super K>*/keyComparator) {
070: localMap().setKeyComparator(keyComparator);
071: return this ;
072: }
073:
074: /**
075: * Sets the value comparator for this local map.
076: *
077: * @param valueComparator the value comparator.
078: * @return <code>this</code>
079: */
080: public LocalMap/*<K,V>*/setValueComparator(
081: FastComparator/*<? super V>*/valueComparator) {
082: localMap().setValueComparator(valueComparator);
083: return this ;
084: }
085:
086: /**
087: * Sets the default value for the specified key (typically done at
088: * initialization).
089: *
090: * @param key the key with which the specified value is to be associated.
091: * @param defaultValue the default value to be associated with the
092: * specified key.
093: * @return the previous default value associated with specified key, or
094: * <code>null</code> if there was no mapping for key. A
095: * <code>null</code> return can also indicate that the map
096: * previously associated <code>null</code> with the specified key.
097: * @throws NullPointerException if the key is <code>null</code>.
098: */
099: public Object/*{V}*/putDefault(Object/*{K}*/key,
100: Object/*{V}*/defaultValue) {
101: return (Object/*{V}*/) ((FastMap) _mapRef.getDefault()).put(
102: key, defaultValue);
103: }
104:
105: /**
106: * Returns the number of key-value mappings in this map.
107: *
108: * @return this map's size.
109: */
110: public int size() {
111: return ((FastMap) _mapRef.get()).size();
112: }
113:
114: /**
115: * Indicates if this map contains no key-value mappings.
116: *
117: * @return <code>true</code> if this map contains no key-value mappings;
118: * <code>false</code> otherwise.
119: */
120: public boolean isEmpty() {
121: return ((FastMap) _mapRef.get()).isEmpty();
122: }
123:
124: /**
125: * Indicates if this map contains a mapping for the specified key.
126: *
127: * @param key the key whose presence in this map is to be tested.
128: * @return <code>true</code> if this map contains a mapping for the
129: * specified key; <code>false</code> otherwise.
130: * @throws NullPointerException if the key is <code>null</code>.
131: */
132: public boolean containsKey(Object key) {
133: return ((FastMap) _mapRef.get()).containsKey(key);
134: }
135:
136: /**
137: * Indicates if this map associates one or more keys to the
138: * specified value.
139: *
140: * @param value the value whose presence in this map is to be tested.
141: * @return <code>true</code> if this map maps one or more keys to the
142: * specified value.
143: * @throws NullPointerException if the key is <code>null</code>.
144: */
145: public boolean containsValue(Object value) {
146: return ((FastMap) _mapRef.get()).containsValue(value);
147: }
148:
149: /**
150: * Returns the value to which this map associates the specified key.
151: *
152: * @param key the key whose associated value is to be returned.
153: * @return the value to which this map maps the specified key, or
154: * <code>null</code> if there is no mapping for the key.
155: * @throws NullPointerException if key is <code>null</code>.
156: */
157: public Object/*{V}*/get(Object key) {
158: return (Object/*{V}*/) ((FastMap) _mapRef.get()).get(key);
159: }
160:
161: /**
162: * Associates the specified value with the specified key in this map.
163: *
164: * @param key the key with which the specified value is to be associated.
165: * @param value the value to be associated with the specified key.
166: * @return the previous value associated with specified key, or
167: * <code>null</code> if there was no mapping for key. A
168: * <code>null</code> return can also indicate that the map
169: * previously associated <code>null</code> with the specified key.
170: * @throws NullPointerException if the key is <code>null</code>.
171: */
172: public Object/*{V}*/put(Object/*{K}*/key, Object/*{V}*/value) {
173: return (Object/*{V}*/) localMap().put(key, value);
174: }
175:
176: /**
177: * Copies all of the mappings from the specified map to this map.
178: *
179: * @param map the mappings to be stored in this map.
180: * @throws NullPointerException the specified map is <code>null</code>,
181: * or the specified map contains <code>null</code> keys.
182: */
183: public void putAll(Map/*<? extends K, ? extends V>*/map) {
184: localMap().putAll(map);
185: }
186:
187: /**
188: * Removes the mapping for this key from this map if present
189: * (sets the local value to <code>null</code>).
190: *
191: * @param key the key whose value is set to <code>null</code>
192: * @return <code>put(key, null)</code>
193: * @throws NullPointerException if the key is <code>null</code>.
194: */
195: public Object/*{V}*/remove(Object key) {
196: return put((Object/*{K}*/) key, null);
197: }
198:
199: /**
200: * Removes all mappings from this map (sets the local values to
201: * <code>null</code>).
202: */
203: public void clear() {
204: FastMap localMap = localMap();
205: for (FastMap.Entry e = localMap.head(), end = localMap.tail(); (e = (FastMap.Entry) e
206: .getNext()) != end;) {
207: e.setValue(null);
208: }
209: }
210:
211: /**
212: * Returns a {@link FastCollection} view of the keys contained in this map.
213: *
214: * @return a set view of the keys contained in this map
215: * (instance of {@link FastCollection}).
216: */
217: public Set/*<K>*/keySet() {
218: return localMap().keySet();
219: }
220:
221: /**
222: * Returns a {@link FastCollection} view of the values contained in this
223: * map.
224: *
225: * @return a collection view of the values contained in this map
226: * (instance of {@link FastCollection}).
227: */
228: public Collection/*<V>*/values() {
229: return localMap().values();
230: }
231:
232: /**
233: * Returns a {@link FastCollection} view of the mappings contained in this
234: * map.
235: *
236: * @return a collection view of the mappings contained in this map
237: * (instance of {@link FastCollection}).
238: */
239: public Set/*<Map.Entry<K,V>>*/entrySet() {
240: return localMap().entrySet();
241: }
242:
243: /**
244: * Returns the local map or creates one on the stack and populates
245: * it from inherited settings.
246: *
247: * @return a shared fast map belonging to the current local context.
248: */
249: private FastMap/*<K,V>*/localMap() {
250: FastMap localMap = (FastMap) _mapRef.getLocal();
251: return (localMap != null) ? localMap : newLocalMap();
252: }
253:
254: private FastMap newLocalMap() {
255: FastMap parentMap = (FastMap) _mapRef.get();
256: FastMap localMap = FastMap.newInstance();
257: localMap.setShared(true);
258: localMap.setKeyComparator(parentMap.getKeyComparator());
259: localMap.setValueComparator(parentMap.getValueComparator());
260: localMap.putAll(parentMap);
261: _mapRef.set(localMap);
262: return localMap;
263: }
264: }
|