20 package net.sf.gridarta.model.index;
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
32 import java.util.Map.Entry;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
49 private final Object
sync =
new Object();
69 private final Map<V, String>
names =
new HashMap<>();
76 private final Collection<V>
pending =
new HashSet<>();
99 return timestamps.size();
105 synchronized (
sync) {
106 final String nameLowerCase = name.toLowerCase();
107 final Collection<V> result =
new HashSet<>();
108 for (
final Entry<V, String> e : names.entrySet()) {
109 if (e.getValue().toLowerCase().contains(nameLowerCase)) {
110 result.add(e.getKey());
119 synchronized (
sync) {
121 transactionDelete.clear();
122 transactionDelete.addAll(timestamps.keySet());
128 synchronized (
sync) {
130 throw new IllegalStateException();
135 transactionDelete.clear();
136 if (!tmp.isEmpty()) {
138 for (
final V value : tmp) {
139 timestamps.remove(value);
140 pending.remove(value);
143 for (
final V value : tmp) {
145 listener.valueRemoved(value);
146 listener.nameChanged();
154 public void add(@NotNull
final V value,
final long timestamp) {
155 synchronized (
sync) {
156 final Long oldTimestamp = timestamps.put(value, timestamp);
157 final boolean notifyPending;
158 final boolean notifyAdded;
159 if (oldTimestamp == null || oldTimestamp != timestamp) {
160 notifyPending = pending.add(value) && pending.size() == 1;
161 notifyAdded = oldTimestamp == null;
164 notifyPending =
false;
167 transactionDelete.remove(value);
170 listener.valueAdded(value);
175 listener.pendingChanged();
182 public void remove(@NotNull
final V value) {
183 synchronized (
sync) {
184 if (timestamps.remove(value) == null) {
188 pending.remove(value);
191 listener.valueRemoved(value);
192 listener.nameChanged();
199 synchronized (
sync) {
200 final boolean notifyPending = pending.add(value) && pending.size() == 1;
201 if (!timestamps.containsKey(value)) {
203 timestamps.put(value, 0L);
205 listener.valueAdded(value);
210 listener.pendingChanged();
217 public void setName(@NotNull
final V value,
final long timestamp, @NotNull
final String name) {
218 synchronized (
sync) {
219 timestamps.put(value, timestamp);
220 final String oldName = names.put(value, name);
221 if (oldName != null && oldName.equals(name)) {
226 listener.nameChanged();
233 public String
getName(@NotNull
final V value) {
234 synchronized (
sync) {
235 return names.get(value);
242 synchronized (
sync) {
243 final Iterator<V> it = pending.iterator();
248 final V result = it.next();
256 synchronized (
sync) {
257 return !pending.isEmpty();
263 synchronized (
sync) {
270 indexListeners.
add(listener);
275 indexListeners.
remove(listener);
279 public void save(@NotNull
final ObjectOutputStream objectOutputStream)
throws IOException {
280 synchronized (
sync) {
281 objectOutputStream.writeObject(timestamps);
282 objectOutputStream.writeObject(names);
291 @SuppressWarnings(
"unchecked")
292 public
void load(@NotNull final ObjectInputStream objectInputStream) throws IOException {
293 synchronized (
sync) {
294 final Map<V, Long> tmpTimestamps;
295 final Map<V, String> tmpNames;
297 tmpTimestamps = (Map<V, Long>) objectInputStream.readObject();
298 tmpNames = (Map<V, String>) objectInputStream.readObject();
299 }
catch (
final ClassNotFoundException ex) {
300 throw new IOException(ex.getMessage(), ex);
303 throw new IOException(
"cannot restore state within active transaction");
307 tmpNames.keySet().retainAll(tmpTimestamps.keySet());
310 timestamps.putAll(tmpTimestamps);
311 names.putAll(tmpNames);
317 synchronized (
sync) {
329 listener.indexingFinished();
void removeIndexListener(@NotNull final IndexListener< V > listener)
Removes an IndexListener to be notified of changes.
T [] getListeners()
Returns an array of all the listeners.
void setPending(@NotNull final V value)
Marks a value as pending.
boolean hasPending()
Returns whether at least one pending value exists.
Abstract base class for Index implementations.
Interface for listeners interested in Index related events.
final Map< V, Long > timestamps
Maps value to timestamp.
void load(@NotNull final ObjectInputStream objectInputStream)
unchecked
V removePending()
Returns one pending value.
void setName(@NotNull final V value, final long timestamp, @NotNull final String name)
Associates a value with a name.
void endUpdate()
Ends an update.
void addIndexListener(@NotNull final IndexListener< V > listener)
Adds an IndexListener to be notified of changes.
Base package of all Gridarta classes.
final Collection< V > transactionDelete
The values to delete at the end of the current transaction.
boolean transaction
Whether a transaction is active.
void remove(@NotNull final T listener)
Removes a listener.
void indexingFinished()
Should be called after indexing has finished.
final Map< V, String > names
Maps value to name.
int size()
Returns the number of values in this cache.
void add(@NotNull final T listener)
Adds a listener.
void save(@NotNull final ObjectOutputStream objectOutputStream)
Saves the state to an ObjectOutputStream.
Collection< V > findPartialName(@NotNull final String name)
Returns all matching values for a (possibly partial) key name.
String getName(@NotNull final V value)
Returns the name associated with a value.
Type-safe version of EventListenerList.
boolean modified
Whether the state (timestamps or names) was modified since last save.
void add(@NotNull final V value, final long timestamp)
Adds a value to the cache.
final EventListenerList2< IndexListener< V > > indexListeners
The registered listeners.
void clear()
Clears all values from the index.
boolean isModified()
Returns whether the state was modified since last save.
final Object sync
Objects used to synchronize accesses to other fields.
void beginUpdate()
Starts an update.
final Collection< V > pending
Pending values.