KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > indexing > IndexCursor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.indexing;
12
13 public class IndexCursor {
14
15     private IndexedStore store;
16     private ObjectAddress anchorAddress;
17     private int entryNumber;
18     private IndexNode leafNode;
19     private boolean entryRemoved;
20
21     /**
22      * Constructor for an IndexCursor. Cursors should only be constructed
23      * by the index during an open operation.
24      */

25     IndexCursor(IndexedStore store, ObjectAddress anchorAddress) {
26         this.anchorAddress = anchorAddress;
27         this.store = store;
28         this.leafNode = null;
29         this.entryNumber = -1;
30     }
31
32     /**
33      * Adjusts the position of a cursor to point to a "real" entry
34      * entry if it is pointing outside of the entries of a node.
35      * If there are no more entries then unset the cursor.
36      */

37     private void adjust() throws IndexedStoreException {
38         if (leafNode == null)
39             return;
40         if (entryNumber >= leafNode.getNumberOfEntries()) {
41             ObjectAddress next = leafNode.getNextAddress();
42             int n = entryNumber - leafNode.getNumberOfEntries();
43             set(next, n);
44         } else if (entryNumber < 0) {
45             ObjectAddress previous = leafNode.getPreviousAddress();
46             int n = entryNumber;
47             set(previous, n);
48         } else {
49         }
50     }
51
52     /**
53      * Closes the cursor. This unsets the cursor and deregisters it from all the
54      * interested parties.
55      */

56     public void close() throws IndexedStoreException {
57         reset();
58     }
59
60     /**
61      * Adjusts a cursor if there is a need after an entry is inserted.
62      * If not, it just returns.
63      */

64     void entryInserted(int i) throws IndexedStoreException {
65         if (entryNumber >= i)
66             entryNumber++;
67         adjust();
68     }
69
70     /**
71      * Adjusts a cursor if there is a need after an entry is removed.
72      */

73     void entryRemoved(int i) throws IndexedStoreException {
74         entryRemoved = (entryNumber == i);
75         if (entryNumber > i)
76             entryNumber--;
77         adjust();
78     }
79
80     /**
81      * Sets the cursor at the first entry of an index whose key is
82      * greater than or equal to that of the argument. Returns the cursor itself
83      * for convenience in chaining method invocations.
84      */

85     public synchronized IndexCursor find(byte[] b) throws IndexedStoreException {
86         IndexAnchor anchor = store.acquireAnchor(anchorAddress);
87         anchor.find(b, this);
88         anchor.release();
89         entryRemoved = false;
90         return this;
91     }
92
93     /**
94      * Sets the cursor at the first entry of an index whose key is
95      * greater than or equal to that of the argument. Returns the cursor itself
96      * for convenience in chaining method invocations.
97      */

98     public synchronized IndexCursor find(String JavaDoc s) throws IndexedStoreException {
99         return find(Convert.toUTF8(s));
100     }
101
102     /**
103      * Sets the cursor at the first entry of an index.
104      */

105     public synchronized IndexCursor findFirstEntry() throws IndexedStoreException {
106         IndexAnchor anchor = store.acquireAnchor(anchorAddress);
107         anchor.findFirstEntry(this);
108         anchor.release();
109         entryRemoved = false;
110         return this;
111     }
112
113     /**
114      * Returns the byte array holding the key for the current cursor location.
115      * If the cursor is at the beginning or end of the index then return null.
116      *
117      * Throws an EntryRemoved condition if the entry at which it has
118      * been pointing has been removed by another cursor.
119      */

120     public synchronized byte[] getKey() throws IndexedStoreException {
121         if (entryRemoved)
122             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
123         if (leafNode == null)
124             return null;
125         byte[] key = leafNode.getKey(entryNumber);
126         return key;
127     }
128
129     /**
130      * Returns the byte array holding the value for the current cursor location. If the cursor is
131      * at the beginning or end of the index then return null.
132      *
133      * Throws an EntryRemoved condition if the entry at which it has
134      * been pointing has been removed by another cursor.
135      */

136     public synchronized byte[] getValue() throws IndexedStoreException {
137         if (entryRemoved)
138             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
139         if (leafNode == null)
140             return null;
141         byte[] value = leafNode.getValue(entryNumber);
142         return value;
143     }
144
145     /**
146      * Returns the value as an object address. May return null if the cursor is at the beginning
147      * or end of the index.
148      */

149     ObjectAddress getValueAsObjectAddress() throws IndexedStoreException {
150         byte[] value = getValue();
151         if (value == null)
152             return null;
153         return new ObjectAddress(value);
154     }
155
156     /**
157      * Returns the ObjectID from the value for the current cursor location.
158      * If the cursor is at the beginning or end of the index then return null.
159      */

160     public synchronized ObjectID getValueAsObjectID() throws IndexedStoreException {
161         byte[] value = getValue();
162         if (value == null)
163             return null;
164         return new ObjectID(value);
165     }
166
167     /**
168      * This method returns true if the current cursor location before the first entry in the index.
169      */

170     public synchronized boolean isAtBeginning() throws IndexedStoreException {
171         if (entryRemoved)
172             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
173         return (leafNode == null);
174     }
175
176     /**
177      * Returns true if the cursor is set to an entry.
178      * Returns false otherwise.
179      */

180     public synchronized boolean isSet() throws IndexedStoreException {
181         if (entryRemoved)
182             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
183         return !(leafNode == null);
184     }
185
186     /**
187      * Compares a byte array to the key in the cursor and
188      * returns true if the byte array is equal to the key at the entry in the cursor.
189      *
190      * Throws an EntryRemoved condition if the entry at which it has
191      * been pointing has been removed by another cursor.
192      */

193     public synchronized boolean keyEquals(byte[] b) throws IndexedStoreException {
194         if (entryRemoved)
195             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
196         if (leafNode == null)
197             return false;
198         byte[] key = leafNode.getKey(entryNumber);
199         if (b.length != key.length) {
200             return false;
201         }
202         for (int i = 0; i < b.length; i++) {
203             if (key[i] != b[i]) {
204                 return false;
205             }
206         }
207         return true;
208     }
209
210     /**
211      * Compares a byte array to the key in the cursor and
212      * returns true if the byte array is a prefix
213      * of the key at the entry in the cursor.
214      *
215      * Throws an EntryRemoved condition if the entry at which it has
216      * been pointing has been removed by another cursor.
217      */

218     public synchronized boolean keyMatches(byte[] b) throws IndexedStoreException {
219         if (entryRemoved)
220             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
221         if (leafNode == null)
222             return false;
223         byte[] key = leafNode.getKey(entryNumber);
224         if (key.length < b.length) {
225             return false;
226         }
227         for (int i = 0; i < b.length; i++) {
228             if (key[i] != b[i]) {
229                 return false;
230             }
231         }
232         return true;
233     }
234
235     /**
236      * Compares a String to the key in the cursor and
237      * returns true if the byte array is a prefix
238      * of the key at the entry in the cursor.
239      */

240     public synchronized boolean keyMatches(String JavaDoc s) throws IndexedStoreException {
241         return keyMatches(Convert.toUTF8(s));
242     }
243
244     /**
245      * Moves the cursor to the next index entry.
246      * If the cursor is at the last entry, it becomes unset.
247      * If the cursor is unset, then it is set to the first entry.
248      * The cursor itself is returned.
249      *
250      * Throws an EntryRemoved condition if the entry at which it has
251      * been pointing has been removed by another cursor.
252      */

253     public synchronized IndexCursor next() throws IndexedStoreException {
254         if (isAtBeginning()) {
255             findFirstEntry();
256         } else {
257             entryNumber++;
258             adjust();
259         }
260         return this;
261     }
262
263     /**
264      * Adjusts a cursor if there is a need after a node has been split.
265      * If not, it just returns.
266      */

267     void nodeSplit() throws IndexedStoreException {
268         adjust();
269     }
270
271     /**
272      * Removes the entry at the current cursor location. If the cursor is not set
273      * then no operation is done. If an element is removed
274      * the cursor automatically advances to the "next" element.
275      * Removing an element adjusts all cursors (including this one) pointing into this node.
276      * If there is no next element, the cursor is unset.
277      *
278      * Throws an EntryRemoved condition if the entry at which it has
279      * been pointing has been removed by another cursor.
280      */

281     public synchronized void remove() throws IndexedStoreException {
282         removeEntry();
283     }
284
285     /**
286      * Removes the entry at the current cursor location. If the cursor is not set
287      * then no operation is done. If an element is removed
288      * the cursor automatically advances to the "next" element.
289      * Removing an element adjusts all cursors (including this one) pointing into this node.
290      * If there is no next element, the cursor is unset.
291      *
292      * Throws an EntryRemoved condition if the entry at which it has
293      * been pointing has been removed by another cursor.
294      */

295     void removeEntry() throws IndexedStoreException {
296         if (entryRemoved)
297             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
298         if (leafNode == null)
299             return;
300         ObjectAddress address = leafNode.getAddress();
301         leafNode.removeEntry(entryNumber);
302         entryRemoved = false; // Clear the flag. This cursor is positioned to the next entry and remains valid.
303

304         /* remove empty nodes from the tree */
305         while (!address.isNull()) {
306             IndexNode node = store.acquireNode(address);
307             if (node.getNumberOfEntries() > 0) {
308                 node.release();
309                 break;
310             }
311             ObjectAddress parentAddress = node.getParentAddress();
312             node.unlink();
313             node.release();
314             store.removeObject(address);
315             address = parentAddress;
316         }
317     }
318
319     /**
320      * Places the cursor in the "unset" state.
321      */

322     public synchronized void reset() throws IndexedStoreException {
323         unset();
324         entryRemoved = false;
325     }
326
327     /**
328      * Sets the cursor to a particular entry of an index node.
329      */

330     void set(ObjectAddress leafNodeAddress, int entryNumber) throws IndexedStoreException {
331         unset();
332         if (leafNodeAddress.isNull())
333             return;
334         leafNode = store.acquireNode(leafNodeAddress);
335         leafNode.addCursor(this);
336         if (entryNumber >= 0)
337             this.entryNumber = entryNumber;
338         else
339             this.entryNumber = leafNode.getNumberOfEntries() + entryNumber;
340         adjust();
341     }
342
343     /**
344      * Places the cursor in the "unset" state.
345      */

346     private void unset() throws IndexedStoreException {
347         if (leafNode != null) {
348             leafNode.removeCursor(this);
349             leafNode.release();
350         }
351         entryNumber = -1;
352         leafNode = null;
353         entryRemoved = false;
354     }
355
356     /**
357      * Updates the value of the index entry at the cursor.
358      * If the cursor is at the beginning or end of the index then do nothing.
359      * Returns true if the value is set, false otherwise.
360      */

361     void updateEntry(byte[] b) throws IndexedStoreException {
362         if (entryRemoved)
363             throw new IndexedStoreException(IndexedStoreException.EntryRemoved);
364         if (b.length > 2048)
365             throw new IndexedStoreException(IndexedStoreException.EntryValueLengthError);
366         if (leafNode == null)
367             return;
368         leafNode.updateValueAt(entryNumber, b);
369     }
370
371     /**
372      * Updates the value of the index entry at the cursor.
373      * If the cursor is at the beginning or end of the index then do nothing.
374      * Returns true if the value is set, false otherwise.
375      *
376      * Throws an EntryRemoved condition if the entry at which it has
377      * been pointing has been removed by another cursor.
378      */

379     public synchronized void updateValue(byte[] b) throws IndexedStoreException {
380         updateEntry(b);
381     }
382
383     /**
384      * Updates the value of the index entry at the cursor.
385      * If the cursor is at the beginning or end of the index then do nothing.
386      */

387     public synchronized void updateValue(Insertable anObject) throws IndexedStoreException {
388         updateValue(anObject.toByteArray());
389     }
390 }
391
Popular Tags