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