Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Utility to fetch a reference for an instance mapped by a particular key.
/*
* Copyright (c) 2012 Michael Nischt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.monoid.util.ref;
/**
* Provides an instance mapped to a particular key
* @author Michael Nischt
*/
public interface InstanceProvider<K, V> {
/**
* Provides the instance to the mapped key
* @param key mapped to the reference
* @return a reference to the mapped key
*/
V get(K key);
}
/*
* Copyright (c) 2012 Michael Nischt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.monoid.util.ref;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
/**
* Provides a reference to an instance. If no instance mapped by the specified key exists, a new one is created.
*
* @author Michael Nischt
*
*/
public final class ReferenceProvider<K, V> implements InstanceProvider<K, V> {
private static class Reference<K, V> extends WeakReference<V> {
private final K key;
public Reference(K key, V referent, ReferenceQueue<? super V> q) {
super(referent, q);
this.key = key;
}
public K getKey() {
return key;
}
}
private final InstanceProvider<K, V> instanceProvider;
private final Map<K, Reference<K, V>> map = new HashMap<>();
private final ReferenceQueue<V> queue = new ReferenceQueue<> ();
/**
* Creates a new ReferenceProvider
* @param instanceProvider used the create a new instance if no reference exists
*/
public ReferenceProvider(InstanceProvider<K, V> instanceProvider) {
if(instanceProvider == null) {
throw new NullPointerException("InstanceProvider cannut be null");
}
this.instanceProvider = instanceProvider;
}
/**
* Retrieves a new reference for the specified key. If no instance exists yet, a new is created using the wrapped @link{InstanceProvider}
* @param key mapped to the reference
* @return a reference to the mapped key
*/
@Override
synchronized public V get(K key) {
V value; {
Reference<K, V> reference = map.get(key);
value = reference != null ? reference.get() : null;
}
if(value == null) {
value = instanceProvider.get(key);
map.put(key, new Reference<>(key, value, queue));
}
return value;
}
/**
* Cleans dead references.
* @return the number dead references removedS
*/
synchronized public int clean() {
int n=0;
Reference<K, V> reference;
do {
reference = (Reference<K, V>) queue.poll();
if(reference == null) {
continue;
}
map.remove(reference.getKey());
n++;
} while(reference != null);
return n;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment