com.opengamma.engine.position.csv.CSVPositionSource.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.engine.position.csv.CSVPositionSource.java

Source

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

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import au.com.bytecode.opencsv.CSVReader;

import com.opengamma.DataNotFoundException;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.change.ChangeManager;
import com.opengamma.core.change.DummyChangeManager;
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.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.util.ArgumentChecker;

/**
 * A source of positions based on CSV-formatted files.
 */
public class CSVPositionSource implements PositionSource {

    /** Logger. */
    private static final Logger s_logger = LoggerFactory.getLogger(CSVPositionSource.class);

    /**
     * The base file directory.
     */
    private final File _baseDirectory;
    /**
     * The portfolio by identifier.
     */
    private final ConcurrentMap<ObjectId, Object> _portfolios = new ConcurrentSkipListMap<ObjectId, Object>();
    /**
     * The nodes by identifier.
     */
    private final Map<UniqueId, PortfolioNode> _nodes = new TreeMap<UniqueId, PortfolioNode>();
    /**
     * The positions by identifier.
     */
    private final Map<ObjectId, Position> _positions = new TreeMap<ObjectId, Position>();
    /**
     * The trades by identifier.
     */
    private final Map<UniqueId, Trade> _trades = new TreeMap<UniqueId, Trade>();

    /**
     * Creates an empty CSV position source.
     */
    public CSVPositionSource() {
        _baseDirectory = null;
    }

    /**
     * Creates a CSV position source using the specified directory.
     * @param baseDirectoryName  the directory name, not null
     */
    public CSVPositionSource(String baseDirectoryName) {
        this(new File(baseDirectoryName));
    }

    /**
     * Creates a CSV position source using the specified directory.
     * @param baseDirectory  the directory, not null
     */
    public CSVPositionSource(File baseDirectory) {
        ArgumentChecker.notNull(baseDirectory, "base directory");
        if (baseDirectory.exists() == false) {
            throw new IllegalArgumentException("Base directory must exist: " + baseDirectory);
        }
        if (baseDirectory.isDirectory() == false) {
            throw new IllegalArgumentException("Base directory must be a directory: " + baseDirectory);
        }
        try {
            _baseDirectory = baseDirectory.getCanonicalFile();
        } catch (IOException ex) {
            throw new OpenGammaRuntimeException(
                    "Base directory must resolve to a canonical reference: " + baseDirectory, ex);
        }
        populatePortfolioIds();
    }

    /**
     * Populate the portfolio identifiers from the base directory.
     */
    private void populatePortfolioIds() {
        File[] filesInBaseDirectory = getBaseDirectory().listFiles();
        for (File file : filesInBaseDirectory) {
            if (file.isFile() == false || file.isHidden() || file.canRead() == false) {
                continue;
            }
            String portfolioName = buildPortfolioName(file.getName());
            _portfolios.put(ObjectId.of("CSV-" + file.getName(), portfolioName), file);
        }
    }

    private String buildPortfolioName(String fileName) {
        if (fileName.endsWith(".csv") || fileName.endsWith(".txt")) {
            return fileName.substring(0, fileName.length() - 4);
        }
        return fileName;
    }

    private Position getPosition(final ObjectId positionId) {
        Position position = _positions.get(positionId);
        if (position == null) {
            throw new DataNotFoundException("Unable to find position: " + positionId);
        }
        return position;
    }

    //-------------------------------------------------------------------------
    /**
     * Gets the base directory.
     * @return the baseDirectory, may be null
     */
    public File getBaseDirectory() {
        return _baseDirectory;
    }

    //-------------------------------------------------------------------------
    public Set<ObjectId> getPortfolioIds() {
        return Collections.unmodifiableSet(_portfolios.keySet());
    }

    @Override
    public Portfolio getPortfolio(UniqueId portfolioId, final VersionCorrection versionCorrection) {
        // Ignore the version
        return getPortfolio(portfolioId.getObjectId(), VersionCorrection.LATEST);
    }

    @Override
    public Portfolio getPortfolio(ObjectId objectId, VersionCorrection versionCorrection) {
        Object portfolio = _portfolios.get(objectId);
        if (portfolio instanceof File) {
            Portfolio created = loadPortfolio(objectId, (File) portfolio);
            _portfolios.replace(objectId, portfolio, created);
            portfolio = _portfolios.get(objectId);
        }
        if (portfolio instanceof Portfolio) {
            return (Portfolio) portfolio;
        }
        throw new DataNotFoundException("Unable to find portfolio: " + objectId);
    }

    @Override
    public PortfolioNode getPortfolioNode(UniqueId nodeId, final VersionCorrection versionCorrection) {
        PortfolioNode node = _nodes.get(nodeId);
        if (node == null) {
            throw new DataNotFoundException("Unable to find node: " + nodeId);
        }
        return node;
    }

    @Override
    public Position getPosition(UniqueId positionId) {
        // Ignore the version
        return getPosition(positionId.getObjectId());
    }

    @Override
    public Position getPosition(ObjectId positionId, VersionCorrection versionCorrection) {
        // Ignore the version
        return getPosition(positionId);
    }

    @Override
    public Trade getTrade(UniqueId tradeId) {
        Trade trade = _trades.get(tradeId);
        if (trade == null) {
            throw new DataNotFoundException("Unable to find trade: " + tradeId);
        }
        return trade;
    }

    //-------------------------------------------------------------------------
    @Override
    public ChangeManager changeManager() {
        return DummyChangeManager.INSTANCE;
    }

    //-------------------------------------------------------------------------
    private Portfolio loadPortfolio(ObjectId portfolioId, File file) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            return loadPortfolio(portfolioId, fis);
        } catch (IOException ex) {
            throw new OpenGammaRuntimeException("Unable to parse portfolio file: " + file, ex);
        } finally {
            IOUtils.closeQuietly(fis);
        }
    }

    private Portfolio loadPortfolio(ObjectId portfolioId, InputStream inStream) throws IOException {
        SimplePortfolio portfolio = new SimplePortfolio(portfolioId.atVersion("0"), portfolioId.getValue());
        UniqueId rootNodeId = UniqueId.of(portfolioId.getScheme(), "0");
        portfolio.getRootNode().setUniqueId(rootNodeId);
        _nodes.put(rootNodeId, portfolio.getRootNode());

        CSVReader csvReader = new CSVReader(new InputStreamReader(inStream));
        String[] tokens = null;
        int curIndex = 1;
        UniqueId positionId = UniqueId.of(portfolioId.getScheme(), Integer.toString(curIndex));
        while ((tokens = csvReader.readNext()) != null) {
            SimplePosition position = parseLine(tokens, positionId);
            if (position != null) {
                ((SimplePortfolioNode) portfolio.getRootNode()).addPosition(position);
                _positions.put(position.getUniqueId().getObjectId(), position);
                positionId = UniqueId.of(portfolioId.getScheme(), Integer.toString(++curIndex));
            }
        }
        s_logger.info("{} parsed stream with {} positions", portfolioId,
                portfolio.getRootNode().getPositions().size());
        return portfolio;
    }

    /**
     * @param line  the line to parse, not null
     * @param positionId  the portfolio id, not null
     * @return the position
     */
    /* package for testing */ static SimplePosition parseLine(String[] tokens, UniqueId positionId) {
        if (tokens.length < 3) {
            return null;
        }
        // First token is the quantity
        BigDecimal quantity = new BigDecimal(tokens[0].trim());

        // Each set of 2 tokens is then security id domain and then id 
        List<ExternalId> securityIdentifiers = new ArrayList<ExternalId>();
        for (int i = 1; i < (tokens.length - 1); i++) {
            String idScheme = tokens[i].trim();
            String idValue = tokens[++i].trim();
            ExternalId id = ExternalId.of(idScheme, idValue);
            securityIdentifiers.add(id);
        }
        ExternalIdBundle securityKey = ExternalIdBundle.of(securityIdentifiers);
        s_logger.debug("Loaded position: {} in {}", quantity, securityKey);

        return new SimplePosition(positionId, quantity, securityKey);
    }

}