KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ldap > server > db > DisjunctionEnumeration


1 /*
2  * Copyright 2004 The Apache Software Foundation
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 org.apache.ldap.server.db;
18
19
20 import javax.naming.NamingEnumeration JavaDoc;
21 import javax.naming.NamingException JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.NoSuchElementException JavaDoc;
25
26
27 /**
28  * A Cursor of Cursors performing a union on all underlying Cursors resulting
29  * in the disjunction of expressions represented by the constituant child
30  * Cursors. This cursor prefetches underlying Cursor values so that it can
31  * comply with the defined Cursor semantics.
32  *
33  * @author <a HREF="mailto:dev@directory.apache.org">Apache Directory Project</a>
34  * @version $Rev: 169198 $
35  */

36 public class DisjunctionEnumeration implements NamingEnumeration JavaDoc
37 {
38     /** The underlying child enumerations */
39     private final NamingEnumeration JavaDoc [] children;
40     /** LUT used to avoid returning duplicates */
41     private final Map JavaDoc candidates = new HashMap JavaDoc();
42     /** Index of current cursor used */
43     private int index = 0;
44     /** Candidate to return */
45     private final IndexRecord candidate = new IndexRecord();
46     /** Prefetched record returned */
47     private final IndexRecord prefetched = new IndexRecord();
48     /** Used to determine if this enumeration has been exhausted */
49     private boolean hasMore = true;
50
51
52     // ------------------------------------------------------------------------
53
// C O N S T R U C T O R S
54
// ------------------------------------------------------------------------
55

56
57     /**
58      * Creates a DisjunctionEnumeration over a set of child NamingEnumerations.
59      * The returned result is the union of all underlying NamingEnumerations
60      * without duplicates.
61      *
62      * @param children array of child NamingInstances
63      * @throws NamingException if something goes wrong
64      */

65     public DisjunctionEnumeration( NamingEnumeration JavaDoc [] children )
66         throws NamingException JavaDoc
67     {
68         this.children = children;
69
70         // Close this cursor if their are no children.
71
if ( children.length <= 0 )
72         {
73             hasMore = false;
74             return;
75         }
76
77         // Advance to the first cursor that has a candidate for us.
78
while ( ! children[index].hasMore() )
79         {
80             index++;
81
82             // Close and return if we exhaust the cursors without finding a
83
// valid candidate to return.
84
if ( index >= children.length )
85             {
86                 close();
87                 return;
88             }
89         }
90
91         // Grab the next candidate and add it's id to the LUT/hash of candidates
92
IndexRecord rec = ( IndexRecord ) children[index].next();
93         prefetched.copy( rec );
94         candidates.put( rec.getEntryId(), rec.getEntryId() );
95     }
96
97
98     // ------------------------------------------------------------------------
99
// java.util.Enumeration Implementation Methods
100
// ------------------------------------------------------------------------
101

102
103     /**
104      * @see java.util.Enumeration#nextElement()
105      */

106     public Object JavaDoc nextElement()
107     {
108         try
109         {
110             return next();
111         }
112         catch ( NamingException JavaDoc e )
113         {
114             throw new NoSuchElementException JavaDoc();
115         }
116     }
117     
118     
119     /**
120      * @see java.util.Enumeration#hasMoreElements()
121      */

122     public boolean hasMoreElements()
123     {
124         return hasMore();
125     }
126     
127
128     // ------------------------------------------------------------------------
129
// NamingEnumeration Method Implementations
130
// ------------------------------------------------------------------------
131

132
133     /**
134      * Advances this Cursor one position. Duplicates are not returned so if
135      * underlying cursors keep returning duplicates the child cursors will be
136      * advanced until a unique candidate is found or all child cursors are
137      * exhausted.
138      *
139      * @return a candidate element
140      * @throws NamingException if an error occurs
141      */

142     public Object JavaDoc next() throws NamingException JavaDoc
143     {
144         // Store the last prefetched candidate to return in candidate
145
candidate.copy( prefetched );
146
147         do
148         {
149             // Advance to a Cursor that has the next valid candidate for us.
150
while ( ! children[index].hasMore() )
151             {
152                 index++;
153         
154                 /* Close and return existing prefetched candidate if we
155                  * have exhausted the underlying Cursors without finding a
156                  * valid candidate to return.
157                  */

158                 if ( index >= children.length )
159                 {
160                     close();
161                     return candidate;
162                 }
163             }
164
165             // Grab next candidate!
166
IndexRecord rec = ( IndexRecord ) children[index].next();
167             prefetched.copy( rec );
168
169             // Break through do/while if the candidate is seen for the first
170
// time, meaning we have not returned it already.
171
} while ( candidates.containsKey( prefetched.getEntryId() ) );
172
173         // Add candidate to LUT of encountered candidates.
174
candidates.put( candidate.getEntryId(), candidate.getEntryId() );
175
176         // Return the original value saved before overwriting prefetched
177
return candidate;
178     }
179
180
181     /**
182      * Tests if a prefetched value exists and a call to advance will hence
183      * succeed.
184      *
185      * @return true if a call to advance will succeed false otherwise.
186      */

187     public boolean hasMore()
188     {
189         return hasMore;
190     }
191
192
193     /**
194      * Closes all the underlying Cursors and not fail fast. All enumerations
195      * will have close attempts made on them.
196      *
197      * @throws NamingException if we cannot close all enumerations
198      */

199     public void close() throws NamingException JavaDoc
200     {
201         Throwable JavaDoc throwable = null;
202         hasMore = false;
203         
204         for ( int ii = 0; ii < children.length; ii++ )
205         {
206             try
207             {
208                 // Close all children but don't fail fast meaning don't stop
209
// closing all children if one fails to close for some reason.
210
children[ii].close();
211             }
212             catch ( Throwable JavaDoc t )
213             {
214                 throwable = t;
215             }
216         }
217         
218         if ( null != throwable && throwable instanceof NamingException JavaDoc )
219         {
220             throw ( NamingException JavaDoc ) throwable;
221         }
222         else if ( null != throwable )
223         {
224             NamingException JavaDoc ne = new NamingException JavaDoc();
225             ne.setRootCause( throwable );
226             throw ne;
227         }
228     }
229 }
230
Popular Tags