1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: StoredSortedMap.java,v 12.10 2008/02/07 17:12:26 mark Exp $
7 */
8
9package com.sleepycat.collections;
10
11import java.util.Comparator;
12import java.util.SortedMap;
13
14import com.sleepycat.bind.EntityBinding;
15import com.sleepycat.bind.EntryBinding;
16import com.sleepycat.db.Database;
17import com.sleepycat.db.OperationStatus;
18
19/**
20 * A SortedMap view of a {@link Database}.
21 *
22 * <p>In addition to the standard SortedMap methods, this class provides the
23 * following methods for stored sorted maps only.  Note that the use of these
24 * methods is not compatible with the standard Java collections interface.</p>
25 * <ul>
26 * <li>{@link #headMap(Object, boolean)}</li>
27 * <li>{@link #tailMap(Object, boolean)}</li>
28 * <li>{@link #subMap(Object, boolean, Object, boolean)}</li>
29 * </ul>
30 *
31 * @author Mark Hayes
32 */
33public class StoredSortedMap extends StoredMap implements SortedMap {
34
35    /**
36     * Creates a sorted map view of a {@link Database}.
37     *
38     * @param database is the Database underlying the new collection.
39     *
40     * @param keyBinding is the binding used to translate between key buffers
41     * and key objects.
42     *
43     * @param valueBinding is the binding used to translate between value
44     * buffers and value objects.
45     *
46     * @param writeAllowed is true to create a read-write collection or false
47     * to create a read-only collection.
48     *
49     * @throws IllegalArgumentException if formats are not consistently
50     * defined or a parameter is invalid.
51     *
52     * @throws RuntimeExceptionWrapper if a {@link
53     * com.sleepycat.db.DatabaseException} is thrown.
54     */
55    public StoredSortedMap(Database database, EntryBinding keyBinding,
56                           EntryBinding valueBinding, boolean writeAllowed) {
57
58        super(new DataView(database, keyBinding, valueBinding, null,
59                           writeAllowed, null));
60    }
61
62    /**
63     * Creates a sorted map view of a {@link Database} with a {@link
64     * PrimaryKeyAssigner}.  Writing is allowed for the created map.
65     *
66     * @param database is the Database underlying the new collection.
67     *
68     * @param keyBinding is the binding used to translate between key buffers
69     * and key objects.
70     *
71     * @param valueBinding is the binding used to translate between value
72     * buffers and value objects.
73     *
74     * @param keyAssigner is used by the {@link #append} method to assign
75     * primary keys.
76     *
77     * @throws IllegalArgumentException if formats are not consistently
78     * defined or a parameter is invalid.
79     *
80     * @throws RuntimeExceptionWrapper if a {@link
81     * com.sleepycat.db.DatabaseException} is thrown.
82     */
83    public StoredSortedMap(Database database, EntryBinding keyBinding,
84                           EntryBinding valueBinding,
85                           PrimaryKeyAssigner keyAssigner) {
86
87        super(new DataView(database, keyBinding, valueBinding, null,
88                           true, keyAssigner));
89    }
90
91    /**
92     * Creates a sorted map entity view of a {@link Database}.
93     *
94     * @param database is the Database underlying the new collection.
95     *
96     * @param keyBinding is the binding used to translate between key buffers
97     * and key objects.
98     *
99     * @param valueEntityBinding is the binding used to translate between
100     * key/value buffers and entity value objects.
101     *
102     * @param writeAllowed is true to create a read-write collection or false
103     * to create a read-only collection.
104     *
105     * @throws IllegalArgumentException if formats are not consistently
106     * defined or a parameter is invalid.
107     *
108     * @throws RuntimeExceptionWrapper if a {@link
109     * com.sleepycat.db.DatabaseException} is thrown.
110     */
111    public StoredSortedMap(Database database, EntryBinding keyBinding,
112                           EntityBinding valueEntityBinding,
113                           boolean writeAllowed) {
114
115        super(new DataView(database, keyBinding, null, valueEntityBinding,
116                           writeAllowed, null));
117    }
118
119    /**
120     * Creates a sorted map entity view of a {@link Database} with a {@link
121     * PrimaryKeyAssigner}.  Writing is allowed for the created map.
122     *
123     * @param database is the Database underlying the new collection.
124     *
125     * @param keyBinding is the binding used to translate between key buffers
126     * and key objects.
127     *
128     * @param valueEntityBinding is the binding used to translate between
129     * key/value buffers and entity value objects.
130     *
131     * @param keyAssigner is used by the {@link #append} method to assign
132     * primary keys.
133     *
134     * @throws IllegalArgumentException if formats are not consistently
135     * defined or a parameter is invalid.
136     *
137     * @throws RuntimeExceptionWrapper if a {@link
138     * com.sleepycat.db.DatabaseException} is thrown.
139     */
140    public StoredSortedMap(Database database, EntryBinding keyBinding,
141                           EntityBinding valueEntityBinding,
142                           PrimaryKeyAssigner keyAssigner) {
143
144        super(new DataView(database, keyBinding, null, valueEntityBinding,
145                           true, keyAssigner));
146    }
147
148    StoredSortedMap(DataView mapView) {
149
150        super(mapView);
151    }
152
153    /**
154     * Returns null since comparators are not supported.  The natural ordering
155     * of a stored collection is data byte order, whether the data classes
156     * implement the {@link java.lang.Comparable} interface or not.
157     * This method does not conform to the {@link SortedMap#comparator}
158     * interface.
159     *
160     * @return null.
161     */
162    public Comparator comparator() {
163
164        return null;
165    }
166
167    /**
168     * Returns the first (lowest) key currently in this sorted map.
169     * This method conforms to the {@link SortedMap#firstKey} interface.
170     *
171     * @return the first key.
172     *
173     * @throws RuntimeExceptionWrapper if a {@link
174     * com.sleepycat.db.DatabaseException} is thrown.
175     */
176    public Object firstKey() {
177
178        return getFirstOrLastKey(true);
179    }
180
181    /**
182     * Returns the last (highest) element currently in this sorted map.
183     * This method conforms to the {@link SortedMap#lastKey} interface.
184     *
185     * @return the last key.
186     *
187     * @throws RuntimeExceptionWrapper if a {@link
188     * com.sleepycat.db.DatabaseException} is thrown.
189     */
190    public Object lastKey() {
191
192        return getFirstOrLastKey(false);
193    }
194
195    private Object getFirstOrLastKey(boolean doGetFirst) {
196
197        DataCursor cursor = null;
198        try {
199            cursor = new DataCursor(view, false);
200            OperationStatus status;
201            if (doGetFirst) {
202                status = cursor.getFirst(false);
203            } else {
204                status = cursor.getLast(false);
205            }
206            return (status == OperationStatus.SUCCESS) ?
207                    cursor.getCurrentKey() : null;
208        } catch (Exception e) {
209            throw StoredContainer.convertException(e);
210        } finally {
211            closeCursor(cursor);
212        }
213    }
214
215    /**
216     * Returns a view of the portion of this sorted set whose keys are
217     * strictly less than toKey.
218     * This method conforms to the {@link SortedMap#headMap} interface.
219     *
220     * <p>Note that the return value is a StoredStoredMap and must be treated
221     * as such; for example, its iterators must be explicitly closed.</p>
222     *
223     * @param toKey is the upper bound.
224     *
225     * @return the submap.
226     *
227     * @throws RuntimeExceptionWrapper if a {@link
228     * com.sleepycat.db.DatabaseException} is thrown.
229     */
230    public SortedMap headMap(Object toKey) {
231
232        return subMap(null, false, toKey, false);
233    }
234
235    /**
236     * Returns a view of the portion of this sorted map whose elements are
237     * strictly less than toKey, optionally including toKey.
238     * This method does not exist in the standard {@link SortedMap} interface.
239     *
240     * <p>Note that the return value is a StoredStoredMap and must be treated
241     * as such; for example, its iterators must be explicitly closed.</p>
242     *
243     * @param toKey is the upper bound.
244     *
245     * @param toInclusive is true to include toKey.
246     *
247     * @return the submap.
248     *
249     * @throws RuntimeExceptionWrapper if a {@link
250     * com.sleepycat.db.DatabaseException} is thrown.
251     */
252    public SortedMap headMap(Object toKey, boolean toInclusive) {
253
254        return subMap(null, false, toKey, toInclusive);
255    }
256
257    /**
258     * Returns a view of the portion of this sorted map whose elements are
259     * greater than or equal to fromKey.
260     * This method conforms to the {@link SortedMap#tailMap} interface.
261     *
262     * <p>Note that the return value is a StoredStoredMap and must be treated
263     * as such; for example, its iterators must be explicitly closed.</p>
264     *
265     * @param fromKey is the lower bound.
266     *
267     * @return the submap.
268     *
269     * @throws RuntimeExceptionWrapper if a {@link
270     * com.sleepycat.db.DatabaseException} is thrown.
271     */
272    public SortedMap tailMap(Object fromKey) {
273
274        return subMap(fromKey, true, null, false);
275    }
276
277    /**
278     * Returns a view of the portion of this sorted map whose elements are
279     * strictly greater than fromKey, optionally including fromKey.
280     * This method does not exist in the standard {@link SortedMap} interface.
281     *
282     * <p>Note that the return value is a StoredStoredMap and must be treated
283     * as such; for example, its iterators must be explicitly closed.</p>
284     *
285     * @param fromKey is the lower bound.
286     *
287     * @param fromInclusive is true to include fromKey.
288     *
289     * @return the submap.
290     *
291     * @throws RuntimeExceptionWrapper if a {@link
292     * com.sleepycat.db.DatabaseException} is thrown.
293     */
294    public SortedMap tailMap(Object fromKey, boolean fromInclusive) {
295
296        return subMap(fromKey, fromInclusive, null, false);
297    }
298
299    /**
300     * Returns a view of the portion of this sorted map whose elements range
301     * from fromKey, inclusive, to toKey, exclusive.
302     * This method conforms to the {@link SortedMap#subMap} interface.
303     *
304     * <p>Note that the return value is a StoredStoredMap and must be treated
305     * as such; for example, its iterators must be explicitly closed.</p>
306     *
307     * @param fromKey is the lower bound.
308     *
309     * @param toKey is the upper bound.
310     *
311     * @return the submap.
312     *
313     * @throws RuntimeExceptionWrapper if a {@link
314     * com.sleepycat.db.DatabaseException} is thrown.
315     */
316    public SortedMap subMap(Object fromKey, Object toKey) {
317
318        return subMap(fromKey, true, toKey, false);
319    }
320
321    /**
322     * Returns a view of the portion of this sorted map whose elements are
323     * strictly greater than fromKey and strictly less than toKey,
324     * optionally including fromKey and toKey.
325     * This method does not exist in the standard {@link SortedMap} interface.
326     *
327     * <p>Note that the return value is a StoredStoredMap and must be treated
328     * as such; for example, its iterators must be explicitly closed.</p>
329     *
330     * @param fromKey is the lower bound.
331     *
332     * @param fromInclusive is true to include fromKey.
333     *
334     * @param toKey is the upper bound.
335     *
336     * @param toInclusive is true to include toKey.
337     *
338     * @return the submap.
339     *
340     * @throws RuntimeExceptionWrapper if a {@link
341     * com.sleepycat.db.DatabaseException} is thrown.
342     */
343    public SortedMap subMap(Object fromKey, boolean fromInclusive,
344                            Object toKey, boolean toInclusive) {
345
346        try {
347            return new StoredSortedMap(
348               view.subView(fromKey, fromInclusive, toKey, toInclusive, null));
349        } catch (Exception e) {
350            throw StoredContainer.convertException(e);
351        }
352    }
353}
354