/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.calcnode; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import com.opengamma.util.ArgumentChecker; /** * Maintains a set of capabilities suitable for a {@link JobInvoker} implementation. */ public class CapabilitySet { private final Map<String, Capability> _capabilitiesById = new ConcurrentHashMap<String, Capability>(); private final AtomicInteger _changeId = new AtomicInteger(); private volatile Wrapper _wrapper; private static final class Wrapper implements Collection<Capability> { private final Collection<Capability> _underlying; private final int _changeId; private Wrapper(final Collection<Capability> underlying, final int changeId) { _underlying = underlying; _changeId = changeId; } private Collection<Capability> getUnderlying() { return _underlying; } private int getChangeId() { return _changeId; } @Override public boolean add(Capability e) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection<? extends Capability> c) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public boolean contains(Object o) { return getUnderlying().contains(o); } @Override public boolean containsAll(Collection<?> c) { return getUnderlying().containsAll(c); } @Override public boolean isEmpty() { return getUnderlying().isEmpty(); } @Override public Iterator<Capability> iterator() { return getUnderlying().iterator(); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException(); } @Override public int size() { return getUnderlying().size(); } @Override public Object[] toArray() { return getUnderlying().toArray(); } @Override public <T> T[] toArray(T[] a) { return getUnderlying().toArray(a); } }; protected Wrapper createWrapper() { return new Wrapper(getCapabilitiesById().values(), _changeId.get()); } protected Map<String, Capability> getCapabilitiesById() { return _capabilitiesById; } /** * Adds (or updates) a capability within the set. If there is an existing capability with the same identifier it will be replaced. * * @param capability the new capability, not null */ public void addCapability(final Capability capability) { ArgumentChecker.notNull(capability, "capability"); final Capability previous = getCapabilitiesById().put(capability.getIdentifier(), capability); if (!capability.equals(previous)) { _changeId.incrementAndGet(); } } public void setCapability(final Capability capability) { ArgumentChecker.notNull(capability, "capability"); getCapabilitiesById().clear(); getCapabilitiesById().put(capability.getIdentifier(), capability); _changeId.incrementAndGet(); } public void addCapabilities(final Collection<Capability> capabilities) { ArgumentChecker.notNull(capabilities, "capabilities"); for (Capability capability : capabilities) { getCapabilitiesById().put(capability.getIdentifier(), capability); } _changeId.incrementAndGet(); } public void setCapabilities(final Collection<Capability> capabilities) { ArgumentChecker.notNull(capabilities, "capabilities"); getCapabilitiesById().clear(); for (Capability capability : capabilities) { getCapabilitiesById().put(capability.getIdentifier(), capability); } _changeId.incrementAndGet(); } public void setParameterCapability(final String identifier, final double parameter) { ArgumentChecker.notNull(identifier, "identifier"); Capability capability = getCapabilitiesById().get(identifier); if (capability != null) { if ((capability.getLowerBoundParameter() <= parameter) && (capability.getUpperBoundParameter() >= parameter)) { return; } } getCapabilitiesById().put(identifier, Capability.parameterInstanceOf(identifier, parameter)); _changeId.incrementAndGet(); } /** * Returns a read-only view of the capabilities, backed by the main set. Whenever capabilities change, * the wrapper is reallocated. It's hashCode and equals are identity based comparisons. * * @return the capabilities */ public Collection<Capability> getCapabilities() { if ((_wrapper == null) || (_wrapper.getChangeId() != _changeId.get())) { _wrapper = createWrapper(); } return _wrapper; } }