1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: StoredEntrySet.java,v 12.7 2008/01/08 20:58:36 bostic Exp $
7 */
8
9package com.sleepycat.collections;
10
11import java.util.Map;
12import java.util.Set;
13
14import com.sleepycat.db.DatabaseEntry;
15import com.sleepycat.db.DatabaseException;
16import com.sleepycat.db.OperationStatus;
17import com.sleepycat.util.RuntimeExceptionWrapper;
18
19/**
20 * The Set returned by Map.entrySet().  This class may not be instantiated
21 * directly.  Contrary to what is stated by {@link Map#entrySet} this class
22 * does support the {@link #add} and {@link #addAll} methods.
23 *
24 * <p>The {@link java.util.Map.Entry#setValue} method of the Map.Entry objects
25 * that are returned by this class and its iterators behaves just as the {@link
26 * StoredIterator#set} method does.</p>
27 *
28 * @author Mark Hayes
29 */
30public class StoredEntrySet extends StoredCollection implements Set {
31
32    StoredEntrySet(DataView mapView) {
33
34        super(mapView);
35    }
36
37    /**
38     * Adds the specified element to this set if it is not already present
39     * (optional operation).
40     * This method conforms to the {@link Set#add} interface.
41     *
42     * @param mapEntry must be a {@link java.util.Map.Entry} instance.
43     *
44     * @return true if the key-value pair was added to the set (and was not
45     * previously present).
46     *
47     * @throws UnsupportedOperationException if the collection is read-only.
48     *
49     * @throws ClassCastException if the mapEntry is not a {@link
50     * java.util.Map.Entry} instance.
51     *
52     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is thrown.
53     */
54    public boolean add(Object mapEntry) {
55
56        Map.Entry entry = (Map.Entry) mapEntry; // allow ClassCastException
57        return add(entry.getKey(), entry.getValue());
58    }
59
60    /**
61     * Removes the specified element from this set if it is present (optional
62     * operation).
63     * This method conforms to the {@link Set#remove} interface.
64     *
65     * @param mapEntry is a {@link java.util.Map.Entry} instance to be removed.
66     *
67     * @return true if the key-value pair was removed from the set, or false if
68     * the mapEntry is not a {@link java.util.Map.Entry} instance or is not
69     * present in the set.
70     *
71     * @throws UnsupportedOperationException if the collection is read-only.
72     *
73     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is thrown.
74     */
75    public boolean remove(Object mapEntry) {
76
77        if (!(mapEntry instanceof Map.Entry)) {
78            return false;
79        }
80        Map.Entry entry = (Map.Entry) mapEntry;
81        DataCursor cursor = null;
82        boolean doAutoCommit = beginAutoCommit();
83        try {
84            cursor = new DataCursor(view, true);
85            OperationStatus status =
86                cursor.findBoth(entry.getKey(), entry.getValue(), true);
87            if (status == OperationStatus.SUCCESS) {
88                cursor.delete();
89            }
90            closeCursor(cursor);
91            commitAutoCommit(doAutoCommit);
92            return (status == OperationStatus.SUCCESS);
93        } catch (Exception e) {
94            closeCursor(cursor);
95            throw handleException(e, doAutoCommit);
96        }
97    }
98
99    /**
100     * Returns true if this set contains the specified element.
101     * This method conforms to the {@link Set#contains} interface.
102     *
103     * @param mapEntry is a {@link java.util.Map.Entry} instance to be checked.
104     *
105     * @return true if the key-value pair is present in the set, or false if
106     * the mapEntry is not a {@link java.util.Map.Entry} instance or is not
107     * present in the set.
108     *
109     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is thrown.
110     */
111    public boolean contains(Object mapEntry) {
112
113        if (!(mapEntry instanceof Map.Entry)) {
114            return false;
115        }
116        Map.Entry entry = (Map.Entry) mapEntry;
117        DataCursor cursor = null;
118        try {
119            cursor = new DataCursor(view, false);
120            OperationStatus status =
121                cursor.findBoth(entry.getKey(), entry.getValue(), false);
122            return (status == OperationStatus.SUCCESS);
123        } catch (Exception e) {
124            throw StoredContainer.convertException(e);
125        } finally {
126            closeCursor(cursor);
127        }
128    }
129
130    // javadoc is inherited
131    public String toString() {
132	StringBuffer buf = new StringBuffer();
133	buf.append("[");
134	StoredIterator i = storedIterator();
135        try {
136            while (i.hasNext()) {
137                Map.Entry entry = (Map.Entry) i.next();
138                if (buf.length() > 1) buf.append(',');
139                Object key = entry.getKey();
140                Object val = entry.getValue();
141                if (key != null) buf.append(key.toString());
142                buf.append('=');
143                if (val != null) buf.append(val.toString());
144            }
145            buf.append(']');
146            return buf.toString();
147        }
148        finally {
149            i.close();
150        }
151    }
152
153    Object makeIteratorData(BaseIterator iterator,
154                            DatabaseEntry keyEntry,
155                            DatabaseEntry priKeyEntry,
156                            DatabaseEntry valueEntry) {
157
158        return new StoredMapEntry(view.makeKey(keyEntry, priKeyEntry),
159                                  view.makeValue(priKeyEntry, valueEntry),
160                                  this, iterator);
161    }
162
163    boolean hasValues() {
164
165        return true;
166    }
167}
168