com.opengamma.master.impl.InMemoryExternalIdCache.java Source code

Java tutorial

Introduction

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

Source

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

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.google.common.collect.Sets;
import com.opengamma.id.ExternalBundleIdentifiable;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ExternalIdSearch;
import com.opengamma.id.ExternalIdentifiable;
import com.opengamma.util.ArgumentChecker;

/**
 * Holds instances of {@link ExternalIdentifiable} for the purpose of improving searching in
 * any of the In Memory Masters.
 * 
 * @param <T> the type of element stored
 * @param <V> the containing document
 */
public class InMemoryExternalIdCache<T extends ExternalBundleIdentifiable, V> {
    private final Map<T, V> _allItems = new ConcurrentHashMap<T, V>();
    private final ConcurrentMap<ExternalId, Map<T, V>> _store = new ConcurrentHashMap<ExternalId, Map<T, V>>();

    public void add(T element, V document) {
        ArgumentChecker.notNull(element, "element");
        ArgumentChecker.notNull(document, "document");
        ExternalIdBundle bundle = element.getExternalIdBundle();
        if (bundle == null) {
            return;
        }
        for (ExternalId externalId : bundle) {
            Map<T, V> elements = _store.get(externalId);
            if (elements == null) {
                Map<T, V> fresh = new ConcurrentHashMap<T, V>();
                elements = _store.putIfAbsent(externalId, fresh);
                elements = (elements == null) ? fresh : elements;
            }
            elements.put(element, document);
        }
        _allItems.put(element, document);
    }

    public void remove(T element) {
        ArgumentChecker.notNull(element, "element");
        ExternalIdBundle bundle = element.getExternalIdBundle();
        if (bundle == null) {
            return;
        }
        for (ExternalId externalId : bundle) {
            Map<T, V> elements = _store.get(externalId);
            if (elements == null) {
                continue;
            }
            elements.remove(element);
        }
        _allItems.remove(element);
    }

    /**
     * Obtain all items that <em>might</em> match the search request.
     * By design, this will return false positives so that a subsequent
     * call to {@link ExternalIdSearch#matches(Iterable)} can be performed
     * for further analysis, typically in the context of a larger check.
     * That being said, this method will attempt to minimize false
     * positives.
     * False negatives will not be returned.
     * 
     * @param search the search to evaluate
     * @return items that are likely to match the search
     */
    public Set<V> getMatches(ExternalIdSearch search) {
        ArgumentChecker.notNull(search, "search");

        switch (search.getSearchType()) {
        case NONE:
            return getMatchesNone(search);
        case EXACT: // Intentional fall-through.
        case ALL:
            return getMatchesAll(search);
        case ANY:
            return getMatchesAny(search);
        }

        throw new IllegalStateException("All branches should have been handled in the switch statement.");
    }

    private Set<V> getMatchesAny(ExternalIdSearch search) {
        Set<V> result = new HashSet<V>();
        for (ExternalId id : search.getExternalIds()) {
            Map<T, V> matches = _store.get(id);
            if (matches == null) {
                continue;
            }
            result.addAll(matches.values());
        }
        return result;
    }

    private Set<V> getMatchesAll(ExternalIdSearch search) {
        Set<V> result = null;
        for (ExternalId id : search.getExternalIds()) {
            Map<T, V> matches = _store.get(id);
            if (matches == null) {
                // We can short circuit it here because by definition
                // these can't be satisfied.
                return Collections.emptySet();
            }
            if (result == null) {
                result = new HashSet<V>(matches.values());
            } else {
                result = Sets.intersection(result, new HashSet<V>(matches.values()));
            }
        }
        return result;
    }

    private Set<V> getMatchesNone(ExternalIdSearch search) {
        Set<V> result = new HashSet<V>(_allItems.values());
        for (ExternalId id : search.getExternalIds()) {
            Map<T, V> matches = _store.get(id);
            if (matches != null) {
                result.removeAll(matches.values());
            }
        }
        return result;
    }

}