org.bson.util.AbstractCopyOnWriteMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mongo-java-driver Show documentation
Show all versions of mongo-java-driver Show documentation
The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson
The newest version!
/*
* Copyright 2008-present MongoDB, Inc.
* Copyright (c) 2008-2014 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bson.util;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.unmodifiableSet;
import static org.bson.assertions.Assertions.notNull;
/**
* Abstract base class for COW {@link java.util.Map} implementations that delegate to an internal map.
*
* @param The key type
* @param The value type
* @param the internal {@link java.util.Map} or extension for things like sorted and navigable maps.
*/
abstract class AbstractCopyOnWriteMap> implements ConcurrentMap {
// @GuardedBy("lock")
private volatile M delegate;
// import edu.umd.cs.findbugs.annotations.@SuppressWarnings
private final transient Lock lock = new ReentrantLock();
// private final transient EntrySet entrySet = new EntrySet();
// private final transient KeySet keySet = new KeySet();
// private final transient Values values = new Values();
// private final View.Type viewType;
private final View view;
/**
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to initialize the values.
*
* @param map the initial map to initialize with
* @param viewType for writable or read-only key, value and entrySet views
*/
protected > AbstractCopyOnWriteMap(final N map, final View.Type viewType) {
this.delegate = notNull("delegate", copy(notNull("map", map)));
this.view = notNull("viewType", viewType).get(this);
}
/**
* Copy function, implemented by sub-classes.
*
* @param the map to copy and return.
* @param map the initial values of the newly created map.
* @return a new map. Will never be modified after construction.
*/
// @GuardedBy("lock")
abstract > M copy(N map);
//
// mutable operations
//
public final void clear() {
lock.lock();
try {
set(copy(Collections.emptyMap()));
} finally {
lock.unlock();
}
}
public final V remove(final Object key) {
lock.lock();
try {
// short circuit if key doesn't exist
if (!delegate.containsKey(key)) {
return null;
}
M map = copy();
try {
return map.remove(key);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean remove(final Object key, final Object value) {
lock.lock();
try {
if (delegate.containsKey(key) && equals(value, delegate.get(key))) {
M map = copy();
map.remove(key);
set(map);
return true;
} else {
return false;
}
} finally {
lock.unlock();
}
}
public boolean replace(final K key, final V oldValue, final V newValue) {
lock.lock();
try {
if (!delegate.containsKey(key) || !equals(oldValue, delegate.get(key))) {
return false;
}
M map = copy();
map.put(key, newValue);
set(map);
return true;
} finally {
lock.unlock();
}
}
public V replace(final K key, final V value) {
lock.lock();
try {
if (!delegate.containsKey(key)) {
return null;
}
M map = copy();
try {
return map.put(key, value);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public final V put(final K key, final V value) {
lock.lock();
try {
M map = copy();
try {
return map.put(key, value);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public V putIfAbsent(final K key, final V value) {
lock.lock();
try {
if (!delegate.containsKey(key)) {
M map = copy();
try {
return map.put(key, value);
} finally {
set(map);
}
}
return delegate.get(key);
} finally {
lock.unlock();
}
}
public final void putAll(final Map extends K, ? extends V> t) {
lock.lock();
try {
M map = copy();
map.putAll(t);
set(map);
} finally {
lock.unlock();
}
}
protected M copy() {
lock.lock();
try {
return copy(delegate);
} finally {
lock.unlock();
}
}
// @GuardedBy("lock")
protected void set(final M map) {
delegate = map;
}
//
// Collection views
//
public final Set> entrySet() {
return view.entrySet();
}
public final Set keySet() {
return view.keySet();
}
public final Collection values() {
return view.values();
}
//
// delegate operations
//
public final boolean containsKey(final Object key) {
return delegate.containsKey(key);
}
public final boolean containsValue(final Object value) {
return delegate.containsValue(value);
}
public final V get(final Object key) {
return delegate.get(key);
}
public final boolean isEmpty() {
return delegate.isEmpty();
}
public final int size() {
return delegate.size();
}
@Override
public final boolean equals(final Object o) {
return delegate.equals(o);
}
@Override
public final int hashCode() {
return delegate.hashCode();
}
protected final M getDelegate() {
return delegate;
}
@Override
public String toString() {
return delegate.toString();
}
//
// inner classes
//
private class KeySet extends CollectionView implements Set {
@Override
Collection getDelegate() {
return delegate.keySet();
}
//
// mutable operations
//
public void clear() {
lock.lock();
try {
M map = copy();
map.keySet().clear();
set(map);
} finally {
lock.unlock();
}
}
public boolean remove(final Object o) {
return AbstractCopyOnWriteMap.this.remove(o) != null;
}
public boolean removeAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.keySet().removeAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean retainAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.keySet().retainAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
}
private final class Values extends CollectionView {
@Override
Collection getDelegate() {
return delegate.values();
}
public void clear() {
lock.lock();
try {
M map = copy();
map.values().clear();
set(map);
} finally {
lock.unlock();
}
}
public boolean remove(final Object o) {
lock.lock();
try {
if (!contains(o)) {
return false;
}
M map = copy();
try {
return map.values().remove(o);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean removeAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.values().removeAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean retainAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.values().retainAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
}
private class EntrySet extends CollectionView> implements Set> {
@Override
Collection> getDelegate() {
return delegate.entrySet();
}
public void clear() {
lock.lock();
try {
M map = copy();
map.entrySet().clear();
set(map);
} finally {
lock.unlock();
}
}
public boolean remove(final Object o) {
lock.lock();
try {
if (!contains(o)) {
return false;
}
M map = copy();
try {
return map.entrySet().remove(o);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean removeAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.entrySet().removeAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
public boolean retainAll(final Collection> c) {
lock.lock();
try {
M map = copy();
try {
return map.entrySet().retainAll(c);
} finally {
set(map);
}
} finally {
lock.unlock();
}
}
}
private static class UnmodifiableIterator implements Iterator {
private final Iterator delegate;
UnmodifiableIterator(final Iterator delegate) {
this.delegate = delegate;
}
public boolean hasNext() {
return delegate.hasNext();
}
public T next() {
return delegate.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
protected abstract static class CollectionView implements Collection {
abstract Collection getDelegate();
//
// delegate operations
//
public final boolean contains(final Object o) {
return getDelegate().contains(o);
}
public final boolean containsAll(final Collection> c) {
return getDelegate().containsAll(c);
}
public final Iterator iterator() {
return new UnmodifiableIterator(getDelegate().iterator());
}
public final boolean isEmpty() {
return getDelegate().isEmpty();
}
public final int size() {
return getDelegate().size();
}
public final Object[] toArray() {
return getDelegate().toArray();
}
public final T[] toArray(final T[] a) {
return getDelegate().toArray(a);
}
@Override
public int hashCode() {
return getDelegate().hashCode();
}
@Override
public boolean equals(final Object obj) {
return getDelegate().equals(obj);
}
@Override
public String toString() {
return getDelegate().toString();
}
//
// unsupported operations
//
public final boolean add(final E o) {
throw new UnsupportedOperationException();
}
public final boolean addAll(final Collection extends E> c) {
throw new UnsupportedOperationException();
}
}
private boolean equals(final Object o1, final Object o2) {
if (o1 == null) {
return o2 == null;
}
return o1.equals(o2);
}
/**
* Provides access to the views of the underlying key, value and entry collections.
*/
public abstract static class View {
View() {
}
abstract Set keySet();
abstract Set> entrySet();
abstract Collection values();
/**
* The different types of {@link View} available
*/
public enum Type {
STABLE {
@Override
> View get(final AbstractCopyOnWriteMap host) {
return host.new Immutable();
}
},
LIVE {
@Override
> View get(final AbstractCopyOnWriteMap host) {
return host.new Mutable();
}
};
abstract > View get(AbstractCopyOnWriteMap host);
}
}
final class Immutable extends View {
@Override
public Set keySet() {
return unmodifiableSet(delegate.keySet());
}
@Override
public Set> entrySet() {
return unmodifiableSet(delegate.entrySet());
}
@Override
public Collection values() {
return unmodifiableCollection(delegate.values());
}
}
final class Mutable extends View {
private final transient KeySet keySet = new KeySet();
private final transient EntrySet entrySet = new EntrySet();
private final transient Values values = new Values();
@Override
public Set keySet() {
return keySet;
}
@Override
public Set> entrySet() {
return entrySet;
}
@Override
public Collection values() {
return values;
}
}
}