/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.core.historicaltimeseries.impl;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.sf.ehcache.CacheManager;
import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Clock;
import org.threeten.bp.LocalDate;
import com.google.common.collect.Maps;
import com.opengamma.core.change.BasicChangeManager;
import com.opengamma.core.change.ChangeEvent;
import com.opengamma.core.change.ChangeListener;
import com.opengamma.core.change.ChangeManager;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.timeseries.date.localdate.ImmutableLocalDateDoubleTimeSeries;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.OpenGammaClock;
import com.opengamma.util.ehcache.EHCacheUtils;
import com.opengamma.util.function.Supplier;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.ObjectsPair;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* A cache decorating a {@code HistoricalTimeSeriesSource}.
* <p>
* The cache is implemented using {@code EHCache}.
*/
public class EHCachingHistoricalTimeSeriesSource implements HistoricalTimeSeriesSource {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(EHCachingHistoricalTimeSeriesSource.class);
/** The cache prefix. */
/*package*/static final String CACHE_PREFIX = "HistoricalTimeSeries";
private final HierarhicalEHCache<Object, HistoricalTimeSeries> _cache;
/** Id bundle cache name. */
private static final String ID_BUNDLE_CACHE_NAME = CACHE_PREFIX + "IdBundleCache";
/** Listens for changes in the underlying security source. */
private ChangeListener _changeListener;
/** The local change manager. */
private final ChangeManager _changeManager;
@Override
public ChangeManager changeManager() {
return _changeManager;
}
/** The underlying source. */
private final HistoricalTimeSeriesSource _underlying;
/** The identifier bundle cache */
private final HierarhicalEHCache<UniqueId, ExternalIdBundle> _identifierBundleCache;
/** The clock. */
private final Clock _clock = OpenGammaClock.getInstance();
/**
* Creates an instance.
*
* @param underlying the underlying source, not null
* @param cacheManager the cache manager, not null
*/
public EHCachingHistoricalTimeSeriesSource(HistoricalTimeSeriesSource underlying, CacheManager cacheManager) {
ArgumentChecker.notNull(underlying, "underlying");
ArgumentChecker.notNull(cacheManager, "Cache Manager");
_underlying = underlying;
_cache = new HierarhicalEHCache<Object, HistoricalTimeSeries>(cacheManager) {
@Override
String getCachePrefix() {
return CACHE_PREFIX;
}
@Override
Object extractKey(Object ignored, HistoricalTimeSeries value) {
return value.getUniqueId().getObjectId();
}
};
_identifierBundleCache = new HierarhicalEHCache<UniqueId, ExternalIdBundle>(cacheManager) {
@Override
String getCachePrefix() {
return ID_BUNDLE_CACHE_NAME;
}
@Override
Object extractKey(UniqueId key, ExternalIdBundle value) {
return key.getObjectId();
}
};
EHCacheUtils.addCache(cacheManager, ID_BUNDLE_CACHE_NAME);
_changeListener = createChangeListener();
_underlying.changeManager().addChangeListener(_changeListener);
_changeManager = new BasicChangeManager();
}
private ChangeListener createChangeListener() {
return new ChangeListener() {
@Override
public void entityChanged(ChangeEvent event) {
cleanCaches(event.getObjectId());
changeManager().entityChanged(event.getType(),
event.getObjectId(),
event.getVersionFrom(),
event.getVersionTo(),
event.getVersionInstant());
}
};
}
private void cleanCaches(ObjectId oid) {
//_uidCache.remove(oid);
_cache.clear(oid);
_identifierBundleCache.clear(oid);
}
//-------------------------------------------------------------------------
/**
* Gets the underlying source.
*
* @return the underlying source, not null
*/
public HistoricalTimeSeriesSource getUnderlying() {
return _underlying;
}
/**
* Gets the clock.
*
* @return the clock, not null
*/
public Clock getClock() {
return _clock;
}
//-------------------------------------------------------------------------
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(final UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "uniqueId");
return _cache.getBySecondKey(uniqueId.getObjectId(), new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
return _underlying.getHistoricalTimeSeries(uniqueId);
}
});
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
UniqueId uniqueId, LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return doGetHistoricalTimeSeries(uniqueId, start, includeStart, end, includeEnd, null);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
UniqueId uniqueId, LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd, int maxPoints) {
return doGetHistoricalTimeSeries(uniqueId, start, includeStart, end, includeEnd, maxPoints);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(UniqueId uniqueId) {
HistoricalTimeSeries hts = doGetHistoricalTimeSeries(uniqueId, null, true, null, true, -1);
if (hts == null || hts.getTimeSeries() == null || hts.getTimeSeries().isEmpty()) {
return null;
} else {
return Pairs.of(hts.getTimeSeries().getLatestTime(), hts.getTimeSeries().getLatestValue());
}
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(UniqueId uniqueId,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd) {
HistoricalTimeSeries hts = doGetHistoricalTimeSeries(uniqueId, start, includeStart, end, includeEnd, -1);
if (hts == null || hts.getTimeSeries() == null || hts.getTimeSeries().isEmpty()) {
return null;
} else {
return Pairs.of(hts.getTimeSeries().getLatestTime(), hts.getTimeSeries().getLatestValue());
}
}
private HistoricalTimeSeries doGetHistoricalTimeSeries(
final UniqueId uniqueId,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
final Integer maxPoints) {
final SubSeriesKey subseriesKey = new SubSeriesKey(start, end, maxPoints);
ObjectsPair<UniqueId, SubSeriesKey> key = ObjectsPair.of(uniqueId, subseriesKey);
Supplier<HistoricalTimeSeries> fetchHts = new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
if (maxPoints == null) {
return _underlying.getHistoricalTimeSeries(uniqueId,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd());
} else {
return _underlying.getHistoricalTimeSeries(uniqueId,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd(),
subseriesKey.getMaxPoints());
}
}
};
HistoricalTimeSeries hts = _cache.get(key, fetchHts);
if (hts != null && !subseriesKey.isMatch(start, includeStart, end, includeEnd, maxPoints)) {
hts = getSubSeries(hts, start, includeStart, end, includeEnd, maxPoints);
}
return hts;
}
//-------------------------------------------------------------------------
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
ExternalIdBundle identifiers, String dataSource, String dataProvider, String dataField) {
return getHistoricalTimeSeries(identifiers, LocalDate.now(getClock()), dataSource, dataProvider, dataField);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
final ExternalIdBundle identifiers,
final LocalDate identifierValidityDate,
final String dataSource,
final String dataProvider,
final String dataField) {
ArgumentChecker.notNull(identifiers, "identifiers");
HistoricalTimeSeriesKey key = new HistoricalTimeSeriesKey(null,
identifierValidityDate,
identifiers,
dataSource,
dataProvider,
dataField);
return _cache.get(key, new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
return _underlying.getHistoricalTimeSeries(identifiers,
identifierValidityDate,
dataSource,
dataProvider,
dataField);
}
});
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
ExternalIdBundle identifiers, String dataSource, String dataProvider, String dataField,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return getHistoricalTimeSeries(
identifiers, LocalDate.now(getClock()), dataSource, dataProvider, dataField,
start, includeStart, end, includeEnd);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
ExternalIdBundle identifiers, LocalDate currentDate, String dataSource, String dataProvider, String dataField,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return doGetHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
start,
includeStart,
end,
includeEnd,
null);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
ExternalIdBundle identifierBundle,
String dataSource,
String dataProvider,
String dataField,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
int maxPoints) {
return getHistoricalTimeSeries(identifierBundle,
LocalDate.now(getClock()),
dataSource,
dataProvider,
dataField,
start,
includeStart,
end,
includeEnd,
maxPoints);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
ExternalIdBundle identifiers, LocalDate currentDate, String dataSource, String dataProvider, String dataField,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd, int maxPoints) {
return doGetHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
start,
includeStart,
end,
includeEnd,
maxPoints);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
ExternalIdBundle identifiers, LocalDate currentDate, String dataSource, String dataProvider, String dataField) {
HistoricalTimeSeries hts = doGetHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
null,
true,
null,
true,
-1);
if (hts == null || hts.getTimeSeries() == null || hts.getTimeSeries().isEmpty()) {
return null;
} else {
return Pairs.of(hts.getTimeSeries().getLatestTime(), hts.getTimeSeries().getLatestValue());
}
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
ExternalIdBundle identifiers, LocalDate currentDate, String dataSource, String dataProvider, String dataField,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
HistoricalTimeSeries hts = doGetHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
start,
includeStart,
end,
includeEnd,
-1);
if (hts == null || hts.getTimeSeries() == null || hts.getTimeSeries().isEmpty()) {
return null;
} else {
return Pairs.of(hts.getTimeSeries().getLatestTime(), hts.getTimeSeries().getLatestValue());
}
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
ExternalIdBundle identifierBundle, String dataSource, String dataProvider, String dataField) {
return getLatestDataPoint(identifierBundle, LocalDate.now(getClock()), dataSource, dataProvider, dataField);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
ExternalIdBundle identifierBundle, String dataSource, String dataProvider, String dataField,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return getLatestDataPoint(identifierBundle, LocalDate.now(getClock()), dataSource, dataProvider, dataField,
start, includeStart, end, includeEnd);
}
private HistoricalTimeSeries doGetHistoricalTimeSeries(
final ExternalIdBundle identifiers,
final LocalDate currentDate,
final String dataSource,
final String dataProvider,
final String dataField,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
final Integer maxPoints) {
HistoricalTimeSeriesKey seriesKey = new HistoricalTimeSeriesKey(null,
currentDate,
identifiers,
dataSource,
dataProvider,
dataField);
final SubSeriesKey subseriesKey = new SubSeriesKey(start, end, maxPoints);
ObjectsPair<HistoricalTimeSeriesKey, SubSeriesKey> key = ObjectsPair.of(seriesKey, subseriesKey);
Supplier<HistoricalTimeSeries> fetchHts = new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
if (maxPoints == null) {
return _underlying.getHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd());
} else {
return _underlying.getHistoricalTimeSeries(identifiers,
currentDate,
dataSource,
dataProvider,
dataField,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd(),
subseriesKey.getMaxPoints());
}
}
};
HistoricalTimeSeries hts = _cache.get(key, fetchHts);
if (hts == null) {
hts = _cache.get(seriesKey, fetchHts);
}
if (hts != null) {
// Pick out the sub-series requested
hts = getSubSeries(hts, start, includeStart, end, includeEnd, maxPoints);
}
return hts;
}
//-------------------------------------------------------------------------
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
String dataField, ExternalIdBundle identifierBundle, String resolutionKey) {
return getHistoricalTimeSeries(dataField, identifierBundle, LocalDate.now(getClock()), resolutionKey);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
final String dataField,
final ExternalIdBundle identifierBundle,
final LocalDate identifierValidityDate,
final String resolutionKey) {
ArgumentChecker.notNull(dataField, "dataField");
ArgumentChecker.notEmpty(identifierBundle, "identifierBundle");
HistoricalTimeSeriesKey key = new HistoricalTimeSeriesKey(resolutionKey,
identifierValidityDate,
identifierBundle,
null,
null,
dataField);
Supplier<HistoricalTimeSeries> fetchHts = new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
return _underlying.getHistoricalTimeSeries(dataField, identifierBundle, identifierValidityDate, resolutionKey);
}
};
return _cache.get(key, fetchHts);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
String dataField, ExternalIdBundle identifierBundle, String resolutionKey,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return doGetHistoricalTimeSeries(
dataField,
identifierBundle,
LocalDate.now(getClock()),
resolutionKey,
start,
includeStart,
end,
includeEnd,
null);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(
String dataField, ExternalIdBundle identifierBundle, String resolutionKey,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd, int maxPoints) {
return doGetHistoricalTimeSeries(
dataField,
identifierBundle,
LocalDate.now(getClock()),
resolutionKey,
start,
includeStart,
end,
includeEnd,
maxPoints);
}
/*
* PLAT-1589
*/
private static final class SubSeriesKey implements Serializable {
private static final long serialVersionUID = 2L;
private final LocalDate _start;
private final LocalDate _end;
private final Integer _maxPoints;
public SubSeriesKey(LocalDate start, LocalDate end, Integer maxPoints) {
super();
this._start = (start != null) ? start.withDayOfMonth(1).withMonth(1) : null;
this._end = (end != null) ? end.plusYears(1).withMonth(1).withDayOfMonth(1) : null;
if (maxPoints != null) {
int mp = maxPoints;
if (mp < 0) {
int amp = -mp;
if (end != null) {
amp += DateUtils.getDaysBetween(end, _end);
}
this._maxPoints = -(amp + 1024 - (amp & 1023));
} else if (mp > 0) {
if (start != null) {
mp += DateUtils.getDaysBetween(_start, start);
}
this._maxPoints = mp + 1024 - (mp & 1023);
} else {
this._maxPoints = maxPoints;
}
} else {
this._maxPoints = null;
}
}
public LocalDate getStart() {
return _start;
}
public LocalDate getEnd() {
return _end;
}
public Integer getMaxPoints() {
return _maxPoints;
}
public boolean getIncludeEnd() {
return getEnd() == null;
}
/**
* Tests whether this key exactly matches the user request, or if it would be a larger time-series that needs to be
* cut down to match.
*
* @return true if an exact match, false if it needs trimming
*/
public boolean isMatch(final LocalDate start,
final boolean includeStart,
final LocalDate end,
final boolean includeEnd,
final Integer maxPoints) {
return ObjectUtils.equals(start, _start)
&& ObjectUtils.equals(end, _end)
&& includeStart
&& (includeEnd == getIncludeEnd())
&& ObjectUtils.equals(maxPoints, _maxPoints);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ObjectUtils.hashCode(_end);
result = prime * result + ObjectUtils.hashCode(_start);
result = prime * result + ObjectUtils.hashCode(_maxPoints);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
SubSeriesKey other = (SubSeriesKey) obj;
if (!ObjectUtils.equals(_end, other._end)) {
return false;
}
if (!ObjectUtils.equals(_start, other._start)) {
return false;
}
if (!ObjectUtils.equals(_maxPoints, other._maxPoints)) {
return false;
}
return true;
}
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(String dataField,
ExternalIdBundle identifierBundle,
LocalDate identifierValidityDate,
String resolutionKey,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd) {
return doGetHistoricalTimeSeries(
dataField, identifierBundle, identifierValidityDate, resolutionKey, start, includeStart, end, includeEnd, null);
}
@Override
public HistoricalTimeSeries getHistoricalTimeSeries(String dataField,
ExternalIdBundle identifierBundle,
LocalDate identifierValidityDate,
String resolutionKey,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
int maxPoints) {
return doGetHistoricalTimeSeries(
dataField,
identifierBundle,
identifierValidityDate,
resolutionKey,
start,
includeStart,
end,
includeEnd,
maxPoints);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
String dataField, ExternalIdBundle identifierBundle, String resolutionKey) {
return getLatestDataPoint(dataField, identifierBundle, LocalDate.now(getClock()), resolutionKey);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
String dataField, ExternalIdBundle identifierBundle, String resolutionKey,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
return getLatestDataPoint(dataField, identifierBundle, LocalDate.now(getClock()), resolutionKey,
start, includeStart, end, includeEnd);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
String dataField, ExternalIdBundle identifierBundle, LocalDate identifierValidityDate, String resolutionKey) {
return getLatestDataPoint(dataField, identifierBundle, identifierValidityDate, resolutionKey,
(LocalDate) null, true, (LocalDate) null, true);
}
@Override
public Pair<LocalDate, Double> getLatestDataPoint(
String dataField, ExternalIdBundle identifierBundle, LocalDate identifierValidityDate, String resolutionKey,
LocalDate start, boolean includeStart, LocalDate end, boolean includeEnd) {
HistoricalTimeSeries hts = getHistoricalTimeSeries(
dataField, identifierBundle, identifierValidityDate, resolutionKey,
start, includeStart, end, includeEnd, -1);
if (hts == null || hts.getTimeSeries() == null || hts.getTimeSeries().isEmpty()) {
return null;
} else {
return Pairs.of(hts.getTimeSeries().getLatestTime(), hts.getTimeSeries().getLatestValue());
}
}
private HistoricalTimeSeries doGetHistoricalTimeSeries(final String dataField,
final ExternalIdBundle identifierBundle,
final LocalDate identifierValidityDate,
final String resolutionKey,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
final Integer maxPoints) {
HistoricalTimeSeriesKey seriesKey = new HistoricalTimeSeriesKey(resolutionKey,
identifierValidityDate,
identifierBundle,
null,
null,
dataField);
final SubSeriesKey subseriesKey = new SubSeriesKey(start, end, maxPoints);
ObjectsPair<HistoricalTimeSeriesKey, SubSeriesKey> key = ObjectsPair.of(seriesKey, subseriesKey);
Supplier<HistoricalTimeSeries> fetchHts = new Supplier<HistoricalTimeSeries>() {
@Override
public HistoricalTimeSeries get() {
if (maxPoints == null) {
return _underlying.getHistoricalTimeSeries(dataField,
identifierBundle,
identifierValidityDate,
resolutionKey,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd());
} else {
return _underlying.getHistoricalTimeSeries(dataField,
identifierBundle,
identifierValidityDate,
resolutionKey,
subseriesKey.getStart(),
true,
subseriesKey.getEnd(),
subseriesKey.getIncludeEnd(),
subseriesKey.getMaxPoints());
}
}
};
HistoricalTimeSeries hts = _cache.get(key, fetchHts);
if (hts != null && !subseriesKey.isMatch(start, includeStart, end, includeEnd, maxPoints)) {
hts = getSubSeries(hts, start, includeStart, end, includeEnd, maxPoints);
}
return hts;
}
//-------------------------------------------------------------------------
@Override
public Map<ExternalIdBundle, HistoricalTimeSeries> getHistoricalTimeSeries(
Set<ExternalIdBundle> identifierSet, String dataSource, String dataProvider, String dataField, LocalDate start,
boolean includeStart, LocalDate end, boolean includeEnd) {
ArgumentChecker.notNull(identifierSet, "identifierSet");
Map<ExternalIdBundle, HistoricalTimeSeries> result = Maps.newHashMap();
Set<ExternalIdBundle> remainingIds = new HashSet<>();
for (ExternalIdBundle identifiers : identifierSet) {
HistoricalTimeSeriesKey key = new HistoricalTimeSeriesKey(null,
null,
identifiers,
dataSource,
dataProvider,
dataField);
HistoricalTimeSeries hts = _cache.get(key, null);
if (hts == null) {
//TODO handle misses
remainingIds.add(identifiers);
} else {
result.put(identifiers, hts);
}
}
if (remainingIds.size() > 0) {
Map<ExternalIdBundle, HistoricalTimeSeries> remainingTsResults =
_underlying.getHistoricalTimeSeries(remainingIds,
dataSource,
dataProvider,
dataField,
start,
includeStart,
end,
includeEnd);
for (Map.Entry<ExternalIdBundle, HistoricalTimeSeries> tsResult : remainingTsResults.entrySet()) {
ExternalIdBundle identifiers = tsResult.getKey();
HistoricalTimeSeries hts = tsResult.getValue();
HistoricalTimeSeriesKey key = new HistoricalTimeSeriesKey(null,
null,
identifiers,
dataSource,
dataProvider,
dataField);
if (hts != null) {
s_logger.debug("Caching time-series {}", hts);
_cache.deepInsert(key, hts.getUniqueId().getObjectId(), hts);
hts = getSubSeries(hts, start, includeStart, end, includeEnd, null);
} else {
s_logger.debug("Caching miss {}", key);
_cache.markMissed(key);
}
result.put(identifiers, hts);
}
}
return result;
}
/**
* Gets a sub-series based on the supplied dates.
*
* @param hts the time-series, null returns null
* @param start the start date, null will load the earliest date
* @param includeStart whether or not the start date is included in the result
* @param end the end date, null will load the latest date
* @param includeEnd whether or not the end date is included in the result
* @return the historical time-series, null if null input
*/
private HistoricalTimeSeries getSubSeries(
HistoricalTimeSeries hts,
LocalDate start,
boolean includeStart,
LocalDate end,
boolean includeEnd,
Integer maxPoints) {
if (hts == null) {
return null;
}
LocalDateDoubleTimeSeries timeSeries = hts.getTimeSeries();
if (timeSeries == null || timeSeries.isEmpty()) {
return hts;
}
LocalDate effectiveStart;
if (start == null) {
effectiveStart = timeSeries.getEarliestTime();
} else {
if (includeStart) {
effectiveStart = start;
} else {
effectiveStart = start.plusDays(1);
}
if (start.isBefore(timeSeries.getEarliestTime())) {
effectiveStart = timeSeries.getEarliestTime();
}
}
LocalDate effectiveEnd;
if (end == null) {
effectiveEnd = timeSeries.getLatestTime();
} else {
if (includeEnd) {
effectiveEnd = end;
} else {
effectiveEnd = end.minusDays(1);
}
if (end.isAfter(timeSeries.getLatestTime())) {
effectiveEnd = timeSeries.getLatestTime();
}
}
if (effectiveStart.isAfter(timeSeries.getLatestTime()) || effectiveEnd.isBefore(timeSeries.getEarliestTime())) {
return new SimpleHistoricalTimeSeries(hts.getUniqueId(), ImmutableLocalDateDoubleTimeSeries.EMPTY_SERIES);
}
timeSeries = timeSeries.subSeries(effectiveStart, true, effectiveEnd, true);
if (((maxPoints != null) && (Math.abs(maxPoints) < timeSeries.size()))) {
timeSeries = maxPoints >= 0 ? timeSeries.head(maxPoints) : timeSeries.tail(-maxPoints);
}
return new SimpleHistoricalTimeSeries(hts.getUniqueId(), timeSeries);
}
//-------------------------------------------------------------------------
@Override
public String toString() {
return getClass().getSimpleName() + "[" + getUnderlying() + "]";
}
@Override
public ExternalIdBundle getExternalIdBundle(final UniqueId uniqueId) {
return _identifierBundleCache.get(uniqueId, new Supplier<ExternalIdBundle>() {
@Override
public ExternalIdBundle get() {
return _underlying.getExternalIdBundle(uniqueId);
}
});
}
/**
* Call this at the end of a unit test run to clear the state of EHCache. It should not be part of a generic lifecycle
* method.
*/
protected void shutdown() {
_cache.shutdown();
_identifierBundleCache.shutdown();
}
}