1 /**
2 * Copyright Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.store;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Set;
24
25 /**
26 * A Set of keys that will encapsulate keys present in a Cache.
27 * It will <em>mostly</em> behave as an immutable {@link java.util.Set}, but for its {@link #size} method
28 *
29 * @param <E> the type of elements maintained by this set
30 * @author Alex Snaps
31 */
32 public class CacheKeySet<E> implements Set<E> {
33
34 private static final Iterator EMPTY_ITERATOR = new Iterator() {
35 public boolean hasNext() {
36 return false;
37 }
38
39 public Object next() {
40 throw new UnsupportedOperationException();
41 }
42
43 public void remove() {
44 throw new UnsupportedOperationException();
45 }
46 };
47
48 private final Collection<E>[] keySets;
49
50 /**
51 * Create a new Set for all tiers in the cache.
52 * Generally, you'd pass the authority's keySet, and higher layer pinned keySets
53 *
54 * @param keySets an array of keySets
55 */
56 public CacheKeySet(final Collection<E>... keySets) {
57 this.keySets = keySets;
58 }
59
60 /**
61 * Sums the size of all sets wrapped by this one, so this will not account for duplicated keys. Like for in-memory pinned keys, that
62 * might also present in lower tiers: e.g. DiskStore when its capacity isn't reached.
63 * @return the sum of all keySet sizes
64 */
65 public int size() {
66 int size = 0;
67 for (Collection keySet : keySets) {
68 size += keySet.size();
69 }
70 return size;
71 }
72
73 /**
74 * {@inheritDoc}
75 */
76 public boolean isEmpty() {
77
78 for (Collection keySet : keySets) {
79 if (!keySet.isEmpty()) {
80 return false;
81 }
82 }
83 return true;
84 }
85
86 /**
87 * {@inheritDoc}
88 */
89 public boolean contains(final Object o) {
90
91 for (Collection keySet : keySets) {
92 if (keySet.contains(o)) {
93 return true;
94 }
95 }
96 return false;
97 }
98
99 /**
100 * {@inheritDoc}
101 */
102 public Iterator<E> iterator() {
103 return new KeySetIterator();
104 }
105
106 /**
107 * {@inheritDoc}
108 */
109 public Object[] toArray() {
110 List<E> list = new ArrayList<E>();
111 for (E e : this) {
112 list.add(e);
113 }
114 return list.toArray();
115 }
116
117 /**
118 * {@inheritDoc}
119 */
120 public <T> T[] toArray(final T[] a) {
121 List<E> list = new ArrayList<E>();
122 for (E e : this) {
123 list.add(e);
124 }
125 return list.toArray(a);
126 }
127
128 /**
129 * You can't add to this set, will throw!
130 * @throws UnsupportedOperationException
131 */
132 public boolean add(final Object o) {
133 throw new UnsupportedOperationException();
134 }
135
136 /**
137 * You can't remove from this set, will throw!
138 * @throws UnsupportedOperationException
139 */
140 public boolean remove(final Object o) {
141 throw new UnsupportedOperationException();
142 }
143
144 /**
145 * {@inheritDoc}
146 */
147 public boolean containsAll(final Collection<?> c) {
148 for (Object o : c) {
149 if (!contains(o)) {
150 return false;
151 }
152 }
153 return true;
154 }
155
156 /**
157 * You can't add to this set, will throw!
158 * @throws UnsupportedOperationException
159 */
160 public boolean addAll(final Collection c) {
161 throw new UnsupportedOperationException();
162 }
163
164 /**
165 * You can't remove from this set, will throw!
166 * @throws UnsupportedOperationException
167 */
168 public boolean removeAll(final Collection<?> c) {
169 throw new UnsupportedOperationException();
170 }
171
172 /**
173 * You can't remove from this set, will throw!
174 * @throws UnsupportedOperationException
175 */
176 public boolean retainAll(final Collection<?> c) {
177 throw new UnsupportedOperationException();
178 }
179
180 /**
181 * You can't remove from this set, will throw!
182 * @throws UnsupportedOperationException
183 */
184 public void clear() {
185 throw new UnsupportedOperationException();
186 }
187
188 /**
189 * An iterator that will iterate over all keySets, avoiding duplicate entries
190 */
191 private final class KeySetIterator implements Iterator<E> {
192
193 private Iterator<E> currentIterator;
194 private int index = 0;
195 private E next;
196 private E current;
197
198 private KeySetIterator() {
199 if (keySets.length == 0) {
200 this.currentIterator = EMPTY_ITERATOR;
201 } else {
202 this.currentIterator = keySets[0].iterator();
203 }
204 advance();
205 }
206
207 /**
208 * {@inheritDoc}
209 */
210 public boolean hasNext() {
211 return next != null;
212 }
213
214 /**
215 * {@inheritDoc}
216 */
217 public E next() {
218 current = next;
219 advance();
220 return current;
221 }
222
223 private void advance() {
224 next = null;
225 while (next == null) {
226 if (currentIterator.hasNext()) {
227 next = currentIterator.next();
228 for (int i = 0; i < index; i++) {
229 if (keySets[i].contains(next)) {
230 next = null;
231 }
232 }
233 } else {
234 next = null;
235 if (++index < keySets.length) {
236 currentIterator = keySets[index].iterator();
237 } else {
238 return;
239 }
240 }
241 }
242 }
243
244 /**
245 * {@inheritDoc}
246 */
247 public void remove() {
248 throw new UnsupportedOperationException();
249 }
250 }
251 }
252