com.opengamma.master.position.impl.MasterPositionSource.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.master.position.impl.MasterPositionSource.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.master.position.impl;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.collect.Maps;
import com.opengamma.DataNotFoundException;
import com.opengamma.core.change.ChangeManager;
import com.opengamma.core.position.Portfolio;
import com.opengamma.core.position.PortfolioNode;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.PositionSource;
import com.opengamma.core.position.Trade;
import com.opengamma.core.position.impl.SimplePortfolio;
import com.opengamma.core.position.impl.SimplePortfolioNode;
import com.opengamma.core.position.impl.SimplePosition;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.VersionedSource;
import com.opengamma.master.portfolio.ManageablePortfolio;
import com.opengamma.master.portfolio.ManageablePortfolioNode;
import com.opengamma.master.portfolio.PortfolioMaster;
import com.opengamma.master.portfolio.PortfolioSearchRequest;
import com.opengamma.master.portfolio.PortfolioSearchResult;
import com.opengamma.master.position.ManageablePosition;
import com.opengamma.master.position.ManageableTrade;
import com.opengamma.master.position.PositionDocument;
import com.opengamma.master.position.PositionMaster;
import com.opengamma.master.position.PositionSearchRequest;
import com.opengamma.master.position.PositionSearchResult;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.PublicSPI;

/**
 * A {@code PositionSource} implemented using an underlying {@code PositionMaster}.
 * <p>
 * The {@link PositionSource} interface provides securities to the engine via a narrow API.
 * This class provides the source on top of a standard {@link PortfolioMaster}.
 */
@PublicSPI
public class MasterPositionSource implements PositionSource, VersionedSource {
    // TODO: This still needs work re versioning, as it crosses the boundary between two masters

    private static final Logger s_logger = LoggerFactory.getLogger(MasterPositionSource.class);

    /**
     * The portfolio master.
     */
    private final PortfolioMaster _portfolioMaster;
    /**
     * The position master.
     */
    private final PositionMaster _positionMaster;
    /**
     * The version-correction locator to search at, null to not override versions.
     */
    private volatile VersionCorrection _versionCorrection;

    /**
     * Creates an instance with underlying masters which does not override versions.
     * 
     * @param portfolioMaster  the portfolio master, not null
     * @param positionMaster  the position master, not null
     */
    public MasterPositionSource(final PortfolioMaster portfolioMaster, final PositionMaster positionMaster) {
        this(portfolioMaster, positionMaster, null);
    }

    /**
     * Creates an instance with underlying masters optionally overriding the requested version.
     * 
     * @param portfolioMaster  the portfolio master, not null
     * @param positionMaster  the position master, not null
     * @param versionCorrection  the version-correction locator to search at, null to not override versions
     */
    public MasterPositionSource(final PortfolioMaster portfolioMaster, final PositionMaster positionMaster,
            final VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(portfolioMaster, "portfolioMaster");
        ArgumentChecker.notNull(positionMaster, "positionMaster");
        _portfolioMaster = portfolioMaster;
        _positionMaster = positionMaster;
        _versionCorrection = versionCorrection;
    }

    //-------------------------------------------------------------------------
    /**
     * Gets the underlying portfolio master.
     * 
     * @return the portfolio master, not null
     */
    public PortfolioMaster getPortfolioMaster() {
        return _portfolioMaster;
    }

    /**
     * Gets the underlying position master.
     * 
     * @return the position master, not null
     */
    public PositionMaster getPositionMaster() {
        return _positionMaster;
    }

    /**
     * Gets the version-correction locator to search at.
     * 
     * @return the version-correction locator to search at, null if not overriding versions
     */
    public VersionCorrection getVersionCorrection() {
        return _versionCorrection;
    }

    /**
     * Sets the version-correction locator to search at.
     * 
     * @param versionCorrection  the version-correction locator to search at, null to not override versions
     */
    @Override
    public void setVersionCorrection(final VersionCorrection versionCorrection) {
        _versionCorrection = versionCorrection;
    }

    //-------------------------------------------------------------------------
    @Override
    public Portfolio getPortfolio(final UniqueId uniqueId) {
        ArgumentChecker.notNull(uniqueId, "uniqueId");
        final VersionCorrection vc = getVersionCorrection(); // lock against change
        ManageablePortfolio manPrt;
        if (vc != null) {
            manPrt = getPortfolioMaster().get(uniqueId, vc).getPortfolio();
        } else {
            manPrt = getPortfolioMaster().get(uniqueId).getPortfolio();
        }
        SimplePortfolio prt = new SimplePortfolio(manPrt.getUniqueId(), manPrt.getName());
        convertNode(manPrt.getRootNode(), prt.getRootNode(), vc);
        copyAttributes(manPrt, prt);
        return prt;
    }

    private void copyAttributes(ManageablePortfolio manPrt, SimplePortfolio prt) {
        if (manPrt.getAttributes() != null) {
            for (Entry<String, String> entry : manPrt.getAttributes().entrySet()) {
                if (entry.getKey() != null && entry.getValue() != null) {
                    prt.addAttribute(entry.getKey(), entry.getValue());
                }
            }
        }
    }

    @Override
    public Portfolio getPortfolio(ObjectId objectId, VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(objectId, "objectId");
        ArgumentChecker.notNull(versionCorrection, "versionCorrection");
        ManageablePortfolio manPrt = getPortfolioMaster().get(objectId, versionCorrection).getPortfolio();
        SimplePortfolio prt = new SimplePortfolio(manPrt.getUniqueId(), manPrt.getName());
        convertNode(manPrt.getRootNode(), prt.getRootNode(), versionCorrection);
        copyAttributes(manPrt, prt);
        return prt;
    }

    @Override
    public PortfolioNode getPortfolioNode(final UniqueId uniqueId) {
        ArgumentChecker.notNull(uniqueId, "uniqueId");
        final VersionCorrection vc = getVersionCorrection(); // lock against change
        ManageablePortfolioNode manNode = null;
        if (vc != null) {
            // use defined instants
            PortfolioSearchRequest portfolioSearch = new PortfolioSearchRequest();
            portfolioSearch.addNodeObjectId(uniqueId);
            portfolioSearch.setVersionCorrection(vc);
            PortfolioSearchResult portfolios = getPortfolioMaster().search(portfolioSearch);
            if (portfolios.getDocuments().size() == 1) {
                ManageablePortfolio manPrt = portfolios.getFirstPortfolio();
                manNode = manPrt.getRootNode().findNodeByObjectId(uniqueId);
            }
        } else {
            // match by uniqueId
            manNode = getPortfolioMaster().getNode(uniqueId);
        }
        if (manNode == null) {
            throw new DataNotFoundException("Unable to find node: " + uniqueId);
        }
        SimplePortfolioNode node = new SimplePortfolioNode();
        convertNode(manNode, node, vc);
        return node;
    }

    @Override
    public Position getPosition(final UniqueId uniqueId) {
        ArgumentChecker.notNull(uniqueId, "uniqueId");
        String[] schemes = StringUtils.split(uniqueId.getScheme(), '-');
        String[] values = StringUtils.split(uniqueId.getValue(), '-');
        String[] versions = Objects.firstNonNull(StringUtils.split(uniqueId.getVersion(), '-'),
                new String[] { null, null });
        if (schemes.length != 2 || values.length != 2 || versions.length != 2) {
            throw new IllegalArgumentException("Invalid position identifier for MasterPositionSource: " + uniqueId);
        }
        UniqueId nodeId = UniqueId.of(schemes[0], values[0], versions[0]);
        UniqueId posId = UniqueId.of(schemes[1], values[1], versions[1]);
        final VersionCorrection vc = getVersionCorrection(); // lock against change
        ManageablePosition manPos;
        if (vc != null) {
            manPos = getPositionMaster().get(posId, vc).getPosition();
        } else {
            manPos = getPositionMaster().get(posId).getPosition();
        }
        if (manPos == null) {
            throw new DataNotFoundException("Unable to find position: " + uniqueId);
        }
        return convertPosition(nodeId, manPos);
    }

    @Override
    public Trade getTrade(UniqueId uniqueId) {
        ArgumentChecker.notNull(uniqueId, "uniqueId");
        String[] schemes = StringUtils.split(uniqueId.getScheme(), '-');
        String[] values = StringUtils.split(uniqueId.getValue(), '-');
        String[] versions = Objects.firstNonNull(StringUtils.split(uniqueId.getVersion(), '-'),
                new String[] { null, null });
        if (schemes.length != 2 || values.length != 2 || versions.length != 2) {
            throw new IllegalArgumentException("Invalid trade identifier for MasterPositionSource: " + uniqueId);
        }
        UniqueId nodeId = versions[0].length() == 0 ? UniqueId.of(schemes[0], values[0])
                : UniqueId.of(schemes[0], values[0], versions[0]);
        UniqueId tradeId = versions[0].length() == 0 ? UniqueId.of(schemes[1], values[1])
                : UniqueId.of(schemes[1], values[1], versions[1]);
        final VersionCorrection vc = getVersionCorrection(); // lock against change
        ManageableTrade manTrade = null;
        if (vc != null) {
            // use defined instants
            PositionSearchRequest positionSearch = new PositionSearchRequest();
            positionSearch.addTradeObjectId(tradeId);
            positionSearch.setVersionCorrection(vc);
            PositionSearchResult positions = getPositionMaster().search(positionSearch);
            if (positions.getDocuments().size() == 1) {
                ManageablePosition manPos = positions.getFirstPosition();
                manTrade = manPos.getTrade(tradeId);
            }
        } else {
            // match by uniqueId
            manTrade = getPositionMaster().getTrade(tradeId);
        }
        if (manTrade == null) {
            throw new DataNotFoundException("Unable to find trade: " + uniqueId);
        }
        convertTrade(nodeId, convertId(manTrade.getParentPositionId(), nodeId), manTrade);
        return manTrade;
    }

    private static int populatePositionSearchRequest(final PositionSearchRequest positionSearch,
            final ManageablePortfolioNode node) {
        int count = 0;
        for (ObjectId positionId : node.getPositionIds()) {
            positionSearch.addPositionObjectId(positionId);
            count++;
        }
        for (ManageablePortfolioNode child : node.getChildNodes()) {
            count += populatePositionSearchRequest(positionSearch, child);
        }
        return count;
    }

    /**
     * Converts a manageable node to a source node.
     * 
     * @param versionCorrection the version correction, not null
     * @param manNode the manageable node, not null
     * @param sourceNode the source node, not null
     */
    protected void convertNode(final ManageablePortfolioNode manNode, final SimplePortfolioNode sourceNode,
            VersionCorrection versionCorrection) {
        PositionSearchRequest positionSearch = new PositionSearchRequest();
        final Map<ObjectId, ManageablePosition> positionCache;
        final int positionCount = populatePositionSearchRequest(positionSearch, manNode);
        if (positionCount > 0) {
            positionCache = Maps.newHashMapWithExpectedSize(positionCount);
            positionSearch.setVersionCorrection(versionCorrection);
            final PositionSearchResult positions = getPositionMaster().search(positionSearch);
            for (PositionDocument position : positions.getDocuments()) {
                positionCache.put(position.getObjectId(), position.getPosition());
            }
        } else {
            positionCache = null;
        }
        convertNode(manNode, sourceNode, positionCache);
    }

    /**
     * Converts a manageable node to a source node.
     * 
     * @param manNode the manageable node, not null
     * @param sourceNode the source node, not null
     * @param positionCache the positions, not null
     */
    protected void convertNode(final ManageablePortfolioNode manNode, final SimplePortfolioNode sourceNode,
            final Map<ObjectId, ManageablePosition> positionCache) {
        final UniqueId nodeId = manNode.getUniqueId();
        sourceNode.setUniqueId(nodeId);
        sourceNode.setName(manNode.getName());
        sourceNode.setParentNodeId(manNode.getParentNodeId());
        if (manNode.getPositionIds().size() > 0) {
            for (ObjectId positionId : manNode.getPositionIds()) {
                final ManageablePosition foundPosition = positionCache.get(positionId);
                if (foundPosition != null) {
                    sourceNode.addPosition(convertPosition(nodeId, foundPosition));
                } else {
                    s_logger.warn("Position {} not found for portfolio node {}", positionId, nodeId);
                }
            }
        }
        for (ManageablePortfolioNode child : manNode.getChildNodes()) {
            SimplePortfolioNode childNode = new SimplePortfolioNode();
            convertNode(child, childNode, positionCache);
            sourceNode.addChildNode(childNode);
        }
    }

    /**
     * Converts a manageable position to a source position
     * 
     * @param nodeId  the parent node unique identifier, null if root
     * @param manPos  the manageable position, not null
     * @return the converted position, not null
     */
    protected SimplePosition convertPosition(final UniqueId nodeId, final ManageablePosition manPos) {
        final SimplePosition position = manPos.toPosition(nodeId);
        UniqueId posId = convertId(manPos.getUniqueId(), nodeId);
        position.setUniqueId(posId);
        for (ManageableTrade manTrade : manPos.getTrades()) {
            convertTrade(nodeId, posId, manTrade);
        }
        return position;
    }

    /**
     * Converts a manageable trade to a source trade.
     * 
     * @param nodeId  the parent node unique identifier, null if root
     * @param posId  the converted position unique identifier, not null
     * @param manTrade  the manageable trade, not null
     */
    protected void convertTrade(final UniqueId nodeId, final UniqueId posId, final ManageableTrade manTrade) {
        manTrade.setUniqueId(convertId(manTrade.getUniqueId(), nodeId));
        manTrade.setParentPositionId(posId);
    }

    /**
     * Converts a position/trade unique identifier to one unique to the node.
     * 
     * @param positionOrTradeId  the unique identifier to convert, not null
     * @param nodeId  the node unique identifier, not null
     * @return the combined unique identifier, not null
     */
    protected UniqueId convertId(final UniqueId positionOrTradeId, final UniqueId nodeId) {
        return UniqueId.of(nodeId.getScheme() + '-' + positionOrTradeId.getScheme(),
                nodeId.getValue() + '-' + positionOrTradeId.getValue(),
                StringUtils.defaultString(nodeId.getVersion()) + '-'
                        + StringUtils.defaultString(positionOrTradeId.getVersion()));
    }

    //-------------------------------------------------------------------------
    @Override
    public ChangeManager changeManager() {
        // NOTE jonathan 2011-08-03 -- PortfolioMaster does not currently implement ChangeProvider so currently return the
        // PositionMaster's ChangeManager.
        return getPositionMaster().changeManager();
    }

    //-------------------------------------------------------------------------
    @Override
    public String toString() {
        String str = getClass().getSimpleName() + "[" + getPortfolioMaster() + "," + getPositionMaster();
        if (getVersionCorrection() != null) {
            str += ",versionCorrection=" + getVersionCorrection();
        }
        return str + "]";
    }

}