Repository: jclouds-chef
Updated Branches:
  refs/heads/master d3019282e -> 793bb7609


JCLOUDS-624 - Fixed bug in ListNodes

To fix this bug, I used the approach debated in the above issue: create
new methods to do the operation using an ExecutorService provided by the
user.The the old methods are still working, but now the operations in
those methods are not concurrent anymore.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-chef/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-chef/commit/793bb760
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-chef/tree/793bb760
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-chef/diff/793bb760

Branch: refs/heads/master
Commit: 793bb7609adbfb7a8bfb98257d28ed180dbea4ba
Parents: d301928
Author: Luciano P. Sabenca([email protected]) 
<[email protected]>
Authored: Mon Jul 14 13:58:38 2014 -0300
Committer: Ignasi Barrera <[email protected]>
Committed: Mon Jul 28 15:31:11 2014 +0200

----------------------------------------------------------------------
 .../main/java/org/jclouds/chef/ChefService.java | 120 +++++++++++++------
 .../jclouds/chef/internal/BaseChefService.java  |  46 ++++++-
 .../org/jclouds/chef/strategy/ListClients.java  |   7 +-
 .../chef/strategy/ListCookbookVersions.java     |   7 +-
 .../ListCookbookVersionsInEnvironment.java      |  10 +-
 .../jclouds/chef/strategy/ListEnvironments.java |   6 +-
 .../org/jclouds/chef/strategy/ListNodes.java    |   7 +-
 .../chef/strategy/ListNodesInEnvironment.java   |   7 +-
 .../internal/BaseListCookbookVersionsImpl.java  |  97 +++++++++++++++
 .../strategy/internal/BaseListNodesImpl.java    |  77 ++++++++++++
 .../chef/strategy/internal/ListClientsImpl.java |  50 +++++---
 .../internal/ListCookbookVersionsImpl.java      |  68 +++--------
 .../ListCookbookVersionsInEnvironmentImpl.java  | 111 +++++++++--------
 .../strategy/internal/ListEnvironmentsImpl.java |  12 +-
 .../chef/strategy/internal/ListNodesImpl.java   |  50 ++------
 .../internal/ListNodesInEnvironmentImpl.java    |  50 ++------
 ...okbookVersionsInEnvironmentImplLiveTest.java |  49 ++++++++
 .../internal/ListNodesImplLiveTest.java         |  23 ++++
 .../ListNodesInEnvironmentImplLiveTest.java     |  31 ++++-
 19 files changed, 576 insertions(+), 252 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/ChefService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/chef/ChefService.java 
b/core/src/main/java/org/jclouds/chef/ChefService.java
index bae2e1b..040107a 100644
--- a/core/src/main/java/org/jclouds/chef/ChefService.java
+++ b/core/src/main/java/org/jclouds/chef/ChefService.java
@@ -16,10 +16,8 @@
  */
 package org.jclouds.chef;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
+import com.google.common.io.InputSupplier;
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.BootstrapConfig;
 import org.jclouds.chef.domain.Client;
 import org.jclouds.chef.domain.CookbookVersion;
@@ -30,8 +28,10 @@ import org.jclouds.domain.JsonBall;
 import org.jclouds.rest.annotations.SinceApiVersion;
 import org.jclouds.scriptbuilder.domain.Statement;
 
-import com.google.common.io.InputSupplier;
-import com.google.inject.ImplementedBy;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
 
 /**
  * Provides high level Chef operations.
@@ -41,7 +41,7 @@ public interface ChefService {
 
    /**
     * Gets the context that created this service.
-    * 
+    *
     * @return The context that created the service.
     */
    ChefContext getContext();
@@ -50,7 +50,7 @@ public interface ChefService {
 
    /**
     * Encrypts the given input stream.
-    * 
+    *
     * @param supplier The input stream to encrypt.
     * @return The encrypted bytes for the given input stream.
     * @throws IOException If there is an error reading from the input stream.
@@ -59,7 +59,7 @@ public interface ChefService {
 
    /**
     * Decrypts the given input stream.
-    * 
+    *
     * @param supplier The input stream to decrypt.
     * @return The decrypted bytes for the given input stream.
     * @throws IOException If there is an error reading from the input stream.
@@ -70,27 +70,27 @@ public interface ChefService {
 
    /**
     * Creates all steps necessary to bootstrap the node.
-    * 
+    *
     * @param group corresponds to a configured
-    *        {@link ChefProperties#CHEF_BOOTSTRAP_DATABAG} data bag where
-    *        run_list and other information are stored.
+    *              {@link ChefProperties#CHEF_BOOTSTRAP_DATABAG} data bag where
+    *              run_list and other information are stored.
     * @return The script used to bootstrap the node.
     */
    Statement createBootstrapScriptForGroup(String group);
 
    /**
     * Configures how the nodes of a certain group will be bootstrapped
-    * 
-    * @param group The group where the given bootstrap configuration will be
-    *        applied.
+    *
+    * @param group           The group where the given bootstrap configuration 
will be
+    *                        applied.
     * @param bootstrapConfig The configuration to be applied to the nodes in 
the
-    *        group.
+    *                        group.
     */
    void updateBootstrapConfigForGroup(String group, BootstrapConfig 
bootstrapConfig);
 
    /**
     * Gets the run list for the given group.
-    * 
+    *
     * @param The group to get the configured run list for.
     * @return run list for all nodes bootstrapped with a certain group
     */
@@ -98,10 +98,10 @@ public interface ChefService {
 
    /**
     * Gets the bootstrap configuration for a given group.
-    * <p>
+    * <p/>
     * The bootstrap configuration is a Json object containing the run list and
     * the configured attributes.
-    * 
+    *
     * @param group The name of the group.
     * @return The bootstrap configuration for the given group.
     */
@@ -111,9 +111,9 @@ public interface ChefService {
 
    /**
     * Creates a new node and populates the automatic attributes.
-    * 
+    *
     * @param nodeName The name of the node to create.
-    * @param runList The run list for the created node.
+    * @param runList  The run list for the created node.
     * @return The created node with the automatic attributes populated.
     * @see OhaiModule
     * @see ChefUtils#ohaiAutomaticAttributeBinder(com.google.inject.Binder)
@@ -122,7 +122,7 @@ public interface ChefService {
 
    /**
     * Updates and populate the automatic attributes of the given node.
-    * 
+    *
     * @param nodeName The node to update.
     */
    void updateAutomaticAttributesOnNode(String nodeName);
@@ -130,37 +130,44 @@ public interface ChefService {
    /**
     * Removes the nodes and clients that have been inactive for a given amount 
of
     * time.
-    * 
-    * @param prefix The prefix for the nodes and clients to delete.
+    *
+    * @param prefix       The prefix for the nodes and clients to delete.
     * @param secondsStale The seconds of inactivity to consider a node and
-    *        client obsolete.
+    *                     client obsolete.
     */
    void cleanupStaleNodesAndClients(String prefix, int secondsStale);
 
    /**
     * Deletes the given nodes.
-    * 
+    *
     * @param names The names of the nodes to delete.
     */
    void deleteAllNodesInList(Iterable<String> names);
 
    /**
     * Deletes the given clients.
-    * 
+    *
     * @param names The names of the client to delete.
     */
    void deleteAllClientsInList(Iterable<String> names);
 
    /**
     * Lists the details of all existing nodes.
-    * 
+    *
     * @return The details of all existing nodes.
     */
    Iterable<? extends Node> listNodes();
 
    /**
+    * Lists the details of all existing nodes, executing concurrently using 
the executorService.
+    *
+    * @return The details of all existing nodes.
+    */
+   Iterable<? extends Node> listNodes(ExecutorService executorService);
+
+   /**
     * Lists the details of all existing nodes in the given environment.
-    * 
+    *
     * @param environmentName The name fo the environment.
     * @return The details of all existing nodes in the given environment.
     */
@@ -168,20 +175,44 @@ public interface ChefService {
    Iterable<? extends Node> listNodesInEnvironment(String environmentName);
 
    /**
+    * Lists the details of all existing nodes in the given environment, using 
the ExecutorService to paralleling the execution.
+    *
+    * @param executorService The thread pool used in this operation
+    * @param environmentName The name fo the environment.
+    * @return The details of all existing nodes in the given environment.
+    */
+   @SinceApiVersion("0.10.0")
+   Iterable<? extends Node> listNodesInEnvironment(String environmentName, 
ExecutorService executorService);
+
+   /**
     * Lists the details of all existing clients.
-    * 
+    *
     * @return The details of all existing clients.
     */
    Iterable<? extends Client> listClients();
 
    /**
+    * Lists the details of all existing clients, but executing concurrently 
using the threads available in the ExecutorService.
+    *
+    * @return The details of all existing clients.
+    */
+   Iterable<? extends Client> listClients(ExecutorService executorService);
+
+   /**
     * Lists the details of all existing cookbooks.
-    * 
+    *
     * @return The details of all existing cookbooks.
     */
    Iterable<? extends CookbookVersion> listCookbookVersions();
 
    /**
+    * Lists the details of all existing cookbooks. This method is executed 
concurrently, using the threads available in the ExecutorService.
+    *
+    * @return The details of all existing cookbooks.
+    */
+   Iterable<? extends CookbookVersion> listCookbookVersions(ExecutorService 
executorService);
+
+   /**
     * Lists the details of all existing cookbooks in an environment.
     *
     * @param environmentName The environment name.
@@ -190,19 +221,40 @@ public interface ChefService {
    Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName);
 
    /**
+    * Lists the details of all existing cookbooks in an environment.
+
+    * @param executorService The thread pool to do the concurrent execution.
+    * @param environmentName The environment name.
+    * @return The details of all existing cookbooks in an environment.
+    */
+   Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName, ExecutorService 
executorService);
+
+   /**
     * Lists the details of all existing cookbooks in an environment
     * limiting number of versions.
     *
     * @param environmentName The environment name.
-    * @param numVersions The number of cookbook versions to include.
-    *                    Use 'all' to return all cookbook versions.
+    * @param numVersions     The number of cookbook versions to include.
+    *                        Use 'all' to return all cookbook versions.
     * @return The details of all existing cookbooks in environment.
     */
    Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName, String numVersions);
 
    /**
+    * Lists the details of all existing cookbooks in an environment
+    * limiting number of versions.
+    *
+    * @param executorService The executorService used to do this operation 
concurrently.
+    * @param environmentName The environment name.
+    * @param numVersions     The number of cookbook versions to include.
+    *                        Use 'all' to return all cookbook versions.
+    * @return The details of all existing cookbooks in environment.
+    */
+   Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName, String numVersions, 
ExecutorService executorService);
+
+   /**
     * Lists the details of all existing environments.
-    * 
+    *
     * @return The details of all existing environments.
     */
    @SinceApiVersion("0.10.0")

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java 
b/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java
index c22e697..d390555 100644
--- a/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java
+++ b/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java
@@ -24,6 +24,7 @@ import java.io.InputStream;
 import java.security.PrivateKey;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutorService;
 
 import javax.annotation.Resource;
 import javax.inject.Inject;
@@ -50,9 +51,9 @@ import org.jclouds.chef.strategy.DeleteAllNodesInList;
 import org.jclouds.chef.strategy.ListClients;
 import org.jclouds.chef.strategy.ListCookbookVersions;
 import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
-import org.jclouds.chef.strategy.ListNodesInEnvironment;
 import org.jclouds.chef.strategy.ListEnvironments;
 import org.jclouds.chef.strategy.ListNodes;
+import org.jclouds.chef.strategy.ListNodesInEnvironment;
 import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
 import org.jclouds.crypto.Crypto;
 import org.jclouds.domain.JsonBall;
@@ -92,7 +93,7 @@ public class BaseChefService implements ChefService {
    private final ListNodesInEnvironment listNodesInEnvironment;
    private final Json json;
    private final Crypto crypto;
-   
+
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
@@ -127,7 +128,7 @@ public class BaseChefService implements ChefService {
       this.runListForGroup = checkNotNull(runListForGroup, "runListForGroup");
       this.listEnvironments = checkNotNull(listEnvironments, 
"listEnvironments");
       this.listNodesInEnvironment = checkNotNull(listNodesInEnvironment, 
"listNodesInEnvironment");
-      this.listCookbookVersionsInEnvironment = 
checkNotNull(listCookbookVersionsInEnvironment, 
"listCookbookVersionsInEnvironment");
+      this.listCookbookVersionsInEnvironment = 
checkNotNull(listCookbookVersionsInEnvironment,"listCookbookVersionsInEnvironment");
       this.json = checkNotNull(json, "json");
       this.crypto = checkNotNull(crypto, "crypto");
    }
@@ -140,13 +141,13 @@ public class BaseChefService implements ChefService {
    @Override
    public byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws 
IOException {
       return ByteStreams.toByteArray(new RSAEncryptingPayload(crypto, 
Payloads.newPayload(supplier.getInput()), privateKey
-            .get()));
+                  .get()));
    }
 
    @Override
    public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws 
IOException {
       return ByteStreams.toByteArray(new RSADecryptingPayload(crypto, 
Payloads.newPayload(supplier.getInput()), privateKey
-            .get()));
+                  .get()));
    }
 
    @VisibleForTesting
@@ -233,26 +234,54 @@ public class BaseChefService implements ChefService {
    }
 
    @Override
+   public Iterable<? extends Node> listNodes(ExecutorService executorService) {
+      return listNodes.execute(executorService);
+   }
+
+   @Override
    public Iterable<? extends Client> listClients() {
       return listClients.execute();
    }
 
    @Override
+   public Iterable<? extends Client> listClients(ExecutorService 
executorService) {
+      return listClients.execute(executorService);
+   }
+
+   @Override
    public Iterable<? extends CookbookVersion> listCookbookVersions() {
       return listCookbookVersions.execute();
    }
 
+   @Override public Iterable<? extends CookbookVersion> listCookbookVersions(
+         ExecutorService executorService) {
+      return listCookbookVersions.execute(executorService);
+   }
+
    @Override
    public Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName) {
       return listCookbookVersionsInEnvironment.execute(environmentName);
    }
 
    @Override
-   public Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName, String numVersions) {
+   public Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName,
+         ExecutorService executorService) {
+      return listCookbookVersionsInEnvironment.execute(executorService, 
environmentName);
+   }
+
+   @Override
+   public Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName,
+         String numVersions) {
       return listCookbookVersionsInEnvironment.execute(environmentName, 
numVersions);
    }
 
    @Override
+   public Iterable<? extends CookbookVersion> 
listCookbookVersionsInEnvironment(String environmentName,
+         String numVersions, ExecutorService executorService) {
+      return listCookbookVersionsInEnvironment.execute(executorService, 
environmentName, numVersions);
+   }
+
+   @Override
    public Iterable<? extends Environment> listEnvironments() {
       return listEnvironments.execute();
    }
@@ -262,4 +291,9 @@ public class BaseChefService implements ChefService {
       return listNodesInEnvironment.execute(environmentName);
    }
 
+   @Override
+   public Iterable<? extends Node> listNodesInEnvironment(String 
environmentName, ExecutorService executorService) {
+      return listNodesInEnvironment.execute(executorService, environmentName);
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListClients.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/chef/strategy/ListClients.java 
b/core/src/main/java/org/jclouds/chef/strategy/ListClients.java
index f531a32..aa40c2a 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/ListClients.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/ListClients.java
@@ -16,16 +16,17 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.Client;
 import org.jclouds.chef.strategy.internal.ListClientsImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListClientsImpl.class)
 public interface ListClients {
 
    Iterable<? extends Client> execute();
 
-   Iterable<? extends Client> execute(ListeningExecutorService executor);
+   Iterable<? extends Client> execute(ExecutorService executor);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java 
b/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java
index 4409e4e..45663a3 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java
@@ -16,16 +16,17 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.CookbookVersion;
 import org.jclouds.chef.strategy.internal.ListCookbookVersionsImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListCookbookVersionsImpl.class)
 public interface ListCookbookVersions {
 
    Iterable<? extends CookbookVersion> execute();
 
-   Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor);
+   Iterable<? extends CookbookVersion> execute(ExecutorService executor);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersionsInEnvironment.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersionsInEnvironment.java
 
b/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersionsInEnvironment.java
index b0e1c54..188d29f 100644
--- 
a/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersionsInEnvironment.java
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersionsInEnvironment.java
@@ -16,11 +16,11 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.CookbookVersion;
 import 
org.jclouds.chef.strategy.internal.ListCookbookVersionsInEnvironmentImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListCookbookVersionsInEnvironmentImpl.class)
 public interface ListCookbookVersionsInEnvironment {
@@ -29,7 +29,9 @@ public interface ListCookbookVersionsInEnvironment {
 
    Iterable<? extends CookbookVersion> execute(String environmentName, String 
numVersions);
 
-   Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor, String environmentName);
+   Iterable<? extends CookbookVersion> execute(ExecutorService executor, 
String environmentName);
+
+   Iterable<? extends CookbookVersion> execute(ExecutorService executor, 
String environmentName, String numVersions);
+
 
-   Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor, String environmentName, String numVersions);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListEnvironments.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/chef/strategy/ListEnvironments.java 
b/core/src/main/java/org/jclouds/chef/strategy/ListEnvironments.java
index 3e5b11f..553e8d4 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/ListEnvironments.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/ListEnvironments.java
@@ -16,16 +16,16 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.Environment;
 import org.jclouds.chef.strategy.internal.ListEnvironmentsImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListEnvironmentsImpl.class)
 public interface ListEnvironments {
 
    Iterable<? extends Environment> execute();
 
-   Iterable<? extends Environment> execute(ListeningExecutorService executor);
+   Iterable<? extends Environment> execute(ExecutorService executor);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListNodes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/chef/strategy/ListNodes.java 
b/core/src/main/java/org/jclouds/chef/strategy/ListNodes.java
index a1a4093..660eed0 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/ListNodes.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/ListNodes.java
@@ -16,16 +16,17 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.Node;
 import org.jclouds.chef.strategy.internal.ListNodesImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListNodesImpl.class)
 public interface ListNodes {
 
    Iterable<? extends Node> execute();
 
-   Iterable<? extends Node> execute(ListeningExecutorService executor);
+   Iterable<? extends Node> execute(ExecutorService executor);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/ListNodesInEnvironment.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/ListNodesInEnvironment.java 
b/core/src/main/java/org/jclouds/chef/strategy/ListNodesInEnvironment.java
index 6a46fab..efeffe6 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/ListNodesInEnvironment.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/ListNodesInEnvironment.java
@@ -16,16 +16,17 @@
  */
 package org.jclouds.chef.strategy;
 
+import com.google.inject.ImplementedBy;
 import org.jclouds.chef.domain.Node;
 import org.jclouds.chef.strategy.internal.ListNodesInEnvironmentImpl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.ImplementedBy;
+import java.util.concurrent.ExecutorService;
 
 @ImplementedBy(ListNodesInEnvironmentImpl.class)
 public interface ListNodesInEnvironment {
 
    Iterable<? extends Node> execute(String environmentName);
 
-   Iterable<? extends Node> execute(ListeningExecutorService executor, String 
environmentName);
+   Iterable<? extends Node> execute(ExecutorService executor, String 
environmentName);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListCookbookVersionsImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListCookbookVersionsImpl.java
 
b/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListCookbookVersionsImpl.java
new file mode 100644
index 0000000..94cf79a
--- /dev/null
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListCookbookVersionsImpl.java
@@ -0,0 +1,97 @@
+/*
+ * 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.chef.strategy.internal;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.domain.CookbookVersion;
+import org.jclouds.logging.Logger;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.util.concurrent.Futures.allAsList;
+import static com.google.common.util.concurrent.Futures.getUnchecked;
+
+public abstract class BaseListCookbookVersionsImpl {
+
+   protected final ChefApi api;
+
+   protected Logger logger = Logger.NULL;
+
+   BaseListCookbookVersionsImpl(ChefApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   protected Iterable<? extends CookbookVersion> execute(Iterable<String> 
toGet) {
+      return concat(transform(toGet, new Function<String, Iterable<? extends 
CookbookVersion>>() {
+
+         @Override
+         public Iterable<? extends CookbookVersion> apply(final String 
cookbook) {
+            // TODO getting each version could also go parallel
+            Set<String> cookbookVersions = 
api.listVersionsOfCookbook(cookbook);
+            Iterable<? extends CookbookVersion> cookbooksVersions = 
transform(cookbookVersions,
+                  new Function<String, CookbookVersion>() {
+                     @Override
+                     public CookbookVersion apply(final String version) {
+                        return api.getCookbook(cookbook, version);
+                     }
+                  }
+            );
+
+            logger.trace(String.format("getting versions of cookbook: %s", 
cookbook));
+            return cookbooksVersions;
+         }
+      }));
+
+   }
+
+   protected Iterable<? extends CookbookVersion> executeConcurrently(final 
ListeningExecutorService executor,
+         Iterable<String> cookbookNames) {
+      return concat(transform(cookbookNames, new Function<String, Iterable<? 
extends CookbookVersion>>() {
+
+         @Override
+         public Iterable<? extends CookbookVersion> apply(final String 
cookbook) {
+            // TODO getting each version could also go parallel
+            Set<String> cookbookVersions = 
api.listVersionsOfCookbook(cookbook);
+            ListenableFuture<List<CookbookVersion>> futures = 
allAsList(transform(cookbookVersions,
+                  new Function<String, ListenableFuture<CookbookVersion>>() {
+                     @Override
+                     public ListenableFuture<CookbookVersion> apply(final 
String version) {
+                        return executor.submit(new Callable<CookbookVersion>() 
{
+                           @Override
+                           public CookbookVersion call() throws Exception {
+                              return api.getCookbook(cookbook, version);
+                           }
+                        });
+                     }
+                  }
+            ));
+
+            logger.trace(String.format("getting versions of cookbook: %s", 
cookbook));
+            return getUnchecked(futures);
+         }
+      }));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java 
b/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
new file mode 100644
index 0000000..a426b8d
--- /dev/null
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.chef.strategy.internal;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.logging.Logger;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.util.concurrent.Futures.allAsList;
+import static com.google.common.util.concurrent.Futures.getUnchecked;
+
+public abstract class BaseListNodesImpl {
+
+   protected final ChefApi api;
+
+   protected Logger logger = Logger.NULL;
+
+   BaseListNodesImpl(ChefApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   protected Iterable<? extends Node> execute(Iterable<String> toGet) {
+      Iterable<? extends Node> nodes = transform(toGet, new Function<String, 
Node>() {
+               @Override
+               public Node apply(final String input) {
+                  return api.getNode(input);
+               }
+            }
+      );
+
+      logger.trace(String.format("getting nodes: %s", 
Joiner.on(',').join(toGet)));
+      return nodes;
+
+   }
+
+   protected Iterable<? extends Node> executeConcurrently(final 
ListeningExecutorService executor,
+         Iterable<String> toGet) {
+      ListenableFuture<List<Node>> futures = allAsList(transform(toGet, new 
Function<String, ListenableFuture<Node>>() {
+         @Override
+         public ListenableFuture<Node> apply(final String input) {
+            return executor.submit(new Callable<Node>() {
+               @Override
+               public Node call() throws Exception {
+                  return api.getNode(input);
+               }
+            });
+         }
+      }));
+
+      logger.trace(String.format("getting nodes: %s", 
Joiner.on(',').join(toGet)));
+      return getUnchecked(futures);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
index 6acda30..105be2f 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
@@ -28,45 +28,66 @@ import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.jclouds.Constants;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.config.ChefProperties;
 import org.jclouds.chef.domain.Client;
 import org.jclouds.chef.strategy.ListClients;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import java.util.concurrent.ExecutorService;
+
 
 @Singleton
 public class ListClientsImpl implements ListClients {
 
    protected final ChefApi api;
-   protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
 
    @Inject
-   ListClientsImpl(@Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor, ChefApi api) {
-      this.userExecutor = checkNotNull(userExecutor, "userExecuor");
+   ListClientsImpl(ChefApi api) {
       this.api = checkNotNull(api, "api");
    }
 
    @Override
    public Iterable<? extends Client> execute() {
-      return execute(userExecutor);
+
+      Iterable<String> toGet = api.listClients();
+      Iterable<? extends Client> clients = transform(toGet,
+            new Function<String, Client>() {
+               @Override
+               public Client apply(final String input) {
+
+                  return api.getClient(input);
+               }
+
+            }
+      );
+
+      logger.trace(String.format("getting clients: %s", 
Joiner.on(',').join(toGet)));
+      return clients;
+
    }
 
    @Override
-   public Iterable<? extends Client> execute(ListeningExecutorService 
executor) {
-      return execute(executor, api.listClients());
+   public Iterable<? extends Client> execute(ExecutorService executorService) {
+      return this.execute(MoreExecutors.listeningDecorator(executorService));
+   }
+
+
+   private Iterable<? extends Client> execute(ListeningExecutorService 
listeningExecutor) {
+      return executeConcurrently(listeningExecutor, api.listClients());
    }
 
-   private Iterable<? extends Client> execute(final ListeningExecutorService 
executor, Iterable<String> toGet) {
+   private Iterable<? extends Client> executeConcurrently(final 
ListeningExecutorService executor,
+         Iterable<String> toGet) {
       ListenableFuture<List<Client>> futures = allAsList(transform(toGet,
             new Function<String, ListenableFuture<Client>>() {
                @Override
@@ -78,7 +99,8 @@ public class ListClientsImpl implements ListClients {
                      }
                   });
                }
-            }));
+            }
+      ));
 
       logger.trace(String.format("getting clients: %s", 
Joiner.on(',').join(toGet)));
       return getUnchecked(futures);

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
index 75794d9..d109038 100644
--- 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
@@ -16,81 +16,45 @@
  */
 package org.jclouds.chef.strategy.internal;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.concat;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.util.concurrent.Futures.allAsList;
-import static com.google.common.util.concurrent.Futures.getUnchecked;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import javax.annotation.Resource;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.Constants;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.config.ChefProperties;
 import org.jclouds.chef.domain.CookbookVersion;
 import org.jclouds.chef.strategy.ListCookbookVersions;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.concurrent.ExecutorService;
 
 @Singleton
-public class ListCookbookVersionsImpl implements ListCookbookVersions {
+public class ListCookbookVersionsImpl extends BaseListCookbookVersionsImpl 
implements ListCookbookVersions {
 
-   protected final ChefApi api;
-   protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
 
    @Inject
-   ListCookbookVersionsImpl(@Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor, ChefApi api) {
-      this.userExecutor = checkNotNull(userExecutor, "userExecuor");
-      this.api = checkNotNull(api, "api");
+   ListCookbookVersionsImpl(ChefApi api) {
+      super(api);
    }
 
    @Override
    public Iterable<? extends CookbookVersion> execute() {
-      return execute(userExecutor);
+      return super.execute(api.listCookbooks());
    }
 
    @Override
-   public Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor) {
-      return execute(executor, api.listCookbooks());
+   public Iterable<? extends CookbookVersion> execute(ExecutorService 
executor) {
+      return 
this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
    }
 
-   private Iterable<? extends CookbookVersion> execute(final 
ListeningExecutorService executor,
-         Iterable<String> cookbookNames) {
-      return concat(transform(cookbookNames, new Function<String, Iterable<? 
extends CookbookVersion>>() {
-
-         @Override
-         public Iterable<? extends CookbookVersion> apply(final String 
cookbook) {
-            // TODO getting each version could also go parallel
-            Set<String> cookbookVersions = 
api.listVersionsOfCookbook(cookbook);
-            ListenableFuture<List<CookbookVersion>> futures = 
allAsList(transform(cookbookVersions,
-                  new Function<String, ListenableFuture<CookbookVersion>>() {
-                     @Override
-                     public ListenableFuture<CookbookVersion> apply(final 
String version) {
-                        return executor.submit(new Callable<CookbookVersion>() 
{
-                           @Override
-                           public CookbookVersion call() throws Exception {
-                              return api.getCookbook(cookbook, version);
-                           }
-                        });
-                     }
-                  }));
 
-            logger.trace(String.format("getting versions of cookbook: %s", 
cookbook));
-            return getUnchecked(futures);
-         }
-      }));
+   private Iterable<? extends CookbookVersion> 
executeConcurrently(ListeningExecutorService executor) {
+      return super.executeConcurrently(executor, api.listCookbooks());
    }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
index ccc2992..a7142dc 100644
--- 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
@@ -16,21 +16,16 @@
  */
 package org.jclouds.chef.strategy.internal;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Iterables.transform;
-import static com.google.common.util.concurrent.Futures.allAsList;
-import static com.google.common.util.concurrent.Futures.getUnchecked;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Callable;
 
 import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.jclouds.Constants;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.config.ChefProperties;
 import org.jclouds.chef.domain.CookbookDefinition;
@@ -38,69 +33,85 @@ import org.jclouds.chef.domain.CookbookVersion;
 import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import java.util.concurrent.ExecutorService;
 
 @Singleton
-public class ListCookbookVersionsInEnvironmentImpl implements 
ListCookbookVersionsInEnvironment {
+public class ListCookbookVersionsInEnvironmentImpl extends 
BaseListCookbookVersionsImpl
+      implements ListCookbookVersionsInEnvironment {
 
-   protected final ChefApi api;
-   protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
 
    @Inject
-   
ListCookbookVersionsInEnvironmentImpl(@Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor, ChefApi api) {
-      this.userExecutor = checkNotNull(userExecutor, "userExecuor");
-      this.api = checkNotNull(api, "api");
+   ListCookbookVersionsInEnvironmentImpl(ChefApi api) {
+      super(api);
    }
 
    @Override
    public Iterable<? extends CookbookVersion> execute(String environmentName) {
-      return execute(userExecutor, environmentName);
+      return 
super.execute(transform(api.listCookbooksInEnvironment(environmentName),
+            new Function<CookbookDefinition, String>() {
+
+               @Override
+               public String apply(CookbookDefinition cookbookDefinition) {
+                  return cookbookDefinition.getName();
+               }
+            }
+      ));
    }
 
    @Override
    public Iterable<? extends CookbookVersion> execute(String environmentName, 
String numVersions) {
-      return execute(userExecutor, environmentName, numVersions);
+      return 
super.execute(transform(api.listCookbooksInEnvironment(environmentName, 
numVersions),
+            new Function<CookbookDefinition, String>() {
+
+               @Override
+               public String apply(CookbookDefinition cookbookDefinition) {
+                  return cookbookDefinition.getName();
+               }
+            }
+      ));
    }
 
-   public Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor, String environmentName) {
-      return execute(executor, 
api.listCookbooksInEnvironment(environmentName));
+   @Override
+   public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
+         String environmentName) {
+      return 
this.executeConcurrently(MoreExecutors.listeningDecorator(executor), 
environmentName);
    }
 
    @Override
-   public Iterable<? extends CookbookVersion> execute(ListeningExecutorService 
executor, String environmentName, String numVersions) {
-      return execute(executor, api.listCookbooksInEnvironment(environmentName, 
numVersions));
+   public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
+         String environmentName, String numVersions) {
+      return 
this.executeConcurrently(MoreExecutors.listeningDecorator(executor), 
environmentName, numVersions);
+   }
+
+
+   private Iterable<? extends CookbookVersion> 
executeConcurrently(ListeningExecutorService executor,
+         String environmentName) {
+      return super.execute(
+            transform(api.listCookbooksInEnvironment(environmentName), new 
Function<CookbookDefinition, String>() {
+
+               @Override
+               public String apply(CookbookDefinition cookbookDefinition) {
+                  return cookbookDefinition.getName();
+               }
+            })
+      );
    }
 
-   private Iterable<? extends CookbookVersion> execute(final 
ListeningExecutorService executor,
-         Iterable<CookbookDefinition> cookbookDefs) {
-      return concat(transform(cookbookDefs, new Function<CookbookDefinition, 
Iterable<? extends CookbookVersion>>() {
-
-         @Override
-         public Iterable<? extends CookbookVersion> apply(final 
CookbookDefinition cookbookDef) {
-            // TODO getting each version could also go parallel
-            Set<CookbookDefinition.Version> cookbookVersions = 
cookbookDef.getVersions();
-            ListenableFuture<List<CookbookVersion>> futures = 
allAsList(transform(cookbookVersions,
-                  new Function<CookbookDefinition.Version, 
ListenableFuture<CookbookVersion>>() {
-                     @Override
-                     public ListenableFuture<CookbookVersion> apply(final 
CookbookDefinition.Version version) {
-                        return executor.submit(new Callable<CookbookVersion>() 
{
-                           @Override
-                           public CookbookVersion call() throws Exception {
-                              return api.getCookbook(cookbookDef.getName(), 
version.getVersion());
-                           }
-                        });
-                     }
-                  }));
-
-            logger.trace(String.format("getting versions of cookbook %s: ", 
cookbookDef.getName()));
-            return getUnchecked(futures);
-         }
-      }));
+
+   private Iterable<? extends CookbookVersion> 
executeConcurrently(ListeningExecutorService executor,
+         String environmentName, String numVersions) {
+      return 
super.execute(transform(api.listCookbooksInEnvironment(environmentName, 
numVersions),
+            new Function<CookbookDefinition, String>() {
+
+               @Override
+               public String apply(CookbookDefinition cookbookDefinition) {
+                  return cookbookDefinition.getName();
+               }
+            }
+      ));
    }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
index 9b79de2..0ed792e 100644
--- 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
@@ -40,6 +40,12 @@ import com.google.common.base.Joiner;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.inject.Inject;
+import com.google.common.util.concurrent.MoreExecutors;
+
+
+import java.util.concurrent.ExecutorService;
+
+
 
 @Singleton
 public class ListEnvironmentsImpl implements ListEnvironments {
@@ -62,7 +68,11 @@ public class ListEnvironmentsImpl implements 
ListEnvironments {
    }
 
    @Override
-   public Iterable<? extends Environment> execute(ListeningExecutorService 
executor) {
+   public Iterable<? extends Environment> execute(ExecutorService executor) {
+      return this.execute(MoreExecutors.listeningDecorator(executor));
+   }
+
+   private Iterable<? extends Environment> execute(ListeningExecutorService 
executor) {
       return execute(executor, api.listEnvironments());
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
index be9b652..8d95965 100644
--- a/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
+++ b/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
@@ -16,71 +16,47 @@
  */
 package org.jclouds.chef.strategy.internal;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.util.concurrent.Futures.allAsList;
-import static com.google.common.util.concurrent.Futures.getUnchecked;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
 import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.jclouds.Constants;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.config.ChefProperties;
 import org.jclouds.chef.domain.Node;
 import org.jclouds.chef.strategy.ListNodes;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import java.util.concurrent.ExecutorService;
 
 @Singleton
-public class ListNodesImpl implements ListNodes {
+public class ListNodesImpl extends BaseListNodesImpl implements ListNodes {
+
 
-   protected final ChefApi api;
-   protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
 
    @Inject
-   ListNodesImpl(@Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor, ChefApi api) {
-      this.userExecutor = checkNotNull(userExecutor, "userExecuor");
-      this.api = checkNotNull(api, "api");
+   ListNodesImpl(ChefApi api) {
+      super(api);
    }
 
    @Override
    public Iterable<? extends Node> execute() {
-      return execute(userExecutor);
+      return super.execute(api.listNodes());
    }
 
    @Override
-   public Iterable<? extends Node> execute(ListeningExecutorService executor) {
-      return execute(executor, api.listNodes());
+   public Iterable<? extends Node> execute(ExecutorService executor) {
+      return 
this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
    }
 
-   private Iterable<? extends Node> execute(final ListeningExecutorService 
executor, Iterable<String> toGet) {
-      ListenableFuture<List<Node>> futures = allAsList(transform(toGet, new 
Function<String, ListenableFuture<Node>>() {
-         @Override
-         public ListenableFuture<Node> apply(final String input) {
-            return executor.submit(new Callable<Node>() {
-               @Override
-               public Node call() throws Exception {
-                  return api.getNode(input);
-               }
-            });
-         }
-      }));
 
-      logger.trace(String.format("getting nodes: %s", 
Joiner.on(',').join(toGet)));
-      return getUnchecked(futures);
+   private Iterable<? extends Node> 
executeConcurrently(ListeningExecutorService executor) {
+      return super.executeConcurrently(executor, api.listNodes());
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
index 8ae747e..58ecaaa 100644
--- 
a/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
+++ 
b/core/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
@@ -16,71 +16,47 @@
  */
 package org.jclouds.chef.strategy.internal;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.util.concurrent.Futures.allAsList;
-import static com.google.common.util.concurrent.Futures.getUnchecked;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
 import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.jclouds.Constants;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.config.ChefProperties;
 import org.jclouds.chef.domain.Node;
 import org.jclouds.chef.strategy.ListNodesInEnvironment;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import java.util.concurrent.ExecutorService;
 
 @Singleton
-public class ListNodesInEnvironmentImpl implements ListNodesInEnvironment {
+public class ListNodesInEnvironmentImpl extends BaseListNodesImpl implements 
ListNodesInEnvironment {
 
-   protected final ChefApi api;
-   protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(ChefProperties.CHEF_LOGGER)
    protected Logger logger = Logger.NULL;
 
    @Inject
-   ListNodesInEnvironmentImpl(@Named(Constants.PROPERTY_USER_THREADS) 
ListeningExecutorService userExecutor, ChefApi api) {
-      this.userExecutor = checkNotNull(userExecutor, "userExecuor");
-      this.api = checkNotNull(api, "api");
+   ListNodesInEnvironmentImpl(ChefApi api) {
+      super(api);
    }
 
    @Override
    public Iterable<? extends Node> execute(String environmentName) {
-      return execute(userExecutor, environmentName);
+      return super.execute(api.listNodesInEnvironment(environmentName));
    }
 
    @Override
-   public Iterable<? extends Node> execute(ListeningExecutorService executor, 
String environmentName) {
-      return execute(executor, environmentName, 
api.listNodesInEnvironment(environmentName));
+   public Iterable<? extends Node> execute(ExecutorService executor, String 
environmentName) {
+      return 
this.executeConcurrently(MoreExecutors.listeningDecorator(executor), 
environmentName);
    }
 
-   private Iterable<? extends Node> execute(final ListeningExecutorService 
executor, String environmentName, Iterable<String> toGet) {
-      ListenableFuture<List<Node>> futures = allAsList(transform(toGet, new 
Function<String, ListenableFuture<Node>>() {
-         @Override
-         public ListenableFuture<Node> apply(final String input) {
-            return executor.submit(new Callable<Node>() {
-               @Override
-               public Node call() throws Exception {
-                  return api.getNode(input);
-               }
-            });
-         }
-      }));
 
-      logger.trace(String.format("getting nodes in environment %s: %s", 
environmentName, Joiner.on(',').join(toGet)));
-      return getUnchecked(futures);
+   private Iterable<? extends Node> 
executeConcurrently(ListeningExecutorService executor,
+         String environmentName) {
+      return super.executeConcurrently(executor, 
api.listNodesInEnvironment(environmentName));
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/test/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImplLiveTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImplLiveTest.java
 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImplLiveTest.java
index a9b667d..5f68fcf 100644
--- 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImplLiveTest.java
+++ 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImplLiveTest.java
@@ -22,7 +22,11 @@ import static org.testng.Assert.fail;
 
 import java.io.File;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.domain.ChecksumStatus;
 import org.jclouds.chef.domain.CookbookVersion;
@@ -51,6 +55,9 @@ public class ListCookbookVersionsInEnvironmentImplLiveTest 
extends BaseChefLiveT
    private ListCookbookVersionsInEnvironmentImpl strategy;
    private CreateNodeAndPopulateAutomaticAttributesImpl creator;
 
+   private ExecutorService testExecutorService;
+   private ListeningExecutorService testListeningExecutorService;
+
    @Override
    protected void initialize() {
       super.initialize();
@@ -63,6 +70,8 @@ public class ListCookbookVersionsInEnvironmentImplLiveTest 
extends BaseChefLiveT
       }
 
       this.strategy = 
injector.getInstance(ListCookbookVersionsInEnvironmentImpl.class);
+      this.testExecutorService = Executors.newFixedThreadPool(5);
+      this.testListeningExecutorService = 
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
    }
 
    @AfterClass(groups = { "integration", "live" })
@@ -72,6 +81,10 @@ public class ListCookbookVersionsInEnvironmentImplLiveTest 
extends BaseChefLiveT
       api.deleteCookbook(PREFIX, "1.0.0");
       api.deleteCookbook(PREFIX + 1, "0.0.0");
       api.deleteCookbook(PREFIX + 1, "1.0.0");
+
+      this.testExecutorService.shutdown();
+      this.testListeningExecutorService.shutdown();
+
       super.tearDown();
    }
 
@@ -81,15 +94,51 @@ public class ListCookbookVersionsInEnvironmentImplLiveTest 
extends BaseChefLiveT
    }
 
    @Test
+   public void testExecuteConcurrentlyWithExecutorService() {
+      assertTrue(size(strategy.execute(testExecutorService, "_default")) > 0,
+            "Expected one or more elements");
+   }
+
+   @Test
+   public void testExecuteConcurrentlyWithListeningExecutorService() {
+      assertTrue(size(strategy.execute(testListeningExecutorService, 
"_default")) > 0,
+            "Expected one or more elements");
+   }
+
+   @Test
    public void testExecuteWithNumVersions() {
       assertTrue(size(strategy.execute("_default", "2")) > 0, "Expected one or 
more elements");
    }
 
    @Test
+   public void testExecuteConcurrentlyWithNumVersionsAndExecutorService() {
+      assertTrue(size(strategy.execute(testExecutorService, "_default", "2")) 
> 0,
+            "Expected one or more elements");
+   }
+
+   @Test
+   public void 
testExecuteConcurrentlyWithNumVersionsAndListeningExecutorService() {
+      assertTrue(size(strategy.execute(testListeningExecutorService, 
"_default", "2")) > 0,
+            "Expected one or more elements");
+   }
+
+   @Test
    public void testExecuteWithNumVersionsAll() {
       assertTrue(size(strategy.execute("_default", "all")) > 0, "Expected one 
or more elements");
    }
 
+   @Test
+   public void testExecuteConcurrentlyWithNumVersionsAllAndExecutorService() {
+      assertTrue(size(strategy.execute(testExecutorService, "_default", 
"all")) > 0,
+            "Expected one or more elements");
+   }
+
+   @Test
+   public void 
testExecuteConcurrentlyWithNumVersionsAllAndListeningExecutorService() {
+      assertTrue(size(strategy.execute(testListeningExecutorService, 
"_default", "all")) > 0,
+            "Expected one or more elements");
+   }
+
    private FilePayload uploadContent(String fileName) throws Exception {
       // Define the file you want in the cookbook
       File file = new File(System.getProperty("user.dir"), fileName);

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesImplLiveTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesImplLiveTest.java
 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesImplLiveTest.java
index b9de2b8..903b998 100644
--- 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesImplLiveTest.java
+++ 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesImplLiveTest.java
@@ -19,6 +19,8 @@ package org.jclouds.chef.strategy.internal;
 import static com.google.common.collect.Iterables.size;
 import static org.testng.Assert.assertTrue;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.internal.BaseChefLiveTest;
 import org.testng.annotations.AfterClass;
@@ -26,6 +28,9 @@ import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
 
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 /**
  * Tests behavior of {@code ListNodesImpl} strategies
  */
@@ -35,6 +40,9 @@ public class ListNodesImplLiveTest extends 
BaseChefLiveTest<ChefApi> {
    private ListNodesImpl strategy;
    private CreateNodeAndPopulateAutomaticAttributesImpl creator;
 
+   private ExecutorService testExecutorService;
+   private ListeningExecutorService testListeningExecutorService;
+
    @Override
    protected void initialize() {
       super.initialize();
@@ -42,6 +50,9 @@ public class ListNodesImplLiveTest extends 
BaseChefLiveTest<ChefApi> {
       this.strategy = injector.getInstance(ListNodesImpl.class);
       creator.execute(prefix, ImmutableSet.<String> of());
       creator.execute(prefix + 1, ImmutableSet.<String> of());
+
+      this.testExecutorService = Executors.newFixedThreadPool(5);
+      this.testListeningExecutorService = 
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
    }
 
    @AfterClass(groups = { "integration", "live" })
@@ -49,6 +60,10 @@ public class ListNodesImplLiveTest extends 
BaseChefLiveTest<ChefApi> {
    protected void tearDown() {
       api.deleteNode(prefix);
       api.deleteNode(prefix + 1);
+
+      this.testExecutorService.shutdown();
+      this.testListeningExecutorService.shutdown();
+
       super.tearDown();
    }
 
@@ -56,4 +71,12 @@ public class ListNodesImplLiveTest extends 
BaseChefLiveTest<ChefApi> {
    public void testExecute() {
       assertTrue(size(strategy.execute()) > 0, "Expected one or more 
elements");
    }
+
+   public void testExecuteConcurrentlyWithExecutorService() {
+      assertTrue(size(strategy.execute(testExecutorService)) > 0, "Expected 
one or more elements");
+   }
+
+   public void testExecuteConcurrentlyWithListeningExecutorService() {
+      assertTrue(size(strategy.execute(testListeningExecutorService)) > 0, 
"Expected one or more elements");
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-chef/blob/793bb760/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImplLiveTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImplLiveTest.java
 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImplLiveTest.java
index 81dd6d8..f655d52 100644
--- 
a/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImplLiveTest.java
+++ 
b/core/src/test/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImplLiveTest.java
@@ -19,6 +19,8 @@ package org.jclouds.chef.strategy.internal;
 import static com.google.common.collect.Iterables.size;
 import static org.testng.Assert.assertTrue;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import org.jclouds.chef.ChefApi;
 import org.jclouds.chef.internal.BaseChefLiveTest;
 import org.testng.annotations.AfterClass;
@@ -26,6 +28,9 @@ import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
 
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 /**
  * Tests behavior of {@code ListNodesInEnvironmentImpl} strategies
  */
@@ -35,13 +40,19 @@ public class ListNodesInEnvironmentImplLiveTest extends 
BaseChefLiveTest<ChefApi
    private ListNodesInEnvironmentImpl strategy;
    private CreateNodeAndPopulateAutomaticAttributesImpl creator;
 
+   private ExecutorService testExecutorService;
+   private ListeningExecutorService testListeningExecutorService;
+
    @Override
    protected void initialize() {
       super.initialize();
       this.creator = 
injector.getInstance(CreateNodeAndPopulateAutomaticAttributesImpl.class);
       this.strategy = injector.getInstance(ListNodesInEnvironmentImpl.class);
-      creator.execute(prefix, ImmutableSet.<String> of());
-      creator.execute(prefix + 1, ImmutableSet.<String> of());
+      creator.execute(prefix, ImmutableSet.<String>of());
+      creator.execute(prefix + 1, ImmutableSet.<String>of());
+
+      this.testExecutorService = Executors.newFixedThreadPool(5);
+      this.testListeningExecutorService = 
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
    }
 
    @AfterClass(groups = { "integration", "live" })
@@ -49,6 +60,10 @@ public class ListNodesInEnvironmentImplLiveTest extends 
BaseChefLiveTest<ChefApi
    protected void tearDown() {
       api.deleteNode(prefix);
       api.deleteNode(prefix + 1);
+
+      this.testExecutorService.shutdown();
+      this.testListeningExecutorService.shutdown();
+
       super.tearDown();
    }
 
@@ -56,4 +71,16 @@ public class ListNodesInEnvironmentImplLiveTest extends 
BaseChefLiveTest<ChefApi
    public void testExecute() {
       assertTrue(size(strategy.execute("_default")) > 0, "Expected one or more 
elements");
    }
+
+   @Test
+   public void testExecuteConcurrentlyWithExecutorService() {
+      assertTrue(size(strategy.execute(testExecutorService, "_default")) > 0,
+            "Expected one or more elements");
+   }
+
+   @Test
+   public void testExecuteConcurrentlyWithListeningExecutorService() {
+      assertTrue(size(strategy.execute(testListeningExecutorService, 
"_default")) > 0,
+            "Expected one or more elements");
+   }
 }

Reply via email to