View Javadoc

1   /*
2    * Created on 9 Nov 2007
3    *
4    */
5   package org.sourceforge.jemm.collections;
6   
7   import java.util.Collection;
8   import java.util.Map;
9   import java.util.Set;
10  import java.util.concurrent.ConcurrentMap;
11  
12  import org.sourceforge.jemm.collections.internal.ClearRequest;
13  import org.sourceforge.jemm.collections.internal.ContainsRequest;
14  import org.sourceforge.jemm.collections.internal.ContainsResponse;
15  import org.sourceforge.jemm.collections.internal.SizeRequest;
16  import org.sourceforge.jemm.collections.internal.SizeResponse;
17  import org.sourceforge.jemm.collections.internal.StoredValue;
18  import org.sourceforge.jemm.collections.internal.map.ContainsValueRequest;
19  import org.sourceforge.jemm.collections.internal.map.MapGetRequest;
20  import org.sourceforge.jemm.collections.internal.map.MapGetResponse;
21  import org.sourceforge.jemm.collections.internal.map.MapKeySetRequest;
22  import org.sourceforge.jemm.collections.internal.map.MapKeySetResponse;
23  import org.sourceforge.jemm.collections.internal.map.MapPutIfAbsentRequest;
24  import org.sourceforge.jemm.collections.internal.map.MapPutIfAbsentResponse;
25  import org.sourceforge.jemm.collections.internal.map.MapPutRequest;
26  import org.sourceforge.jemm.collections.internal.map.MapPutResponse;
27  import org.sourceforge.jemm.collections.internal.map.MapRemoveKVRequest;
28  import org.sourceforge.jemm.collections.internal.map.MapRemoveKVResponse;
29  import org.sourceforge.jemm.collections.internal.map.MapRemoveRequest;
30  import org.sourceforge.jemm.collections.internal.map.MapRemoveResponse;
31  import org.sourceforge.jemm.collections.internal.map.MapReplaceKONRequest;
32  import org.sourceforge.jemm.collections.internal.map.MapReplaceKONResponse;
33  import org.sourceforge.jemm.collections.internal.map.MapReplaceKVRequest;
34  import org.sourceforge.jemm.collections.internal.map.MapReplaceKVResponse;
35  import org.sourceforge.jemm.collections.internal.map.MapValuesRequest;
36  import org.sourceforge.jemm.collections.internal.map.MapValuesResponse;
37  import org.sourceforge.jemm.lifecycle.ShadowTypeObject;
38  import org.sourceforge.jemm.util.JEMMType;
39  
40  /**
41   * JemmMap is a map implementation designed for use with the JEMM architecture.
42   * 
43   * @author Rory Graves
44   *
45   * @param <K> The map key type 
46   * @param <V> The map data type
47   * 
48   */
49  public final class JemmMap<K, V> extends JEMMType implements ConcurrentMap<K, V> {
50  
51      /**
52       * Creates a JemmMap.
53       */
54      public JemmMap() {
55          super();
56      }
57      
58      /** Internally JEMM used constructor
59       * @param jemmOIF The underlying shadow object 
60       */
61      protected JemmMap(ShadowTypeObject jemmOIF) {
62          super(jemmOIF);
63      }
64  
65      public void clear() {
66          jemmOIF.processRequest(new ClearRequest());
67      }
68  
69      public boolean containsKey(final Object uKey) {
70          ContainsResponse result = (ContainsResponse) jemmOIF.processRequest(new ContainsRequest(uKey));
71          if(result.isFound())
72          	return true;
73          else
74          	if(result.getPossibles() != null)
75          		for (Object possible : result.getPossibles())
76          			if(uKey.equals(possible))
77          				return true;        				
78  		return false;
79      }
80  
81      public boolean containsValue(final Object value) {
82          ContainsResponse result = (ContainsResponse) jemmOIF.processRequest(new ContainsValueRequest(value));
83          if(result.isFound())
84          	return true;
85          else
86          	if(result.getPossibles() != null)
87          		for (Object possible : result.getPossibles())
88          			if(value.equals(possible))
89          				return true;        				
90  		return false;
91      }
92  
93      /**
94       * entrySet() is not supported by JemmMap
95       */
96      public Set<java.util.Map.Entry<K, V>> entrySet() {
97          throw new UnsupportedOperationException();
98      }        
99  
100     @SuppressWarnings("unchecked")
101 	public V get(final Object uKey) {
102     	StoredValue key = new StoredValue(uKey);
103     	MapGetRequest req = new MapGetRequest(key);
104     	while(true) {
105     		MapGetResponse resp = (MapGetResponse) jemmOIF.processRequest(req);
106     		if(resp.isFound())
107     			return (V) resp.getValue();
108     		
109     		if(!resp.hasPossibleMatches())
110     			return null;
111     		
112     		StoredValue newKey = null;
113     		StoredValue[] possibleMatches = resp.getPossibleMatches();
114     		for(int i=0; i<possibleMatches.length && newKey == null; i++)
115     			if(possibleMatches[i].equals(key))
116     				newKey = possibleMatches[i];
117     		
118     		if(newKey == null)
119     			return null;
120     		else
121     			req = new MapGetRequest(newKey);
122     	}
123     }
124 
125     public boolean isEmpty() {
126     	return size() == 0;
127     }
128 
129     @SuppressWarnings("unchecked")
130 	public Set<K> keySet() {
131     	return (Set<K>) ((MapKeySetResponse) jemmOIF.processRequest(new MapKeySetRequest())).getKeySet();
132     }
133 
134     @SuppressWarnings("unchecked")
135 	public V put(K uKey, V uValue) {
136     	
137     	StoredValue sKey = new StoredValue(uKey);
138     	StoredValue sValue = new StoredValue(uValue);
139     	
140 		MapPutRequest req = new MapPutRequest(sKey,sValue,null);
141     	while(true) {
142             MapPutResponse response = (MapPutResponse) jemmOIF.processRequest(req);
143             if(response.isSuccess())
144             	return (V) response.getPreviousValue();
145 
146             StoredValue keyTarget = null;
147             StoredValue[] possibleMatches = response.getPossibleMatches();
148             for(int i=0; i<possibleMatches.length && keyTarget==null; i++)
149             	if(possibleMatches[i].equals(sKey))
150             		keyTarget = possibleMatches[i];
151             
152             if(keyTarget == null)
153             	req = new MapPutRequest(sKey,sValue,possibleMatches);
154             else
155             	req = new MapPutRequest(keyTarget,sValue,null);
156     	}    	
157     }
158 
159     /**
160      * Not Supported.
161      */
162     public void putAll(Map<? extends K, ? extends V> t) {        
163         // operation not supported at present
164         throw new UnsupportedOperationException();
165     }
166 
167     @SuppressWarnings("unchecked")
168 	public V remove(Object uKey) {
169     	StoredValue key = new StoredValue(uKey);
170     	
171     	MapRemoveRequest req = new MapRemoveRequest(key);
172     	while(true) {
173     		MapRemoveResponse resp = (MapRemoveResponse) jemmOIF.processRequest(req);
174     		if(resp.isRemoved())
175     			return (V) resp.getOldValue();
176     		else {
177     			StoredValue[] potentialMatches = resp.getPotentialMatches();
178     			if(potentialMatches == null)
179     				return null;
180     			
181     			StoredValue match = null;
182     			for(int i=0; i<potentialMatches.length && match == null; i++)
183     				if(key.equals(potentialMatches[i]))
184     					match = potentialMatches[i];
185     					
186     			if(match == null)
187     				return null; 
188     			
189     			req = new MapRemoveRequest(match);
190     		}
191     	}
192 
193     }
194 
195     public int size() {
196     	return ((SizeResponse) jemmOIF.processRequest(new SizeRequest())).getSize();
197     }
198 
199     @SuppressWarnings("unchecked")
200 	public Collection<V> values() {
201     	return (Collection<V>) ((MapValuesResponse) jemmOIF.processRequest(new MapValuesRequest())).getValues();
202     }
203 
204     @SuppressWarnings("unchecked")
205 	public V putIfAbsent(K uKey, V uValue) {
206     	
207     	StoredValue key = new StoredValue(uKey);
208     	StoredValue value = new StoredValue(uValue);
209     	    	
210     	MapPutIfAbsentRequest req = new MapPutIfAbsentRequest(key,value,null);
211     	while(true) {
212     		MapPutIfAbsentResponse resp = (MapPutIfAbsentResponse) jemmOIF.processRequest(req);
213     		if(resp.wasPut() || resp.getPossibleMatches() == null)
214     			return (V) resp.getPreviousValue();
215     		
216     		StoredValue[] possibles = resp.getPossibleMatches();
217     		Object[] possibleValues = resp.getPossibleValues();
218     		for (int i = 0; i < possibles.length; i++) {
219 				StoredValue possible = possibles[i];
220 				if(possible.equals(key))
221 					return (V) possibleValues[i];
222 			}
223     		
224     		req = new MapPutIfAbsentRequest(key,value,possibles);
225     	}
226     }
227 
228     public boolean remove(Object uKey, Object uValue) {
229     	
230     	StoredValue key = new StoredValue(uKey);
231     	StoredValue value = new StoredValue(uValue);
232     	
233     	
234     	MapRemoveKVRequest req = new MapRemoveKVRequest(key,value);
235     	while(true) {
236     		MapRemoveKVResponse resp = (MapRemoveKVResponse) jemmOIF.processRequest(req);
237     		if(resp.isSuccess())
238     			return true;
239     		
240     		if(!resp.hasPotentials())
241     			return false;
242 
243     		StoredValue potentialKeys[] = resp.getPotentialKeyMatches();
244     		StoredValue potentialValues[] = resp.getPotentialValueMatches();
245     		
246     		StoredValue newKey= null;
247     		StoredValue newValue = null;
248     		
249     		for (int i = 0; i < potentialKeys.length && newKey == null; i++) {
250 				if(potentialKeys[i].equals(key)) {
251 					if(potentialValues[i].equals(value)) {
252 						newKey = potentialKeys[i];
253 						newValue = potentialValues[i];
254 					} else
255 						return false;
256 				}
257 			}
258     		
259     		if(newKey == null)
260     			return false;
261     		
262     		req = new MapRemoveKVRequest(newKey,newValue);
263     	}
264     }
265 
266     @SuppressWarnings("unchecked")
267 	public V replace(K uKey, V uValue) {
268     	StoredValue key = new StoredValue(uKey);
269     	StoredValue value = new StoredValue(uValue);
270     	
271     	MapReplaceKVRequest req = new MapReplaceKVRequest(key,value);
272     	while(true) {
273     		MapReplaceKVResponse resp = (MapReplaceKVResponse) jemmOIF.processRequest(req);
274     		if(resp.isSuccess())
275     			return (V) resp.getOldValue();
276     		
277     		if(!resp.hasPotentialKeyMatches())
278     			return null;
279     		
280     		StoredValue newKey = null;
281     		
282     		StoredValue[] potentialKeyMatches = resp.getPotentialKeyMatches();
283     		for (int i = 0; i < potentialKeyMatches.length && newKey != null; i++) {
284 				if(potentialKeyMatches[i].equals(key))
285 					newKey = potentialKeyMatches[i];
286 			}
287     		
288     		if(newKey == null)
289     			return null;
290     		
291     		req = new MapReplaceKVRequest(newKey,value);    		
292     	}
293     }
294 
295     public boolean replace(K uKey, V uOldValue, V uNewValue) {
296     	StoredValue key = new StoredValue(uKey);
297     	StoredValue oldValue = new StoredValue(uOldValue);
298     	final StoredValue newValue = new StoredValue(uNewValue);
299     	
300     	MapReplaceKONRequest req = new MapReplaceKONRequest(key,oldValue,newValue);
301     	while(true) {
302     		MapReplaceKONResponse resp = (MapReplaceKONResponse) jemmOIF.processRequest(req);
303     		if(resp.isSuccess())
304     			return true;
305     		
306     		if(!resp.hasPotentialKeyMatches())
307     			return false;
308     		
309     		StoredValue newKey = null;
310     		StoredValue newOldValue = null;
311     		
312     		StoredValue[] potentialKeyMatches = resp.getPotentialKeyMatches();
313     		StoredValue[] potentialValueMatches = resp.getPotentialValueMatches();
314     		
315     		for (int i = 0; i < potentialKeyMatches.length && newKey != null; i++) {
316 				if(potentialKeyMatches[i].equals(key)) {
317 					if(!potentialValueMatches[i].equals(oldValue))
318 						return false;
319 					
320 					newKey = potentialKeyMatches[i];
321 					newOldValue = potentialValueMatches[i];
322 				}
323 			}
324     		
325     		if(newKey == null)
326     		    return false;
327     		req = new MapReplaceKONRequest(newKey,newOldValue,newValue);
328     	}
329     }
330 }