KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > collections > StoredMap


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2000,2006 Oracle. All rights reserved.
5  *
6  * $Id: StoredMap.java,v 1.45 2006/10/30 21:14:10 bostic Exp $
7  */

8
9 package com.sleepycat.collections;
10
11 import java.util.Collection JavaDoc;
12 import java.util.Collections JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.Set JavaDoc;
16
17 import com.sleepycat.bind.EntityBinding;
18 import com.sleepycat.bind.EntryBinding;
19 import com.sleepycat.je.Database;
20 import com.sleepycat.util.keyrange.KeyRangeException;
21
22 /**
23  * A Map view of a {@link Database}.
24  *
25  * <p>In addition to the standard Map methods, this class provides the
26  * following methods for stored maps only. Note that the use of these methods
27  * is not compatible with the standard Java collections interface.</p>
28  * <ul>
29  * <li>{@link #duplicates}</li>
30  * <li>{@link #duplicatesMap}</li>
31  * <li>{@link #append}</li>
32  * </ul>
33  *
34  * @author Mark Hayes
35  */

36 public class StoredMap extends StoredContainer implements Map JavaDoc {
37
38     private StoredKeySet keySet;
39     private StoredEntrySet entrySet;
40     private StoredValueSet valueSet;
41
42     /**
43      * Creates a map view of a {@link Database}.
44      *
45      * @param database is the Database underlying the new collection.
46      *
47      * @param keyBinding is the binding used to translate between key buffers
48      * and key objects.
49      *
50      * @param valueBinding is the binding used to translate between value
51      * buffers and value objects.
52      *
53      * @param writeAllowed is true to create a read-write collection or false
54      * to create a read-only collection.
55      *
56      * @throws IllegalArgumentException if formats are not consistently
57      * defined or a parameter is invalid.
58      *
59      * @throws RuntimeExceptionWrapper if a {@link
60      * com.sleepycat.je.DatabaseException} is thrown.
61      */

62     public StoredMap(Database database, EntryBinding keyBinding,
63                      EntryBinding valueBinding, boolean writeAllowed) {
64
65         super(new DataView(database, keyBinding, valueBinding, null,
66                            writeAllowed, null));
67         initView();
68     }
69
70     /**
71      * Creates a map view of a {@link Database} with a {@link
72      * PrimaryKeyAssigner}. Writing is allowed for the created map.
73      *
74      * @param database is the Database underlying the new collection.
75      *
76      * @param keyBinding is the binding used to translate between key buffers
77      * and key objects.
78      *
79      * @param valueBinding is the binding used to translate between value
80      * buffers and value objects.
81      *
82      * @param keyAssigner is used by the {@link #append} method to assign
83      * primary keys.
84      *
85      * @throws IllegalArgumentException if formats are not consistently
86      * defined or a parameter is invalid.
87      *
88      * @throws RuntimeExceptionWrapper if a {@link
89      * com.sleepycat.je.DatabaseException} is thrown.
90      */

91     public StoredMap(Database database, EntryBinding keyBinding,
92                      EntryBinding valueBinding,
93                      PrimaryKeyAssigner keyAssigner) {
94
95         super(new DataView(database, keyBinding, valueBinding, null,
96                            true, keyAssigner));
97         initView();
98     }
99
100     /**
101      * Creates a map entity view of a {@link Database}.
102      *
103      * @param database is the Database underlying the new collection.
104      *
105      * @param keyBinding is the binding used to translate between key buffers
106      * and key objects.
107      *
108      * @param valueEntityBinding is the binding used to translate between
109      * key/value buffers and entity value objects.
110      *
111      * @param writeAllowed is true to create a read-write collection or false
112      * to create a read-only collection.
113      *
114      * @throws IllegalArgumentException if formats are not consistently
115      * defined or a parameter is invalid.
116      *
117      * @throws RuntimeExceptionWrapper if a {@link
118      * com.sleepycat.je.DatabaseException} is thrown.
119      */

120     public StoredMap(Database database, EntryBinding keyBinding,
121                      EntityBinding valueEntityBinding, boolean writeAllowed) {
122
123         super(new DataView(database, keyBinding, null, valueEntityBinding,
124                            writeAllowed, null));
125         initView();
126     }
127
128     /**
129      * Creates a map entity view of a {@link Database} with a {@link
130      * PrimaryKeyAssigner}. Writing is allowed for the created map.
131      *
132      * @param database is the Database underlying the new collection.
133      *
134      * @param keyBinding is the binding used to translate between key buffers
135      * and key objects.
136      *
137      * @param valueEntityBinding is the binding used to translate between
138      * key/value buffers and entity value objects.
139      *
140      * @param keyAssigner is used by the {@link #append} method to assign
141      * primary keys.
142      *
143      * @throws IllegalArgumentException if formats are not consistently
144      * defined or a parameter is invalid.
145      *
146      * @throws RuntimeExceptionWrapper if a {@link
147      * com.sleepycat.je.DatabaseException} is thrown.
148      */

149     public StoredMap(Database database, EntryBinding keyBinding,
150                      EntityBinding valueEntityBinding,
151                      PrimaryKeyAssigner keyAssigner) {
152
153         super(new DataView(database, keyBinding, null, valueEntityBinding,
154                            true, keyAssigner));
155         initView();
156     }
157
158     StoredMap(DataView view) {
159
160         super(view);
161         initView();
162     }
163
164     /**
165      * Override this method to initialize view-dependent fields.
166      */

167     void initAfterClone() {
168         initView();
169     }
170
171     /**
172      * The keySet, entrySet and valueSet are created during Map construction
173      * rather than lazily when requested (as done with the java.util.Map
174      * implementations). This is done to avoid synchronization every time they
175      * are requested. Since they are requested often but a StoredMap is
176      * created infrequently, this gives the best performance. The additional
177      * views are small objects and are cheap to construct.
178      */

179     private void initView() {
180
181         /* entrySet */
182         if (isOrdered()) {
183             entrySet = new StoredSortedEntrySet(view);
184         } else {
185             entrySet = new StoredEntrySet(view);
186         }
187
188         /* keySet */
189         DataView newView = view.keySetView();
190         if (isOrdered()) {
191             keySet = new StoredSortedKeySet(newView);
192         } else {
193             keySet = new StoredKeySet(newView);
194         }
195
196         /* valueSet */
197         newView = view.valueSetView();
198         if (isOrdered() && newView.canDeriveKeyFromValue()) {
199             valueSet = new StoredSortedValueSet(newView);
200         } else {
201             valueSet = new StoredValueSet(newView);
202         }
203     }
204
205     /**
206      * Returns the value to which this map maps the specified key. If
207      * duplicates are allowed, this method returns the first duplicate, in the
208      * order in which duplicates are configured, that maps to the specified
209      * key.
210      *
211      * This method conforms to the {@link Map#get} interface.
212      *
213      * @throws RuntimeExceptionWrapper if a {@link
214      * com.sleepycat.je.DatabaseException} is thrown.
215      */

216     public Object JavaDoc get(Object JavaDoc key) {
217
218         return super.get(key);
219     }
220
221     /**
222      * Associates the specified value with the specified key in this map
223      * (optional operation). If duplicates are allowed and the specified key
224      * is already mapped to a value, this method appends the new duplicate
225      * after the existing duplicates. This method conforms to the {@link
226      * Map#put} interface.
227      *
228      * <p>The key parameter may be null if an entity binding is used and the
229      * key will be derived from the value (entity) parameter. If an entity
230      * binding is used and the key parameter is non-null, then the key
231      * parameter must be equal to the key derived from the value parameter.</p>
232      *
233      * @return the previous value associated with specified key, or null if
234      * there was no mapping for the key or if duplicates are allowed.
235      *
236      * @throws UnsupportedOperationException if the collection is indexed, or
237      * if the collection is read-only.
238      *
239      * @throws IllegalArgumentException if an entity value binding is used and
240      * the primary key of the value given is different than the existing stored
241      * primary key.
242      *
243      * @throws RuntimeExceptionWrapper if a {@link
244      * com.sleepycat.je.DatabaseException} is thrown.
245      */

246     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
247
248         return super.put(key, value);
249     }
250
251     /**
252      * Appends a given value returning the newly assigned key. If a {@link
253      * PrimaryKeyAssigner} is associated with Store for this map, it will be
254      * used to assigned the returned key. Otherwise the Store must be a QUEUE
255      * or RECNO database and the next available record number is assigned as
256      * the key. This method does not exist in the standard {@link Map}
257      * interface.
258      *
259      * <p>Note that for the JE product, QUEUE and RECNO databases are not
260      * supported, and therefore a PrimaryKeyAssigner must be associated with
261      * the map in order to call this method.</p>
262      *
263      * @param value the value to be appended.
264      *
265      * @return the assigned key.
266      *
267      * @throws UnsupportedOperationException if the collection is indexed, or
268      * if the collection is read-only, or if the Store has no {@link
269      * PrimaryKeyAssigner} and is not a QUEUE or RECNO database.
270      *
271      * @throws RuntimeExceptionWrapper if a {@link
272      * com.sleepycat.je.DatabaseException} is thrown.
273      */

274     public Object JavaDoc append(Object JavaDoc value) {
275
276         boolean doAutoCommit = beginAutoCommit();
277         try {
278             Object JavaDoc[] key = new Object JavaDoc[1];
279             view.append(value, key, null);
280             commitAutoCommit(doAutoCommit);
281             return key[0];
282         } catch (Exception JavaDoc e) {
283             throw handleException(e, doAutoCommit);
284         }
285     }
286
287     /**
288      * Removes the mapping for this key from this map if present (optional
289      * operation). If duplicates are allowed, this method removes all
290      * duplicates for the given key. This method conforms to the {@link
291      * Map#remove} interface.
292      *
293      * @throws UnsupportedOperationException if the collection is read-only.
294      *
295      * @throws RuntimeExceptionWrapper if a {@link
296      * com.sleepycat.je.DatabaseException} is thrown.
297      */

298     public Object JavaDoc remove(Object JavaDoc key) {
299
300         Object JavaDoc[] oldVal = new Object JavaDoc[1];
301         removeKey(key, oldVal);
302         return oldVal[0];
303     }
304
305     /**
306      * Returns true if this map contains the specified key. This method
307      * conforms to the {@link Map#containsKey} interface.
308      *
309      * @throws RuntimeExceptionWrapper if a {@link
310      * com.sleepycat.je.DatabaseException} is thrown.
311      */

312     public boolean containsKey(Object JavaDoc key) {
313
314         return super.containsKey(key);
315     }
316
317     /**
318      * Returns true if this map contains the specified value. When an entity
319      * binding is used, this method returns whether the map contains the
320      * primary key and value mapping of the entity. This method conforms to
321      * the {@link Map#containsValue} interface.
322      *
323      * @throws RuntimeExceptionWrapper if a {@link
324      * com.sleepycat.je.DatabaseException} is thrown.
325      */

326     public boolean containsValue(Object JavaDoc value) {
327
328         return super.containsValue(value);
329     }
330
331     /**
332      * Copies all of the mappings from the specified map to this map (optional
333      * operation). When duplicates are allowed, the mappings in the specified
334      * map are effectively appended to the existing mappings in this map, that
335      * is no previously existing mappings in this map are replaced. This
336      * method conforms to the {@link Map#putAll} interface.
337      *
338      * @throws UnsupportedOperationException if the collection is read-only, or
339      * if the collection is indexed.
340      *
341      * @throws RuntimeExceptionWrapper if a {@link
342      * com.sleepycat.je.DatabaseException} is thrown.
343      */

344     public void putAll(Map JavaDoc map) {
345
346         boolean doAutoCommit = beginAutoCommit();
347         Iterator JavaDoc i = null;
348         try {
349             Collection JavaDoc coll = map.entrySet();
350             i = storedOrExternalIterator(coll);
351             while (i.hasNext()) {
352                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
353                 put(entry.getKey(), entry.getValue());
354             }
355             StoredIterator.close(i);
356             commitAutoCommit(doAutoCommit);
357         } catch (Exception JavaDoc e) {
358             StoredIterator.close(i);
359             throw handleException(e, doAutoCommit);
360         }
361     }
362
363     /**
364      * Returns a set view of the keys contained in this map. A {@link
365      * java.util.SortedSet} is returned if the map is ordered. The returned
366      * collection will be read-only if the map is read-only. This method
367      * conforms to the {@link Map#keySet()} interface.
368      *
369      * <p>Note that the return value is a StoredCollection and must be treated
370      * as such; for example, its iterators must be explicitly closed.</p>
371      *
372      * @return a {@link StoredKeySet} or a {@link StoredSortedKeySet} for this
373      * map.
374      *
375      * @throws RuntimeExceptionWrapper if a {@link
376      * com.sleepycat.je.DatabaseException} is thrown.
377      *
378      * @see #isOrdered
379      * @see #isWriteAllowed
380      */

381     public Set JavaDoc keySet() {
382
383         return keySet;
384     }
385
386     /**
387      * Returns a set view of the mappings contained in this map. A {@link
388      * java.util.SortedSet} is returned if the map is ordered. The returned
389      * collection will be read-only if the map is read-only. This method
390      * conforms to the {@link Map#entrySet()} interface.
391      *
392      * <p>Note that the return value is a StoredCollection and must be treated
393      * as such; for example, its iterators must be explicitly closed.</p>
394      *
395      * @return a {@link StoredEntrySet} or a {@link StoredSortedEntrySet} for
396      * this map.
397      *
398      * @throws RuntimeExceptionWrapper if a {@link
399      * com.sleepycat.je.DatabaseException} is thrown.
400      *
401      * @see #isOrdered
402      * @see #isWriteAllowed
403      */

404     public Set JavaDoc entrySet() {
405
406         return entrySet;
407     }
408
409     /**
410      * Returns a collection view of the values contained in this map. A {@link
411      * java.util.SortedSet} is returned if the map is ordered and the
412      * value/entity binding can be used to derive the map's key from its
413      * value/entity object. The returned collection will be read-only if the
414      * map is read-only. This method conforms to the {@link Map#values()}
415      * interface.
416      *
417      * <p>Note that the return value is a StoredCollection and must be treated
418      * as such; for example, its iterators must be explicitly closed.</p>
419      *
420      * @return a {@link StoredValueSet} or a {@link StoredSortedValueSet} for
421      * this map.
422      *
423      * @throws RuntimeExceptionWrapper if a {@link
424      * com.sleepycat.je.DatabaseException} is thrown.
425      *
426      * @see #isOrdered
427      * @see #isWriteAllowed
428      */

429     public Collection JavaDoc values() {
430
431         return valueSet;
432     }
433
434     /**
435      * Returns a new collection containing the values mapped to the given key
436      * in this map. This collection's iterator() method is particularly useful
437      * for iterating over the duplicates for a given key, since this is not
438      * supported by the standard Map interface. This method does not exist in
439      * the standard {@link Map} interface.
440      *
441      * <p>If no mapping for the given key is present, an empty collection is
442      * returned. If duplicates are not allowed, at most a single value will be
443      * in the collection returned. If duplicates are allowed, the returned
444      * collection's add() method may be used to add values for the given
445      * key.</p>
446      *
447      * @param key is the key for which values are to be returned.
448      *
449      * @throws RuntimeExceptionWrapper if a {@link
450      * com.sleepycat.je.DatabaseException} is thrown.
451      */

452     public Collection JavaDoc duplicates(Object JavaDoc key) {
453
454         try {
455             DataView newView = view.valueSetView(key);
456             return new StoredValueSet(newView);
457         } catch (KeyRangeException e) {
458             return Collections.EMPTY_SET;
459         } catch (Exception JavaDoc e) {
460             throw StoredContainer.convertException(e);
461         }
462     }
463
464     /**
465      * Returns a new map from primary key to value for the subset of records
466      * having a given secondary key (duplicates). This method does not exist
467      * in the standard {@link Map} interface.
468      *
469      * <p>If no mapping for the given key is present, an empty collection is
470      * returned. If duplicates are not allowed, at most a single value will be
471      * in the collection returned. If duplicates are allowed, the returned
472      * collection's add() method may be used to add values for the given
473      * key.</p>
474      *
475      * @param secondaryKey is the secondary key for which duplicates values
476      * will be represented by the returned map.
477      *
478      * @param primaryKeyBinding is the binding used for keys in the returned
479      * map.
480      *
481      * @throws RuntimeExceptionWrapper if a {@link
482      * com.sleepycat.je.DatabaseException} is thrown.
483      */

484     public Map JavaDoc duplicatesMap(Object JavaDoc secondaryKey,
485                              EntryBinding primaryKeyBinding) {
486         try {
487             DataView newView =
488                 view.duplicatesView(secondaryKey, primaryKeyBinding);
489             if (isOrdered()) {
490                 return new StoredSortedMap(newView);
491             } else {
492                 return new StoredMap(newView);
493             }
494         } catch (Exception JavaDoc e) {
495             throw StoredContainer.convertException(e);
496         }
497     }
498
499     /**
500      * Compares the specified object with this map for equality. A value
501      * comparison is performed by this method and the stored values are
502      * compared rather than calling the equals() method of each element. This
503      * method conforms to the {@link Map#equals} interface.
504      *
505      * @throws RuntimeExceptionWrapper if a {@link
506      * com.sleepycat.je.DatabaseException} is thrown.
507      */

508     public boolean equals(Object JavaDoc other) {
509
510         if (other instanceof Map JavaDoc) {
511             return entrySet().equals(((Map JavaDoc) other).entrySet());
512         } else {
513             return false;
514         }
515     }
516
517     /*
518      * Add this in to keep FindBugs from whining at us about implementing
519      * equals(), but not hashCode().
520      */

521     public int hashCode() {
522     return super.hashCode();
523     }
524
525     // Inherit javadoc
526
public int size() {
527         return values().size();
528     }
529
530     /**
531      * Converts the map to a string representation for debugging. WARNING: All
532      * mappings will be converted to strings and returned and therefore the
533      * returned string may be very large.
534      *
535      * @return the string representation.
536      *
537      * @throws RuntimeExceptionWrapper if a {@link
538      * com.sleepycat.je.DatabaseException} is thrown.
539      */

540     public String JavaDoc toString() {
541
542         return entrySet().toString();
543     }
544 }
545
546
Popular Tags