@Test(expectedExceptions = IllegalArgumentException.class)
 public void testEmptyData2() {
   final List<Pair<double[], Double>> data = new ArrayList<>();
   final double[] temp = new double[] {};
   final Pair<double[], Double> pair = Pairs.of(temp, 0.0);
   data.add(pair);
   new InterpolatorNDDataBundle(data);
 }
 @SuppressWarnings("unchecked")
 @Override
 public V getSingle(final ExternalIdBundle bundle, final VersionCorrection versionCorrection) {
   ArgumentChecker.notNull(bundle, "bundle");
   ArgumentChecker.notNull(versionCorrection, "versionCorrection");
   final Pair<ExternalIdBundle, VersionCorrection> key = Pairs.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) {
         V result;
         try {
           result = get(uid);
         } catch (DataNotFoundException dnfe) {
           s_logger.warn("Cached {} for {} no longer available", uid, key);
           result = null;
         }
         if (result != null) {
           return result;
         }
       }
       return null;
     } else if (e.getObjectValue() instanceof UniqueId) {
       // REVIEW 2013-11-06 Andrew -- Get will probably throw a DNFE instead of returning NULL
       final UniqueId uid = (UniqueId) e.getObjectValue();
       try {
         return get(uid);
       } catch (DataNotFoundException dnfe) {
         s_logger.warn("Cached {} for {} no longer available", uid, key);
         return null;
       }
     }
   }
   final V result = getUnderlying().getSingle(bundle, versionCorrection);
   if (result == null) {
     cacheIdentifiers(Collections.<UniqueId>emptyList(), key);
   } else {
     cacheIdentifiers(result.getUniqueId(), key);
     cacheItem(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 = Pairs.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;
 }
 @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 = Pairs.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 = Pairs.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;
 }
 @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 = Pairs.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 = Pairs.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<>(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;
 }
 @Test
 public void testFXOptionVolatilitySurfaceInstrumentProvider() {
   final ICAPFXOptionVolatilitySurfaceInstrumentProvider provider =
       new ICAPFXOptionVolatilitySurfaceInstrumentProvider("I", "EURUSD", "Market_Value");
   assertEquals(
       provider, cycleObject(ICAPFXOptionVolatilitySurfaceInstrumentProvider.class, provider));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1WK"),
       provider.getInstrument(Tenor.ofDays(7), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1M"),
       provider.getInstrument(Tenor.ofMonths(1), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1YR"),
       provider.getInstrument(Tenor.ofYears(1), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1WK"),
       provider.getInstrument(Tenor.ofDays(7), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1M"),
       provider.getInstrument(Tenor.ofMonths(1), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSD_1YR"),
       provider.getInstrument(Tenor.ofYears(1), Pairs.of((Number) 0, FXVolQuoteType.ATM)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF25_1WK"),
       provider.getInstrument(Tenor.ofDays(7), Pairs.of((Number) 25, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF25_1M"),
       provider.getInstrument(Tenor.ofMonths(1), Pairs.of((Number) 25, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF25_1YR"),
       provider.getInstrument(Tenor.ofYears(1), Pairs.of((Number) 25, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF10_1WK"),
       provider.getInstrument(Tenor.ofDays(7), Pairs.of((Number) 10, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF10_1M"),
       provider.getInstrument(Tenor.ofMonths(1), Pairs.of((Number) 10, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDBF10_1YR"),
       provider.getInstrument(Tenor.ofYears(1), Pairs.of((Number) 10, FXVolQuoteType.BUTTERFLY)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR25_1WK"),
       provider.getInstrument(
           Tenor.ofDays(7), Pairs.of((Number) 25, FXVolQuoteType.RISK_REVERSAL)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR25_1M"),
       provider.getInstrument(
           Tenor.ofMonths(1), Pairs.of((Number) 25, FXVolQuoteType.RISK_REVERSAL)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR25_1YR"),
       provider.getInstrument(
           Tenor.ofYears(1), Pairs.of((Number) 25, FXVolQuoteType.RISK_REVERSAL)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR10_1WK"),
       provider.getInstrument(
           Tenor.ofDays(7), Pairs.of((Number) 10, FXVolQuoteType.RISK_REVERSAL)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR10_1M"),
       provider.getInstrument(
           Tenor.ofMonths(1), Pairs.of((Number) 10, FXVolQuoteType.RISK_REVERSAL)));
   assertEquals(
       ExternalId.of(ExternalSchemes.ICAP, "IEURUSDRR10_1YR"),
       provider.getInstrument(
           Tenor.ofYears(1), Pairs.of((Number) 10, FXVolQuoteType.RISK_REVERSAL)));
 }