1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.partition.impl.btree;
18
19
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.NoSuchElementException;
23
24 import javax.naming.NamingEnumeration;
25 import javax.naming.NamingException;
26
27
28 /***
29 * A Cursor of Cursors performing a union on all underlying Cursors resulting
30 * in the disjunction of expressions represented by the constituant child
31 * Cursors. This cursor prefetches underlying Cursor values so that it can
32 * comply with the defined Cursor semantics.
33 *
34 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
35 * @version $Rev: 264732 $
36 */
37 public class DisjunctionEnumeration implements NamingEnumeration
38 {
39 /*** The underlying child enumerations */
40 private final NamingEnumeration [] children;
41 /*** LUT used to avoid returning duplicates */
42 private final Map candidates = new HashMap();
43 /*** Index of current cursor used */
44 private int index = 0;
45 /*** Candidate to return */
46 private final IndexRecord candidate = new IndexRecord();
47 /*** Prefetched record returned */
48 private final IndexRecord prefetched = new IndexRecord();
49 /*** Used to determine if this enumeration has been exhausted */
50 private boolean hasMore = true;
51
52
53
54
55
56
57
58 /***
59 * Creates a DisjunctionEnumeration over a set of child NamingEnumerations.
60 * The returned result is the union of all underlying NamingEnumerations
61 * without duplicates.
62 *
63 * @param children array of child NamingInstances
64 * @throws NamingException if something goes wrong
65 */
66 public DisjunctionEnumeration( NamingEnumeration [] children )
67 throws NamingException
68 {
69 this.children = children;
70
71
72 if ( children.length <= 0 )
73 {
74 hasMore = false;
75 return;
76 }
77
78
79 while ( ! children[index].hasMore() )
80 {
81 index++;
82
83
84
85 if ( index >= children.length )
86 {
87 close();
88 return;
89 }
90 }
91
92
93 IndexRecord rec = ( IndexRecord ) children[index].next();
94 prefetched.copy( rec );
95 candidates.put( rec.getEntryId(), rec.getEntryId() );
96 }
97
98
99
100
101
102
103
104 /***
105 * @see java.util.Enumeration#nextElement()
106 */
107 public Object nextElement()
108 {
109 try
110 {
111 return next();
112 }
113 catch ( NamingException e )
114 {
115 throw new NoSuchElementException();
116 }
117 }
118
119
120 /***
121 * @see java.util.Enumeration#hasMoreElements()
122 */
123 public boolean hasMoreElements()
124 {
125 return hasMore();
126 }
127
128
129
130
131
132
133
134 /***
135 * Advances this Cursor one position. Duplicates are not returned so if
136 * underlying cursors keep returning duplicates the child cursors will be
137 * advanced until a unique candidate is found or all child cursors are
138 * exhausted.
139 *
140 * @return a candidate element
141 * @throws NamingException if an error occurs
142 */
143 public Object next() throws NamingException
144 {
145
146 candidate.copy( prefetched );
147
148 do
149 {
150
151 while ( ! children[index].hasMore() )
152 {
153 index++;
154
155
156
157
158
159 if ( index >= children.length )
160 {
161 close();
162 return candidate;
163 }
164 }
165
166
167 IndexRecord rec = ( IndexRecord ) children[index].next();
168 prefetched.copy( rec );
169
170
171
172 } while ( candidates.containsKey( prefetched.getEntryId() ) );
173
174
175 candidates.put( candidate.getEntryId(), candidate.getEntryId() );
176
177
178 return candidate;
179 }
180
181
182 /***
183 * Tests if a prefetched value exists and a call to advance will hence
184 * succeed.
185 *
186 * @return true if a call to advance will succeed false otherwise.
187 */
188 public boolean hasMore()
189 {
190 return hasMore;
191 }
192
193
194 /***
195 * Closes all the underlying Cursors and not fail fast. All enumerations
196 * will have close attempts made on them.
197 *
198 * @throws NamingException if we cannot close all enumerations
199 */
200 public void close() throws NamingException
201 {
202 Throwable throwable = null;
203 hasMore = false;
204
205 for ( int ii = 0; ii < children.length; ii++ )
206 {
207 try
208 {
209
210
211 children[ii].close();
212 }
213 catch ( Throwable t )
214 {
215 throwable = t;
216 }
217 }
218
219 if ( null != throwable && throwable instanceof NamingException )
220 {
221 throw ( NamingException ) throwable;
222 }
223 else if ( null != throwable )
224 {
225 NamingException ne = new NamingException();
226 ne.setRootCause( throwable );
227 throw ne;
228 }
229 }
230 }