diff --git a/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java b/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java index 2cbdb858e01..1ddf6c198bf 100644 --- a/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java +++ b/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java @@ -16,17 +16,20 @@ */ package org.jclouds.suppliers; +import java.util.Collection; import java.util.Map; import javax.annotation.Resource; import org.jclouds.logging.Logger; +import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; /** * Allows you to lazy discover a key by value. This is useful for example in service discovery, @@ -49,12 +52,30 @@ public SupplyKeyMatchingValueOrNull(Supplier>> supplier, Supp public K get() { V uri = valueSupplier.get(); // eagerly get all the values, so we can see which is default - Map map = Maps.transformValues(supplier.get(), Suppliers. supplierFunction()); - K region = ImmutableBiMap.copyOf(map).inverse().get(uri); - if (region == null && !map.isEmpty()) { - region = Iterables.get(map.keySet(), 0); - logger.warn("failed to find key for value %s in %s; choosing first: %s", uri, map, region); + final Map map = Maps.transformValues(supplier.get(), Suppliers. supplierFunction()); + + // There can be keys with the same value so we need a multimap here + Multimap inverted = Multimaps.index(map.keySet(), new Function() { + @Override public V apply(K input) { + return map.get(input); + } + }); + + Collection keys = inverted.get(uri); + K key = null; + + if (keys == null || keys.isEmpty()) { + if (!map.isEmpty()) { + key = Iterables.get(map.keySet(), 0); + logger.warn("failed to find key for value %s in %s; choosing first: %s", uri, map, key); + } + } else { + key = Iterables.get(keys, 0); + if (keys.size() > 1) { + logger.debug("found %s keys for value %s. choosing first: %s", keys.size(), uri, key); + } } - return region; + + return key; } } diff --git a/core/src/test/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNullTest.java b/core/src/test/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNullTest.java new file mode 100644 index 00000000000..5c7b88a888b --- /dev/null +++ b/core/src/test/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNullTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.suppliers; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import java.util.Map; + +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; + +@Test(groups = "unit", testName = "SupplyKeyMatchingValueOrNullTest") +public class SupplyKeyMatchingValueOrNullTest { + + private static final Supplier valueSupplier = Suppliers.ofInstance("v3"); + + public void testValueFound() { + SupplyKeyMatchingValueOrNull supplier = supplier("k1", "v1", "k2", "v2", "k3", "v3"); + assertEquals(supplier.get(), "k3"); + } + + public void testFirstKeyIsReturnedIfValueNotFound() { + SupplyKeyMatchingValueOrNull supplier = supplier("k1", "v1", "k2", "v2", "k4", "v4"); + assertEquals(supplier.get(), "k1"); + } + + public void testFirstKeyIsReturnedIfMultipleValuesFound() { + SupplyKeyMatchingValueOrNull supplier = supplier("k1", "v1", "k2", "v3", "k3", "v3"); + assertEquals(supplier.get(), "k2"); + } + + public void testReturnsNullIfEmptyMap() { + SupplyKeyMatchingValueOrNull supplier = new SupplyKeyMatchingValueOrNull( + Suppliers.>> ofInstance(ImmutableMap.> of()), + valueSupplier); + assertNull(supplier.get()); + } + + private static SupplyKeyMatchingValueOrNull supplier(String k1, String v1, String k2, String v2, + String k3, String v3) { + return new SupplyKeyMatchingValueOrNull(map(k1, v1, k2, v2, k3, v3), valueSupplier); + } + + private static Supplier>> map(String k1, String v1, String k2, String v2, String k3, + String v3) { + return Suppliers.>> ofInstance(ImmutableMap.of(k1, Suppliers.ofInstance(v1), k2, + Suppliers.ofInstance(v2), k3, Suppliers.ofInstance(v3))); + } +}