com.opengamma.bbg.referencedata.cache.EHValueCachingReferenceDataProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.bbg.referencedata.cache.EHValueCachingReferenceDataProvider.java

Source

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

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;

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

import org.fudgemsg.FudgeContext;
import org.fudgemsg.FudgeMsg;
import org.fudgemsg.mapping.FudgeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;
import com.opengamma.bbg.referencedata.ReferenceData;
import com.opengamma.bbg.referencedata.ReferenceDataProvider;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.fudgemsg.OpenGammaFudgeContext;

/**
 * Decorates a reference data provider, adding caching.
 * <p>
 * The cache is implemented using {@code EHCache}.
 */
public class EHValueCachingReferenceDataProvider extends AbstractValueCachingReferenceDataProvider {

    /** Logger. */
    private static final Logger s_logger = LoggerFactory.getLogger(EHValueCachingReferenceDataProvider.class);
    /**
     * Cache key for reference data.
     */
    /*package*/ static final String REFERENCE_DATA_CACHE = "referenceData";

    /**
     * The cache manager.
     */
    private final CacheManager _cacheManager;
    /**
     * The reference data cache.
     */
    private final Cache _cache;

    /**
     * Creates an instance.
     * 
     * @param underlying  the underlying reference data provider, not null
     * @param cacheManager  the cache manager, not null
     */
    public EHValueCachingReferenceDataProvider(final ReferenceDataProvider underlying,
            final CacheManager cacheManager) {
        this(underlying, cacheManager, OpenGammaFudgeContext.getInstance());
    }

    /**
     * Creates an instance.
     * 
     * @param underlying  the underlying reference data provider, not null
     * @param cacheManager  the cache manager, not null
     * @param fudgeContext  the Fudge context, not null
     */
    public EHValueCachingReferenceDataProvider(final ReferenceDataProvider underlying,
            final CacheManager cacheManager, final FudgeContext fudgeContext) {
        super(underlying, fudgeContext);
        ArgumentChecker.notNull(cacheManager, "cacheManager");
        _cacheManager = cacheManager;
        _cacheManager.addCacheIfAbsent(REFERENCE_DATA_CACHE);
        _cache = _cacheManager.getCache(REFERENCE_DATA_CACHE);
    }

    //-------------------------------------------------------------------------
    /**
     * Gets the cache manager.
     * 
     * @return the cache manager, not null
     */
    public CacheManager getCacheManager() {
        return _cacheManager;
    }

    //-------------------------------------------------------------------------
    @Override
    protected Map<String, ReferenceData> loadFieldValues(Set<String> identifiers) {
        Map<String, ReferenceData> result = Maps.newTreeMap();
        FudgeSerializer serializer = new FudgeSerializer(getFudgeContext());
        for (String identifier : identifiers) {
            ReferenceData cachedResult = loadStateFromCache(serializer, identifier);
            if (cachedResult != null) {
                result.put(identifier, cachedResult);
            }
        }
        return result;
    }

    @Override
    protected void saveFieldValues(ReferenceData result) {
        String identifier = result.getIdentifier();
        FudgeMsg fieldData = result.getFieldValues();

        if (identifier != null && fieldData != null) {
            s_logger.info("Persisting fields for \"{}\": {}", identifier, result.getFieldValues());
            Object cachedObject = createCachedObject(result);
            s_logger.debug("cachedObject={}", cachedObject);
            Element element = new Element(identifier, cachedObject);
            _cache.put(element);
        }
    }

    //-------------------------------------------------------------------------
    /**
     * Loads the state from the cache.
     * 
     * @param serializer  the Fudge serializer, not null
     * @param identifier  the identifier, not null
     * @return the result, null if not found
     */
    protected ReferenceData loadStateFromCache(FudgeSerializer serializer, String identifier) {
        Element element = _cache.get(identifier);
        if (element != null) {
            s_logger.debug("Have security data for des {} in cache", identifier);
            Object fromCache = element.getObjectValue();
            s_logger.debug("cachedObject={}", fromCache);
            return parseCachedObject(fromCache);
        }
        return null;
    }

    //-------------------------------------------------------------------------
    /**
     * Data holder for storing the results.
     */
    private static final class CachedReferenceData implements Serializable {

        private static final long serialVersionUID = 3L;

        private transient String _security;

        private transient FudgeContext _fudgeContext;

        private transient volatile FudgeMsg _fieldDataMsg;

        private transient volatile byte[] _fieldData;

        private byte[] getFieldData() {
            byte[] fieldData = _fieldData;
            if (fieldData == null) {
                synchronized (this) {
                    fieldData = _fieldData;
                    if (fieldData == null) {
                        fieldData = _fudgeContext.toByteArray(_fieldDataMsg);
                        _fieldData = fieldData;
                        _fieldDataMsg = null;
                    }
                }
            }
            return fieldData;
        }

        private void setFieldData(final byte[] fieldData) {
            _fieldData = fieldData;
        }

        public FudgeMsg getFieldDataMsg(final FudgeContext fudgeContext) {
            FudgeMsg fieldDataMsg = _fieldDataMsg;
            if (fieldDataMsg == null) {
                synchronized (this) {
                    fieldDataMsg = _fieldDataMsg;
                    if (fieldDataMsg == null) {
                        _fudgeContext = fudgeContext;
                        fieldDataMsg = fudgeContext.deserialize(_fieldData).getMessage();
                        _fieldDataMsg = fieldDataMsg;
                        _fieldData = null;
                    }
                }
            }
            return _fieldDataMsg;
        }

        public void setFieldDataMsg(final FudgeMsg fieldDataMsg, final FudgeContext fudgeContext) {
            _fieldDataMsg = fieldDataMsg;
            _fudgeContext = fudgeContext;
        }

        public String getSecurity() {
            return _security;
        }

        public void setSecurity(final String security) {
            _security = security;
        }

        private void writeObject(final ObjectOutputStream out) throws IOException {
            out.writeUTF(getSecurity());
            final byte[] fieldData = getFieldData();
            out.writeInt(fieldData.length);
            out.write(fieldData);
        }

        private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
            setSecurity(in.readUTF());
            final int dataLength = in.readInt();
            final byte[] data = new byte[dataLength];
            in.readFully(data);
            setFieldData(data);
        }

    }

    //-------------------------------------------------------------------------
    /**
     * Parse the cached object.
     * 
     * @param fromCache  the data from the cache, not null
     * @return the result, not null
     */
    protected ReferenceData parseCachedObject(Object fromCache) {
        CachedReferenceData rd = (CachedReferenceData) fromCache;
        return new ReferenceData(rd.getSecurity(), rd.getFieldDataMsg(getFudgeContext()));
    }

    /**
     * Creates the cached object.
     * 
     * @param refDataResult  the reference data result.
     * @return the cache object, not null
     */
    protected Object createCachedObject(ReferenceData refDataResult) {
        CachedReferenceData result = new CachedReferenceData();
        result.setSecurity(refDataResult.getIdentifier());
        result.setFieldDataMsg(getFudgeContext().newMessage(refDataResult.getFieldValues()), getFudgeContext());
        return result;
    }

}