/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.livedata.client; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.livedata.LiveDataClient; import com.opengamma.livedata.LiveDataListener; import com.opengamma.livedata.LiveDataSpecification; import com.opengamma.livedata.UserPrincipal; import com.opengamma.livedata.msg.LiveDataSubscriptionResponse; import com.opengamma.util.ArgumentChecker; /** * An implementation of {@link LiveDataClient} that delegates all calls to other * clients, keyed by the external ID scheme of the items to be loaded. * Where requests are made that may be satisfied by any of the underlying clients, * the actual underlying client that will be chosen is non-deterministic. */ public class DelegatingLiveDataClient implements LiveDataClient { private static final Logger s_logger = LoggerFactory.getLogger(DelegatingLiveDataClient.class); private final Map<String, LiveDataClient> _underlyingClients = new ConcurrentSkipListMap<String, LiveDataClient>(); private LiveDataClient _defaultClient; public void addUnderlyingClient(String idScheme, LiveDataClient liveDataClient) { ArgumentChecker.notNull(idScheme, "idScheme"); ArgumentChecker.notNull(liveDataClient, "liveDataClient"); _underlyingClients.put(idScheme, liveDataClient); } public void setDefaultClient(LiveDataClient defaultClient) { _defaultClient = defaultClient; } protected LiveDataClient identifyUnderlying(LiveDataSpecification specification) { ExternalIdBundle idBundle = specification.getIdentifiers(); for (ExternalId id : idBundle.getExternalIds()) { LiveDataClient underlying = _underlyingClients.get(id.getScheme().getName()); if (underlying != null) { s_logger.debug("Delegating {} to {}", specification, underlying); return underlying; } } if (_defaultClient != null) { return _defaultClient; } throw new OpenGammaRuntimeException("No underlying client configured to handle " + specification); } protected Map<LiveDataClient, List<LiveDataSpecification>> splitCollection(Collection<LiveDataSpecification> specifications) { Map<LiveDataClient, List<LiveDataSpecification>> result = new HashMap<LiveDataClient, List<LiveDataSpecification>>(); for (LiveDataSpecification specification : specifications) { LiveDataClient underlying = identifyUnderlying(specification); List<LiveDataSpecification> perUnderlyingSpecs = result.get(underlying); if (perUnderlyingSpecs == null) { perUnderlyingSpecs = new LinkedList<LiveDataSpecification>(); result.put(underlying, perUnderlyingSpecs); } perUnderlyingSpecs.add(specification); } return result; } @Override public boolean isEntitled(UserPrincipal user, LiveDataSpecification requestedSpecification) { LiveDataClient underlying = identifyUnderlying(requestedSpecification); return underlying.isEntitled(user, requestedSpecification); } @Override public Map<LiveDataSpecification, Boolean> isEntitled(UserPrincipal user, Collection<LiveDataSpecification> requestedSpecifications) { Map<LiveDataClient, List<LiveDataSpecification>> split = splitCollection(requestedSpecifications); Map<LiveDataSpecification, Boolean> result = new HashMap<LiveDataSpecification, Boolean>(); for (Map.Entry<LiveDataClient, List<LiveDataSpecification>> entry : split.entrySet()) { Map<LiveDataSpecification, Boolean> perUnderlyingResult = entry.getKey().isEntitled(user, entry.getValue()); if (perUnderlyingResult != null) { result.putAll(perUnderlyingResult); } } return result; } @Override public void subscribe(UserPrincipal user, LiveDataSpecification requestedSpecification, LiveDataListener listener) { LiveDataClient underlying = identifyUnderlying(requestedSpecification); underlying.subscribe(user, requestedSpecification, listener); } @Override public void subscribe(UserPrincipal user, Collection<LiveDataSpecification> requestedSpecifications, LiveDataListener listener) { Map<LiveDataClient, List<LiveDataSpecification>> split = splitCollection(requestedSpecifications); for (Map.Entry<LiveDataClient, List<LiveDataSpecification>> entry : split.entrySet()) { entry.getKey().subscribe(user, entry.getValue(), listener); } } @Override public void unsubscribe(UserPrincipal user, LiveDataSpecification fullyQualifiedSpecification, LiveDataListener listener) { LiveDataClient underlying = identifyUnderlying(fullyQualifiedSpecification); underlying.unsubscribe(user, fullyQualifiedSpecification, listener); } @Override public void unsubscribe(UserPrincipal user, Collection<LiveDataSpecification> fullyQualifiedSpecifications, LiveDataListener listener) { Map<LiveDataClient, List<LiveDataSpecification>> split = splitCollection(fullyQualifiedSpecifications); for (Map.Entry<LiveDataClient, List<LiveDataSpecification>> entry : split.entrySet()) { entry.getKey().unsubscribe(user, entry.getValue(), listener); } } @Override public LiveDataSubscriptionResponse snapshot(UserPrincipal user, LiveDataSpecification requestedSpecification, long timeout) { LiveDataClient underlying = identifyUnderlying(requestedSpecification); return underlying.snapshot(user, requestedSpecification, timeout); } @Override public Collection<LiveDataSubscriptionResponse> snapshot(UserPrincipal user, Collection<LiveDataSpecification> requestedSpecifications, long timeout) { Map<LiveDataClient, List<LiveDataSpecification>> split = splitCollection(requestedSpecifications); List<LiveDataSubscriptionResponse> snapshots = new ArrayList<LiveDataSubscriptionResponse>(requestedSpecifications.size()); for (Map.Entry<LiveDataClient, List<LiveDataSpecification>> entry : split.entrySet()) { snapshots.addAll(entry.getKey().snapshot(user, entry.getValue(), timeout)); } return snapshots; } @Override public String getDefaultNormalizationRuleSetId() { // REVIEW kirk 2012-08-17 -- This probably isn't the best behavior here. if (_underlyingClients.isEmpty()) { return null; } return _underlyingClients.values().iterator().next().getDefaultNormalizationRuleSetId(); } @Override public void close() { for (LiveDataClient underlying : _underlyingClients.values()) { underlying.close(); } } }