1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: StoredValueSet.java,v 12.7 2008/01/08 20:58:36 bostic Exp $
7 */
8
9package com.sleepycat.collections;
10
11import java.util.Set;
12
13import com.sleepycat.bind.EntityBinding;
14import com.sleepycat.bind.EntryBinding;
15import com.sleepycat.db.Database;
16import com.sleepycat.db.DatabaseEntry;
17import com.sleepycat.db.DatabaseException;
18import com.sleepycat.db.OperationStatus;
19
20/**
21 * The Set returned by Map.values() and Map.duplicates(), and which can also be
22 * constructed directly if a Map is not needed.
23 * Although this collection is a set it may contain duplicate values.  Only if
24 * an entity value binding is used are all elements guaranteed to be unique.
25 *
26 * @author Mark Hayes
27 */
28public class StoredValueSet extends StoredCollection implements Set {
29
30    /*
31     * This class is also used internally for the set returned by duplicates().
32     */
33
34    /**
35     * Creates a value set view of a {@link Database}.
36     *
37     * @param database is the Database underlying the new collection.
38     *
39     * @param valueBinding is the binding used to translate between value
40     * buffers and value objects.
41     *
42     * @param writeAllowed is true to create a read-write collection or false
43     * to create a read-only collection.
44     *
45     * @throws IllegalArgumentException if formats are not consistently
46     * defined or a parameter is invalid.
47     *
48     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is
49     * thrown.
50     */
51    public StoredValueSet(Database database,
52                          EntryBinding valueBinding,
53                          boolean writeAllowed) {
54
55        super(new DataView(database, null, valueBinding, null,
56                           writeAllowed, null));
57    }
58
59    /**
60     * Creates a value set entity view of a {@link Database}.
61     *
62     * @param database is the Database underlying the new collection.
63     *
64     * @param valueEntityBinding is the binding used to translate between
65     * key/value buffers and entity value objects.
66     *
67     * @param writeAllowed is true to create a read-write collection or false
68     * to create a read-only collection.
69     *
70     * @throws IllegalArgumentException if formats are not consistently
71     * defined or a parameter is invalid.
72     *
73     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is
74     * thrown.
75     */
76    public StoredValueSet(Database database,
77                          EntityBinding valueEntityBinding,
78                          boolean writeAllowed) {
79
80        super(new DataView(database, null, null, valueEntityBinding,
81                           writeAllowed, null));
82    }
83
84    StoredValueSet(DataView valueSetView) {
85
86        super(valueSetView);
87    }
88
89    /**
90     * Adds the specified entity to this set if it is not already present
91     * (optional operation).
92     * This method conforms to the {@link Set#add} interface.
93     *
94     * @param entity is the entity to be added.
95     *
96     * @return true if the entity was added, that is the key-value pair
97     * represented by the entity was not previously present in the collection.
98     *
99     * @throws UnsupportedOperationException if the collection is read-only,
100     * if the collection is indexed, or if an entity binding is not used.
101     *
102     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is
103     * thrown.
104     */
105    public boolean add(Object entity) {
106
107        if (view.isSecondary()) {
108            throw new UnsupportedOperationException(
109                "add() not allowed with index");
110        } else if (view.range.isSingleKey()) {
111            /* entity is actually just a value in this case */
112            if (!view.dupsAllowed) {
113                throw new UnsupportedOperationException("duplicates required");
114            }
115            DataCursor cursor = null;
116            boolean doAutoCommit = beginAutoCommit();
117            try {
118                cursor = new DataCursor(view, true);
119                cursor.useRangeKey();
120                OperationStatus status =
121                    cursor.putNoDupData(null, entity, null, true);
122                closeCursor(cursor);
123                commitAutoCommit(doAutoCommit);
124                return (status == OperationStatus.SUCCESS);
125            } catch (Exception e) {
126                closeCursor(cursor);
127                throw handleException(e, doAutoCommit);
128            }
129        } else if (view.entityBinding == null) {
130            throw new UnsupportedOperationException(
131                "add() requires entity binding");
132        } else {
133            return add(null, entity);
134        }
135    }
136
137    /**
138     * Returns true if this set contains the specified element.
139     * This method conforms to the {@link java.util.Set#contains}
140     * interface.
141     *
142     * @param value the value to check.
143     *
144     * @return whether the set contains the given value.
145     */
146    public boolean contains(Object value) {
147
148        return containsValue(value);
149    }
150
151    /**
152     * Removes the specified value from this set if it is present (optional
153     * operation).
154     * If an entity binding is used, the key-value pair represented by the
155     * given entity is removed.  If an entity binding is used, the first
156     * occurrence of a key-value pair with the given value is removed.
157     * This method conforms to the {@link Set#remove} interface.
158     *
159     * @throws UnsupportedOperationException if the collection is read-only.
160     *
161     * @throws RuntimeExceptionWrapper if a {@link DatabaseException} is
162     * thrown.
163     */
164    public boolean remove(Object value) {
165
166        return removeValue(value);
167    }
168
169    Object makeIteratorData(BaseIterator iterator,
170                            DatabaseEntry keyEntry,
171                            DatabaseEntry priKeyEntry,
172                            DatabaseEntry valueEntry) {
173
174        return view.makeValue(priKeyEntry, valueEntry);
175    }
176
177    boolean hasValues() {
178
179        return true;
180    }
181}
182