1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.db;
18
19
20 import javax.naming.NamingEnumeration;
21 import javax.naming.NamingException;
22 import java.util.*;
23
24
25 /***
26 * NamingEnumeration that enumerates over duplicate values nested into a value
27 * using a TreeSet.
28 *
29 * @warning The Tuple returned by this listing is always the same instance
30 * object returned every time. It is reused to for the sake of efficency rather
31 * than creating a new tuple for each next() call.
32 *
33 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
34 * @version $Rev: 159259 $
35 */
36 public class DupsEnumeration implements NamingEnumeration
37 {
38 /*** Marker for whether or not next() will return successfully */
39 private boolean hasMore = true;
40 /*** The Tuple to return */
41 private final Tuple returned = new Tuple();
42 /*** The Tuple to store prefetched values with */
43 private final Tuple prefetched = new Tuple();
44 /*** The underlying no duplicates enumeration this enum expands out */
45 private final NoDupsEnumeration underlying;
46
47 /***
48 * The current Tuple returned from the underlying NoDupsEnumeration which
49 * contains TreeSets for Tuple values. A NoDupsEnumeration on a Table that
50 * allows duplicates essentially returns Strings for keys and TreeSets for
51 * their values.
52 */
53 private Tuple duplicates;
54 /***
55 * The iterator over a set of Tuple values with the same key. Basically
56 * iterates over the TreeSet values in the duplicates Tuple.
57 */
58 private Iterator dupIterator;
59
60
61
62
63
64
65
66 /***
67 * Creates a DupsEnumeration over a enumeration of Tuples holding TreeSets
68 * for values that have the same key.
69 *
70 * @param list the underlying enumeration
71 * @throws NamingException if there is a problem
72 */
73 public DupsEnumeration( NoDupsEnumeration list ) throws NamingException
74 {
75 underlying = list;
76
77
78 if ( ! underlying.hasMore() )
79 {
80 close();
81 return;
82 }
83
84 prefetch();
85 }
86
87
88
89
90
91
92
93 /***
94 * Returns the same Tuple every time but with different key/value pairs.
95 *
96 * @see javax.naming.NamingEnumeration#next()
97 */
98 public Object next() throws NamingException
99 {
100 returned.setKey( prefetched.getKey() );
101 returned.setValue( prefetched.getValue() );
102
103 prefetch();
104
105 return returned;
106 }
107
108
109 /***
110 * Returns the same Tuple every time but with different key/value pairs.
111 *
112 * @see java.util.Enumeration#nextElement()
113 */
114 public Object nextElement()
115 {
116 try
117 {
118 return next();
119 }
120 catch ( NamingException ne )
121 {
122 throw new NoSuchElementException();
123 }
124 }
125
126
127 /***
128 * @see javax.naming.NamingEnumeration#hasMore()
129 */
130 public boolean hasMore()
131 {
132 return hasMore;
133 }
134
135
136 /***
137 * Calls hasMore.
138 *
139 * @see java.util.Enumeration#hasMoreElements()
140 */
141 public boolean hasMoreElements()
142 {
143 return hasMore;
144 }
145
146
147 /***
148 * Closes the underlying NamingEnumeration
149 *
150 * @see javax.naming.NamingEnumeration#close()
151 */
152 public void close()
153 {
154 hasMore = false;
155 underlying.close();
156 }
157
158
159
160
161
162
163
164 /***
165 * Prefetches values into the prefetched Tuple taking into account that
166 * the returned Tuple values of the underlying enumeration list are really
167 * TreeSets that hold multiple sorted values for the same key.
168 *
169 * <p> The values prefetched into the prefetched Tuple are actual values
170 * taken from the TreeSet. So this NamingEnumeration simply expands out
171 * duplicate keyed Tuples which it returns. iterator is an iteration over
172 * the values held in the TreeSet returned by the underlying enumeration.
173 * The values pulled off of this iterator are put into prefetched.
174 * </p>
175 *
176 * @throws NamingException TODO
177 */
178 private void prefetch() throws NamingException
179 {
180
181
182
183
184 while ( null == dupIterator || ! dupIterator.hasNext() )
185 {
186
187
188
189
190 if ( underlying.hasMore() )
191 {
192 duplicates = ( Tuple ) underlying.next();
193 TreeSet set = ( TreeSet ) duplicates.getValue();
194
195 if ( underlying.doAscendingScan() )
196 {
197 dupIterator = set.iterator();
198 }
199 else
200 {
201
202
203
204
205
206
207
208
209 ArrayList list = new ArrayList( set.size() );
210 list.addAll( set );
211 Collections.reverse( list );
212 dupIterator = list.iterator();
213 }
214 }
215 else
216 {
217 close();
218 return;
219 }
220 }
221
222
223
224
225
226
227
228
229 prefetched.setKey( duplicates.getKey() );
230 prefetched.setValue( dupIterator.next() );
231 }
232 }