com.opengamma.core.AbstractEHCachingSourceWithExternalBundle.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.core.AbstractEHCachingSourceWithExternalBundle.java

Source

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opengamma.id.ExternalBundleIdentifiable;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.UniqueId;
import com.opengamma.id.UniqueIdentifiable;
import com.opengamma.id.VersionCorrection;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.ehcache.EHCacheUtils;

/**
 * A cache decorating a {@code FinancialSecuritySource}.
 * <p>
 * The cache is implemented using {@code EHCache}.
 * 
 * @param <V> the type returned by the source
 * @param <S> the source
 */
public abstract class AbstractEHCachingSourceWithExternalBundle<V extends UniqueIdentifiable & ExternalBundleIdentifiable, S extends SourceWithExternalBundle<V>>
        extends AbstractEHCachingSource<V, S> implements SourceWithExternalBundle<V> {

    private static final String EID_TO_UID_CACHE = "-eid-to-uid";

    /**
     * The cache of external identifiers at a version/correction to matching unique identifiers.
     */
    private final Cache _eidToUidCache;

    /**
     * Creates an instance over an underlying source specifying the cache manager.
     * 
     * @param underlying the underlying security source, not null
     * @param cacheManager the cache manager, not null
     */
    public AbstractEHCachingSourceWithExternalBundle(final S underlying, final CacheManager cacheManager) {
        super(underlying, cacheManager);
        EHCacheUtils.addCache(cacheManager, this.getClass().getName() + EID_TO_UID_CACHE);
        _eidToUidCache = EHCacheUtils.getCacheFromManager(cacheManager,
                this.getClass().getName() + EID_TO_UID_CACHE);
    }

    @Override
    public Collection<V> get(final ExternalIdBundle bundle) {
        final Collection<V> result = getUnderlying().get(bundle);
        cacheItems(result);
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Collection<V> get(final ExternalIdBundle bundle, final VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(bundle, "bundle");
        ArgumentChecker.notNull(versionCorrection, "versionCorrection");
        if (versionCorrection.containsLatest()) {
            Collection<V> results = getUnderlying().get(bundle, versionCorrection);
            cacheItems(results);
            return results;
        }
        final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(bundle, versionCorrection);
        final Element e = _eidToUidCache.get(key);
        if (e != null) {
            if (e.getObjectValue() instanceof Collection) {
                final Collection<UniqueId> identifiers = (Collection<UniqueId>) e.getObjectValue();
                if (identifiers.isEmpty()) {
                    return Collections.emptySet();
                } else {
                    return get(identifiers).values();
                }
            }
        }
        final Collection<V> result = getUnderlying().get(bundle, versionCorrection);
        if (result.isEmpty()) {
            cacheIdentifiers(Collections.<UniqueId>emptyList(), key);
        } else {
            final List<UniqueId> uids = new ArrayList<UniqueId>(result.size());
            for (final V item : result) {
                uids.add(item.getUniqueId());
            }
            Collections.sort(uids);
            cacheIdentifiers(uids, key);
            cacheItems(result);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Map<ExternalIdBundle, Collection<V>> getAll(final Collection<ExternalIdBundle> bundles,
            VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(bundles, "bundles");
        ArgumentChecker.notNull(versionCorrection, "versionCorrection");
        if (versionCorrection.containsLatest()) {
            return getUnderlying().getAll(bundles, versionCorrection);
        }
        final Map<ExternalIdBundle, Collection<V>> results = Maps.newHashMapWithExpectedSize(bundles.size());
        final Collection<ExternalIdBundle> misses = new ArrayList<ExternalIdBundle>(bundles.size());
        final Map<ExternalIdBundle, Collection<UniqueId>> lookupBundles = Maps
                .newHashMapWithExpectedSize(bundles.size());
        final Set<UniqueId> lookupIds = Sets.newHashSetWithExpectedSize(bundles.size());
        for (ExternalIdBundle bundle : bundles) {
            final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(bundle, versionCorrection);
            final Element e = _eidToUidCache.get(key);
            if (e != null) {
                if (e.getObjectValue() instanceof Collection) {
                    final Collection<UniqueId> identifiers = (Collection<UniqueId>) e.getObjectValue();
                    if (identifiers.isEmpty()) {
                        results.put(bundle, Collections.<V>emptySet());
                    } else {
                        lookupBundles.put(bundle, identifiers);
                        lookupIds.addAll(identifiers);
                    }
                    continue;
                }
            }
            misses.add(bundle);
        }
        if (!lookupIds.isEmpty()) {
            final Map<UniqueId, V> underlying = get(lookupIds);
            for (Map.Entry<ExternalIdBundle, Collection<UniqueId>> lookupBundle : lookupBundles.entrySet()) {
                final ArrayList<V> resultCollection = new ArrayList<V>(lookupBundle.getValue().size());
                for (UniqueId uid : lookupBundle.getValue()) {
                    final V resultValue = underlying.get(uid);
                    if (resultValue != null) {
                        resultCollection.add(resultValue);
                    }
                }
                resultCollection.trimToSize();
                results.put(lookupBundle.getKey(), resultCollection);
            }
        }
        if (!misses.isEmpty()) {
            final Map<ExternalIdBundle, Collection<V>> underlying = getUnderlying().getAll(misses,
                    versionCorrection);
            for (ExternalIdBundle miss : misses) {
                final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(miss, versionCorrection);
                final Collection<V> result = underlying.get(miss);
                if ((result == null) || result.isEmpty()) {
                    cacheIdentifiers(Collections.<UniqueId>emptyList(), key);
                } else {
                    final List<UniqueId> uids = new ArrayList<UniqueId>(result.size());
                    for (final V item : result) {
                        uids.add(item.getUniqueId());
                    }
                    Collections.sort(uids);
                    cacheIdentifiers(uids, key);
                    cacheItems(result);
                    results.put(miss, result);
                }
            }
        }
        return results;
    }

    @Override
    public V getSingle(final ExternalIdBundle bundle) {
        final V result = getUnderlying().getSingle(bundle);
        if (result != null) {
            cacheItem(result);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public V getSingle(final ExternalIdBundle bundle, final VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(bundle, "bundle");
        ArgumentChecker.notNull(versionCorrection, "versionCorrection");
        if (versionCorrection.containsLatest()) {
            return getUnderlying().getSingle(bundle, versionCorrection);
        }
        final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(bundle, versionCorrection);
        final Element e = _eidToUidCache.get(key);
        if (e != null) {
            if (e.getObjectValue() instanceof List) {
                final List<UniqueId> identifiers = (List<UniqueId>) e.getObjectValue();
                for (final UniqueId uid : identifiers) {
                    final V result = get(uid);
                    if (result != null) {
                        return result;
                    }
                }
                return null;
            } else if (e.getObjectValue() instanceof UniqueId) {
                return get((UniqueId) e.getObjectValue());
            }
        }
        final V result = getUnderlying().getSingle(bundle, versionCorrection);
        if (result == null) {
            cacheIdentifiers(Collections.<UniqueId>emptyList(), key);
        } else {
            cacheIdentifiers(result.getUniqueId(), key);
            cacheItem(result);
        }
        return result;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<ExternalIdBundle, V> getSingle(final Collection<ExternalIdBundle> bundles,
            final VersionCorrection versionCorrection) {
        ArgumentChecker.notNull(bundles, "bundles");
        ArgumentChecker.notNull(versionCorrection, "versionCorrection");
        if (versionCorrection.containsLatest()) {
            return getUnderlying().getSingle(bundles, versionCorrection);
        }
        final Map<ExternalIdBundle, V> results = Maps.newHashMapWithExpectedSize(bundles.size());
        final Collection<ExternalIdBundle> misses = new ArrayList<ExternalIdBundle>(bundles.size());
        final Map<ExternalIdBundle, Collection<UniqueId>> hits = Maps.newHashMapWithExpectedSize(bundles.size());
        final Set<UniqueId> lookup = Sets.newHashSetWithExpectedSize(bundles.size());
        for (ExternalIdBundle bundle : bundles) {
            final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(bundle, versionCorrection);
            final Element e = _eidToUidCache.get(key);
            if (e != null) {
                if (e.getObjectValue() instanceof List) {
                    final List<UniqueId> identifiers = (List<UniqueId>) e.getObjectValue();
                    lookup.addAll(identifiers);
                    hits.put(bundle, identifiers);
                    continue;
                } else if (e.getObjectValue() instanceof UniqueId) {
                    final UniqueId identifier = (UniqueId) e.getObjectValue();
                    lookup.add(identifier);
                    hits.put(bundle, Collections.singleton(identifier));
                    continue;
                }
            }
            misses.add(bundle);
        }
        if (!lookup.isEmpty()) {
            final Map<UniqueId, V> underlying = getUnderlying().get(lookup);
            for (Map.Entry<ExternalIdBundle, Collection<UniqueId>> hit : hits.entrySet()) {
                final ExternalIdBundle bundle = hit.getKey();
                for (UniqueId uid : hit.getValue()) {
                    final V result = underlying.get(uid);
                    if (result != null) {
                        results.put(bundle, result);
                        break;
                    }
                }
            }
        }
        if (!misses.isEmpty()) {
            final Map<ExternalIdBundle, ? extends V> underlying = getUnderlying().getSingle(misses,
                    versionCorrection);
            for (ExternalIdBundle miss : misses) {
                final Pair<ExternalIdBundle, VersionCorrection> key = Pair.of(miss, versionCorrection);
                final V result = underlying.get(miss);
                if (result == null) {
                    cacheIdentifiers(Collections.<UniqueId>emptyList(), key);
                } else {
                    cacheIdentifiers(result.getUniqueId(), key);
                    cacheItem(result);
                    results.put(miss, result);
                }
            }
        }
        return results;
    }

    protected void cacheIdentifiers(final UniqueId uniqueId, final Pair<ExternalIdBundle, VersionCorrection> key) {
        synchronized (_eidToUidCache) {
            final Element e = _eidToUidCache.get(key);
            if (e == null) {
                _eidToUidCache.put(new Element(key, uniqueId));
            }
        }
    }

    protected void cacheIdentifiers(final List<UniqueId> uniqueIds,
            final Pair<ExternalIdBundle, VersionCorrection> key) {
        synchronized (_eidToUidCache) {
            _eidToUidCache.put(new Element(key, uniqueIds));
        }
    }

    @Override
    public void shutdown() {
        super.shutdown();
        getCacheManager().removeCache(EID_TO_UID_CACHE);
    }
}