/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.user.rest;
import java.net.URI;
import org.fudgemsg.FudgeContext;
import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveDefinitionMaster;
import com.opengamma.financial.analytics.ircurve.rest.RemoteInterpolatedYieldCurveDefinitionMaster;
import com.opengamma.financial.convention.ConventionBundleMaster;
import com.opengamma.financial.convention.InMemoryConventionBundleMaster;
import com.opengamma.master.config.ConfigMaster;
import com.opengamma.master.config.impl.RemoteConfigMaster;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesMaster;
import com.opengamma.master.historicaltimeseries.impl.RemoteHistoricalTimeSeriesMaster;
import com.opengamma.master.marketdatasnapshot.MarketDataSnapshotMaster;
import com.opengamma.master.marketdatasnapshot.impl.RemoteMarketDataSnapshotMaster;
import com.opengamma.master.portfolio.PortfolioMaster;
import com.opengamma.master.portfolio.impl.RemotePortfolioMaster;
import com.opengamma.master.position.PositionMaster;
import com.opengamma.master.position.impl.RemotePositionMaster;
import com.opengamma.master.security.SecurityMaster;
import com.opengamma.master.security.impl.RemoteSecurityMaster;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.rest.FudgeRestClient;
/**
* Provides access to a remote representation of a "client". A client is defined as a set of coherent
* and related masters. These might be the set of masters corresponding to the "shared" data used by
* all users of an OpenGamma instance, or the masters containing data specific to a single user or
* perhaps a group of users.
*/
public class RemoteClient {
/**
* Source of targets for the entities this client will connect to.
*/
public abstract static class TargetProvider {
protected <T> T notImplemented(final String what) {
throw new UnsupportedOperationException("The '" + what + "' is not available for this client");
}
public URI getPortfolioMaster() {
return notImplemented("portfolioMaster");
}
public URI getPositionMaster() {
return notImplemented("positionMaster");
}
public URI getSecurityMaster() {
return notImplemented("securityMaster");
}
public URI getConfigMaster() {
return notImplemented("configMaster");
}
public URI getInterpolatedYieldCurveDefinitionMaster() {
return notImplemented("interpolatedYieldCurveDefinitionMaster");
}
public URI getHeartbeat() {
return notImplemented("heartbeat");
}
public URI getMarketDataSnapshotMaster() {
return notImplemented("marketDataSnapshotMaster");
}
public URI getHistoricalTimeSeriesMaster() {
return notImplemented("historicalTimeSeriesMaster");
}
}
/**
* Source of targets externally specified.
*/
public static final class ExternalTargetProvider extends TargetProvider {
private URI _portfolioMaster;
private URI _positionMaster;
private URI _securityMaster;
private URI _configMaster;
private URI _interpolatedYieldCurveDefinitionMaster;
private URI _heartbeat;
private URI _marketDataSnapshotMaster;
private URI _historicalTimeSeriesMaster;
public void setPortfolioMaster(final URI portfolioMaster) {
_portfolioMaster = portfolioMaster;
}
@Override
public URI getPortfolioMaster() {
return (_portfolioMaster != null) ? _portfolioMaster : super.getPortfolioMaster();
}
public void setPositionMaster(final URI positionMaster) {
_positionMaster = positionMaster;
}
@Override
public URI getPositionMaster() {
return (_positionMaster != null) ? _positionMaster : super.getPositionMaster();
}
public void setSecurityMaster(final URI securityMaster) {
_securityMaster = securityMaster;
}
@Override
public URI getSecurityMaster() {
return (_securityMaster != null) ? _securityMaster : super.getSecurityMaster();
}
public void setConfigMaster(final URI configMaster) {
_configMaster = configMaster;
}
@Override
public URI getConfigMaster() {
return (_configMaster != null) ? _configMaster : super.getConfigMaster();
}
public void setInterpolatedYieldCurveDefinitionMaster(final URI interpolatedYieldCurveDefinitionMaster) {
_interpolatedYieldCurveDefinitionMaster = interpolatedYieldCurveDefinitionMaster;
}
@Override
public URI getInterpolatedYieldCurveDefinitionMaster() {
return (_interpolatedYieldCurveDefinitionMaster != null) ? _interpolatedYieldCurveDefinitionMaster : super.getInterpolatedYieldCurveDefinitionMaster();
}
public void setHeartbeat(final URI heartbeat) {
_heartbeat = heartbeat;
}
@Override
public URI getHeartbeat() {
return (_heartbeat != null) ? _heartbeat : super.getHeartbeat();
}
public void setMarketDataSnapshotMaster(final URI marketDataSnapshotMaster) {
_marketDataSnapshotMaster = marketDataSnapshotMaster;
}
@Override
public URI getMarketDataSnapshotMaster() {
return (_marketDataSnapshotMaster != null) ? _marketDataSnapshotMaster : super.getMarketDataSnapshotMaster();
}
public void setHistoricalTimeSeriesMaster(final URI historicalTimeSeriesMaster) {
_historicalTimeSeriesMaster = historicalTimeSeriesMaster;
}
@Override
public URI getHistoricalTimeSeriesMaster() {
return (_historicalTimeSeriesMaster != null) ? _historicalTimeSeriesMaster : super.getHistoricalTimeSeriesMaster();
}
}
/**
* Source of targets built from a single "base" URI.
*/
public static final class BaseUriTargetProvider extends TargetProvider {
private final URI _baseUri;
private final String _userName;
private final String _clientName;
public BaseUriTargetProvider(final URI baseUri, final String userName, final String clientName) {
ArgumentChecker.notNull(baseUri, "baseUri");
_baseUri = baseUri;
_userName = userName;
_clientName = clientName;
}
@Override
public URI getSecurityMaster() {
return DataFinancialClientResource.uriSecurityMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getPositionMaster() {
return DataFinancialClientResource.uriPositionMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getPortfolioMaster() {
return DataFinancialClientResource.uriPortfolioMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getConfigMaster() {
return DataFinancialClientResource.uriConfigMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getInterpolatedYieldCurveDefinitionMaster() {
return DataFinancialClientResource.uriInterpolatedYieldCurveDefinitionMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getMarketDataSnapshotMaster() {
return DataFinancialClientResource.uriSnapshotMaster(_baseUri, _userName, _clientName);
}
@Override
public URI getHeartbeat() {
return DataFinancialClientResource.uriHeartbeat(_baseUri, _userName, _clientName);
}
}
private final String _clientId;
private final TargetProvider _targetProvider;
private volatile PortfolioMaster _portfolioMaster;
private volatile PositionMaster _positionMaster;
private volatile SecurityMaster _securityMaster;
private volatile ConfigMaster _configMaster;
private volatile InterpolatedYieldCurveDefinitionMaster _interpolatedYieldCurveDefinitionMaster;
private volatile MarketDataSnapshotMaster _marketDataSnapshotMaster;
private volatile HistoricalTimeSeriesMaster _historicalTimeSeriesMaster;
// TODO [PLAT-637] We're using the in memory job as a hack
private static ConventionBundleMaster s_conventionBundleMaster;
public RemoteClient(final String clientId, final FudgeContext fudgeContext, final TargetProvider uriProvider) {
_clientId = clientId;
_targetProvider = uriProvider;
}
public String getClientId() {
return _clientId;
}
public PortfolioMaster getPortfolioMaster() {
if (_portfolioMaster == null) {
_portfolioMaster = new RemotePortfolioMaster(_targetProvider.getPortfolioMaster());
}
return _portfolioMaster;
}
public PositionMaster getPositionMaster() {
if (_positionMaster == null) {
_positionMaster = new RemotePositionMaster(_targetProvider.getPositionMaster());
}
return _positionMaster;
}
public SecurityMaster getSecurityMaster() {
if (_securityMaster == null) {
_securityMaster = new RemoteSecurityMaster(_targetProvider.getSecurityMaster());
}
return _securityMaster;
}
public ConfigMaster getConfigMaster() {
if (_configMaster == null) {
_configMaster = new RemoteConfigMaster(_targetProvider.getConfigMaster());
}
return _configMaster;
}
public InterpolatedYieldCurveDefinitionMaster getInterpolatedYieldCurveDefinitionMaster() {
if (_interpolatedYieldCurveDefinitionMaster == null) {
_interpolatedYieldCurveDefinitionMaster = new RemoteInterpolatedYieldCurveDefinitionMaster(_targetProvider.getInterpolatedYieldCurveDefinitionMaster());
}
return _interpolatedYieldCurveDefinitionMaster;
}
public MarketDataSnapshotMaster getMarketDataSnapshotMaster() {
if (_marketDataSnapshotMaster == null) {
_marketDataSnapshotMaster = new RemoteMarketDataSnapshotMaster(_targetProvider.getMarketDataSnapshotMaster());
}
return _marketDataSnapshotMaster;
}
public HistoricalTimeSeriesMaster getHistoricalTimeSeriesMaster() {
if (_historicalTimeSeriesMaster == null) {
_historicalTimeSeriesMaster = new RemoteHistoricalTimeSeriesMaster(_targetProvider.getHistoricalTimeSeriesMaster());
}
return _historicalTimeSeriesMaster;
}
public ConventionBundleMaster getConventionBundleMaster() {
// TODO [PLAT-637] We're using the in memory job as a hack
synchronized (RemoteClient.class) {
if (s_conventionBundleMaster == null) {
s_conventionBundleMaster = new InMemoryConventionBundleMaster();
}
return s_conventionBundleMaster;
}
}
/**
* Creates a heartbeat sender. If nothing has happened for a timeout duration, that would result in messages being sent to the server,
* the heartbeat signal should be sent as a keep-alive.
*
* @return a runnable sender. Each invocation of {@link Runnable#run} will send a heartbeat signal
*/
public Runnable createHeartbeatSender() {
final FudgeRestClient client = FudgeRestClient.create();
final URI uri = _targetProvider.getHeartbeat();
return new Runnable() {
@Override
public void run() {
client.accessFudge(uri).post();
}
};
}
//-------------------------------------------------------------------------
/**
* A hack to allow the Excel side to get hold of a RemoteClient without it having to be aware of the URI. Eventually
* we will need a UserMaster to host users and their clients, and the entry point for Excel will be a
* RemoteUserMaster.
*
* @param fudgeContext the Fudge context, not null
* @param baseUserManagerUri base URI for the user manager, does not include "users/{user}", not null
* @param userName the username
* @return a {@link RemoteClient} instance for the new client
*/
public static RemoteClient forNewClient(final FudgeContext fudgeContext, final URI baseUserManagerUri, final String userName) {
final String clientName = GUIDGenerator.generate().toString();
return forClient(fudgeContext, baseUserManagerUri, userName, clientName);
}
public static RemoteClient forClient(final FudgeContext fudgeContext, final URI baseUserManagerUri, final String userName, final String clientName) {
return new RemoteClient(clientName, fudgeContext, new BaseUriTargetProvider(baseUserManagerUri, userName, clientName));
}
}