diff --git .gitignore .gitignore
index 235c27b..2c05264 100644
--- .gitignore
+++ .gitignore
@@ -20,4 +20,6 @@
 .settings
 /tags
 /build.properties
+/conf/managers.d
+/conf/tools.d
 
diff --git build.xml build.xml
index 4bcce79..1827a6e 100644
--- build.xml
+++ build.xml
@@ -381,6 +381,7 @@
         <exclude name=".project" />
         <exclude name=".classpath" />
         <exclude name="conf/managers.d/**" />
+        <exclude name="conf/tools.d/**" />
       </fileset>
     </copy>
 
diff --git conf/sqoop-site-template.xml conf/sqoop-site-template.xml
index f84dcb2..5d5a358 100644
--- conf/sqoop-site-template.xml
+++ conf/sqoop-site-template.xml
@@ -45,6 +45,28 @@
   -->
 
   <!--
+    Set the value of this property to enable third-party tools.
+
+    If this is not used, you can alternately specify a set of ToolPlugins
+    in the $SQOOP_CONF_DIR/tools.d/ subdirectory.  Each file should contain
+    one or more lines like:
+      plugin.class.name[=/path/to/containing.jar]
+
+    Files will be consulted in lexicographical order only if this property
+    is unset.
+  -->
+  <!--
+  <property>
+    <name>sqoop.tool.plugins</name>
+    <value></value>
+    <description>A comma-delimited list of ToolPlugin implementations
+      which are consulted, in order, to register SqoopTool instances which
+      allow third-party tools to be used.
+    </description>
+  </property>
+  -->
+
+  <!--
     By default, the Sqoop metastore will auto-connect to a local embedded
     database stored in ~/.sqoop/. To disable metastore auto-connect, uncomment
     this next property.
diff --git src/java/com/cloudera/sqoop/ConnFactory.java src/java/com/cloudera/sqoop/ConnFactory.java
index b0aacfd..3eaa5a0 100644
--- src/java/com/cloudera/sqoop/ConnFactory.java
+++ src/java/com/cloudera/sqoop/ConnFactory.java
@@ -182,8 +182,10 @@ public class ConnFactory {
    * not set, then we look through the files in that directory; they should
    * contain lines of the form mgr.class.name[=/path/to/containing.jar].
    *
+   * <p>
    * Put all mgr.class.names into the Configuration, and load any specified
    * jars into the ClassLoader.
+   * </p>
    *
    * @param conf the current configuration to populate with class names.
    * @return conf again, after possibly populating sqoop.connection.factories.
diff --git src/java/com/cloudera/sqoop/Sqoop.java src/java/com/cloudera/sqoop/Sqoop.java
index 9076440..1a9b7c7 100644
--- src/java/com/cloudera/sqoop/Sqoop.java
+++ src/java/com/cloudera/sqoop/Sqoop.java
@@ -177,7 +177,7 @@ public class Sqoop extends Configured implements Tool {
   public static int runSqoop(Sqoop sqoop, String [] args) {
     try {
       String [] toolArgs = sqoop.stashChildPrgmArgs(args);
-      return ToolRunner.run(sqoop, toolArgs);
+      return ToolRunner.run(sqoop.getConf(), sqoop, toolArgs);
     } catch (Exception e) {
       LOG.error("Got exception running Sqoop: " + e.toString());
       e.printStackTrace();
@@ -206,6 +206,7 @@ public class Sqoop extends Configured implements Tool {
     }
 
     String toolName = expandedArgs[0];
+    Configuration pluginConf = SqoopTool.loadPlugins(new Configuration());
     SqoopTool tool = SqoopTool.getTool(toolName);
     if (null == tool) {
       System.err.println("No such sqoop tool: " + toolName
@@ -214,7 +215,7 @@ public class Sqoop extends Configured implements Tool {
     }
 
 
-    Sqoop sqoop = new Sqoop(tool);
+    Sqoop sqoop = new Sqoop(tool, pluginConf);
     return runSqoop(sqoop,
         Arrays.copyOfRange(expandedArgs, 1, expandedArgs.length));
   }
diff --git src/java/com/cloudera/sqoop/SqoopOptions.java src/java/com/cloudera/sqoop/SqoopOptions.java
index 4327757..851d825 100644
--- src/java/com/cloudera/sqoop/SqoopOptions.java
+++ src/java/com/cloudera/sqoop/SqoopOptions.java
@@ -32,6 +32,8 @@ import org.apache.hadoop.conf.Configuration;
 
 import com.cloudera.sqoop.lib.DelimiterSet;
 import com.cloudera.sqoop.lib.LargeObjectLoader;
+
+import com.cloudera.sqoop.tool.SqoopTool;
 import com.cloudera.sqoop.util.RandomHash;
 import com.cloudera.sqoop.util.StoredAsProperty;
 
@@ -240,6 +242,11 @@ public class SqoopOptions implements Cloneable {
   // the connection manager fully qualified class name
   @StoredAsProperty("connection.manager") private String connManagerClassName;
 
+  // The currently active tool. (Not saved in properties)
+  // Used to pass the SqoopTool instance in to mapreduce job configuration
+  // (JobBase, etc).
+  private SqoopTool activeSqoopTool;
+
   public SqoopOptions() {
     initDefaults(null);
   }
@@ -1649,6 +1656,15 @@ public class SqoopOptions implements Cloneable {
     return connManagerClassName;
   }
 
+  /** @return the SqoopTool that is operating this session. */
+  public SqoopTool getActiveSqoopTool() {
+    return activeSqoopTool;
+  }
+
+  public void setActiveSqoopTool(SqoopTool tool) {
+    activeSqoopTool = tool;
+  }
+
   public void setNullStringValue(String nullString) {
     this.nullStringValue = nullString;
   }
@@ -1665,21 +1681,20 @@ public class SqoopOptions implements Cloneable {
     return inNullStringValue;
   }
 
-public void setNullNonStringValue(String nullNonString) {
+  public void setNullNonStringValue(String nullNonString) {
     this.nullNonStringValue = nullNonString;
-}
+  }
 
-public String getNullNonStringValue() {
+  public String getNullNonStringValue() {
     return nullNonStringValue;
-}
+  }
 
-public void setInNullNonStringValue(String inNullNonString) {
+  public void setInNullNonStringValue(String inNullNonString) {
     this.inNullNonStringValue = inNullNonString;
-}
+  }
 
-public String getInNullNonStringValue() {
+  public String getInNullNonStringValue() {
     return inNullNonStringValue;
-}
-
+  }
 }
 
diff --git src/java/com/cloudera/sqoop/mapreduce/JobBase.java src/java/com/cloudera/sqoop/mapreduce/JobBase.java
index 0242bd0..27eb639 100644
--- src/java/com/cloudera/sqoop/mapreduce/JobBase.java
+++ src/java/com/cloudera/sqoop/mapreduce/JobBase.java
@@ -22,6 +22,7 @@ import java.io.File;
 import java.io.IOException;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
@@ -42,6 +43,8 @@ import com.cloudera.sqoop.SqoopOptions;
 
 import com.cloudera.sqoop.config.ConfigurationHelper;
 import com.cloudera.sqoop.manager.ConnManager;
+
+import com.cloudera.sqoop.tool.SqoopTool;
 import com.cloudera.sqoop.util.ClassLoaderStack;
 import com.cloudera.sqoop.util.Jars;
 
@@ -143,6 +146,18 @@ public class JobBase {
       addToCache(Jars.getJarPathForClass(mgr.getClass()), fs, localUrls);
     }
 
+    SqoopTool tool = this.options.getActiveSqoopTool();
+    if (null != tool) {
+      // Make sure the jar for the tool itself is on the classpath. (In case
+      // this is a third-party plugin tool.)
+      addToCache(Jars.getJarPathForClass(tool.getClass()), fs, localUrls);
+      List<String> toolDeps = tool.getDependencyJars();
+      if (null != toolDeps) {
+        for (String depFile : toolDeps) {
+          addToCache(depFile, fs, localUrls);
+        }
+      }
+    }
 
     // If the user specified a particular jar file name,
 
diff --git src/java/com/cloudera/sqoop/tool/BaseSqoopTool.java src/java/com/cloudera/sqoop/tool/BaseSqoopTool.java
index 81d90a2..8b72a5b 100644
--- src/java/com/cloudera/sqoop/tool/BaseSqoopTool.java
+++ src/java/com/cloudera/sqoop/tool/BaseSqoopTool.java
@@ -165,7 +165,7 @@ public abstract class BaseSqoopTool extends SqoopTool {
     return manager;
   }
 
-  protected void setManager(ConnManager mgr) {
+  public void setManager(ConnManager mgr) {
     this.manager = mgr;
   }
 
diff --git src/java/com/cloudera/sqoop/tool/SqoopTool.java src/java/com/cloudera/sqoop/tool/SqoopTool.java
index d845278..10a0c71 100644
--- src/java/com/cloudera/sqoop/tool/SqoopTool.java
+++ src/java/com/cloudera/sqoop/tool/SqoopTool.java
@@ -18,8 +18,16 @@
 
 package com.cloudera.sqoop.tool;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.TreeMap;
 
@@ -38,6 +46,8 @@ import com.cloudera.sqoop.cli.SqoopParser;
 import com.cloudera.sqoop.cli.ToolOptions;
 import com.cloudera.sqoop.config.ConfigurationHelper;
 
+import com.cloudera.sqoop.util.ClassLoaderStack;
+
 /**
  * Base class for Sqoop subprograms (e.g., SqoopImport, SqoopExport, etc.)
  * Allows subprograms to configure the arguments they accept and
@@ -47,6 +57,12 @@ public abstract class SqoopTool {
 
   public static final Log LOG = LogFactory.getLog(SqoopTool.class.getName());
 
+  /**
+   * Configuration key that specifies the set of ToolPlugin instances to load
+   * before determining which SqoopTool instance to load.
+   */
+  public static final String TOOL_PLUGINS_KEY = "sqoop.tool.plugins";
+
   private static final Map<String, Class<? extends SqoopTool>> TOOLS;
   private static final Map<String, String> DESCRIPTIONS;
 
@@ -96,6 +112,145 @@ public abstract class SqoopTool {
   }
 
   /**
+   * Add tool to available set of SqoopTool instances using the ToolDesc
+   * struct as the sole argument.
+   */
+  private static void registerTool(ToolDesc toolDescription) {
+    registerTool(toolDescription.getName(), toolDescription.getToolClass(),
+        toolDescription.getDesc());
+  }
+
+  /**
+   * Load plugins referenced in sqoop-site.xml or other config (e.g., tools.d/),
+   * to allow external tool definitions.
+   *
+   * @return the Configuration used to load the plugins.
+   */
+  public static Configuration loadPlugins(Configuration conf) {
+    conf = loadPluginsFromConfDir(conf);
+    List<ToolPlugin> plugins = conf.getInstances(TOOL_PLUGINS_KEY,
+        ToolPlugin.class);
+    for (ToolPlugin plugin : plugins) {
+      LOG.debug("Loading plugin: " + plugin.getClass().getName());
+      List<ToolDesc> descriptions = plugin.getTools();
+      for (ToolDesc desc : descriptions) {
+        LOG.debug("  Adding tool: " + desc.getName()
+            + " -> " + desc.getToolClass().getName());
+        registerTool(desc);
+      }
+    }
+
+    return conf;
+  }
+
+  /**
+   * If $SQOOP_CONF_DIR/tools.d/ exists and sqoop.tool.plugins is not set,
+   * then we look through the files in that directory; they should contain
+   * lines of the form 'plugin.class.name[=/path/to/containing.jar]'.
+   *
+   * <p>Put all plugin.class.names into the Configuration, and load any
+   * specified jars into the ClassLoader.
+   * </p>
+   *
+   * @param conf the current configuration to populate with class names.
+   * @return conf again, after possibly populating sqoop.tool.plugins.
+   */
+  private static Configuration loadPluginsFromConfDir(Configuration conf) {
+    if (conf.get(TOOL_PLUGINS_KEY) != null) {
+      LOG.debug(TOOL_PLUGINS_KEY + " is set; ignoring tools.d");
+      return conf;
+    }
+
+    String confDirName = System.getenv("SQOOP_CONF_DIR");
+    if (null == confDirName) {
+      LOG.warn("$SQOOP_CONF_DIR has not been set in the environment. "
+          + "Cannot check for additional configuration.");  
+      return conf;
+    }
+
+    File confDir = new File(confDirName);
+    File toolsDir = new File(confDir, "tools.d");
+
+    if (toolsDir.exists() && toolsDir.isDirectory()) {
+      // We have a tools.d subdirectory. Get the file list, sort it,
+      // and process them in order.
+      String [] fileNames = toolsDir.list();
+      Arrays.sort(fileNames);
+
+      for (String fileName : fileNames) {
+        File f = new File(toolsDir, fileName);
+        if (f.isFile()) {
+          loadPluginsFromFile(conf, f);
+        }
+      }
+    }
+
+    // Set the classloader in this configuration so that it will use
+    // the jars we just loaded in.
+    conf.setClassLoader(Thread.currentThread().getContextClassLoader());
+    return conf;
+  }
+
+  /**
+   * Read the specified file and extract any ToolPlugin implementation
+   * names from there.
+   * @param conf the configuration to populate.
+   * @param f the file containing the configuration data to add.
+   */
+  private static void loadPluginsFromFile(Configuration conf, File f) {
+    Reader r = null;
+    try {
+      // The file format is actually Java properties-file syntax.
+      r = new InputStreamReader(new FileInputStream(f));
+      Properties props = new Properties();
+      props.load(r);
+
+      for (Map.Entry<Object, Object> entry : props.entrySet()) {
+        // Each key is a ToolPlugin class name.
+        // Each value, if set, is the jar that contains it.
+        String plugin = entry.getKey().toString();
+        addPlugin(conf, plugin);
+
+        String jarName = entry.getValue().toString();
+        if (jarName.length() > 0) {
+          ClassLoaderStack.addJarFile(jarName, plugin);
+          LOG.debug("Added plugin " + plugin + " in jar " + jarName
+              + " specified by " + f);
+        } else if (LOG.isDebugEnabled()) {
+          LOG.debug("Added plugin " + plugin + " specified by " + f);
+        }
+      }
+    } catch (IOException ioe) {
+      LOG.error("Error loading ToolPlugin information from file "
+          + f + ": " + StringUtils.stringifyException(ioe));
+    } finally {
+      if (null != r) {
+        try {
+          r.close();
+        } catch (IOException ioe) {
+          LOG.warn("Error closing file " + f + ": " + ioe);
+        }
+      }
+    }
+  }
+
+  /**
+   * Add the specified plugin class name to the configuration string
+   * listing plugin classes.
+   */
+  private static void addPlugin(Configuration conf, String pluginName) {
+    String existingPlugins = conf.get(TOOL_PLUGINS_KEY);
+    String newPlugins = null;
+    if (null == existingPlugins || existingPlugins.length() == 0) {
+      newPlugins = pluginName;
+    } else {
+      newPlugins = existingPlugins + "," + pluginName;
+    }
+
+    conf.set(TOOL_PLUGINS_KEY, newPlugins);
+  }
+
+  /**
    * @return the list of available tools.
    */
   public static final Set<String> getToolNames() {
@@ -243,6 +398,9 @@ public abstract class SqoopTool {
       out.setConf(new Configuration());
     }
 
+    // This tool is the "active" tool; bind it in the SqoopOptions.
+    out.setActiveSqoopTool(this);
+
     String [] toolArgs = args; // args after generic parser is done.
     if (useGenericOptions) {
       try {
@@ -286,6 +444,51 @@ public abstract class SqoopTool {
     this.extraArguments = newExtra;
   }
 
+  /**
+   * Allow a tool to specify a set of dependency jar filenames. This is used
+   * to allow tools to bundle arbitrary dependency jars necessary for a
+   * MapReduce job executed by Sqoop. The jar containing the SqoopTool
+   * instance itself will already be handled by Sqoop.
+   *
+   * <p>Called by JobBase.cacheJars().</p>
+   *
+   * <p>
+   * This does not load the jars into the current VM; they are assumed to be
+   * already on the classpath if they are needed on the client side (or
+   * otherwise classloaded by the tool itself). This is purely to specify jars
+   * necessary to be added to the distributed cache. The tool itself can
+   * classload these jars by running loadDependencyJars().
+   * </p>
+   *
+   * <p>See also: c.c.s.util.Jars.getJarPathForClass()</p>
+   */
+  public List<String> getDependencyJars() {
+    // Default behavior: no additional dependencies.
+    return Collections.emptyList();
+  }
+
+  /**
+   * Loads dependency jars specified by getDependencyJars() into the current
+   * classloader stack. May optionally be called by a [third-party] tool
+   * before doing work, to ensure that all of its dependencies get classloaded
+   * properly. Note that dependencies will not be available until after the
+   * tool is already constructed.
+   */
+  protected void loadDependencyJars(SqoopOptions options) throws IOException {
+    List<String> deps = getDependencyJars();
+    if (null == deps) {
+      return;
+    }
+
+    for (String depFilename : deps) {
+      LOG.debug("Loading dependency: " + depFilename);
+      ClassLoaderStack.addJarFile(depFilename, null);
+    }
+
+    options.getConf().setClassLoader(
+        Thread.currentThread().getContextClassLoader());
+  }
+
   @Override
   public String toString() {
     return getToolName();
diff --git src/java/com/cloudera/sqoop/tool/ToolDesc.java src/java/com/cloudera/sqoop/tool/ToolDesc.java
new file mode 100644
index 0000000..dc56cce
--- /dev/null
+++ src/java/com/cloudera/sqoop/tool/ToolDesc.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to Cloudera, Inc. under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  Cloudera, Inc. 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 com.cloudera.sqoop.tool;
+
+/**
+ * Describes a SqoopTool.
+ */
+public final class ToolDesc {
+  private final String toolName;
+  private final Class<? extends SqoopTool> toolClass;
+  private final String description;
+
+
+  /**
+   * Main c'tor; sets all fields that describe a SqoopTool. 
+   */
+  public ToolDesc(String name, Class<? extends SqoopTool> cls, String desc) {
+    this.toolName = name;
+    this.toolClass = cls;
+    this.description = desc;
+  }
+
+  /**
+   * @return the name used to invoke the tool (e.g., 'sqoop &lt;foo&gt;')
+   */
+  public String getName() {
+    return toolName;
+  }
+
+  /**
+   * @return a human-readable description of what the tool does.
+   */
+  public String getDesc() {
+    return description;
+  }
+
+  /**
+   * @return the class that implements SqoopTool.
+   */
+  public Class<? extends SqoopTool> getToolClass() {
+    return toolClass;
+  }
+
+}
diff --git src/java/com/cloudera/sqoop/tool/ToolPlugin.java src/java/com/cloudera/sqoop/tool/ToolPlugin.java
new file mode 100644
index 0000000..4100401
--- /dev/null
+++ src/java/com/cloudera/sqoop/tool/ToolPlugin.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to Cloudera, Inc. under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  Cloudera, Inc. 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 com.cloudera.sqoop.tool;
+
+import java.util.List;
+
+/**
+ * Abstract base class that defines the ToolPlugin API; additional SqoopTool
+ * implementations may be registered with the system via ToolPlugin classes.
+ */
+public abstract class ToolPlugin {
+  /**
+   * Describes the tools made available by this plugin.
+   * @return a list of ToolDesc objects containing the tool name, class,
+   * and description.
+   */
+  public abstract List<ToolDesc> getTools();
+}
diff --git src/test/com/cloudera/sqoop/SmokeTests.java src/test/com/cloudera/sqoop/SmokeTests.java
index 60c9bd9..6a7fdb8 100644
--- src/test/com/cloudera/sqoop/SmokeTests.java
+++ src/test/com/cloudera/sqoop/SmokeTests.java
@@ -36,6 +36,8 @@ import com.cloudera.sqoop.metastore.TestSavedJobs;
 import com.cloudera.sqoop.orm.TestClassWriter;
 import com.cloudera.sqoop.orm.TestParseMethods;
 
+import com.cloudera.sqoop.tool.TestToolPlugin;
+
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
@@ -79,6 +81,7 @@ public final class SmokeTests {
     suite.addTestSuite(TestNamedFifo.class);
     suite.addTestSuite(TestBooleanParser.class);
     suite.addTestSuite(TestMerge.class);
+    suite.addTestSuite(TestToolPlugin.class);
     suite.addTest(MapreduceTests.suite());
 
     return suite;
diff --git src/test/com/cloudera/sqoop/tool/TestToolPlugin.java src/test/com/cloudera/sqoop/tool/TestToolPlugin.java
new file mode 100644
index 0000000..02ea16d
--- /dev/null
+++ src/test/com/cloudera/sqoop/tool/TestToolPlugin.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to Cloudera, Inc. under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  Cloudera, Inc. 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 com.cloudera.sqoop.tool;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+
+import org.apache.hadoop.conf.Configuration;
+
+import com.cloudera.sqoop.Sqoop;
+import com.cloudera.sqoop.SqoopOptions;
+
+import com.cloudera.sqoop.SqoopOptions.InvalidOptionsException;
+
+import com.cloudera.sqoop.cli.ToolOptions;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import junit.framework.TestCase;
+
+/**
+ * Test that tool plugins work.
+ */
+public class TestToolPlugin extends TestCase {
+
+  public static final Log LOG = LogFactory
+      .getLog(TestToolPlugin.class.getName());
+
+  /**
+   * The plugin that registers the tool.
+   */
+  public static class PluginClass extends ToolPlugin {
+    public List<ToolDesc> getTools() {
+      return Collections.singletonList(new ToolDesc("fooTool",
+          FooTool.class, "does foo things"));
+    }
+  }
+
+  /**
+   * The dummy tool itself.
+   */
+  public static class FooTool extends BaseSqoopTool {
+    /** Holds the name of the last user we "operated" as.  */
+    private static String lastUser; 
+    static String getLastUser() {
+      return lastUser;
+    }
+
+    private static void setLastUser(String last) {
+      lastUser = last;
+    }
+
+    public FooTool() {
+      super("fooTool");
+    }
+
+    /** Just save the username and call it a day. */
+    @Override
+    public int run(SqoopOptions opts) {
+      setLastUser(opts.getUsername());
+      LOG.info("FooTool operating on user: " + lastUser);
+      return 0;
+    }
+
+    @Override
+    public void configureOptions(ToolOptions toolOptions) {
+      toolOptions.addUniqueOptions(getCommonOptions());
+    }
+
+    @Override
+    public void applyOptions(CommandLine in, SqoopOptions out) 
+        throws InvalidOptionsException {
+      applyCommonOptions(in, out);
+    }
+
+    @Override
+    public void validateOptions(SqoopOptions options)
+        throws InvalidOptionsException {
+      validateCommonOptions(options);
+    }
+  }
+  
+  public void testPlugin() {
+    // Register the plugin with SqoopTool.
+    Configuration pluginConf = new Configuration();
+    pluginConf.set(SqoopTool.TOOL_PLUGINS_KEY, PluginClass.class.getName());
+    SqoopTool.loadPlugins(pluginConf);
+
+    ArrayList<String> args = new ArrayList<String>();
+    args.add("fooTool");
+    args.add("--username");
+    args.add("bob");
+    args.add("--connect");
+    args.add("anywhere");
+
+    int ret = Sqoop.runTool(args.toArray(new String[0]));
+    assertEquals("Expected tool run success", 0, ret);
+
+    String actualUser = FooTool.getLastUser();
+    assertEquals("Failed to set username correctly.", "bob", actualUser);
+  }
+}
