Package com.opengamma.integration.copier.portfolio.writer

Source Code of com.opengamma.integration.copier.portfolio.writer.MasterPortfolioWriter

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.copier.portfolio.writer;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;

import com.google.common.collect.ImmutableMap;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdSearch;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.portfolio.ManageablePortfolio;
import com.opengamma.master.portfolio.ManageablePortfolioNode;
import com.opengamma.master.portfolio.PortfolioDocument;
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.master.security.ManageableSecurity;
import com.opengamma.master.security.ManageableSecurityLink;
import com.opengamma.master.security.SecurityDocument;
import com.opengamma.master.security.SecurityMaster;
import com.opengamma.master.security.SecuritySearchRequest;
import com.opengamma.master.security.SecuritySearchResult;
import com.opengamma.master.security.SecuritySearchSortOrder;
import com.opengamma.master.security.impl.MasterSecuritySource;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.beancompare.BeanCompare;
import com.opengamma.util.tuple.ObjectsPair;

/**
* A class that writes securities and portfolio positions and trades to the OG masters
*/
public class MasterPortfolioWriter implements PortfolioWriter {

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

  private static final int NUMBER_OF_THREADS = 30;

  private final PortfolioMaster _portfolioMaster;
  private final PositionMaster _positionMaster;
  private final SecurityMaster _securityMaster;
  private final SecuritySource _securitySource;

  private PortfolioDocument _portfolioDocument;
  private ManageablePortfolioNode _currentNode;
  private ManageablePortfolioNode _originalNode;
  private ManageablePortfolioNode _originalRoot;

  private String[] _currentPath;

  private BeanCompare _beanCompare;

  private boolean _mergePositions;
  private Map<ObjectId, ManageablePosition> _securityIdToPosition;

  private boolean _keepCurrentPositions;

  private boolean _discardIncompleteOptions;

  private boolean _multithread;
  private ExecutorService _executorService;


  /**
   * Create a master portfolio writer
   * @param portfolioName             The name of the portfolio to create/write to
   * @param portfolioMaster           The portfolio master to which to write the portfolio
   * @param positionMaster            The position master to which to write positions
   * @param securityMaster            The security master to which to write securities
   * @param mergePositions            If true, attempt to roll multiple positions in the same security into one position,
   *                                  for all positions in the same portfolio node;
   *                                  if false, each position is loaded separately
   * @param keepCurrentPositions      If true, keep the existing portfolio node tree and add new entries;
   *                                  if false, delete the entire existing portfolio node tree before loading the new
   *                                  portfolio
   * @param discardIncompleteOptions  If true, when an underlying cannot be loaded, the position/trade will be discarded;
   *                                  if false, the option will be created with a dangling reference to the underlying
   */

  public MasterPortfolioWriter(String portfolioName,
                               PortfolioMaster portfolioMaster,
                               PositionMaster positionMaster,
                               SecurityMaster securityMaster,
                               boolean mergePositions,
                               boolean keepCurrentPositions,
                               boolean discardIncompleteOptions) {
    this(portfolioName, portfolioMaster, positionMaster, securityMaster, mergePositions,
         keepCurrentPositions, discardIncompleteOptions, false);
  }

  public MasterPortfolioWriter(String portfolioName,
                               PortfolioMaster portfolioMaster,
                               PositionMaster positionMaster,
                               SecurityMaster securityMaster,
                               boolean mergePositions,
                               boolean keepCurrentPositions,
                               boolean discardIncompleteOptions,
                               boolean multithread) {

    ArgumentChecker.notEmpty(portfolioName, "portfolioName");
    ArgumentChecker.notNull(portfolioMaster, "portfolioMaster");
    ArgumentChecker.notNull(positionMaster, "positionMaster");
    ArgumentChecker.notNull(securityMaster, "securityMaster");

    _mergePositions = mergePositions;
    _keepCurrentPositions = keepCurrentPositions;
    _discardIncompleteOptions = discardIncompleteOptions;

    _portfolioMaster = portfolioMaster;
    _positionMaster = positionMaster;
    _securityMaster = securityMaster;

    _securitySource = new MasterSecuritySource(_securityMaster);

    // unique ID and external ID bundle are ignored when comparing securities
    Comparator<Object> alwaysEqualComparator = new Comparator<Object>() {
      @Override
      public int compare(Object notUsed1, Object notUsed2) {
        return 0;
      }
    };
    Map<MetaProperty<?>, Comparator<Object>> comparators = ImmutableMap.<MetaProperty<?>, Comparator<Object>>of(
        ManageableSecurity.meta().uniqueId(), alwaysEqualComparator,
        ManageableSecurity.meta().externalIdBundle(), alwaysEqualComparator);
    _beanCompare = new BeanCompare(comparators, Collections.<Class<?>, Comparator<Object>>emptyMap());

    //_currentPath = new String[0];
    //_securityIdToPosition = new HashMap<ObjectId, ManageablePosition>();

    _multithread = multithread;
    if (_multithread) {
      _executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
    }

    createPortfolio(portfolioName);

    _securityIdToPosition = new HashMap<>();
    setPath(new String[0]);
  }

  @Override
  public void addAttribute(String key, String value) {
    _portfolioDocument.getPortfolio().addAttribute(key, value);
  }

  /**
   * Returns the sum of the quantities for the specified positions. This is separated out into a method to allow
   * custom behaviour for different clients. For instance, in one case the sums of the quantities of all the trades
   * of both positions might be required, whereas in another case the preference might be to sum the quantities of
   * the positions themselves without regard to the quantities specified in their trades (this is the default behaviour).
   * This is not featured in the PortfolioWriter interface, and as such is a hack.
   * @param position1 the first position
   * @param position2 the second position
   * @return the sum of the positions' quantities
   */
  protected BigDecimal sumPositionQuantities(final ManageablePosition position1, final ManageablePosition position2) {
    return position1.getQuantity().add(position2.getQuantity());
  }

  /**
   * WritePosition checks if the position exists in the previous version of the portfolio.
   * If so, the existing position is reused.
   * @param position    the position to be written
   * @param securities  the security(ies) related to the above position, also to be written; index 1 onwards are underlyings
   * @return            the positions/securities in the masters after writing, null on failure
   */
  @Override
  public ObjectsPair<ManageablePosition, ManageableSecurity[]> writePosition(final ManageablePosition position, final ManageableSecurity[] securities) {
   
    ArgumentChecker.notNull(position, "position");
    ArgumentChecker.notNull(securities, "securities");

    // Write securities
    final List<ManageableSecurity> writtenSecurities = new ArrayList<>();
    for (ManageableSecurity security : securities) {
      if (security != null || !_discardIncompleteOptions) { // latter term preserves old behaviour
        ManageableSecurity writtenSecurity = writeSecurity(security);
        if (writtenSecurity != null) {
          writtenSecurities.add(writtenSecurity);
        }
      }
    }

    // If no securities were actually written successfully, just skip writing this position entirely
    if (writtenSecurities.size() != securities.length && _discardIncompleteOptions) {
      // this does persist the securities that it is given so that we don't keep hitting Bloomberg when there are missing underlyings.
      return null;
    } else if (writtenSecurities.isEmpty()) { // preserve old behaviour if _discardIncompleteOptions is false
      return null;
    }

    // If merging positions, check if any of the positions in the current node reference the same security id
    // and if so, just update the existing position and return
    if (_mergePositions && _securityIdToPosition.containsKey(writtenSecurities.get(0).getUniqueId().getObjectId())) {

      // Add new quantity to existing position's quantity
      final ManageablePosition existingPosition = _securityIdToPosition.get(writtenSecurities.get(0).getUniqueId().getObjectId());
      existingPosition.setQuantity(sumPositionQuantities(existingPosition, position));

      // Add new trades to existing position's trades
      for (ManageableTrade trade : position.getTrades()) {
        existingPosition.addTrade(trade);
      }

      if (!_multithread) {
        // Save the updated existing position to the position master
        PositionDocument addedDoc = _positionMaster.update(new PositionDocument(existingPosition));
        s_logger.debug("Updated position {}, delta position {}", addedDoc.getPosition(), position);

        // update position map (huh?)
        _securityIdToPosition.put(writtenSecurities.get(0).getUniqueId().getObjectId(), addedDoc.getPosition());

        // Return the updated position
        return new ObjectsPair<>(addedDoc.getPosition(),
            securities);
      } else {
        // update position map
        _securityIdToPosition.put(writtenSecurities.get(0).getUniqueId().getObjectId(), existingPosition);

         // Return the updated position
        return new ObjectsPair<>(existingPosition, securities);
      }
    }
    // Attempt to reuse an existing position from the previous version of the portfolio, and return if an exact match is found
    if (!(_originalNode == null) && !_originalNode.getPositionIds().isEmpty()) {
      ManageablePosition existingPosition = matchExistingPosition(position, writtenSecurities);
      if (existingPosition != null) {
        return new ObjectsPair<>(existingPosition,
            writtenSecurities.toArray(new ManageableSecurity[writtenSecurities.size()]));
      }
    }

    // If security has no ExternalId, link position to security ObjectId now
    if (position.getSecurityLink().getExternalId().isEmpty() && position.getSecurityLink().getObjectId() == null) {
      position.setSecurityLink(ManageableSecurityLink.of(writtenSecurities.get(0)));
    }
    // also check trades within position for a valid securityLink
    for (ManageableTrade trade : position.getTrades()) {
      if (trade.getSecurityLink().getExternalId().isEmpty() && trade.getSecurityLink().getObjectId() == null) {
        trade.setSecurityLink(ManageableSecurityLink.of(writtenSecurities.get(0))); // or reuse link from position?
      }
    }

    // No existing position could be reused/updated: just Add the new position to the position master as a new document
    // (can't launch a thread since we need the position id immediately, to be stored with the pos document in the map)
    PositionDocument addedDoc;
    try {
      addedDoc = _positionMaster.add(new PositionDocument(position));
      s_logger.debug("Added position {}", position);
    } catch (Exception e) {
      s_logger.error("Unable to add position " + position.getUniqueId() + ": " + e.getMessage());
      return null;
    }
    // Add the new position to the portfolio
    _currentNode.addPosition(addedDoc.getUniqueId());

    // Update position map
    _securityIdToPosition.put(writtenSecurities.get(0).getUniqueId().getObjectId(), addedDoc.getPosition());

    // Return the new position
    return new ObjectsPair<>(addedDoc.getPosition(),
        writtenSecurities.toArray(new ManageableSecurity[writtenSecurities.size()]));
  }

  private ManageablePosition matchExistingPosition(final ManageablePosition position, final List<ManageableSecurity> writtenSecurities) {
    PositionSearchRequest searchReq = new PositionSearchRequest();

    // Filter positions in current node of original portfolio
    searchReq.setPositionObjectIds(_originalNode.getPositionIds());

    // Filter positions with the same quantity
    searchReq.setMinQuantity(position.getQuantity());
    searchReq.setMaxQuantity(position.getQuantity());

    // TODO Compare position attributes

    PositionSearchResult searchResult = _positionMaster.search(searchReq);
    for (ManageablePosition existingPosition : searchResult.getPositions()) {
      ManageablePosition chosenPosition = null;
      if (writtenSecurities.get(0).getUniqueId().getObjectId().equals(existingPosition.getSecurityLink().getObjectId())) {
        chosenPosition = existingPosition;
      } else {
        for (ExternalId id : existingPosition.getSecurityLink().getExternalIds()) {
          if (writtenSecurities.get(0).getExternalIdBundle().contains(id) && existingPosition.getQuantity().equals(position.getQuantity())) {
            chosenPosition = existingPosition;
            break;
          }
        }
      }
      // Check for trade equality
      if (chosenPosition != null && (chosenPosition.getTrades().size() == position.getTrades().size())) {

        for (ManageableTrade trade : chosenPosition.getTrades()) {

          ManageableTrade comparableTrade = JodaBeanUtils.clone(trade);
          comparableTrade.setUniqueId(null);
          if (!(position.getTrades().contains(comparableTrade))) {
            chosenPosition = null;
            break;
          }
        }

        // If identical, reuse the chosen position
        if (chosenPosition != null) {
          // Add the existing position to the portfolio
          _currentNode.addPosition(chosenPosition.getUniqueId());

          // Update position map
          _securityIdToPosition.put(writtenSecurities.get(0).getUniqueId().getObjectId(), chosenPosition);

          // return existing position
          return chosenPosition;
        }
      }
    }

    return null;
  }

  /**
   * Searches for an existing security that matches an {@code ExternalId} search, and attempts to
   * reuse/update it wherever possible, instead of creating a new one.
   * @param security  The security to be written to the master.
   * @return The new security as added to the master or the existing security found in the master
   */
  protected ManageableSecurity writeSecurity(ManageableSecurity security) {
   
    ArgumentChecker.notNull(security, "security");
   
    SecuritySearchResult searchResult = lookupSecurity(security);

    ManageableSecurity foundSecurity = updateSecurityVersionIfFound(security, searchResult);

    if (foundSecurity != null) {
      return foundSecurity;
    } else {
      return addSecurity(security);
    }
  }

  /**
   * Adds a security to master and returns the newly added security.  Returns null if
   * unable to add security
   */
  private ManageableSecurity addSecurity(ManageableSecurity security) {
    SecurityDocument addDoc = new SecurityDocument(security);
    try {
      SecurityDocument result = _securityMaster.add(addDoc);
      return result.getSecurity();
    } catch (Exception e) {
      s_logger.error("Failed to write security " + security + " to the security master", e);
      return null;
    }
  }

  /**
   * If there is an existing {@code ManageableSecurity} in the searchResult that matches security, for the 1st match:
   * <p><ul>
   * <li>if the only difference is the {@link UniqueId} do nothing and return the existing
   * <li> If there are other differences, update the existing and return the new security
   * <li> If there are no matches or any errors are encountered, return null
   * @param security new security being searched for
   * <ul><p>
   * @param searchResult results from search of Master for security
   * @return found or updated security, null if no matches
   */
  protected ManageableSecurity updateSecurityVersionIfFound(ManageableSecurity security, SecuritySearchResult searchResult) {
    for (ManageableSecurity foundSecurity : searchResult.getSecurities()) {
      if (foundSecurity.getClass().equals(security.getClass())) {
        s_logger.info("Returning existing security " + foundSecurity);
        return foundSecurity;
      }
    }
    return null;
    // TODO this is too prone to finding trivial differences and creating unnecessary new security versions
    /*for (ManageableSecurity foundSecurity : searchResult.getSecurities()) {
      List<BeanDifference<?>> differences = null;
      if (foundSecurity.getClass().equals(security.getClass())) {
        try {
          differences = _beanCompare.compare(foundSecurity, security);
        } catch (Exception e) {
          s_logger.error("Error comparing securities with ID bundle " + security.getExternalIdBundle(), e);
          return null;
        }
      }
      if (differences.isEmpty()) {
        // It's already there, don't update or add it
        return foundSecurity;
      } else {
        s_logger.debug("Updating security " + foundSecurity + " due to differences: " + differences);
        SecurityDocument updateDoc = new SecurityDocument(security);
        updateDoc.setVersionFromInstant(Instant.now());
        try {
          //updateDoc.setUniqueId(foundSecurity.getUniqueId());
          //return _securityMaster.update(updateDoc).getSecurity();
          UniqueId newId = _securityMaster.addVersion(foundSecurity.getUniqueId().getObjectId(), updateDoc);
          security.setUniqueId(newId);
          return security;
        } catch (Throwable t) {
          s_logger.error("Unable to update security " + security.getUniqueId() + ": " + t.getMessage());
          return null;
        }
      }
    }
    // no matching security in searchResult, return null
    return null;*/
  }

  /**
   * Attempts to find a security in the master by {@code ExternalId}.  If any of the {@code ExternalId}s on the security
   * match any {@code ExternalId} on an existing security, the existing security will be added to the returned
   * {@link SecuritySearchResult}.  The current version of the existing securities are used.
   * @param security new security to search for in Master
   * @return search result
   */
  protected SecuritySearchResult lookupSecurity(ManageableSecurity security) {
    SecuritySearchRequest searchReq = new SecuritySearchRequest();
    ExternalIdSearch idSearch = new ExternalIdSearch(security.getExternalIdBundle())// match any one of the IDs
    searchReq.setVersionCorrection(VersionCorrection.ofVersionAsOf(Instant.now())); // valid now
    searchReq.setExternalIdSearch(idSearch);
    searchReq.setFullDetail(true);
    searchReq.setSortOrder(SecuritySearchSortOrder.VERSION_FROM_INSTANT_DESC);
    SecuritySearchResult searchResult = _securityMaster.search(searchReq);
    return searchResult;
  }

  private void testQuantities(ManageablePosition position) {
    int tradeQty = 0;
    for (ManageableTrade trade : position.getTrades()) {
      tradeQty += trade.getQuantity().intValue();
    }
    if (tradeQty != position.getQuantity().intValue()) {
      s_logger.warn("Position quantity and total trade quantities do not match for " + position);
    }
  }

  @Override
  public String[] getCurrentPath() {
    Stack<ManageablePortfolioNode> stack =
        _portfolioDocument.getPortfolio().getRootNode().findNodeStackByObjectId(_currentNode.getUniqueId());
    String[] result = new String[stack.size()];
    int i = stack.size();
    while (!stack.isEmpty()) {
      result[--i] = stack.pop().getName();
    }
    return result;
  }

  @Override
  public void setPath(String[] newPath) {
    ArgumentChecker.noNulls(newPath, "newPath");

    if (!Arrays.equals(newPath, _currentPath)) {

      // Update positions in position map, concurrently, and wait for their completion
      if (_mergePositions && _multithread) {
        List<Callable<Integer>> tasks = new ArrayList<>();
        for (final ManageablePosition position : _securityIdToPosition.values()) {
          testQuantities(position);
          tasks.add(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
              try {
                // Update the position in the position master
                PositionDocument addedDoc = _positionMaster.update(new PositionDocument(position));
                s_logger.debug("Updated position {}", position);
                 // Add the new position to the portfolio node
                _currentNode.addPosition(addedDoc.getUniqueId());
              } catch (Exception e) {
                s_logger.error("Unable to update position " + position.getUniqueId() + ": " + e.getMessage());
              }
              return 0;
            }
          });
        }
        try {
          List<Future<Integer>> futures = _executorService.invokeAll(tasks);
        } catch (Exception e) {
          s_logger.warn("ExecutorService invokeAll failed: " + e.getMessage());
        }
      }

      // Reset position map
      _securityIdToPosition = new HashMap<>();

      if (_originalRoot != null) {
        _originalNode = findNode(newPath, _originalRoot);
        _currentNode = getOrCreateNode(newPath, _portfolioDocument.getPortfolio().getRootNode());
      } else {
        _currentNode = getOrCreateNode(newPath, _portfolioDocument.getPortfolio().getRootNode());
      }

      // If keeping original portfolio nodes and merging positions, populate position map with existing positions in node
      if (_keepCurrentPositions && _mergePositions && _originalNode != null) {
        s_logger.debug("Storing security associations for positions " + _originalNode.getPositionIds() + " at path " + StringUtils.join(newPath, '/'));
        for (ObjectId positionId : _originalNode.getPositionIds()) {
          ManageablePosition position = null;
          try {
            position = _positionMaster.get(positionId, VersionCorrection.LATEST).getPosition();
          } catch (Exception e) {
            // no action
            s_logger.error("Exception retrieving position " + positionId, e);
          }
          if (position != null) {
            position.getSecurityLink().resolve(_securitySource);
            if (position.getSecurity() != null) {
              if (_securityIdToPosition.containsKey(position.getSecurity())) {
                ManageablePosition existing = _securityIdToPosition.get(position.getSecurity());
                s_logger.warn("Merging positions but found existing duplicates under path " + StringUtils.join(newPath, '/') + ": " + position + " and " + existing
                    + ".  New trades for security " + position.getSecurity().getUniqueId().getObjectId() + " will be added to position " + position.getUniqueId());
             
              } else {
                _securityIdToPosition.put(position.getSecurity().getUniqueId().getObjectId(), position);
              }
            }
          }
        }
        if (s_logger.isDebugEnabled()) {
          StringBuilder sb = new StringBuilder("Cached security to position mappings at path ").append(StringUtils.join(newPath, '/')).append(":");
          for (Map.Entry<ObjectId, ManageablePosition> entry : _securityIdToPosition.entrySet()) {
            sb.append(System.lineSeparator()).append("  ").append(entry.getKey()).append(" = ").append(entry.getValue().getUniqueId());
          }
          s_logger.debug(sb.toString());
        }
      }

      _currentPath = newPath;
    }
  }

  @Override
  public void flush() {
    _portfolioDocument = _portfolioMaster.update(_portfolioDocument);
  }
 
  @Override
  public void close() {
    // Execute remaining position writing threads, which will update the portfolio nodes with any written positions'
    // object IDs
    if (_executorService != null) {
      _executorService.shutdown();
    }

    // Write the portfolio (include the node tree) to the portfolio master
    flush();
  }
 
  private ManageablePortfolioNode findNode(String[] path, ManageablePortfolioNode startNode) {

    // Degenerate case
    if (path.length == 0) {
      return startNode;
    }

    for (ManageablePortfolioNode childNode : startNode.getChildNodes()) {
      if (path[0].equals(childNode.getName())) {
        ManageablePortfolioNode result = findNode((String[]) ArrayUtils.subarray(path, 1, path.length), childNode);
        if (result != null) {
          return result;
        }
      }
    }
    return null;
  }
 
  private ManageablePortfolioNode getOrCreateNode(String[] path, ManageablePortfolioNode startNode) {
    ManageablePortfolioNode node = startNode;
    for (String p : path) {
      ManageablePortfolioNode foundNode = null;
      for (ManageablePortfolioNode n : node.getChildNodes()) {
        if (n.getName().equals(p)) {
          foundNode = n;
          break;
        }
      }
      if (foundNode == null) {
        ManageablePortfolioNode newNode = new ManageablePortfolioNode(p);
        node.addChildNode(newNode);
        node = newNode;
      } else {
        node = foundNode;
      }
    }
    return node;
  }

  protected void createPortfolio(String portfolioName) {

    // Check to see whether the portfolio already exists
    PortfolioSearchRequest portSearchRequest = new PortfolioSearchRequest();
    portSearchRequest.setName(portfolioName);
    PortfolioSearchResult portSearchResult = _portfolioMaster.search(portSearchRequest);

    _portfolioDocument = portSearchResult.getFirstDocument();

    // If it doesn't, create it (add)
    if (_portfolioDocument == null) {
      // Create a new root node
      ManageablePortfolioNode rootNode = new ManageablePortfolioNode(portfolioName);

      ManageablePortfolio portfolio = new ManageablePortfolio(portfolioName, rootNode);
      _portfolioDocument = new PortfolioDocument();
      _portfolioDocument.setPortfolio(portfolio);
      _portfolioDocument = _portfolioMaster.add(_portfolioDocument);
      _originalRoot = null;
      _originalNode = null;

      // Set current node to the root node
      _currentNode = rootNode;

      // If it does, create a new version of the existing portfolio (update)
    } else {
      ManageablePortfolio portfolio = _portfolioDocument.getPortfolio();
      _originalRoot = portfolio.getRootNode();
      _originalNode = _originalRoot;

      if (_keepCurrentPositions) {
        // Use the original root node
        portfolio.setRootNode(cloneTree(_originalRoot));
        _portfolioDocument.setPortfolio(portfolio);

        // Set current node to the root node
        _currentNode = portfolio.getRootNode();
      } else {
        // Create a new root node
        ManageablePortfolioNode rootNode;
        rootNode = JodaBeanUtils.clone(_originalRoot);
        rootNode.setChildNodes(new ArrayList<ManageablePortfolioNode>());
        rootNode.setPositionIds(new ArrayList<ObjectId>());
        portfolio.setRootNode(rootNode);
        _portfolioDocument.setPortfolio(portfolio);

        // Set current node to the root node
        _currentNode = rootNode;
      }
    }
  }

  private static ManageablePortfolioNode cloneTree(final ManageablePortfolioNode originalRoot) {
    ManageablePortfolioNode newRoot = JodaBeanUtils.clone(originalRoot);
    newRoot.setChildNodes(new ArrayList<ManageablePortfolioNode>());
    for (ManageablePortfolioNode child : originalRoot.getChildNodes()) {
      newRoot.addChildNode(cloneTree(child));
    }
    return newRoot;
  }

  // TODO are these methods necessary? they're not used
  public PortfolioMaster getPortfolioMaster() {
    return _portfolioMaster;
  }

  public PositionMaster getPositionMaster() {
    return _positionMaster;
  }

  public SecurityMaster getSecurityMaster() {
    return _securityMaster;
  }
}
TOP

Related Classes of com.opengamma.integration.copier.portfolio.writer.MasterPortfolioWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.