/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.master.security.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.threeten.bp.Instant; import com.google.common.base.Supplier; import com.opengamma.DataNotFoundException; import com.opengamma.core.change.BasicChangeManager; import com.opengamma.core.change.ChangeManager; import com.opengamma.core.change.ChangeType; import com.opengamma.core.security.Security; import com.opengamma.id.ObjectId; import com.opengamma.id.ObjectIdSupplier; import com.opengamma.id.ObjectIdentifiable; import com.opengamma.id.UniqueId; import com.opengamma.id.VersionCorrection; import com.opengamma.master.SimpleAbstractInMemoryMaster; import com.opengamma.master.impl.InMemoryExternalIdCache; import com.opengamma.master.security.ManageableSecurity; import com.opengamma.master.security.SecurityDocument; import com.opengamma.master.security.SecurityHistoryRequest; import com.opengamma.master.security.SecurityHistoryResult; import com.opengamma.master.security.SecurityMaster; import com.opengamma.master.security.SecurityMetaDataRequest; import com.opengamma.master.security.SecurityMetaDataResult; import com.opengamma.master.security.SecuritySearchRequest; import com.opengamma.master.security.SecuritySearchResult; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.paging.Paging; /** * A simple, in-memory implementation of {@code SecurityMaster}. * <p> * This security master does not support versioning of securities. */ public class InMemorySecurityMaster extends SimpleAbstractInMemoryMaster<SecurityDocument> implements SecurityMaster { // TODO: This is not hardened for production, as the data in the master can // be altered from outside as it is the same object /** * The default scheme used for each {@link ObjectId}. */ public static final String DEFAULT_OID_SCHEME = "MemSec"; private final InMemoryExternalIdCache<Security, SecurityDocument> _externalIdCache = new InMemoryExternalIdCache<Security, SecurityDocument>(); /** * Creates an instance. */ public InMemorySecurityMaster() { this(new ObjectIdSupplier(DEFAULT_OID_SCHEME)); } /** * Creates an instance specifying the change manager. * * @param changeManager the change manager, not null */ public InMemorySecurityMaster(final ChangeManager changeManager) { this(new ObjectIdSupplier(DEFAULT_OID_SCHEME), changeManager); } /** * Creates an instance specifying the supplier of object identifiers. * * @param objectIdSupplier the supplier of object identifiers, not null */ public InMemorySecurityMaster(final Supplier<ObjectId> objectIdSupplier) { this(objectIdSupplier, new BasicChangeManager()); } /** * Creates an instance specifying the supplier of object identifiers and change manager. * * @param objectIdSupplier the supplier of object identifiers, not null * @param changeManager the change manager, not null */ public InMemorySecurityMaster(final Supplier<ObjectId> objectIdSupplier, final ChangeManager changeManager) { super(objectIdSupplier, changeManager); } @Override protected void updateCaches(ObjectIdentifiable replacedObject, SecurityDocument updatedDocument) { if (replacedObject != null) { SecurityDocument document = _store.get(replacedObject.getObjectId()); if (document != null) { _externalIdCache.remove(document.getSecurity()); } } if (updatedDocument != null) { SecurityDocument updatedSecurityDocument = (SecurityDocument) updatedDocument; _externalIdCache.add(updatedSecurityDocument.getSecurity(), updatedSecurityDocument); } } //------------------------------------------------------------------------- @Override public SecurityMetaDataResult metaData(final SecurityMetaDataRequest request) { ArgumentChecker.notNull(request, "request"); SecurityMetaDataResult result = new SecurityMetaDataResult(); if (request.isSecurityTypes()) { Set<String> types = new HashSet<String>(); for (SecurityDocument doc : _store.values()) { types.add(doc.getSecurity().getSecurityType()); } result.getSecurityTypes().addAll(types); } return result; } //------------------------------------------------------------------------- @Override public SecuritySearchResult search(final SecuritySearchRequest request) { ArgumentChecker.notNull(request, "request"); Collection<SecurityDocument> docsToSearch = null; if (request.getExternalIdSearch() != null) { docsToSearch = _externalIdCache.getMatches(request.getExternalIdSearch()); } else { docsToSearch = _store.values(); } final List<SecurityDocument> list = new ArrayList<SecurityDocument>(); for (SecurityDocument doc : docsToSearch) { if (request.matches(doc)) { list.add(doc); } } Collections.sort(list, request.getSortOrder()); final SecuritySearchResult result = new SecuritySearchResult(); result.setPaging(Paging.of(request.getPagingRequest(), list)); result.getDocuments().addAll(request.getPagingRequest().select(list)); return result; } //------------------------------------------------------------------------- @Override public SecurityDocument get(final UniqueId uniqueId) { return get(uniqueId, VersionCorrection.LATEST); } //------------------------------------------------------------------------- @Override public SecurityDocument get(final ObjectIdentifiable objectId, final VersionCorrection versionCorrection) { ArgumentChecker.notNull(objectId, "objectId"); ArgumentChecker.notNull(versionCorrection, "versionCorrection"); final SecurityDocument document = _store.get(objectId.getObjectId()); if (document == null) { throw new DataNotFoundException("Security not found: " + objectId); } return document; } //------------------------------------------------------------------------- @Override public SecurityDocument add(final SecurityDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getSecurity(), "document.security"); final ObjectId objectId = _objectIdSupplier.get(); final UniqueId uniqueId = objectId.atVersion(""); final ManageableSecurity security = document.getSecurity(); security.setUniqueId(uniqueId); final Instant now = Instant.now(); final SecurityDocument doc = new SecurityDocument(security); doc.setVersionFromInstant(now); doc.setCorrectionFromInstant(now); _store.put(objectId, doc); _changeManager.entityChanged(ChangeType.ADDED, objectId, doc.getVersionFromInstant(), doc.getVersionToInstant(), now); _externalIdCache.add(doc.getSecurity(), doc); return doc; } //------------------------------------------------------------------------- @Override public SecurityDocument update(final SecurityDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getUniqueId(), "document.uniqueId"); ArgumentChecker.notNull(document.getSecurity(), "document.security"); final UniqueId uniqueId = document.getUniqueId(); final Instant now = Instant.now(); final SecurityDocument storedDocument = _store.get(uniqueId.getObjectId()); if (storedDocument == null) { throw new DataNotFoundException("Security not found: " + uniqueId); } document.setVersionFromInstant(now); document.setVersionToInstant(null); document.setCorrectionFromInstant(now); document.setCorrectionToInstant(null); if (_store.replace(uniqueId.getObjectId(), storedDocument, document) == false) { throw new IllegalArgumentException("Concurrent modification"); } _changeManager.entityChanged(ChangeType.CHANGED, uniqueId.getObjectId(), storedDocument.getVersionFromInstant(), document.getVersionToInstant(), now); _externalIdCache.remove(storedDocument.getSecurity()); _externalIdCache.add(document.getSecurity(), document); return document; } //------------------------------------------------------------------------- @Override public void remove(final ObjectIdentifiable objectIdentifiable) { ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable"); SecurityDocument removedDocument = _store.remove(objectIdentifiable.getObjectId()); if (removedDocument == null) { throw new DataNotFoundException("Security not found: " + objectIdentifiable); } _changeManager.entityChanged(ChangeType.REMOVED, objectIdentifiable.getObjectId(), null, null, Instant.now()); _externalIdCache.remove(removedDocument.getSecurity()); } //------------------------------------------------------------------------- @Override public SecurityDocument correct(final SecurityDocument document) { return update(document); } //------------------------------------------------------------------------- @Override public SecurityHistoryResult history(final SecurityHistoryRequest request) { ArgumentChecker.notNull(request, "request"); ArgumentChecker.notNull(request.getObjectId(), "request.objectId"); final SecurityHistoryResult result = new SecurityHistoryResult(); final SecurityDocument doc = get(request.getObjectId(), VersionCorrection.LATEST); if (doc != null) { result.getDocuments().add(doc); } result.setPaging(Paging.ofAll(result.getDocuments())); return result; } @Override protected void validateDocument(SecurityDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getSecurity(), "document.security"); } }