/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.resource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.opengamma.id.UniqueId;
import com.opengamma.util.ArgumentChecker;
/**
* Default implementation of {@link EngineResourceManager}
*
* @param <T> the type of resource
*/
public class EngineResourceManagerImpl<T extends EngineResource> implements EngineResourceManagerInternal<T> {
private final ConcurrentMap<UniqueId, ReferenceCountedResource<T>> _resourceMap = new ConcurrentHashMap<UniqueId, ReferenceCountedResource<T>>();
@Override
public EngineResourceReferenceImpl<T> manage(T resource) {
ArgumentChecker.notNull(resource, "resource");
ReferenceCountedResource<T> refCountedResource = new ReferenceCountedResource<T>(resource);
if (_resourceMap.put(resource.getUniqueId(), refCountedResource) != null) {
throw new IllegalArgumentException("A resource with ID " + resource.getUniqueId() + " is already being managed");
}
return new EngineResourceReferenceImpl<T>(this, resource);
}
@Override
public EngineResourceReference<T> createReference(UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "uniqueId");
T resource = incrementCycleReferenceCountCore(uniqueId);
return resource == null ? null : new EngineResourceReferenceImpl<T>(this, resource);
}
@Override
public boolean incrementCycleReferenceCount(UniqueId uniqueId) {
return incrementCycleReferenceCountCore(uniqueId) != null;
}
@Override
public boolean decrementCycleReferenceCount(UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "uniqueId");
ReferenceCountedResource<T> refCountedResource = _resourceMap.get(uniqueId);
if (refCountedResource == null) {
return false;
}
synchronized (refCountedResource) {
if (refCountedResource.decrementReferenceCount() == 0) {
_resourceMap.remove(uniqueId);
refCountedResource.get().release();
}
}
return true;
}
@Override
public int getResourceCount() {
return _resourceMap.size();
}
//-------------------------------------------------------------------------
private T incrementCycleReferenceCountCore(UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "uniqueId");
ReferenceCountedResource<T> refCountedResource = _resourceMap.get(uniqueId);
if (refCountedResource == null) {
return null;
}
synchronized (refCountedResource) {
if (refCountedResource.getReferenceCount() > 0) {
refCountedResource.incrementReferenceCount();
} else {
// Concurrently being released, so to the external user it's already been deleted
throw new IllegalArgumentException("No resource with ID " + uniqueId + " could be found");
}
}
return refCountedResource.get();
}
//-------------------------------------------------------------------------
/**
* Holds reference counting state for a resource. Intentionally not thread-safe, so requires external
* synchronisation.
*/
private static class ReferenceCountedResource<T> {
private final T _resource;
private long _refCount = 1;
public ReferenceCountedResource(T resource) {
_resource = resource;
}
public T get() {
return _resource;
}
public long getReferenceCount() {
return _refCount;
}
public long incrementReferenceCount() {
return ++_refCount;
}
public long decrementReferenceCount() {
return --_refCount;
}
}
}