1   package com.trendmicro.grid.acl.ds.cache.commands;
2   
3   import java.util.*;
4   import java.util.concurrent.Callable;
5   
6   import static net.sf.tinyjee.util.Assert.assertEquals;
7   
8   /**
9    * Defines the base for cache commands.
10   *
11   * @author juergen_kellerer, 2011-03-24
12   * @version 1.0
13   */
14  public abstract class AbstractCommand<K, V> implements Callable<Map<K, V>> {
15  
16  	protected Collection<K> keys;
17  
18  	protected AbstractCommand(Collection<K> keys) {
19  		this.keys = keys;
20  	}
21  
22  	/**
23  	 * Converts the keys to a map that may be returned with {@link #call()}.
24  	 *
25  	 * @return a map containing the command's key mapped against 'null'.
26  	 */
27  	protected Map<K, V> keysToCallResult() {
28  		return new MapAdapter<K, V>(keys, Collections.nCopies(keys.size(), (V) null));
29  	}
30  
31  	/**
32  	 * Adapts a key and corresponding values collection to a map.
33  	 * <p/>
34  	 * The implementation does not copy any of the collections.
35  	 *
36  	 * @param <K> the keys of the map.
37  	 * @param <V> the values of the map.
38  	 */
39  	protected static final class MapAdapter<K, V> extends AbstractMap<K, V> {
40  
41  		private final Collection<K> keys;
42  		private final Collection<V> values;
43  		private final Set<Entry<K, V>> entries;
44  
45  		public MapAdapter(Collection<K> keys, Collection<V> values) {
46  			assertEquals("keys#size() != values#size()", keys.size(), values.size());
47  			this.keys = keys;
48  			this.values = values;
49  
50  			entries = new AbstractSet<Entry<K, V>>() {
51  				@Override
52  				public Iterator<Entry<K, V>> iterator() {
53  					return new Iterator<Entry<K, V>>() {
54  
55  						final Iterator<K> kI = MapAdapter.this.keys.iterator();
56  						final Iterator<V> vI = MapAdapter.this.values.iterator();
57  
58  						@Override
59  						public boolean hasNext() {
60  							return kI.hasNext();
61  						}
62  
63  						@Override
64  						public Entry<K, V> next() {
65  							return new SimpleImmutableEntry<K, V>(kI.next(), vI.next());
66  						}
67  
68  						@Override
69  						public void remove() {
70  							kI.remove();
71  							vI.remove();
72  						}
73  					};
74  				}
75  
76  				@Override
77  				public int size() {
78  					return MapAdapter.this.keys.size();
79  				}
80  
81  				@Override
82  				public boolean isEmpty() {
83  					return MapAdapter.this.keys.isEmpty();
84  				}
85  			};
86  		}
87  
88  		@Override
89  		public Set<K> keySet() {
90  			return keys instanceof Set ? (Set<K>) keys :
91  					new AbstractSet<K>() {
92  						@Override
93  						public Iterator<K> iterator() {
94  							return keys.iterator();
95  						}
96  
97  						@Override
98  						public int size() {
99  							return keys.size();
100 						}
101 					};
102 		}
103 
104 		@Override
105 		public Collection<V> values() {
106 			return values;
107 		}
108 
109 		@Override
110 		public Set<Entry<K, V>> entrySet() {
111 			return entries;
112 		}
113 	}
114 
115 	/**
116 	 * Is a map implementation that has the same performance characteristics as ArrayList or
117 	 * LinkedList (depending on the constructor) for puts and iterations, at the cost that it does not
118 	 * guarantee uniqueness of key and values pairs and does not offer indexed key access.
119 	 * <p/>
120 	 * Do not use it as general purpose map as it violates uniqueness and is efficient only in
121 	 * iterating and building the map entries.
122 	 */
123 	protected static final class NonUniqueMap<K, V> extends AbstractMap<K, V> {
124 
125 		protected static class ArraySet<E> extends ArrayList<E> implements Set<E> {
126 			private static final long serialVersionUID = -5172793228894213934L;
127 
128 			private ArraySet(int initialCapacity) {
129 				super(initialCapacity);
130 			}
131 		}
132 
133 		protected static class LinkedSet<E> extends LinkedList<E> implements Set<E> {
134 			private static final long serialVersionUID = -5172793228894213934L;
135 		}
136 
137 		private final Set<Entry<K, V>> entries;
138 		private boolean readonly;
139 
140 		protected NonUniqueMap() {
141 			entries = new LinkedSet<Entry<K, V>>();
142 		}
143 
144 		protected NonUniqueMap(int capacity) {
145 			entries = new ArraySet<Entry<K, V>>(capacity);
146 		}
147 
148 		/**
149 		 * Makes the map readonly.
150 		 */
151 		protected void makeReadonly() {
152 			this.readonly = true;
153 		}
154 
155 		@Override
156 		public V put(K key, V value) {
157 			if (readonly)
158 				throw new UnsupportedOperationException();
159 			entries.add(new SimpleEntry<K, V>(key, value));
160 			return null;
161 		}
162 
163 		@Override
164 		public Set<Entry<K, V>> entrySet() {
165 			return entries;
166 		}
167 	}
168 }