JCLOUDS-107: Use Guice multibinding extensions
diff --git a/core/pom.xml b/core/pom.xml
index f4c4ac8..2035020 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -73,6 +73,12 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <!--  for ohai -->
+    <dependency>
+        <groupId>com.google.inject.extensions</groupId>
+        <artifactId>guice-multibindings</artifactId>
+        <version>3.0</version>
+    </dependency>
     <!--  for transient chef provider -->
     <dependency>
       <groupId>org.apache.jclouds</groupId>
diff --git a/core/src/main/java/org/jclouds/chef/util/ChefUtils.java b/core/src/main/java/org/jclouds/chef/util/ChefUtils.java
index 0e9e66a..aff08d3 100644
--- a/core/src/main/java/org/jclouds/chef/util/ChefUtils.java
+++ b/core/src/main/java/org/jclouds/chef/util/ChefUtils.java
@@ -25,13 +25,13 @@
 
 import org.jclouds.domain.JsonBall;
 import org.jclouds.ohai.Automatic;
-import org.jclouds.ohai.config.multibindings.MapBinder;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Iterables;
 import com.google.inject.Binder;
 import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.MapBinder;
 
 /**
  * 
diff --git a/core/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java b/core/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
index acff81a..1f106ec 100644
--- a/core/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
+++ b/core/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
@@ -22,11 +22,11 @@
 import javax.inject.Singleton;
 
 import org.jclouds.domain.JsonBall;
-import org.jclouds.ohai.config.multibindings.MapBinder;
 import org.jclouds.ohai.suppliers.UptimeSecondsSupplier;
 
 import com.google.common.base.Supplier;
 import com.google.inject.Provides;
+import com.google.inject.multibindings.MapBinder;
 
 /**
  * Wires the components needed to parse ohai data from a JVM
diff --git a/core/src/main/java/org/jclouds/ohai/config/OhaiModule.java b/core/src/main/java/org/jclouds/ohai/config/OhaiModule.java
index 62a7630..152b120 100644
--- a/core/src/main/java/org/jclouds/ohai/config/OhaiModule.java
+++ b/core/src/main/java/org/jclouds/ohai/config/OhaiModule.java
@@ -32,7 +32,6 @@
 import org.jclouds.json.Json;
 import org.jclouds.ohai.Automatic;
 import org.jclouds.ohai.AutomaticSupplier;
-import org.jclouds.ohai.config.multibindings.MapBinder;
 import org.jclouds.ohai.functions.ByteArrayToMacAddress;
 import org.jclouds.ohai.functions.MapSetToMultimap;
 
@@ -42,6 +41,7 @@
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.MapBinder;
 
 /**
  * Wires the components needed to parse ohai data
diff --git a/core/src/main/java/org/jclouds/ohai/config/multibindings/Element.java b/core/src/main/java/org/jclouds/ohai/config/multibindings/Element.java
deleted file mode 100644
index db8d16a..0000000
--- a/core/src/main/java/org/jclouds/ohai/config/multibindings/Element.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.ohai.config.multibindings;
-
-import com.google.inject.BindingAnnotation;
-
-import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * An internal binding annotation applied to each element in a multibinding. All
- * elements are assigned a globally-unique id to allow different modules to
- * contribute multibindings independently.
- * 
- * @author jessewilson@google.com (Jesse Wilson)
- */
-@Retention(RUNTIME)
-@BindingAnnotation
-@interface Element {
-   String setName();
-
-   int uniqueId();
-}
diff --git a/core/src/main/java/org/jclouds/ohai/config/multibindings/MapBinder.java b/core/src/main/java/org/jclouds/ohai/config/multibindings/MapBinder.java
deleted file mode 100644
index 2cde1b0..0000000
--- a/core/src/main/java/org/jclouds/ohai/config/multibindings/MapBinder.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * 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.ohai.config.multibindings;
-
-import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
-import static org.jclouds.ohai.config.multibindings.Multibinder.checkConfiguration;
-import static org.jclouds.ohai.config.multibindings.Multibinder.checkNotNull;
-import static org.jclouds.ohai.config.multibindings.Multibinder.setOf;
-
-import java.lang.annotation.Annotation;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
-
-import org.jclouds.ohai.config.multibindings.Multibinder.RealMultibinder;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Binder;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.TypeLiteral;
-import com.google.inject.binder.LinkedBindingBuilder;
-import com.google.inject.spi.Dependency;
-import com.google.inject.spi.ProviderWithDependencies;
-import com.google.inject.util.Types;
-
-/**
- * An API to bind multiple map entries separately, only to later inject them as
- * a complete map. MapBinder is intended for use in your application's module:
- * 
- * <pre>
- * <code>
- * public class SnacksModule extends AbstractModule {
- *   protected void configure() {
- *     MapBinder&lt;String, Snack&gt; mapbinder
- *         = MapBinder.newMapBinder(binder(), String.class, Snack.class);
- *     mapbinder.addBinding("twix").toInstance(new Twix());
- *     mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
- *     mapbinder.addBinding("skittles").to(Skittles.class);
- *   }
- * }</code>
- * </pre>
- * 
- * <p>
- * With this binding, a {@link Map}{@code <String, Snack>} can now be injected:
- * 
- * <pre>
- * <code>
- * class SnackMachine {
- *   {@literal @}Inject
- *   public SnackMachine(Map&lt;String, Snack&gt; snacks) { ... }
- * }</code>
- * </pre>
- * 
- * <p>
- * In addition to binding {@code Map<K, V>}, a mapbinder will also bind
- * {@code Map<K, Provider<V>>} for lazy value provision:
- * 
- * <pre>
- * <code>
- * class SnackMachine {
- *   {@literal @}Inject
- *   public SnackMachine(Map&lt;String, Provider&lt;Snack&gt;&gt; snackSuppliers) { ... }
- * }</code>
- * </pre>
- * 
- * <p>
- * Contributing mapbindings from different modules is supported. For example, it
- * is okay to have both {@code CandyModule} and {@code ChipsModule} both create
- * their own {@code MapBinder<String, Snack>}, and to each contribute bindings
- * to the snacks map. When that map is injected, it will contain entries from
- * both modules.
- * 
- * <p>
- * The map's iteration order is consistent with the binding order. This is
- * convenient when multiple elements are contributed by the same module because
- * that module can order its bindings appropriately. Avoid relying on the
- * iteration order of elements contributed by different modules, since there is
- * no equivalent mechanism to order modules.
- * 
- * <p>
- * Values are resolved at map injection time. If a value is bound to a provider,
- * that provider's get method will be called each time the map is injected
- * (unless the binding is also scoped, or a map of providers is injected).
- * 
- * <p>
- * Annotations are used to create different maps of the same key/value type.
- * Each distinct annotation gets its own independent map.
- * 
- * <p>
- * <strong>Keys must be distinct.</strong> If the same key is bound more than
- * once, map injection will fail. However, use {@link #permitDuplicates()} in
- * order to allow duplicate keys; extra bindings to {@code Map<K, Set<V>>} and
- * {@code Map<K, Set<Provider<V>>} will be added.
- * 
- * <p>
- * <strong>Keys must be non-null.</strong> {@code addBinding(null)} will throw
- * an unchecked exception.
- * 
- * <p>
- * <strong>Values must be non-null to use map injection.</strong> If any value
- * is null, map injection will fail (although injecting a map of providers will
- * not).
- * 
- * @author dpb@google.com (David P. Baker)
- */
-public abstract class MapBinder<K, V> {
-   private MapBinder() {
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with no binding
-    * annotation.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
-      binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
-      return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType)),
-            Key.get(mapOfProviderOf(keyType, valueType)), Key.get(mapOf(keyType, setOf(valueType))),
-            Key.get(mapOfSetOfProviderOf(keyType, valueType)),
-            Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType)));
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with no binding
-    * annotation.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType) {
-      return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType));
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with
-    * {@code annotation}.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
-         Annotation annotation) {
-      binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
-      return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotation),
-            Key.get(mapOfProviderOf(keyType, valueType), annotation),
-            Key.get(mapOf(keyType, setOf(valueType)), annotation),
-            Key.get(mapOfSetOfProviderOf(keyType, valueType), annotation),
-            Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotation));
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with
-    * {@code annotation}.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
-         Annotation annotation) {
-      return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation);
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with
-    * {@code annotationType}.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
-         Class<? extends Annotation> annotationType) {
-      binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
-      return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotationType),
-            Key.get(mapOfProviderOf(keyType, valueType), annotationType),
-            Key.get(mapOf(keyType, setOf(valueType)), annotationType),
-            Key.get(mapOfSetOfProviderOf(keyType, valueType), annotationType),
-            Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotationType));
-   }
-
-   /**
-    * Returns a new mapbinder that collects entries of {@code keyType}/
-    * {@code valueType} in a {@link Map} that is itself bound with
-    * {@code annotationType}.
-    */
-   public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
-         Class<? extends Annotation> annotationType) {
-      return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType);
-   }
-
-   @SuppressWarnings("unchecked")
-   // a map of <K, V> is safely a Map<K, V>
-   private static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
-      return (TypeLiteral<Map<K, V>>) TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType()));
-   }
-
-   @SuppressWarnings("unchecked")
-   // a provider map <K, V> is safely a Map<K, Provider<V>>
-   private static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(TypeLiteral<K> keyType,
-         TypeLiteral<V> valueType) {
-      return (TypeLiteral<Map<K, Provider<V>>>) TypeLiteral.get(Types.mapOf(keyType.getType(),
-            Types.providerOf(valueType.getType())));
-   }
-
-   @SuppressWarnings("unchecked")
-   // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
-   private static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(TypeLiteral<K> keyType,
-         TypeLiteral<V> valueType) {
-      return (TypeLiteral<Map<K, Set<Provider<V>>>>) TypeLiteral.get(Types.mapOf(keyType.getType(),
-            Types.setOf(Types.providerOf(valueType.getType()))));
-   }
-
-   @SuppressWarnings("unchecked")
-   // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
-   private static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(TypeLiteral<K> keyType,
-         TypeLiteral<V> valueType) {
-      return (TypeLiteral<Entry<K, Provider<V>>>) TypeLiteral.get(newParameterizedTypeWithOwner(Map.class, Entry.class,
-            keyType.getType(), Types.providerOf(valueType.getType())));
-   }
-
-   private static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
-         Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
-         Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Entry<K, Provider<V>>> entrySetBinder) {
-      RealMapBinder<K, V> mapBinder = new RealMapBinder<K, V>(binder, valueType, mapKey, providerMapKey, multimapKey,
-            providerMultimapKey, entrySetBinder);
-      binder.install(mapBinder);
-      return mapBinder;
-   }
-
-   /**
-    * Configures the {@code MapBinder} to handle duplicate entries.
-    * <p>
-    * When multiple equal keys are bound, the value that gets included in the
-    * map is arbitrary.
-    * <p>
-    * In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>} maps
-    * that are normally bound, a {@code Map<K, Set<V>>} and {@code Map<K,
-    * Set<Provider<V>>>} are <em>also</em> bound, which contain all values bound
-    * to each key.
-    * <p>
-    * When multiple modules contribute elements to the map, this configuration
-    * option impacts all of them.
-    * 
-    * @return this map binder
-    */
-   public abstract MapBinder<K, V> permitDuplicates();
-
-   /**
-    * Returns a binding builder used to add a new entry in the map. Each key
-    * must be distinct (and non-null). Bound providers will be evaluated each
-    * time the map is injected.
-    * 
-    * <p>
-    * It is an error to call this method without also calling one of the
-    * {@code to} methods on the returned binding builder.
-    * 
-    * <p>
-    * Scoping elements independently is supported. Use the {@code in} method to
-    * specify a binding scope.
-    */
-   public abstract LinkedBindingBuilder<V> addBinding(K key);
-
-   /**
-    * The actual mapbinder plays several roles:
-    * 
-    * <p>
-    * As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of
-    * the map's values. It delegates to a {@link Multibinder} of entries (keys
-    * to value providers).
-    * 
-    * <p>
-    * As a Module, it installs the binding to the map itself, as well as to a
-    * corresponding map whose values are providers. It uses the entry set
-    * multibinder to construct the map and the provider map.
-    * 
-    * <p>
-    * As a module, this implements equals() and hashcode() in order to trick
-    * Guice into executing its configure() method only once. That makes it so
-    * that multiple mapbinders can be created for the same target map, but only
-    * one is bound. Since the list of bindings is retrieved from the injector
-    * itself (and not the mapbinder), each mapbinder has access to all
-    * contributions from all equivalent mapbinders.
-    * 
-    * <p>
-    * Rather than binding a single Map.Entry&lt;K, V&gt;, the map binder binds
-    * keys and values independently. This allows the values to be properly
-    * scoped.
-    * 
-    * <p>
-    * We use a subclass to hide 'implements Module' from the public API.
-    */
-   private static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
-      private final TypeLiteral<V> valueType;
-      private final Key<Map<K, V>> mapKey;
-      private final Key<Map<K, Provider<V>>> providerMapKey;
-      private final Key<Map<K, Set<V>>> multimapKey;
-      private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
-      private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
-
-      /*
-       * the target injector's binder. non-null until initialization, null
-       * afterwards
-       */
-      private Binder binder;
-
-      private RealMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
-            Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
-            Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
-         this.valueType = valueType;
-         this.mapKey = mapKey;
-         this.providerMapKey = providerMapKey;
-         this.multimapKey = multimapKey;
-         this.providerMultimapKey = providerMultimapKey;
-         this.entrySetBinder = (RealMultibinder<Entry<K, Provider<V>>>) entrySetBinder;
-         this.binder = binder;
-      }
-
-      @Override
-      public MapBinder<K, V> permitDuplicates() {
-         entrySetBinder.permitDuplicates();
-         binder.install(new MultimapBinder<K, V>(multimapKey, providerMultimapKey, entrySetBinder.getSetKey()));
-         return this;
-      }
-
-      /**
-       * This creates two bindings. One for the {@code Map.Entry<K,
-       * Provider<V>>} and another for {@code V}.
-       */
-      @Override
-      public LinkedBindingBuilder<V> addBinding(K key) {
-         checkNotNull(key, "key");
-         checkConfiguration(!isInitialized(), "MapBinder was already initialized");
-
-         Key<V> valueKey = Key.get(valueType, new RealElement(entrySetBinder.getSetName()));
-         entrySetBinder.addBinding().toInstance(new MapEntry<K, Provider<V>>(key, binder.getProvider(valueKey)));
-         return binder.bind(valueKey);
-      }
-
-      public void configure(Binder binder) {
-         checkConfiguration(!isInitialized(), "MapBinder was already initialized");
-
-         final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency.get(entrySetBinder
-               .getSetKey()));
-
-         // Binds a Map<K, Provider<V>> from a collection of Map<Entry<K,
-         // Provider<V>>.
-         final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetBinder.getSetKey());
-         binder.bind(providerMapKey).toProvider(new ProviderWithDependencies<Map<K, Provider<V>>>() {
-            private Map<K, Provider<V>> providerMap;
-
-            @SuppressWarnings("unused")
-            @Inject
-            void initialize(Injector injector) {
-               RealMapBinder.this.binder = null;
-               boolean permitDuplicates = entrySetBinder.permitsDuplicates(injector);
-
-               Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>();
-               for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
-                  Provider<V> previous = providerMapMutable.put(entry.getKey(), entry.getValue());
-                  checkConfiguration(previous == null || permitDuplicates,
-                        "Map injection failed due to duplicated key \"%s\"", entry.getKey());
-               }
-
-               providerMap = ImmutableMap.copyOf(providerMapMutable);
-            }
-
-            public Map<K, Provider<V>> get() {
-               return providerMap;
-            }
-
-            public Set<Dependency<?>> getDependencies() {
-               return dependencies;
-            }
-         });
-
-         final Provider<Map<K, Provider<V>>> mapProvider = binder.getProvider(providerMapKey);
-         binder.bind(mapKey).toProvider(new ProviderWithDependencies<Map<K, V>>() {
-            public Map<K, V> get() {
-               Map<K, V> map = new LinkedHashMap<K, V>();
-               for (Entry<K, Provider<V>> entry : mapProvider.get().entrySet()) {
-                  V value = entry.getValue().get();
-                  K key = entry.getKey();
-                  checkConfiguration(value != null, "Map injection failed due to null value for key \"%s\"", key);
-                  map.put(key, value);
-               }
-               return Collections.unmodifiableMap(map);
-            }
-
-            public Set<Dependency<?>> getDependencies() {
-               return dependencies;
-            }
-         });
-      }
-
-      private boolean isInitialized() {
-         return binder == null;
-      }
-
-      @Override
-      public boolean equals(Object o) {
-         return o instanceof RealMapBinder<?, ?> && ((RealMapBinder<?, ?>) o).mapKey.equals(mapKey);
-      }
-
-      @Override
-      public int hashCode() {
-         return mapKey.hashCode();
-      }
-
-      /**
-       * Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
-       */
-      private static final class MultimapBinder<K, V> implements Module {
-
-         private final Key<Map<K, Set<V>>> multimapKey;
-         private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
-         private final Key<Set<Entry<K, Provider<V>>>> entrySetKey;
-
-         public MultimapBinder(Key<Map<K, Set<V>>> multimapKey, Key<Map<K, Set<Provider<V>>>> providerMultimapKey,
-               Key<Set<Entry<K, Provider<V>>>> entrySetKey) {
-            this.multimapKey = multimapKey;
-            this.providerMultimapKey = providerMultimapKey;
-            this.entrySetKey = entrySetKey;
-         }
-
-         public void configure(Binder binder) {
-            final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency
-                  .get(entrySetKey));
-
-            final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetKey);
-            // Binds a Map<K, Set<Provider<V>>> from a collection of
-            // Map<Entry<K, Provider<V>> if
-            // permitDuplicates was called.
-            binder.bind(providerMultimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<Provider<V>>>>() {
-               private Map<K, Set<Provider<V>>> providerMultimap;
-
-               @SuppressWarnings("unused")
-               @Inject
-               void initialize(Injector injector) {
-                  Map<K, ImmutableSet.Builder<Provider<V>>> providerMultimapMutable = new LinkedHashMap<K, ImmutableSet.Builder<Provider<V>>>();
-                  for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
-                     if (!providerMultimapMutable.containsKey(entry.getKey())) {
-                        providerMultimapMutable.put(entry.getKey(), ImmutableSet.<Provider<V>> builder());
-                     }
-                     providerMultimapMutable.get(entry.getKey()).add(entry.getValue());
-                  }
-
-                  ImmutableMap.Builder<K, Set<Provider<V>>> providerMultimapBuilder = ImmutableMap.builder();
-                  for (Entry<K, ImmutableSet.Builder<Provider<V>>> entry : providerMultimapMutable.entrySet()) {
-                     providerMultimapBuilder.put(entry.getKey(), entry.getValue().build());
-                  }
-                  providerMultimap = providerMultimapBuilder.build();
-               }
-
-               public Map<K, Set<Provider<V>>> get() {
-                  return providerMultimap;
-               }
-
-               public Set<Dependency<?>> getDependencies() {
-                  return dependencies;
-               }
-            });
-
-            final Provider<Map<K, Set<Provider<V>>>> multimapProvider = binder.getProvider(providerMultimapKey);
-            binder.bind(multimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<V>>>() {
-
-               public Map<K, Set<V>> get() {
-                  ImmutableMap.Builder<K, Set<V>> multimapBuilder = ImmutableMap.builder();
-                  for (Entry<K, Set<Provider<V>>> entry : multimapProvider.get().entrySet()) {
-                     K key = entry.getKey();
-                     ImmutableSet.Builder<V> valuesBuilder = ImmutableSet.builder();
-                     for (Provider<V> valueProvider : entry.getValue()) {
-                        V value = valueProvider.get();
-                        checkConfiguration(value != null, "Multimap injection failed due to null value for key \"%s\"",
-                              key);
-                        valuesBuilder.add(value);
-                     }
-                     multimapBuilder.put(key, valuesBuilder.build());
-                  }
-                  return multimapBuilder.build();
-               }
-
-               public Set<Dependency<?>> getDependencies() {
-                  return dependencies;
-               }
-            });
-         }
-      }
-
-      private static final class MapEntry<K, V> implements Map.Entry<K, V> {
-         private final K key;
-         private final V value;
-
-         private MapEntry(K key, V value) {
-            this.key = key;
-            this.value = value;
-         }
-
-         public K getKey() {
-            return key;
-         }
-
-         public V getValue() {
-            return value;
-         }
-
-         public V setValue(V value) {
-            throw new UnsupportedOperationException();
-         }
-
-         @Override
-         public boolean equals(Object obj) {
-            return obj instanceof Map.Entry<?, ?> && key.equals(((Map.Entry<?, ?>) obj).getKey())
-                  && value.equals(((Map.Entry<?, ?>) obj).getValue());
-         }
-
-         @Override
-         public int hashCode() {
-            return 127 * ("key".hashCode() ^ key.hashCode()) + 127 * ("value".hashCode() ^ value.hashCode());
-         }
-
-         @Override
-         public String toString() {
-            return "MapEntry(" + key + ", " + value + ")";
-         }
-      }
-   }
-}
diff --git a/core/src/main/java/org/jclouds/ohai/config/multibindings/Multibinder.java b/core/src/main/java/org/jclouds/ohai/config/multibindings/Multibinder.java
deleted file mode 100644
index 3d521b2..0000000
--- a/core/src/main/java/org/jclouds/ohai/config/multibindings/Multibinder.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * 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.ohai.config.multibindings;
-
-import static com.google.inject.name.Names.named;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.inject.AbstractModule;
-import com.google.inject.Binder;
-import com.google.inject.Binding;
-import com.google.inject.ConfigurationException;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.TypeLiteral;
-import com.google.inject.binder.LinkedBindingBuilder;
-import com.google.inject.spi.Dependency;
-import com.google.inject.spi.HasDependencies;
-import com.google.inject.spi.Message;
-import com.google.inject.spi.Toolable;
-import com.google.inject.util.Types;
-
-/**
- * 
- * An API to bind multiple values separately, only to later inject them as a
- * complete collection. Multibinder is intended for use in your application's
- * module:
- * 
- * <pre>
- * <code>
- * public class SnacksModule extends AbstractModule {
- *   protected void configure() {
- *     Multibinder&lt;Snack&gt; multibinder
- *         = Multibinder.newSetBinder(binder(), Snack.class);
- *     multibinder.addBinding().toInstance(new Twix());
- *     multibinder.addBinding().toProvider(SnickersProvider.class);
- *     multibinder.addBinding().to(Skittles.class);
- *   }
- * }</code>
- * </pre>
- * 
- * <p>
- * With this binding, a {@link Set}{@code <Snack>} can now be injected:
- * 
- * <pre>
- * <code>
- * class SnackMachine {
- *   {@literal @}Inject
- *   public SnackMachine(Set&lt;Snack&gt; snacks) { ... }
- * }</code>
- * </pre>
- * 
- * <p>
- * Contributing multibindings from different modules is supported. For example,
- * it is okay to have both {@code CandyModule} and {@code ChipsModule} to both
- * create their own {@code Multibinder<Snack>}, and to each contribute bindings
- * to the set of snacks. When that set is injected, it will contain elements
- * from both modules.
- * 
- * <p>
- * The set's iteration order is consistent with the binding order. This is
- * convenient when multiple elements are contributed by the same module because
- * that module can order its bindings appropriately. Avoid relying on the
- * iteration order of elements contributed by different modules, since there is
- * no equivalent mechanism to order modules.
- * 
- * <p>
- * Elements are resolved at set injection time. If an element is bound to a
- * provider, that provider's get method will be called each time the set is
- * injected (unless the binding is also scoped).
- * 
- * <p>
- * Annotations are be used to create different sets of the same element type.
- * Each distinct annotation gets its own independent collection of elements.
- * 
- * <p>
- * <strong>Elements must be distinct.</strong> If multiple bound elements have
- * the same value, set injection will fail.
- * 
- * <p>
- * <strong>Elements must be non-null.</strong> If any set element is null, set
- * injection will fail.
- * 
- * @author jessewilson@google.com (Jesse Wilson)
- */
-public abstract class Multibinder<T> {
-   private Multibinder() {
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with no binding annotation.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) {
-      binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
-      RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "", Key.get(Multibinder.<T> setOf(type)));
-      binder.install(result);
-      return result;
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with no binding annotation.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) {
-      return newSetBinder(binder, TypeLiteral.get(type));
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with {@code annotation}.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type, Annotation annotation) {
-      binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
-      RealMultibinder<T> result = new RealMultibinder<T>(binder, type, annotation.toString(), Key.get(
-            Multibinder.<T> setOf(type), annotation));
-      binder.install(result);
-      return result;
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with {@code annotation}.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type, Annotation annotation) {
-      return newSetBinder(binder, TypeLiteral.get(type), annotation);
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with {@code annotationType}.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type,
-         Class<? extends Annotation> annotationType) {
-      binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
-      RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "@" + annotationType.getName(), Key.get(
-            Multibinder.<T> setOf(type), annotationType));
-      binder.install(result);
-      return result;
-   }
-
-   /**
-    * Returns a new multibinder that collects instances of {@code type} in a
-    * {@link Set} that is itself bound with {@code annotationType}.
-    */
-   public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type,
-         Class<? extends Annotation> annotationType) {
-      return newSetBinder(binder, TypeLiteral.get(type), annotationType);
-   }
-
-   @SuppressWarnings("unchecked")
-   // wrapping a T in a Set safely returns a Set<T>
-   static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> elementType) {
-      Type type = Types.setOf(elementType.getType());
-      return (TypeLiteral<Set<T>>) TypeLiteral.get(type);
-   }
-
-   /**
-    * Configures the bound set to silently discard duplicate elements. When
-    * multiple equal values are bound, the one that gets included is arbitrary.
-    * When multiple modules contribute elements to the set, this configuration
-    * option impacts all of them.
-    * 
-    * @return this multibinder
-    */
-   public abstract Multibinder<T> permitDuplicates();
-
-   /**
-    * Returns a binding builder used to add a new element in the set. Each bound
-    * element must have a distinct value. Bound providers will be evaluated each
-    * time the set is injected.
-    * 
-    * <p>
-    * It is an error to call this method without also calling one of the
-    * {@code to} methods on the returned binding builder.
-    * 
-    * <p>
-    * Scoping elements independently is supported. Use the {@code in} method to
-    * specify a binding scope.
-    */
-   public abstract LinkedBindingBuilder<T> addBinding();
-
-   /**
-    * The actual multibinder plays several roles:
-    * 
-    * <p>
-    * As a Multibinder, it acts as a factory for LinkedBindingBuilders for each
-    * of the set's elements. Each binding is given an annotation that identifies
-    * it as a part of this set.
-    * 
-    * <p>
-    * As a Module, it installs the binding to the set itself. As a module, this
-    * implements equals() and hashcode() in order to trick Guice into executing
-    * its configure() method only once. That makes it so that multiple
-    * multibinders can be created for the same target collection, but only one
-    * is bound. Since the list of bindings is retrieved from the injector itself
-    * (and not the multibinder), each multibinder has access to all
-    * contributions from all multibinders.
-    * 
-    * <p>
-    * As a Provider, this constructs the set instances.
-    * 
-    * <p>
-    * We use a subclass to hide 'implements Module, Provider' from the public
-    * API.
-    */
-   static final class RealMultibinder<T> extends Multibinder<T> implements Module, Provider<Set<T>>, HasDependencies {
-
-      private final TypeLiteral<T> elementType;
-      private final String setName;
-      private final Key<Set<T>> setKey;
-      private final Key<Boolean> permitDuplicatesKey;
-
-      /*
-       * the target injector's binder. non-null until initialization, null
-       * afterwards
-       */
-      private Binder binder;
-
-      /*
-       * a provider for each element in the set. null until initialization,
-       * non-null afterwards
-       */
-      private List<Provider<T>> providers;
-      private Set<Dependency<?>> dependencies;
-
-      /**
-       * whether duplicates are allowed. Possibly configured by a different
-       * instance
-       */
-      private boolean permitDuplicates;
-
-      private RealMultibinder(Binder binder, TypeLiteral<T> elementType, String setName, Key<Set<T>> setKey) {
-         this.binder = checkNotNull(binder, "binder");
-         this.elementType = checkNotNull(elementType, "elementType");
-         this.setName = checkNotNull(setName, "setName");
-         this.setKey = checkNotNull(setKey, "setKey");
-         this.permitDuplicatesKey = Key.get(Boolean.class, named(toString() + " permits duplicates"));
-      }
-
-      public void configure(Binder binder) {
-         checkConfiguration(!isInitialized(), "Multibinder was already initialized");
-         binder.bind(setKey).toProvider(this);
-      }
-
-      @Override
-      public Multibinder<T> permitDuplicates() {
-         binder.install(new PermitDuplicatesModule(permitDuplicatesKey));
-         return this;
-      }
-
-      @Override
-      public LinkedBindingBuilder<T> addBinding() {
-         checkConfiguration(!isInitialized(), "Multibinder was already initialized");
-
-         return binder.bind(Key.get(elementType, new RealElement(setName)));
-      }
-
-      /**
-       * Invoked by Guice at Injector-creation time to prepare providers for
-       * each element in this set. At this time the set's size is known, but its
-       * contents are only evaluated when get() is invoked.
-       */
-      @Toolable
-      @Inject
-      void initialize(Injector injector) {
-         providers = Lists.newArrayList();
-         List<Dependency<?>> dependencies = Lists.newArrayList();
-         for (Binding<?> entry : injector.findBindingsByType(elementType)) {
-
-            if (keyMatches(entry.getKey())) {
-               @SuppressWarnings("unchecked")
-               // protected by findBindingsByType()
-               Binding<T> binding = (Binding<T>) entry;
-               providers.add(binding.getProvider());
-               dependencies.add(Dependency.get(binding.getKey()));
-            }
-         }
-
-         this.dependencies = ImmutableSet.copyOf(dependencies);
-         this.permitDuplicates = permitsDuplicates(injector);
-         this.binder = null;
-      }
-
-      boolean permitsDuplicates(Injector injector) {
-         return injector.getBindings().containsKey(permitDuplicatesKey);
-      }
-
-      private boolean keyMatches(Key<?> key) {
-         return key.getTypeLiteral().equals(elementType) && key.getAnnotation() instanceof Element
-               && ((Element) key.getAnnotation()).setName().equals(setName);
-      }
-
-      private boolean isInitialized() {
-         return binder == null;
-      }
-
-      public Set<T> get() {
-         checkConfiguration(isInitialized(), "Multibinder is not initialized");
-
-         Set<T> result = new LinkedHashSet<T>();
-         for (Provider<T> provider : providers) {
-            final T newValue = provider.get();
-            checkConfiguration(newValue != null, "Set injection failed due to null element");
-            checkConfiguration(result.add(newValue) || permitDuplicates,
-                  "Set injection failed due to duplicated element \"%s\"", newValue);
-         }
-         return Collections.unmodifiableSet(result);
-      }
-
-      String getSetName() {
-         return setName;
-      }
-
-      Key<Set<T>> getSetKey() {
-         return setKey;
-      }
-
-      public Set<Dependency<?>> getDependencies() {
-         return dependencies;
-      }
-
-      @Override
-      public boolean equals(Object o) {
-         return o instanceof RealMultibinder<?> && ((RealMultibinder<?>) o).setKey.equals(setKey);
-      }
-
-      @Override
-      public int hashCode() {
-         return setKey.hashCode();
-      }
-
-      @Override
-      public String toString() {
-         return new StringBuilder().append(setName).append(setName.length() > 0 ? " " : "").append("Multibinder<")
-               .append(elementType).append(">").toString();
-      }
-   }
-
-   /**
-    * We install the permit duplicates configuration as its own binding, all by
-    * itself. This way, if only one of a multibinder's users remember to call
-    * permitDuplicates(), they're still permitted.
-    */
-   private static class PermitDuplicatesModule extends AbstractModule {
-      private final Key<Boolean> key;
-
-      PermitDuplicatesModule(Key<Boolean> key) {
-         this.key = key;
-      }
-
-      @Override
-      protected void configure() {
-         bind(key).toInstance(true);
-      }
-
-      @Override
-      public boolean equals(Object o) {
-         return o instanceof PermitDuplicatesModule && ((PermitDuplicatesModule) o).key.equals(key);
-      }
-
-      @Override
-      public int hashCode() {
-         return getClass().hashCode() ^ key.hashCode();
-      }
-   }
-
-   static void checkConfiguration(boolean condition, String format, Object... args) {
-      if (condition) {
-         return;
-      }
-
-      throw new ConfigurationException(ImmutableSet.of(new Message(String.format(format, args))));
-   }
-
-   static <T> T checkNotNull(T reference, String name) {
-      if (reference != null) {
-         return reference;
-      }
-
-      NullPointerException npe = new NullPointerException(name);
-      throw new ConfigurationException(ImmutableSet.of(new Message(ImmutableList.of(), npe.toString(), npe)));
-   }
-}
diff --git a/core/src/main/java/org/jclouds/ohai/config/multibindings/RealElement.java b/core/src/main/java/org/jclouds/ohai/config/multibindings/RealElement.java
deleted file mode 100644
index f727445..0000000
--- a/core/src/main/java/org/jclouds/ohai/config/multibindings/RealElement.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.ohai.config.multibindings;
-
-import java.lang.annotation.Annotation;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
-class RealElement implements Element {
-   private static final AtomicInteger nextUniqueId = new AtomicInteger(1);
-
-   private final int uniqueId;
-   private final String setName;
-
-   RealElement(String setName) {
-      uniqueId = nextUniqueId.getAndIncrement();
-      this.setName = setName;
-   }
-
-   public String setName() {
-      return setName;
-   }
-
-   public int uniqueId() {
-      return uniqueId;
-   }
-
-   public Class<? extends Annotation> annotationType() {
-      return Element.class;
-   }
-
-   @Override
-   public String toString() {
-      return "@" + Element.class.getName() + "(setName=" + setName + ",uniqueId=" + uniqueId + ")";
-   }
-
-   @Override
-   public boolean equals(Object o) {
-      return o instanceof Element && ((Element) o).setName().equals(setName())
-            && ((Element) o).uniqueId() == uniqueId();
-   }
-
-   @Override
-   public int hashCode() {
-      return 127 * ("setName".hashCode() ^ setName.hashCode()) + 127 * ("uniqueId".hashCode() ^ uniqueId);
-   }
-}
diff --git a/core/src/main/java/org/jclouds/ohai/config/multibindings/package-info.java b/core/src/main/java/org/jclouds/ohai/config/multibindings/package-info.java
deleted file mode 100644
index cccfea4..0000000
--- a/core/src/main/java/org/jclouds/ohai/config/multibindings/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-/**
- *  Taken from r1154 of Guice, as they decided to stop supporting multiple bindings and instead silently throw them away.
- */
-package org.jclouds.ohai.config.multibindings;
-
diff --git a/core/src/test/java/org/jclouds/ohai/config/OhaiModuleTest.java b/core/src/test/java/org/jclouds/ohai/config/OhaiModuleTest.java
index 213106d..e2bed2e 100644
--- a/core/src/test/java/org/jclouds/ohai/config/OhaiModuleTest.java
+++ b/core/src/test/java/org/jclouds/ohai/config/OhaiModuleTest.java
@@ -31,7 +31,6 @@
 import org.jclouds.json.Json;
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.ohai.Automatic;
-import org.jclouds.ohai.config.multibindings.MapBinder;
 import org.jclouds.rest.annotations.ApiVersion;
 import org.testng.annotations.Test;
 
@@ -41,6 +40,7 @@
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.MapBinder;
 import com.google.inject.util.Providers;
 
 /**