]> source.dussan.org Git - jgit.git/commitdiff
Support a configured credentials provider in LsRemoteCommand 71/4571/4
authorKevin Sawicki <kevin@github.com>
Tue, 8 Nov 2011 20:49:16 +0000 (12:49 -0800)
committerChris Aniszczyk <zx@twitter.com>
Thu, 10 Nov 2011 18:57:47 +0000 (10:57 -0800)
Refactored the three common transport configuration options:
credentials provider, timeout, and transport config callback
into a new TransportCommand base class which is now extended
by all commands that use a Transport object during execution.

Bug: 349188
Change-Id: I90c2c14fb4e3cc4712905158f9047153a0c235c2
Signed-off-by: Kevin Sawicki <kevin@github.com>
Signed-off-by: Chris Aniszczyk <zx@twitter.com>
org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java [new file with mode: 0644]

index 281704fadfbf7f578fbb85472fd10682808bc486..5c98e6a28d38ed79962b4eabfdb0801e4544fc93 100644 (file)
@@ -49,7 +49,6 @@ import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.concurrent.Callable;
 
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -67,7 +66,6 @@ import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.FetchResult;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.RemoteConfig;
@@ -80,7 +78,7 @@ import org.eclipse.jgit.transport.URIish;
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-clone.html"
  *      >Git documentation about Clone</a>
  */
-public class CloneCommand implements Callable<Git> {
+public class CloneCommand extends TransportCommand<CloneCommand, Git> {
 
        private String uri;
 
@@ -94,17 +92,18 @@ public class CloneCommand implements Callable<Git> {
 
        private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
-       private CredentialsProvider credentialsProvider;
-
-       private int timeout;
-
        private boolean cloneAllBranches;
 
        private boolean noCheckout;
 
        private Collection<String> branchesToClone;
 
-       private TransportConfigCallback transportConfigCallback;
+       /**
+        * Create clone command with no repository set
+        */
+       public CloneCommand() {
+               super(null);
+       }
 
        /**
         * Executes the {@code Clone} command.
@@ -142,12 +141,12 @@ public class CloneCommand implements Callable<Git> {
                return command.call().getRepository();
        }
 
-       private FetchResult fetch(Repository repo, URIish u)
+       private FetchResult fetch(Repository clonedRepo, URIish u)
                        throws URISyntaxException,
                        JGitInternalException,
                        InvalidRemoteException, IOException {
                // create the remote config and save it
-               RemoteConfig config = new RemoteConfig(repo.getConfig(), remote);
+               RemoteConfig config = new RemoteConfig(clonedRepo.getConfig(), remote);
                config.addURI(u);
 
                final String dst = bare ? Constants.R_HEADS : Constants.R_REMOTES
@@ -157,19 +156,16 @@ public class CloneCommand implements Callable<Git> {
                refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", dst + "/*"); //$NON-NLS-1$ //$NON-NLS-2$
 
                config.addFetchRefSpec(refSpec);
-               config.update(repo.getConfig());
+               config.update(clonedRepo.getConfig());
 
-               repo.getConfig().save();
+               clonedRepo.getConfig().save();
 
                // run the fetch command
-               FetchCommand command = new FetchCommand(repo);
+               FetchCommand command = new FetchCommand(clonedRepo);
                command.setRemote(remote);
                command.setProgressMonitor(monitor);
                command.setTagOpt(TagOpt.FETCH_TAGS);
-               command.setTimeout(timeout);
-               if (credentialsProvider != null)
-                       command.setCredentialsProvider(credentialsProvider);
-               command.setTransportConfigCallback(transportConfigCallback);
+               configure(command);
 
                List<RefSpec> specs = calculateRefSpecs(dst);
                command.setRefSpecs(specs);
@@ -193,7 +189,7 @@ public class CloneCommand implements Callable<Git> {
                return specs;
        }
 
-       private void checkout(Repository repo, FetchResult result)
+       private void checkout(Repository clonedRepo, FetchResult result)
                        throws JGitInternalException,
                        MissingObjectException, IncorrectObjectTypeException, IOException {
 
@@ -208,22 +204,22 @@ public class CloneCommand implements Callable<Git> {
                        return; // throw exception?
 
                if (head.getName().startsWith(Constants.R_HEADS)) {
-                       final RefUpdate newHead = repo.updateRef(Constants.HEAD);
+                       final RefUpdate newHead = clonedRepo.updateRef(Constants.HEAD);
                        newHead.disableRefLog();
                        newHead.link(head.getName());
-                       addMergeConfig(repo, head);
+                       addMergeConfig(clonedRepo, head);
                }
 
-               final RevCommit commit = parseCommit(repo, head);
+               final RevCommit commit = parseCommit(clonedRepo, head);
 
                boolean detached = !head.getName().startsWith(Constants.R_HEADS);
-               RefUpdate u = repo.updateRef(Constants.HEAD, detached);
+               RefUpdate u = clonedRepo.updateRef(Constants.HEAD, detached);
                u.setNewObjectId(commit.getId());
                u.forceUpdate();
 
                if (!bare) {
-                       DirCache dc = repo.lockDirCache();
-                       DirCacheCheckout co = new DirCacheCheckout(repo, dc,
+                       DirCache dc = clonedRepo.lockDirCache();
+                       DirCacheCheckout co = new DirCacheCheckout(clonedRepo, dc,
                                        commit.getTree());
                        co.checkout();
                }
@@ -246,19 +242,20 @@ public class CloneCommand implements Callable<Git> {
                return foundBranch;
        }
 
-       private void addMergeConfig(Repository repo, Ref head) throws IOException {
+       private void addMergeConfig(Repository clonedRepo, Ref head)
+                       throws IOException {
                String branchName = Repository.shortenRefName(head.getName());
-               repo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION,
+               clonedRepo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION,
                                branchName, ConfigConstants.CONFIG_KEY_REMOTE, remote);
-               repo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION,
+               clonedRepo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION,
                                branchName, ConfigConstants.CONFIG_KEY_MERGE, head.getName());
-               repo.getConfig().save();
+               clonedRepo.getConfig().save();
        }
 
-       private RevCommit parseCommit(final Repository repo, final Ref ref)
+       private RevCommit parseCommit(final Repository clonedRepo, final Ref ref)
                        throws MissingObjectException, IncorrectObjectTypeException,
                        IOException {
-               final RevWalk rw = new RevWalk(repo);
+               final RevWalk rw = new RevWalk(clonedRepo);
                final RevCommit commit;
                try {
                        commit = rw.parseCommit(ref.getObjectId());
@@ -342,27 +339,6 @@ public class CloneCommand implements Callable<Git> {
                return this;
        }
 
-       /**
-        * @param credentialsProvider
-        *            the {@link CredentialsProvider} to use
-        * @return {@code this}
-        */
-       public CloneCommand setCredentialsProvider(
-                       CredentialsProvider credentialsProvider) {
-               this.credentialsProvider = credentialsProvider;
-               return this;
-       }
-
-       /**
-        * @param timeout
-        *            the timeout used for the fetch step
-        * @return {@code this}
-        */
-       public CloneCommand setTimeout(int timeout) {
-               this.timeout = timeout;
-               return this;
-       }
-
        /**
         * @param cloneAllBranches
         *            true when all branches have to be fetched (indicates wildcard
@@ -396,18 +372,4 @@ public class CloneCommand implements Callable<Git> {
                this.noCheckout = noCheckout;
                return this;
        }
-
-       /**
-        * @param transportConfigCallback
-        *            if set, the callback will be invoked after the Transport has
-        *            created, but before the Transport is used. The callback can
-        *            use this opportunity to set additional type-specific
-        *            configuration on the Transport instance.
-        * @return {@code this}
-        */
-       public CloneCommand setTransportConfigCallback(
-                       TransportConfigCallback transportConfigCallback) {
-               this.transportConfigCallback = transportConfigCallback;
-               return this;
-       }
 }
index 8fe9d59a2f912d148ed1326c04a0afc1e58eb1b2..3ed78ee23291f35dcbc9bb0117f10f4282d1f527 100644 (file)
@@ -57,7 +57,6 @@ import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.FetchResult;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.TagOpt;
@@ -71,7 +70,7 @@ import org.eclipse.jgit.transport.Transport;
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html"
  *      >Git documentation about Fetch</a>
  */
-public class FetchCommand extends GitCommand<FetchResult> {
+public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> {
 
        private String remote = Constants.DEFAULT_REMOTE_NAME;
 
@@ -87,14 +86,8 @@ public class FetchCommand extends GitCommand<FetchResult> {
 
        private boolean thin = Transport.DEFAULT_FETCH_THIN;
 
-       private int timeout;
-
-       private CredentialsProvider credentialsProvider;
-
        private TagOpt tagOption;
 
-       private TransportConfigCallback transportConfigCallback;
-
        /**
         * @param repo
         */
@@ -127,15 +120,11 @@ public class FetchCommand extends GitCommand<FetchResult> {
                        try {
                                transport.setCheckFetchedObjects(checkFetchedObjects);
                                transport.setRemoveDeletedRefs(removeDeletedRefs);
-                               transport.setTimeout(timeout);
                                transport.setDryRun(dryRun);
                                if (tagOption != null)
                                        transport.setTagOpt(tagOption);
                                transport.setFetchThin(thin);
-                               if (credentialsProvider != null)
-                                       transport.setCredentialsProvider(credentialsProvider);
-                               if (transportConfigCallback != null)
-                                       transportConfigCallback.configure(transport);
+                               configure(transport);
 
                                FetchResult result = transport.fetch(monitor, refSpecs);
                                return result;
@@ -182,17 +171,6 @@ public class FetchCommand extends GitCommand<FetchResult> {
                return remote;
        }
 
-       /**
-        * @param timeout
-        *            the timeout used for the fetch operation
-        * @return {@code this}
-        */
-       public FetchCommand setTimeout(int timeout) {
-               checkCallable();
-               this.timeout = timeout;
-               return this;
-       }
-
        /**
         * @return the timeout used for the fetch operation
         */
@@ -334,18 +312,6 @@ public class FetchCommand extends GitCommand<FetchResult> {
                return this;
        }
 
-       /**
-        * @param credentialsProvider
-        *            the {@link CredentialsProvider} to use
-        * @return {@code this}
-        */
-       public FetchCommand setCredentialsProvider(
-                       CredentialsProvider credentialsProvider) {
-               checkCallable();
-               this.credentialsProvider = credentialsProvider;
-               return this;
-       }
-
        /**
         * Sets the specification of annotated tag behavior during fetch
         *
@@ -357,19 +323,4 @@ public class FetchCommand extends GitCommand<FetchResult> {
                this.tagOption = tagOpt;
                return this;
        }
-
-       /**
-        * @param transportConfigCallback
-        *            if set, the callback will be invoked after the Transport has
-        *            created, but before the Transport is used. The callback can
-        *            use this opportunity to set additional type-specific
-        *            configuration on the Transport instance.
-        * @return {@code this}
-        */
-       public FetchCommand setTransportConfigCallback(
-                       TransportConfigCallback transportConfigCallback) {
-               checkCallable();
-               this.transportConfigCallback = transportConfigCallback;
-               return this;
-       }
 }
index 093d6cc1b2774cef7003c6c51b7ce0a7ed81e79c..f158596143d4353e5df52af71ff69b1245b04952 100644 (file)
@@ -68,7 +68,8 @@ import org.eclipse.jgit.transport.Transport;
  *      href="http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
  *      >Git documentation about ls-remote</a>
  */
-public class LsRemoteCommand extends GitCommand<Collection<Ref>> {
+public class LsRemoteCommand extends
+               TransportCommand<LsRemoteCommand, Collection<Ref>> {
 
        private String remote = Constants.DEFAULT_REMOTE_NAME;
 
@@ -133,6 +134,7 @@ public class LsRemoteCommand extends GitCommand<Collection<Ref>> {
                try {
                        Transport transport = Transport.open(repo, remote);
                        transport.setOptionUploadPack(uploadPack);
+                       configure(transport);
 
                        try {
                                Collection<RefSpec> refSpecs = new ArrayList<RefSpec>(1);
index 3e42da5677449656851672931880cfd2708d554a..67f9832fb6dc40c6019ed0a4a658b6507847ede6 100644 (file)
@@ -70,7 +70,6 @@ import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryState;
-import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.FetchResult;
 
 /**
@@ -79,17 +78,12 @@ import org.eclipse.jgit.transport.FetchResult;
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-pull.html"
  *      >Git documentation about Pull</a>
  */
-public class PullCommand extends GitCommand<PullResult> {
-       private int timeout = 0;
+public class PullCommand extends TransportCommand<PullCommand, PullResult> {
 
        private final static String DOT = ".";
 
        private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
-       private CredentialsProvider credentialsProvider;
-
-       private TransportConfigCallback transportConfigCallback;
-
        /**
         * @param repo
         */
@@ -97,16 +91,6 @@ public class PullCommand extends GitCommand<PullResult> {
                super(repo);
        }
 
-       /**
-        * @param timeout
-        *            in seconds
-        * @return this instance
-        */
-       public PullCommand setTimeout(int timeout) {
-               this.timeout = timeout;
-               return this;
-       }
-
        /**
         * @param monitor
         *            a progress monitor
@@ -117,33 +101,6 @@ public class PullCommand extends GitCommand<PullResult> {
                return this;
        }
 
-       /**
-        * @param credentialsProvider
-        *            the {@link CredentialsProvider} to use
-        * @return this instance
-        */
-       public PullCommand setCredentialsProvider(
-                       CredentialsProvider credentialsProvider) {
-               checkCallable();
-               this.credentialsProvider = credentialsProvider;
-               return this;
-       }
-
-       /**
-        * @param transportConfigCallback
-        *            if set, the callback will be invoked after the Transport has
-        *            created, but before the Transport is used. The callback can
-        *            use this opportunity to set additional type-specific
-        *            configuration on the Transport instance.
-        * @return {@code this}
-        */
-       public PullCommand setTransportConfigCallback(
-                       TransportConfigCallback transportConfigCallback) {
-               checkCallable();
-               this.transportConfigCallback = transportConfigCallback;
-               return this;
-       }
-
        /**
         * Executes the {@code Pull} command with all the options and parameters
         * collected by the setter methods (e.g.
@@ -229,9 +186,7 @@ public class PullCommand extends GitCommand<PullResult> {
                        FetchCommand fetch = new FetchCommand(repo);
                        fetch.setRemote(remote);
                        fetch.setProgressMonitor(monitor);
-                       fetch.setTimeout(this.timeout);
-                       fetch.setCredentialsProvider(credentialsProvider);
-                       fetch.setTransportConfigCallback(transportConfigCallback);
+                       configure(fetch);
 
                        fetchRes = fetch.call();
                } else {
index a89e131bae2ffc614b3cef553022708f3f17af77..a7a0577158a5bc7308e775a191122440fd2a809e 100644 (file)
@@ -60,7 +60,6 @@ import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.PushResult;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.RemoteConfig;
@@ -75,7 +74,8 @@ import org.eclipse.jgit.transport.Transport;
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-push.html"
  *      >Git documentation about Push</a>
  */
-public class PushCommand extends GitCommand<Iterable<PushResult>> {
+public class PushCommand extends
+               TransportCommand<PushCommand, Iterable<PushResult>> {
 
        private String remote = Constants.DEFAULT_REMOTE_NAME;
 
@@ -91,12 +91,6 @@ public class PushCommand extends GitCommand<Iterable<PushResult>> {
 
        private boolean thin = Transport.DEFAULT_PUSH_THIN;
 
-       private int timeout;
-
-       private CredentialsProvider credentialsProvider;
-
-       private TransportConfigCallback transportConfigCallback;
-
        /**
         * @param repo
         */
@@ -145,16 +139,11 @@ public class PushCommand extends GitCommand<Iterable<PushResult>> {
                        final List<Transport> transports;
                        transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
                        for (final Transport transport : transports) {
-                               if (0 <= timeout)
-                                       transport.setTimeout(timeout);
                                transport.setPushThin(thin);
                                if (receivePack != null)
                                        transport.setOptionReceivePack(receivePack);
                                transport.setDryRun(dryRun);
-                               if (credentialsProvider != null)
-                                       transport.setCredentialsProvider(credentialsProvider);
-                               if (transportConfigCallback != null)
-                                       transportConfigCallback.configure(transport);
+                               configure(transport);
 
                                final Collection<RemoteRefUpdate> toPush = transport
                                                .findRemoteRefUpdatesFor(refSpecs);
@@ -233,17 +222,6 @@ public class PushCommand extends GitCommand<Iterable<PushResult>> {
                return receivePack;
        }
 
-       /**
-        * @param timeout
-        *            the timeout used for the push operation
-        * @return {@code this}
-        */
-       public PushCommand setTimeout(int timeout) {
-               checkCallable();
-               this.timeout = timeout;
-               return this;
-       }
-
        /**
         * @return the timeout used for the push operation
         */
@@ -423,31 +401,4 @@ public class PushCommand extends GitCommand<Iterable<PushResult>> {
                this.force = force;
                return this;
        }
-
-       /**
-        * @param credentialsProvider
-        *            the {@link CredentialsProvider} to use
-        * @return {@code this}
-        */
-       public PushCommand setCredentialsProvider(
-                       CredentialsProvider credentialsProvider) {
-               checkCallable();
-               this.credentialsProvider = credentialsProvider;
-               return this;
-       }
-
-       /**
-        * @param transportConfigCallback
-        *            if set, the callback will be invoked after the Transport has
-        *            created, but before the Transport is used. The callback can
-        *            use this opportunity to set additional type-specific
-        *            configuration on the Transport instance.
-        * @return {@code this}
-        */
-       public PushCommand setTransportConfigCallback(
-                       TransportConfigCallback transportConfigCallback) {
-               checkCallable();
-               this.transportConfigCallback = transportConfigCallback;
-               return this;
-       }
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
new file mode 100644 (file)
index 0000000..1aeb610
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011, GitHub Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.Transport;
+
+/**
+ * Base class for commands that use a {@link Transport} during execution.
+ * <p>
+ * This class provides standard configuration of a transport for options such as
+ * a {@link CredentialsProvider}, a timeout, and a
+ * {@link TransportConfigCallback}.
+ *
+ * @param <C>
+ * @param <T>
+ */
+public abstract class TransportCommand<C extends GitCommand, T> extends
+               GitCommand<T> {
+
+       /**
+        * Configured credentials provider
+        */
+       protected CredentialsProvider credentialsProvider;
+
+       /**
+        * Configured transport timeout
+        */
+       protected int timeout;
+
+       /**
+        * Configured callback for transport configuration
+        */
+       protected TransportConfigCallback transportConfigCallback;
+
+       /**
+        * @param repo
+        */
+       protected TransportCommand(final Repository repo) {
+               super(repo);
+       }
+
+       /**
+        * @param credentialsProvider
+        *            the {@link CredentialsProvider} to use
+        * @return {@code this}
+        */
+       public C setCredentialsProvider(
+                       final CredentialsProvider credentialsProvider) {
+               this.credentialsProvider = credentialsProvider;
+               return self();
+       }
+
+       /**
+        * @param timeout
+        *            the timeout used for the transport step
+        * @return {@code this}
+        */
+       public C setTimeout(int timeout) {
+               this.timeout = timeout;
+               return self();
+       }
+
+       /**
+        * @param transportConfigCallback
+        *            if set, the callback will be invoked after the
+        *            {@link Transport} has created, but before the
+        *            {@link Transport} is used. The callback can use this
+        *            opportunity to set additional type-specific configuration on
+        *            the {@link Transport} instance.
+        * @return {@code this}
+        */
+       public C setTransportConfigCallback(
+                       final TransportConfigCallback transportConfigCallback) {
+               this.transportConfigCallback = transportConfigCallback;
+               return self();
+       }
+
+       /** @return {@code this} */
+       @SuppressWarnings("unchecked")
+       protected final C self() {
+               return (C) this;
+       }
+
+       /**
+        * Configure transport with credentials provider, timeout, and config
+        * callback
+        *
+        * @param transport
+        * @return {@code this}
+        */
+       protected C configure(final Transport transport) {
+               if (credentialsProvider != null)
+                       transport.setCredentialsProvider(credentialsProvider);
+               transport.setTimeout(timeout);
+               if (transportConfigCallback != null)
+                       transportConfigCallback.configure(transport);
+               return self();
+       }
+
+       /**
+        * Configure a child command with the current configuration set in
+        * {@code this} command
+        *
+        * @param childCommand
+        * @return {@code this}
+        */
+       protected C configure(final TransportCommand childCommand) {
+               childCommand.setCredentialsProvider(credentialsProvider);
+               childCommand.setTimeout(timeout);
+               childCommand.setTransportConfigCallback(transportConfigCallback);
+               return self();
+       }
+}