org.jboss.weld.util.cache.ReentrantMapBackedComputingCache Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.weld.util.cache;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.jboss.weld.util.Function;
import org.jboss.weld.util.LazyValueHolder;
import org.jboss.weld.util.ValueHolder;
/**
* A {@link ComputingCache} backed by a {@link ConcurrentHashMap} which is reentrant.
*
* @author Jozef Hartinger
*
* @param the key type
* @param the value type
* @see ValueHolder
* @see LazyValueHolder
*/
class ReentrantMapBackedComputingCache implements ComputingCache, Iterable {
private final ConcurrentMap> map;
private final Long maxSize;
private final Function> function;
ReentrantMapBackedComputingCache(Function computingFunction, Long maxSize) {
this(computingFunction, LazyValueHolder.forValue(), maxSize);
}
ReentrantMapBackedComputingCache(final Function computingFunction, final Function> valueHolderFunction, Long maxSize) {
this.map = new ConcurrentHashMap<>();
this.maxSize = maxSize;
this.function = new Function>() {
@Override
public ValueHolder apply(K key) {
return valueHolderFunction.apply(computingFunction.apply(key));
}
};
}
@Override
public V getValue(final K key) {
ValueHolder value = map.get(key);
if (value == null) {
value = function.apply(key);
ValueHolder previous = map.putIfAbsent(key, value);
if (previous != null) {
value = previous;
}
// finally, check that we are not over the bound
if (maxSize != null && size() > maxSize) {
clear();
}
}
return value.get();
}
@SuppressWarnings("unchecked")
@Override
public T getCastValue(Object key) {
return (T) getValue((K) key);
}
@Override
public V getValueIfPresent(K key) {
ValueHolder value = map.get(key);
if (value == null) {
return null;
}
return value.getIfPresent();
}
@Override
public long size() {
return map.size();
}
@Override
public void clear() {
map.clear();
}
@Override
public void invalidate(Object key) {
map.remove(key);
}
@Override
public Iterable getAllPresentValues() {
return this;
}
@Override
public String toString() {
return map.toString();
}
@Override
public Iterator iterator() {
return new Iterator() {
private final Iterator> delegate = map.values().iterator();
private V next = findNext();
@Override
public boolean hasNext() {
return next != null;
}
private V findNext() {
while (delegate.hasNext()) {
V next = delegate.next().getIfPresent();
if (next != null) {
return next;
}
}
return null;
}
@Override
public V next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
V current = next;
this.next = findNext();
return current;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
};
}
}