You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sqoop.apache.org by hs...@apache.org on 2013/08/07 01:22:00 UTC

[2/6] SQOOP-921. Sqoop2: Create standalone shell package

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StartCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StartCommand.java b/shell/src/main/java/org/apache/sqoop/shell/StartCommand.java
new file mode 100644
index 0000000..f03e08f
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StartCommand.java
@@ -0,0 +1,58 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.apache.sqoop.shell.core.Constants;
+import org.codehaus.groovy.tools.shell.Shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.printlnResource;
+
+public class StartCommand extends SqoopCommand {
+  public static final Logger LOG = Logger.getLogger(StartCommand.class);
+
+  private StartJobFunction startJobFunction;
+
+  @SuppressWarnings("static-access")
+  protected StartCommand(Shell shell) {
+    super(shell, Constants.CMD_START, Constants.CMD_START_SC,
+        new String[] {Constants.FN_JOB}, Constants.PRE_START, null);
+  }
+
+  @Override
+  public Object executeCommand(List args) {
+    if (args.size() == 0) {
+      printlnResource(Constants.RES_START_USAGE, getUsage());
+      return null;
+    }
+
+    String func = (String) args.get(0);
+    if (func.equals(Constants.FN_JOB)) {
+      if (startJobFunction == null) {
+        startJobFunction = new StartJobFunction();
+      }
+      return startJobFunction.execute(args);
+    } else {
+      printlnResource(Constants.RES_FUNCTION_UNKNOWN, func);
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StartJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StartJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/StartJobFunction.java
new file mode 100644
index 0000000..02148de
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StartJobFunction.java
@@ -0,0 +1,89 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.client;
+import static org.apache.sqoop.shell.ShellEnvironment.getPollTimeout;
+import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.log4j.Logger;
+import org.apache.sqoop.client.SubmissionCallback;
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.shell.core.ShellError;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.shell.utils.SubmissionDisplayer;
+
+public class StartJobFunction extends SqoopFunction {
+  public static final Logger LOG = Logger.getLogger(StartJobFunction.class);
+
+  @SuppressWarnings("static-access")
+  public StartJobFunction() {
+    this.addOption(OptionBuilder.hasArg().withArgName(Constants.OPT_JID)
+       .withDescription(resourceString(Constants.RES_PROMPT_JOB_ID))
+       .withLongOpt(Constants.OPT_JID)
+       .create(Constants.OPT_JID_CHAR));
+    this.addOption(OptionBuilder
+       .withDescription(resourceString(Constants.RES_PROMPT_SYNCHRONOUS))
+       .withLongOpt(Constants.OPT_SYNCHRONOUS)
+       .create(Constants.OPT_SYNCHRONOUS_CHAR));
+  }
+
+  @Override
+  public Object executeFunction(CommandLine line) {
+    // Poll until finished
+    if (line.hasOption(Constants.OPT_SYNCHRONOUS) && line.hasOption(Constants.OPT_JID)) {
+      long pollTimeout = getPollTimeout();
+      SubmissionCallback callback = new SubmissionCallback() {
+        @Override
+        public void submitted(MSubmission submission) {
+          SubmissionDisplayer.displayHeader(submission);
+          SubmissionDisplayer.displayProgress(submission);
+        }
+
+        @Override
+        public void updated(MSubmission submission) {
+          SubmissionDisplayer.displayProgress(submission);
+        }
+
+        @Override
+        public void finished(MSubmission submission) {
+          SubmissionDisplayer.displayFooter(submission);
+        }
+      };
+
+      try {
+        client.startSubmission(getLong(line, Constants.OPT_JID), callback, pollTimeout);
+      } catch (InterruptedException e) {
+        throw new SqoopException(ShellError.SHELL_0008, e);
+      }
+    } else if (line.hasOption(Constants.OPT_JID)) {
+      MSubmission submission = client.startSubmission(getLong(line, Constants.OPT_JID));
+      if(submission.getStatus().isFailure()) {
+        SubmissionDisplayer.displayFooter(submission);
+      } else {
+        SubmissionDisplayer.displayHeader(submission);
+        SubmissionDisplayer.displayProgress(submission);
+      }
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StatusCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StatusCommand.java b/shell/src/main/java/org/apache/sqoop/shell/StatusCommand.java
new file mode 100644
index 0000000..184892a
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StatusCommand.java
@@ -0,0 +1,56 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import java.util.List;
+
+import org.apache.sqoop.shell.core.Constants;
+import org.codehaus.groovy.tools.shell.Shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.printlnResource;
+
+public class StatusCommand extends SqoopCommand {
+
+  private StatusJobFunction statusJobFunction;
+
+  @SuppressWarnings("static-access")
+  protected StatusCommand(Shell shell) {
+    super(shell, Constants.CMD_STATUS, Constants.CMD_STATUS_SC,
+        new String[] { Constants.FN_JOB }, Constants.PRE_STATUS, null);
+  }
+
+  @Override
+  public Object executeCommand(List args) {
+    if (args.size() == 0) {
+      printlnResource(Constants.RES_STATUS_USAGE, getUsage());
+      return null;
+    }
+
+    String func = (String) args.get(0);
+    if (func.equals(Constants.FN_JOB)) {
+      if (statusJobFunction == null) {
+        statusJobFunction = new StatusJobFunction();
+      }
+      return statusJobFunction.execute(args);
+    } else {
+      printlnResource(Constants.RES_FUNCTION_UNKNOWN, func);
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StatusJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StatusJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/StatusJobFunction.java
new file mode 100644
index 0000000..be0de8c
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StatusJobFunction.java
@@ -0,0 +1,55 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.client;
+import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.shell.utils.SubmissionDisplayer;
+import org.apache.sqoop.submission.SubmissionStatus;
+
+public class StatusJobFunction extends SqoopFunction{
+
+  @SuppressWarnings("static-access")
+  public StatusJobFunction() {
+    this.addOption(OptionBuilder.hasArg().withArgName(Constants.OPT_JID)
+       .withDescription(resourceString(Constants.RES_PROMPT_JOB_ID))
+       .withLongOpt(Constants.OPT_JID)
+       .create(Constants.OPT_JID_CHAR));
+  }
+
+  @Override
+  public Object executeFunction(CommandLine line) {
+    if (line.hasOption(Constants.OPT_JID)) {
+      MSubmission submission = client.getSubmissionStatus(getLong(line, Constants.OPT_JID));
+      if(submission.getStatus().isFailure() || submission.getStatus().equals(SubmissionStatus.SUCCEEDED)) {
+        SubmissionDisplayer.displayHeader(submission);
+        SubmissionDisplayer.displayFooter(submission);
+      } else {
+        SubmissionDisplayer.displayHeader(submission);
+        SubmissionDisplayer.displayProgress(submission);
+      }
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StopCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StopCommand.java b/shell/src/main/java/org/apache/sqoop/shell/StopCommand.java
new file mode 100644
index 0000000..698bca7
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StopCommand.java
@@ -0,0 +1,54 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import java.util.List;
+
+import org.apache.sqoop.shell.core.Constants;
+import org.codehaus.groovy.tools.shell.Shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.printlnResource;
+
+public class StopCommand extends SqoopCommand {
+
+  private StopJobFunction stopJobFunction;
+
+  @SuppressWarnings("static-access")
+  protected StopCommand(Shell shell) {
+    super(shell, Constants.CMD_STOP, Constants.CMD_STOP_SC,
+        new String[] { Constants.FN_JOB }, Constants.PRE_STOP, null);
+  }
+  @Override
+  public Object executeCommand(List args) {
+    if (args.size() == 0) {
+      printlnResource(Constants.RES_STOP_USAGE, getUsage());
+      return null;
+    }
+
+    String func = (String) args.get(0);
+    if (func.equals(Constants.FN_JOB)) {
+      if (stopJobFunction == null) {
+        stopJobFunction = new StopJobFunction();
+      }
+      return stopJobFunction.execute(args);
+    } else {
+      printlnResource(Constants.RES_FUNCTION_UNKNOWN, func);
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/StopJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/StopJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/StopJobFunction.java
new file mode 100644
index 0000000..6c0e3c2
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/StopJobFunction.java
@@ -0,0 +1,53 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import static org.apache.sqoop.shell.ShellEnvironment.client;
+import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.shell.utils.SubmissionDisplayer;
+
+public class StopJobFunction extends SqoopFunction {
+
+  @SuppressWarnings("static-access")
+  public StopJobFunction() {
+    this.addOption(OptionBuilder.hasArg().withArgName(Constants.OPT_JID)
+       .withDescription(resourceString(Constants.RES_PROMPT_JOB_ID))
+       .withLongOpt(Constants.OPT_JID)
+       .create(Constants.OPT_JID_CHAR));
+  }
+
+  @Override
+  public Object executeFunction(CommandLine line) {
+    if (line.hasOption(Constants.OPT_JID)) {
+      MSubmission submission = client.stopSubmission(getLong(line, Constants.OPT_JID));
+      if(submission.getStatus().isFailure()) {
+        SubmissionDisplayer.displayFooter(submission);
+      } else {
+        SubmissionDisplayer.displayHeader(submission);
+        SubmissionDisplayer.displayProgress(submission);
+      }
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/UpdateCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateCommand.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateCommand.java
new file mode 100644
index 0000000..9262ccd
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateCommand.java
@@ -0,0 +1,69 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.shell.core.ShellError;
+import org.apache.sqoop.shell.core.Constants;
+import org.codehaus.groovy.tools.shell.Shell;
+
+import java.util.List;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+
+/**
+ *
+ */
+public class UpdateCommand extends SqoopCommand {
+
+  private UpdateConnectionFunction connectionFunction;
+  private UpdateJobFunction jobFunction;
+
+  public UpdateCommand(Shell shell) {
+    super(shell, Constants.CMD_UPDATE, Constants.CMD_UPDATE_SC,
+      new String[] {Constants.FN_CONNECTION, Constants.FN_JOB},
+      Constants.PRE_UPDATE, Constants.SUF_INFO);
+  }
+
+  public Object executeCommand(List args) {
+    if(!isInteractive()) {
+      throw new SqoopException(ShellError.SHELL_0007, "update");
+    }
+
+    if (args.size() == 0) {
+      printlnResource(Constants.RES_UPDATE_USAGE, getUsage());
+      return null;
+    }
+
+    String func = (String)args.get(0);
+    if (func.equals(Constants.FN_CONNECTION)) {
+      if (connectionFunction == null) {
+        connectionFunction = new UpdateConnectionFunction();
+      }
+      return connectionFunction.execute(args);
+    } else if (func.equals(Constants.FN_JOB)) {
+      if (jobFunction == null) {
+        jobFunction = new UpdateJobFunction();
+      }
+      return jobFunction.execute(args);
+    } else {
+      printlnResource(Constants.RES_FUNCTION_UNKNOWN, func);
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/UpdateConnectionFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateConnectionFunction.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateConnectionFunction.java
new file mode 100644
index 0000000..c062fe6
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateConnectionFunction.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.apache.sqoop.shell;
+
+import jline.ConsoleReader;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.MConnection;
+import org.apache.sqoop.shell.core.ShellError;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.shell.utils.FormDisplayer;
+import org.apache.sqoop.validation.Status;
+
+import java.io.IOException;
+import java.util.ResourceBundle;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+import static org.apache.sqoop.shell.utils.FormFiller.*;
+
+/**
+ *
+ */
+public class UpdateConnectionFunction extends SqoopFunction {
+  @SuppressWarnings("static-access")
+  public UpdateConnectionFunction() {
+    this.addOption(OptionBuilder
+      .withDescription(resourceString(Constants.RES_PROMPT_CONN_ID))
+      .withLongOpt(Constants.OPT_XID)
+      .hasArg()
+      .create(Constants.OPT_XID_CHAR));
+  }
+
+  public Object executeFunction(CommandLine line) {
+    if (!line.hasOption(Constants.OPT_XID)) {
+      printlnResource(Constants.RES_ARGS_XID_MISSING);
+      return null;
+    }
+
+    try {
+      updateConnection(getLong(line, Constants.OPT_XID));
+    } catch (IOException ex) {
+      throw new SqoopException(ShellError.SHELL_0005, ex);
+    }
+
+    return null;
+  }
+
+  private void updateConnection(Long connectionId) throws IOException {
+    printlnResource(Constants.RES_UPDATE_UPDATING_CONN, connectionId);
+
+    ConsoleReader reader = new ConsoleReader();
+
+    MConnection connection = client.getConnection(connectionId);
+
+    ResourceBundle connectorBundle = client.getResourceBundle(connection.getConnectorId());
+    ResourceBundle frameworkBundle = client.getFrameworkResourceBundle();
+
+    Status status = Status.FINE;
+
+    printlnResource(Constants.RES_PROMPT_UPDATE_CONN_METADATA);
+
+    do {
+      // Print error introduction if needed
+      if( !status.canProceed() ) {
+        errorIntroduction();
+      }
+
+      // Fill in data from user
+      if(!fillConnection(reader, connection, connectorBundle, frameworkBundle)) {
+        return;
+      }
+
+      // Try to create
+      status = client.updateConnection(connection);
+    } while(!status.canProceed());
+    FormDisplayer.displayFormWarning(connection);
+    printlnResource(Constants.RES_UPDATE_CONN_SUCCESSFUL, status.name());
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
new file mode 100644
index 0000000..da1e0c5
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
@@ -0,0 +1,95 @@
+/**
+ * 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.apache.sqoop.shell;
+
+import jline.ConsoleReader;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.shell.core.ShellError;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.shell.utils.FormDisplayer;
+import org.apache.sqoop.validation.Status;
+
+import java.io.IOException;
+import java.util.ResourceBundle;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+import static org.apache.sqoop.shell.utils.FormFiller.*;
+
+/**
+ *
+ */
+public class UpdateJobFunction extends SqoopFunction {
+  @SuppressWarnings("static-access")
+  public UpdateJobFunction() {
+    this.addOption(OptionBuilder
+      .withDescription(resourceString(Constants.RES_PROMPT_JOB_ID))
+      .withLongOpt(Constants.OPT_JID)
+      .hasArg()
+      .create(Constants.OPT_JID_CHAR));
+  }
+
+  public Object executeFunction(CommandLine line) {
+    if (!line.hasOption(Constants.OPT_JID)) {
+      printlnResource(Constants.RES_ARGS_JID_MISSING);
+      return null;
+    }
+
+    try {
+      updateJob(getLong(line, Constants.OPT_JID));
+    } catch (IOException ex) {
+      throw new SqoopException(ShellError.SHELL_0005, ex);
+    }
+
+    return null;
+  }
+
+  private void updateJob(Long jobId) throws IOException {
+    printlnResource(Constants.RES_UPDATE_UPDATING_JOB, jobId);
+
+    ConsoleReader reader = new ConsoleReader();
+
+    MJob job = client.getJob(jobId);
+
+    ResourceBundle connectorBundle = client.getResourceBundle(job.getConnectorId());
+    ResourceBundle frameworkBundle = client.getFrameworkResourceBundle();
+
+    Status status = Status.FINE;
+
+    printlnResource(Constants.RES_PROMPT_UPDATE_JOB_METADATA);
+
+    do {
+      // Print error introduction if needed
+      if( !status.canProceed() ) {
+        errorIntroduction();
+      }
+
+      // Fill in data from user
+      if(!fillJob(reader, job, connectorBundle, frameworkBundle)) {
+        return;
+      }
+
+      // Try to create
+      status = client.updateJob(job);
+    } while(!status.canProceed());
+    FormDisplayer.displayFormWarning(job);
+    printlnResource(Constants.RES_UPDATE_JOB_SUCCESSFUL, status.name());
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/core/Constants.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/core/Constants.java b/shell/src/main/java/org/apache/sqoop/shell/core/Constants.java
new file mode 100644
index 0000000..0e33d42
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/core/Constants.java
@@ -0,0 +1,451 @@
+/**
+ * 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.apache.sqoop.shell.core;
+
+/**
+ *
+ */
+public class Constants {
+
+  // General string constants
+  public static final String RESOURCE_NAME = "shell-resource";
+  public static final String BOLD_STR_SEQUENCE = "@|bold";
+  public static final String END_STR_SEQUENCE = "|@";
+
+  // Environmental variables
+  public static final String ENV_HOST = "SQOOP2_HOST";
+  public static final String ENV_PORT = "SQOOP2_PORT";
+  public static final String ENV_WEBAPP = "SQOOP2_WEBAPP";
+
+  // Options
+
+  public static final String OPT_XID = "xid";
+  public static final String OPT_ALL = "all";
+  public static final String OPT_JID = "jid";
+  public static final String OPT_CID = "cid";
+  public static final String OPT_TYPE = "type";
+  public static final String OPT_NAME = "name";
+  public static final String OPT_VALUE = "value";
+  public static final String OPT_VERBOSE = "verbose";
+  public static final String OPT_HOST = "host";
+  public static final String OPT_PORT = "port";
+  public static final String OPT_WEBAPP = "webapp";
+  public static final String OPT_URL = "url";
+  public static final String OPT_SERVER = "server";
+  public static final String OPT_CLIENT = "client";
+  public static final String OPT_PROTOCOL = "protocol";
+  public static final String OPT_SYNCHRONOUS = "synchronous";
+  public static final String OPT_POLL_TIMEOUT = "poll-timeout";
+  public static final String OPT_DETAIL = "detail";
+
+  public static final char OPT_XID_CHAR = 'x';
+  public static final char OPT_ALL_CHAR = 'a';
+  public static final char OPT_JID_CHAR = 'j';
+  public static final char OPT_CID_CHAR = 'c';
+  public static final char OPT_TYPE_CHAR = 't';
+  public static final char OPT_NAME_CHAR = 'n';
+  public static final char OPT_VALUE_CHAR = 'v';
+  public static final char OPT_HOST_CHAR = 'h';
+  public static final char OPT_PORT_CHAR = 'p';
+  public static final char OPT_WEBAPP_CHAR = 'w';
+  public static final char OPT_URL_CHAR = 'u';
+  public static final char OPT_SERVER_CHAR = 's';
+  public static final char OPT_CLIENT_CHAR = 'c';
+  public static final char OPT_PROTOCOL_CHAR = 'p';
+  public static final char OPT_SYNCHRONOUS_CHAR = 's';
+  public static final char OPT_POLL_TIMEOUT_CHAR = 'p';
+  public static final char OPT_DETAIL_CHAR = 'd';
+
+  // Resource keys for various commands, command options,
+  // functions and descriptions
+  public static final String CMD_CLONE = "clone";
+  public static final String CMD_CLONE_SC = "\\cl";
+
+  public static final String CMD_CREATE = "create";
+  public static final String CMD_CREATE_SC = "\\cr";
+
+  public static final String CMD_DELETE = "delete";
+  public static final String CMD_DELETE_SC = "\\d";
+
+  public static final String CMD_HELP = "help";
+  public static final String CMD_HELP_SC = "\\h";
+
+  public static final String CMD_SET = "set";
+  public static final String CMD_SET_SC = "\\st";
+
+  public static final String CMD_SHOW = "show";
+  public static final String CMD_SHOW_SC = "\\sh";
+
+  public static final String CMD_UPDATE = "update";
+  public static final String CMD_UPDATE_SC = "\\up";
+
+  public static final String CMD_START = "start";
+  public static final String CMD_START_SC = "\\sta";
+
+  public static final String CMD_STOP = "stop";
+  public static final String CMD_STOP_SC = "\\stp";
+
+  public static final String CMD_STATUS = "status";
+  public static final String CMD_STATUS_SC = "\\stu";
+
+  public static final String CMD_ENABLE = "enable";
+  public static final String CMD_ENABLE_SC = "\\en";
+
+  public static final String CMD_DISABLE = "disable";
+  public static final String CMD_DISABLE_SC = "\\di";
+
+  public static final String FN_CONNECTION = "connection";
+  public static final String FN_JOB = "job";
+  public static final String FN_SUBMISSION = "submission";
+  public static final String FN_SERVER = "server";
+  public static final String FN_OPTION = "option";
+  public static final String FN_CONNECTOR = "connector";
+  public static final String FN_VERSION = "version";
+  public static final String FN_FRAMEWORK = "framework";
+
+  public static final String PRE_CLONE = "Clone";
+  public static final String PRE_CREATE = "Create";
+  public static final String PRE_DELETE = "Delete";
+  public static final String PRE_SET = "Set";
+  public static final String PRE_SHOW = "Show";
+  public static final String PRE_UPDATE = "Update";
+  public static final String PRE_START = "Start";
+  public static final String PRE_STATUS = "Status";
+  public static final String PRE_STOP = "Stop";
+  public static final String PRE_ENABLE = "Enable";
+  public static final String PRE_DISABLE = "Disable";
+  public static final String SUF_INFO = "Info";
+
+
+  public static final String PROP_HOMEDIR = "user.home";
+  public static final String PROP_CURDIR = "user.dir";
+  public static final String SQOOP_PROMPT = "sqoop";
+
+
+  // Resource Keys for various messages
+
+  public static final String RES_FUNCTION_UNKNOWN =
+      "args.function.unknown";
+  public static final String RES_ARGS_XID_MISSING =
+      "args.xid_missing";
+  public static final String RES_ARGS_JID_MISSING =
+      "args.jid_missing";
+  public static final String RES_ARGS_CID_MISSING =
+      "args.cid_missing";
+  public static final String RES_ARGS_TYPE_MISSING =
+      "args.type_missing";
+  public static final String RES_ARGS_NAME_MISSING =
+      "args.name_missing";
+  public static final String RES_ARGS_VALUE_MISSING =
+      "args.value_missing";
+
+  public static final String RES_PROMPT_CONN_ID =
+      "prompt.conn_id";
+  public static final String RES_PROMPT_JOB_ID =
+      "prompt.job_id";
+  public static final String RES_CONNECTOR_ID =
+      "prompt.connector_id";
+  public static final String RES_PROMPT_JOB_TYPE =
+      "prompt.job_type";
+  public static final String RES_PROMPT_UPDATE_CONN_METADATA =
+      "prompt.update_conn_metadata";
+  public static final String RES_PROMPT_UPDATE_JOB_METADATA =
+      "prompt.update_job_metadata";
+  public static final String RES_PROMPT_FILL_CONN_METADATA =
+      "prompt.fill_conn_metadata";
+  public static final String RES_PROMPT_FILL_JOB_METADATA =
+      "prompt.fill_job_metadata";
+
+  public static final String RES_CLONE_USAGE =
+      "clone.usage";
+  public static final String RES_CLONE_CONN_SUCCESSFUL =
+      "clone.conn.successful";
+  public static final String RES_CLONE_JOB_SUCCESSFUL =
+      "clone.job.successful";
+  public static final String RES_CLONE_CLONING_CONN =
+      "clone.cloning_conn";
+  public static final String RES_CLONE_CLONING_JOB =
+      "clone.cloning_job";
+
+  public static final String RES_CREATE_USAGE =
+      "create.usage";
+  public static final String RES_CREATE_CONN_SUCCESSFUL =
+      "create.conn_successful";
+  public static final String RES_CREATE_JOB_SUCCESSFUL =
+      "create.job_successful";
+  public static final String RES_CREATE_CREATING_CONN =
+      "create.creating_conn";
+  public static final String RES_CREATE_CREATING_JOB =
+      "create.creating_job";
+
+  public static final String RES_DELETE_USAGE =
+      "delete.usage";
+
+  public static final String RES_DISABLE_USAGE =
+      "disable.usage";
+  public static final String RES_DISABLE_CONNECTION_SUCCESSFUL =
+      "disable.conn_successful";
+  public static final String RES_DISABLE_JOB_SUCCESSFUL =
+      "disable.job_successful";
+
+  public static final String RES_ENABLE_USAGE =
+      "enable.usage";
+  public static final String RES_ENABLE_CONNECTION_SUCCESSFUL =
+      "enable.conn_successful";
+  public static final String RES_ENABLE_JOB_SUCCESSFUL =
+      "enable.job_successful";
+
+  public static final String RES_HELP_USAGE =
+      "help.usage";
+  public static final String RES_HELP_DESCRIPTION =
+      "help.description";
+  public static final String RES_HELP_CMD_USAGE =
+      "help.cmd_usage";
+  public static final String RES_HELP_MESSAGE =
+      "help.message";
+  public static final String RES_HELP_INFO =
+      "help.info";
+  public static final String RES_HELP_AVAIL_COMMANDS =
+      "help.avail_commands";
+  public static final String RES_HELP_CMD_DESCRIPTION =
+      "help.cmd_description";
+  public static final String RES_HELP_SPECIFIC_CMD_INFO =
+      "help.specific_cmd_info";
+
+  public static final String RES_UNRECOGNIZED_CMD =
+      "unrecognized.cmd";
+
+  public static final String RES_SET_USAGE =
+      "set.usage";
+  public static final String RES_SET_PROMPT_OPT_NAME =
+      "set.prompt_opt_name";
+  public static final String RES_SET_PROMPT_OPT_VALUE =
+      "set.prompt_opt_value";
+  public static final String RES_SET_VERBOSE_CHANGED =
+      "set.verbose_changed";
+  public static final String RES_SET_POLL_TIMEOUT_CHANGED =
+      "set.poll_timeout_changed";
+  public static final String RES_SET_UNKNOWN_OPT_IGNORED =
+      "set.unknown_opt_ignored";
+  public static final String RES_SET_HOST_DESCRIPTION =
+      "set.host_description";
+  public static final String RES_SET_PORT_DESCRIPTION =
+      "set.port_description";
+  public static final String RES_WEBAPP_DESCRIPTION =
+      "set.webapp_description";
+  public static final String RES_URL_DESCRIPTION =
+      "set.url_description";
+  public static final String RES_SET_SERVER_USAGE =
+      "set.server_usage";
+  public static final String RES_SET_SERVER_SUCCESSFUL =
+      "set.server_successful";
+  public static final String RES_SET_SERVER_IGNORED =
+      "set.server_ignored";
+
+  public static final String RES_SHOW_USAGE =
+      "show.usage";
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_CONNS =
+      "show.prompt_display_all_conns";
+  public static final String RES_SHOW_PROMPT_DISPLAY_CONN_XID =
+      "show.prompt_display_conn_xid";
+  public static final String RES_SHOW_CONN_USAGE =
+      "show.conn_usage";
+  public static final String RES_SHOW_PROMPT_CONNS_TO_SHOW =
+      "show.prompt_conns_to_show";
+  public static final String RES_SHOW_PROMPT_CONN_INFO =
+      "show.prompt_conn_info";
+  public static final String RES_SHOW_PROMPT_CONN_CID_INFO =
+      "show.prompt_conn_cid_info";
+
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_CONNECTORS =
+      "show.prompt_display_all_connectors";
+  public static final String RES_SHOW_PROMPT_DISPLAY_CONNECTOR_CID =
+      "show.prompt_display_connector_cid";
+  public static final String RES_SHOW_CONNECTOR_USAGE =
+      "show.connector_usage";
+  public static final String RES_SHOW_PROMPT_CONNECTORS_TO_SHOW =
+      "show.prompt_connectors_to_show";
+  public static final String RES_SHOW_PROMPT_CONNECTOR_INFO =
+      "show.prompt_connector_info";
+
+  public static final String RES_SHOW_FRAMEWORK_USAGE =
+      "show.framework_usage";
+  public static final String RES_SHOW_PROMPT_FRAMEWORK_OPTS =
+      "show.prompt_framework_opts";
+
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_JOBS =
+      "show.prompt_display_all_jobs";
+  public static final String RES_SHOW_PROMPT_DISPLAY_JOB_JID =
+      "show.prompt_display_job_jid";
+  public static final String RES_SHOW_JOB_USAGE =
+      "show.job_usage";
+  public static final String RES_SHOW_PROMPT_JOBS_TO_SHOW =
+      "show.prompt_jobs_to_show";
+  public static final String RES_SHOW_PROMPT_JOB_INFO =
+      "show.prompt_job_info";
+  public static final String RES_SHOW_PROMPT_JOB_XID_CID_INFO =
+      "show.prompt_job_xid_cid_info";
+
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_SUBMISSIONS =
+      "show.prompt_display_all_submissions";
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_SUBMISSIONS_JOB_ID =
+      "show.prompt_display_all_submissions_jid";
+
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_SERVERS =
+      "show.prompt_display_all_servers";
+  public static final String RES_SHOW_PROMPT_DISPLAY_SERVER_HOST =
+      "show.prompt_display_server_host";
+  public static final String RES_SHOW_PROMPT_DISPLAY_SERVER_PORT =
+      "show.prompt_display_server_port";
+  public static final String RES_SHOW_PROMPT_DISPLAY_SERVER_WEBAPP =
+      "show.prompt_display_server_webapp";
+  public static final String RES_SHOW_SERVER_USAGE =
+      "show.server_usage";
+  public static final String RES_SHOW_PROMPT_SERVER_HOST =
+      "show.prompt_server_host";
+  public static final String RES_SHOW_PROMPT_SERVER_PORT =
+      "show.prompt_server_port";
+  public static final String RES_SHOW_PROMPT_SERVER_WEBAPP =
+      "show.prompt_server_webapp";
+
+  public static final String RES_SHOW_PROMPT_DISPLAY_ALL_VERSIONS =
+      "show.prompt_display_all_versions";
+  public static final String RES_SHOW_PROMPT_DISPLAY_VERSION_SERVER =
+      "show.prompt_display_version_server";
+  public static final String RES_SHOW_PROMPT_DISPLAY_VERSION_CLIENT =
+      "show.prompt_display_version_client";
+  public static final String RES_SHOW_PROMPT_DISPLAY_VERSION_PROTOCOL =
+      "show.prompt_display_version_protocol";
+  public static final String RES_SHOW_VERSION_USAGE =
+      "show.version_usage";
+  public static final String RES_SHOW_PROMPT_VERSION_CLIENT_SERVER =
+      "show.prompt_version_client_server";
+  public static final String RES_SHOW_PROMPT_VERSION_PROTOCOL =
+      "show.prompt_version_protocol";
+
+  public static final String RES_START_USAGE =
+      "start.usage";
+
+  public static final String RES_STATUS_USAGE =
+      "status.usage";
+  public static final String RES_PROMPT_SYNCHRONOUS =
+      "start.prompt_synchronous";
+
+  public static final String RES_STOP_USAGE =
+      "stop.usage";
+
+  public static final String RES_SQOOP_SHELL_BANNER =
+      "sqoop.shell_banner";
+  public static final String RES_SQOOP_PROMPT_SHELL_LOADRC =
+      "sqoop.prompt_shell_loadrc";
+  public static final String RES_SQOOP_PROMPT_SHELL_LOADEDRC =
+      "sqoop.prompt_shell_loadedrc";
+
+  public static final String RES_UPDATE_USAGE =
+      "update.usage";
+  public static final String RES_UPDATE_UPDATING_CONN =
+      "update.conn";
+  public static final String RES_UPDATE_CONN_SUCCESSFUL =
+      "update.conn_successful";
+  public static final String RES_UPDATE_UPDATING_JOB =
+      "update.job";
+  public static final String RES_UPDATE_JOB_SUCCESSFUL =
+      "update.job_successful";
+
+  public static final String RES_TABLE_HEADER_ID =
+      "table.header.id";
+  public static final String RES_TABLE_HEADER_NAME =
+      "table.header.name";
+  public static final String RES_TABLE_HEADER_VERSION =
+      "table.header.version";
+  public static final String RES_TABLE_HEADER_CLASS =
+      "table.header.class";
+  public static final String RES_TABLE_HEADER_TYPE =
+      "table.header.type";
+  public static final String RES_TABLE_HEADER_CONNECTOR =
+      "table.header.connector";
+  public static final String RES_TABLE_HEADER_JOB_ID =
+      "table.header.jid";
+  public static final String RES_TABLE_HEADER_EXTERNAL_ID =
+      "table.header.eid";
+  public static final String RES_TABLE_HEADER_STATUS =
+      "table.header.status";
+  public static final String RES_TABLE_HEADER_DATE =
+      "table.header.date";
+  public static final String RES_TABLE_HEADER_ENABLED =
+      "table.header.enabled";
+
+  public static final String RES_FORMDISPLAYER_SUPPORTED_JOBTYPE =
+      "formdisplayer.supported_job_types";
+  public static final String RES_FORMDISPLAYER_CONNECTION =
+      "formdisplayer.connection";
+  public static final String RES_FORMDISPLAYER_JOB =
+      "formdisplayer.job";
+  public static final String RES_FORMDISPLAYER_FORM_JOBTYPE =
+      "formdisplayer.forms_jobtype";
+  public static final String RES_FORMDISPLAYER_FORM =
+      "formdisplayer.form";
+  public static final String RES_FORMDISPLAYER_NAME =
+      "formdisplayer.name";
+  public static final String RES_FORMDISPLAYER_LABEL =
+      "formdisplayer.label";
+  public static final String RES_FORMDISPLAYER_HELP =
+      "formdisplayer.help";
+  public static final String RES_FORMDISPLAYER_INPUT =
+      "formdisplayer.input";
+  public static final String RES_FORMDISPLAYER_TYPE =
+      "formdisplayer.type";
+  public static final String RES_FORMDISPLAYER_SENSITIVE =
+      "formdisplayer.sensitive";
+  public static final String RES_FORMDISPLAYER_SIZE =
+      "formdisplayer.size";
+  public static final String RES_FORMDISPLAYER_POSSIBLE_VALUES =
+      "formdisplayer.possible_values";
+  public static final String RES_FORMDISPLAYER_UNSUPPORTED_DATATYPE =
+      "formdisplayer.unsupported_datatype";
+  public static final String RES_FORMDISPLAYER_INPUT_SENSITIVE =
+      "formdisplayer.input_sensitive";
+
+  public static final String RES_FORMDISPLAYER_FORM_WARNING =
+      "formdisplayer.warning_message";
+
+  public static final String RES_SUBMISSION_SUBMISSION_DETAIL =
+      "submission.submission_detail";
+  public static final String RES_SUBMISSION_JOB_ID =
+      "submission.job_id";
+  public static final String RES_SUBMISSION_CREATION_DATE =
+      "submission.creation_date";
+  public static final String RES_SUBMISSION_EXTERNAL_ID =
+      "submission.external_id";
+  public static final String RES_SUBMISSION_PROGRESS_NOT_AVAIL =
+      "submission.progress_not_available";
+  public static final String RES_SUBMISSION_COUNTERS =
+      "submission.counters";
+  public static final String RES_SUBMISSION_EXECUTED_SUCCESS =
+      "submission.executed_success";
+  public static final String RES_SUBMISSION_SERVER_URL =
+      "submission.server_url";
+  public static final String RES_CONNECTOR_SCHEMA =
+      "submission.connector_schema";
+  public static final String RES_HIO_SCHEMA =
+    "submission.hio_schema";
+
+  private Constants() {
+    // Instantiation is prohibited
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/core/ShellError.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/core/ShellError.java b/shell/src/main/java/org/apache/sqoop/shell/core/ShellError.java
new file mode 100644
index 0000000..e5a99f1
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/core/ShellError.java
@@ -0,0 +1,66 @@
+/**
+ * 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.apache.sqoop.shell.core;
+
+import org.apache.sqoop.common.ErrorCode;
+
+public enum ShellError implements ErrorCode {
+
+  /** An unknown error has occurred. */
+  SHELL_0000("An unknown error has occurred"),
+
+  /** The specified command is not recognized. */
+  SHELL_0001("The specified command is not recognized"),
+
+  /** The specified function is not recognized. */
+  SHELL_0002("The specified function is not recognized"),
+
+  /** An error has occurred when parsing options. */
+  SHELL_0003("An error has occurred when parsing options"),
+
+  /** Unable to resolve the variables. */
+  SHELL_0004("Unable to resolve the variables"),
+
+  /** We're not able to get user input */
+  SHELL_0005("Can't get user input"),
+
+  /** There occurred exception on server side **/
+  SHELL_0006("Server has returned exception"),
+
+  /** Command not compatible with batch mode */
+  SHELL_0007("Command not compatible with batch mode"),
+
+  /** Job Submission : Cannot sleep */
+  SHELL_0008("Cannot sleep"),
+
+  ;
+
+  private final String message;
+
+  private ShellError(String message) {
+    this.message = message;
+  }
+
+  public String getCode() {
+    return name();
+  }
+
+  public String getMessage() {
+    return message;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/utils/FormDisplayer.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/FormDisplayer.java b/shell/src/main/java/org/apache/sqoop/shell/utils/FormDisplayer.java
new file mode 100644
index 0000000..56e0b4e
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/FormDisplayer.java
@@ -0,0 +1,249 @@
+/**
+ * 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.apache.sqoop.shell.utils;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sqoop.model.MAccountableEntity;
+import org.apache.sqoop.model.MBooleanInput;
+import org.apache.sqoop.model.MConnection;
+import org.apache.sqoop.model.MEnumInput;
+import org.apache.sqoop.model.MForm;
+import org.apache.sqoop.model.MFramework;
+import org.apache.sqoop.model.MInput;
+import org.apache.sqoop.model.MInputType;
+import org.apache.sqoop.model.MIntegerInput;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MJobForms;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.validation.Status;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+
+/**
+ * Convenience static methods for displaying form related information
+ */
+public final class FormDisplayer {
+
+  public static void displayFormMetadataDetails(MFramework framework,
+                                                ResourceBundle bundle) {
+    print("  %s: ", resourceString(Constants.RES_FORMDISPLAYER_SUPPORTED_JOBTYPE));
+    println(framework.getAllJobsForms().keySet().toString());
+
+    displayFormsMetadata(
+      framework.getConnectionForms().getForms(),
+      resourceString(Constants.RES_FORMDISPLAYER_CONNECTION),
+      bundle);
+
+    for (MJobForms jobForms : framework.getAllJobsForms().values()) {
+      print("  %s ", resourceString(Constants.RES_FORMDISPLAYER_FORM_JOBTYPE));
+      print(jobForms.getType().name());
+      println(":");
+
+      displayFormsMetadata(jobForms.getForms(), resourceString(Constants.RES_FORMDISPLAYER_JOB), bundle);
+    }
+  }
+
+  public static void displayFormsMetadata(List<MForm> forms,
+                                         String type,
+                                         ResourceBundle bundle) {
+    Iterator<MForm> fiter = forms.iterator();
+    int findx = 1;
+    while (fiter.hasNext()) {
+      print("    ");
+      print(type);
+      print(" %s ", resourceString(Constants.RES_FORMDISPLAYER_FORM));
+      print(findx++);
+      println(":");
+
+      MForm form = fiter.next();
+      print("      %s: ", resourceString(Constants.RES_FORMDISPLAYER_NAME));
+      println(form.getName());
+
+      // Label
+      print("      %s: ", resourceString(Constants.RES_FORMDISPLAYER_LABEL));
+      println(bundle.getString(form.getLabelKey()));
+
+      // Help text
+      print("      %s: ", resourceString(Constants.RES_FORMDISPLAYER_HELP));
+      println(bundle.getString(form.getHelpKey()));
+
+      List<MInput<?>> inputs = form.getInputs();
+      Iterator<MInput<?>> iiter = inputs.iterator();
+      int iindx = 1;
+      while (iiter.hasNext()) {
+        print("      %s ", resourceString(Constants.RES_FORMDISPLAYER_INPUT));
+        print(iindx++);
+        println(":");
+
+        MInput<?> input = iiter.next();
+        print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_NAME));
+        println(input.getName());
+        print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_LABEL));
+        println(bundle.getString(input.getLabelKey()));
+        print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_HELP));
+        println(bundle.getString(input.getHelpKey()));
+        print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_TYPE));
+        println(input.getType());
+        print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_SENSITIVE));
+        println(input.isSensitive());
+        if (input.getType() == MInputType.STRING) {
+          print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_SIZE));
+          println(((MStringInput)input).getMaxLength());
+        } else if(input.getType() == MInputType.ENUM) {
+          print("        %s: ", resourceString(Constants.RES_FORMDISPLAYER_POSSIBLE_VALUES));
+          println(StringUtils.join(((MEnumInput)input).getValues(), ","));
+        }
+      }
+    }
+  }
+
+  public static void displayForms(List<MForm> forms, ResourceBundle bundle) {
+    for(MForm form : forms) {
+      displayForm(form, bundle);
+    }
+  }
+
+  /**
+   * Method prints the warning message of ACCEPTABLE status
+   * @param entity - connection or job instance
+   */
+  public static void displayFormWarning(MAccountableEntity entity) {
+    List<MForm> formList = new ArrayList<MForm>();
+    boolean showMessage = true;
+    if (entity instanceof MConnection) {
+      MConnection connection = (MConnection) entity;
+      formList.addAll(connection.getConnectorPart().getForms());
+      formList.addAll(connection.getFrameworkPart().getForms());
+    } else if(entity instanceof MJob) {
+      MJob job = (MJob) entity;
+      formList.addAll(job.getConnectorPart().getForms());
+      formList.addAll(job.getFrameworkPart().getForms());
+    }
+    for(MForm form : formList) {
+      if(form.getValidationStatus() == Status.ACCEPTABLE) {
+        if(showMessage) {
+          print("\n@|yellow %s|@\n", resourceString(Constants.RES_FORMDISPLAYER_FORM_WARNING));
+          showMessage = false;
+        }
+        FormFiller.warningMessage(form.getValidationMessage());
+      }
+    }
+  }
+
+  private static void displayForm(MForm form, ResourceBundle bundle) {
+    print("  ");
+    println(bundle.getString(form.getLabelKey()));
+
+    for (MInput<?> input : form.getInputs()) {
+      print("    ");
+      print(bundle.getString(input.getLabelKey()));
+      print(": ");
+      if(!input.isEmpty()) {
+        if (input.isSensitive()) {
+          print("(%s)", resourceString(Constants.RES_FORMDISPLAYER_INPUT_SENSITIVE));
+        } else {
+          // Based on the input type, let's perform specific load
+          switch (input.getType()) {
+            case STRING:
+              displayInputString((MStringInput) input);
+              break;
+            case INTEGER:
+              displayInputInteger((MIntegerInput) input);
+              break;
+            case BOOLEAN:
+              displayInputBoolean((MBooleanInput) input);
+              break;
+            case MAP:
+              displayInputMap((MMapInput) input);
+              break;
+            case ENUM:
+              displayInputEnum((MEnumInput) input);
+              break;
+            default:
+              print("\n%s " + input.getType(), resourceString(Constants.RES_FORMDISPLAYER_UNSUPPORTED_DATATYPE));
+              return;
+          }
+        }
+      }
+      println("");
+    }
+  }
+
+  /**
+   * Display content of String input.
+   *
+   * @param input String input
+   */
+  private static void displayInputString(MStringInput input) {
+    print(input.getValue());
+  }
+
+  /**
+   * Display content of Integer input.
+   *
+   * @param input Integer input
+   */
+  private static void displayInputInteger(MIntegerInput input) {
+    print(input.getValue());
+  }
+
+  /**
+   * Display content of Boolean input.
+   *
+   * @param input Boolean input
+   */
+  private static void displayInputBoolean(MBooleanInput input) {
+    print(input.getValue());
+  }
+
+  /**
+   * Display content of Map input
+   *
+   * @param input Map input
+   */
+  private static void displayInputMap(MMapInput input) {
+    for(Map.Entry<String, String> entry : input.getValue().entrySet()) {
+      println();
+      print("      ");
+      print(entry.getKey());
+      print(" = ");
+      print(entry.getValue());
+    }
+  }
+
+  /**
+   * Display content of Enum input
+   *
+   * @param input Enum input
+   */
+  private static void displayInputEnum(MEnumInput input) {
+    print(input.getValue());
+  }
+
+  private FormDisplayer() {
+    // Do not instantiate
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/utils/FormFiller.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/FormFiller.java b/shell/src/main/java/org/apache/sqoop/shell/utils/FormFiller.java
new file mode 100644
index 0000000..9bc0b93
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/FormFiller.java
@@ -0,0 +1,566 @@
+/**
+ * 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.apache.sqoop.shell.utils;
+
+import jline.ConsoleReader;
+import org.apache.sqoop.model.MBooleanInput;
+import org.apache.sqoop.model.MConnection;
+import org.apache.sqoop.model.MEnumInput;
+import org.apache.sqoop.model.MForm;
+import org.apache.sqoop.model.MInput;
+import org.apache.sqoop.model.MIntegerInput;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MStringInput;
+import org.apache.sqoop.model.MValidatedElement;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ResourceBundle;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+
+/**
+ * Convenient methods for retrieving user input.
+ */
+public final class FormFiller {
+
+  /**
+   * Internal input that will be reused for loading names for connection and
+   * job objects.
+   */
+  private static MStringInput nameInput = new MStringInput("object-name", false, (short)25);
+
+  /**
+   * Fill job object based on user input.
+   *
+   * @param reader Associated console reader object
+   * @param job Job that user is suppose to fill in
+   * @param connectorBundle Connector resource bundle
+   * @param frameworkBundle Framework resource bundle
+   * @return True if we filled all inputs, false if user has stopped processing
+   * @throws IOException
+   */
+  public static boolean fillJob(ConsoleReader reader,
+                                MJob job,
+                                ResourceBundle connectorBundle,
+                                ResourceBundle frameworkBundle)
+                                throws IOException {
+
+    job.setName(getName(reader, job.getName()));
+
+    // Fill in data from user
+     return fillForms(reader,
+                      job.getConnectorPart().getForms(),
+                      connectorBundle,
+                      job.getFrameworkPart().getForms(),
+                      frameworkBundle);
+  }
+
+  /**
+   * Fill connection object based on user input.
+   *
+   * @param reader Associated console reader object
+   * @param connection Connection that user is suppose to fill in
+   * @param connectorBundle Connector resource bundle
+   * @param frameworkBundle Framework resouce bundle
+   * @return True if we filled all inputs, false if user has stopped processing
+   * @throws IOException
+   */
+  public static boolean fillConnection(ConsoleReader reader,
+                                       MConnection connection,
+                                       ResourceBundle connectorBundle,
+                                       ResourceBundle frameworkBundle)
+                                       throws IOException {
+
+    connection.setName(getName(reader, connection.getName()));
+
+    // Fill in data from user
+     return fillForms(reader,
+                      connection.getConnectorPart().getForms(),
+                      connectorBundle,
+                      connection.getFrameworkPart().getForms(),
+                      frameworkBundle);
+  }
+
+  public static boolean fillForms(ConsoleReader reader,
+                                  List<MForm> connectorForms,
+                                  ResourceBundle connectorBundle,
+                                  List<MForm> frameworkForms,
+                                  ResourceBundle frameworkBundle
+                                  ) throws IOException {
+
+
+    // Query connector forms
+    if(!fillForms(connectorForms, reader, connectorBundle)) {
+      return false;
+    }
+
+    // Query framework forms
+    if(!fillForms(frameworkForms, reader, frameworkBundle)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  public static boolean fillForms(List<MForm> forms,
+                                  ConsoleReader reader,
+                                  ResourceBundle bundle)
+    throws IOException {
+    for (MForm form : forms) {
+      if(!fillForm(form, reader, bundle)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  public static boolean fillForm(MForm form,
+                                 ConsoleReader reader,
+                                 ResourceBundle bundle) throws IOException {
+    println("");
+    println(bundle.getString(form.getLabelKey()));
+
+    // Print out form validation
+    printValidationMessage(form);
+    println("");
+
+    for (MInput input : form.getInputs()) {
+      if(!fillInput(input, reader, bundle)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  public static boolean fillInput(MInput input,
+                                  ConsoleReader reader,
+                                  ResourceBundle bundle) throws IOException {
+    // Print out validation
+    printValidationMessage(input);
+
+    // Based on the input type, let's perform specific load
+    switch (input.getType()) {
+      case STRING:
+        return fillInputString((MStringInput) input, reader, bundle);
+      case INTEGER:
+        return fillInputInteger((MIntegerInput) input, reader, bundle);
+      case BOOLEAN:
+        return fillInputBoolean((MBooleanInput) input, reader, bundle);
+      case MAP:
+        return fillInputMap((MMapInput) input, reader, bundle);
+      case ENUM:
+        return fillInputEnum((MEnumInput) input, reader, bundle);
+      default:
+        println("Unsupported data type " + input.getType());
+        return true;
+    }
+  }
+
+  /**
+   * Load user input for enum type.
+   *
+   * Print out numbered list of all available options and let user choose one
+   * item from that.
+   *
+   * @param input Input that we should read or edit
+   * @param reader Associated console reader
+   * @param bundle Resource bundle
+   * @return True if user with to continue with loading addtional inputs
+   * @throws IOException
+   */
+  private static boolean fillInputEnum(MEnumInput input,
+                                       ConsoleReader reader,
+                                       ResourceBundle bundle)
+                                       throws IOException {
+    // Prompt in enum case
+    println(bundle.getString(input.getLabelKey()) + ": ");
+
+    // Indexes
+    int i = -1;
+    int lastChoice = -1;
+
+    // Print out all values as a numbered list
+    for(String value : input.getValues()) {
+      i++;
+
+      println("  " + i  + " : " + value);
+
+      // Only show last choice if not sensitive
+      if(!input.isEmpty() && value.equals(input.getValue()) && !input.isSensitive()) {
+        lastChoice = i;
+      }
+    }
+
+    // Prompt
+    reader.printString("Choose: ");
+
+    // Fill previously filled index when available
+    if(lastChoice != -1) {
+      reader.putString(Integer.toString(lastChoice));
+    }
+
+    reader.flushConsole();
+    String userTyped;
+    if(input.isSensitive()) {
+      userTyped = reader.readLine('*');
+    } else {
+      userTyped = reader.readLine();
+    }
+
+    if (userTyped == null) {
+      return false;
+    } else if (userTyped.isEmpty()) {
+      input.setEmpty();
+    } else {
+      Integer index;
+      try {
+        index = Integer.valueOf(userTyped);
+
+        if(index < 0 || index >= input.getValues().length) {
+          errorMessage("Invalid index");
+          return fillInputEnum(input, reader, bundle);
+        }
+
+        input.setValue(input.getValues()[index]);
+      } catch (NumberFormatException ex) {
+        errorMessage("Input is not valid integer number");
+        return fillInputEnum(input, reader, bundle);
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Load user input for map type.
+   *
+   * This implementation will load one map entry at the time. Current flows is
+   * as follows: if user did not enter anything (empty input) finish loading
+   * and return from function. If user specified input with equal sign (=),
+   * lets add new key value pair. Otherwise consider entire input as a key name
+   * and try to remove it from the map.
+   *
+   * Please note that following code do not supports equal sign in property
+   * name. It's however perfectly fine to have equal sign in value.
+   *
+   * @param input Input that we should read or edit
+   * @param reader Associated console reader
+   * @param bundle Resource bundle
+   * @return True if user wish to continue with loading additional inputs
+   * @throws IOException
+   */
+  private static boolean fillInputMap(MMapInput input,
+                                      ConsoleReader reader,
+                                      ResourceBundle bundle)
+                                      throws IOException {
+    // Special prompt in Map case
+    println(bundle.getString(input.getLabelKey()) + ": ");
+
+    // Internal loading map
+    Map<String, String> values = input.getValue();
+    if(values == null) {
+      values = new HashMap<String, String>();
+    }
+
+    String userTyped;
+
+    while(true) {
+      // Print all current items in each iteration
+      // However do not printout if this input contains sensitive information.
+      println("There are currently " + values.size() + " values in the map:");
+      if (!input.isSensitive()) {
+        for(Map.Entry<String, String> entry : values.entrySet()) {
+          println(entry.getKey() + " = " + entry.getValue());
+        }
+      }
+
+      // Special prompt for Map entry
+      reader.printString("entry# ");
+      reader.flushConsole();
+
+      if(input.isSensitive()) {
+        userTyped = reader.readLine('*');
+      } else {
+        userTyped = reader.readLine();
+      }
+
+      if(userTyped == null) {
+        // Finish loading and return back to Sqoop shell
+        return false;
+      } else if(userTyped.isEmpty()) {
+        // User has finished loading data to Map input, either set input empty
+        // if there are no entries or propagate entries to the input
+        if(values.size() == 0) {
+          input.setEmpty();
+        } else {
+          input.setValue(values);
+        }
+        return true;
+      } else {
+        // User has specified regular input, let's check if it contains equals
+        // sign. Save new entry (or update existing one) if it does. Otherwise
+        // try to remove entry that user specified.
+        if(userTyped.contains("=")) {
+          String []keyValue = userTyped.split("=", 2);
+          values.put(handleUserInput(keyValue[0]), handleUserInput(keyValue[1]));
+        } else {
+          String key = handleUserInput(userTyped);
+          if(values.containsKey(key)) {
+            values.remove(key);
+          } else {
+            errorMessage("Don't know what to do with " + userTyped);
+          }
+        }
+      }
+
+    }
+  }
+
+  /**
+   * Handle special cases in user input.
+   *
+   * Preserve null and empty values, remove whitespace characters before and
+   * after loaded string and de-quote the string if it's quoted (to preserve
+   * spaces for example).
+   *
+   * @param input String loaded from user
+   * @return Unquoted transformed string
+   */
+  private static String handleUserInput(String input) {
+    // Preserve null and empty values
+    if(input == null) {
+      return null;
+    }
+    if(input.isEmpty()) {
+      return input;
+    }
+
+    // Removes empty characters at the begging and end of loaded string
+    input = input.trim();
+
+    int lastIndex = input.length() - 1;
+    char first = input.charAt(0);
+    char last = input.charAt(lastIndex);
+
+    // Remove quoting if present
+    if(first == '\'' && last == '\'') {
+      input = input.substring(1, lastIndex);
+    } else if(first == '"' && last == '"') {
+      input =  input.substring(1, lastIndex);
+    }
+
+    // Return final string
+    return input;
+  }
+
+  private static boolean fillInputInteger(MIntegerInput input,
+                                          ConsoleReader reader,
+                                          ResourceBundle bundle)
+                                          throws IOException {
+    generatePrompt(reader, bundle, input);
+
+    // Fill already filled data when available
+    // However do not printout if this input contains sensitive information.
+    if(!input.isEmpty() && !input.isSensitive()) {
+      reader.putString(input.getValue().toString());
+    }
+
+    // Get the data
+    String userTyped;
+    if(input.isSensitive()) {
+      userTyped = reader.readLine('*');
+    } else {
+      userTyped = reader.readLine();
+    }
+
+    if (userTyped == null) {
+      return false;
+    } else if (userTyped.isEmpty()) {
+      input.setEmpty();
+    } else {
+      Integer value;
+      try {
+        value = Integer.valueOf(userTyped);
+        input.setValue(value);
+      } catch (NumberFormatException ex) {
+        errorMessage("Input is not valid integer number");
+        return fillInputInteger(input, reader, bundle);
+      }
+
+      input.setValue(Integer.valueOf(userTyped));
+    }
+
+    return true;
+  }
+
+  /**
+   * Load string input from the user.
+   *
+   * @param input Input that we should load in
+   * @param reader Associated console reader
+   * @param bundle Resource bundle for this input
+   * @return
+   * @throws IOException
+   */
+  public static boolean fillInputString(MStringInput input,
+                                        ConsoleReader reader,
+                                        ResourceBundle bundle)
+                                        throws IOException {
+    generatePrompt(reader, bundle, input);
+
+    // Fill already filled data when available
+    // However do not printout if this input contains sensitive information.
+    if(!input.isEmpty() && !input.isSensitive()) {
+      reader.putString(input.getValue());
+    }
+
+    // Get the data
+    String userTyped;
+    if(input.isSensitive()) {
+       userTyped = reader.readLine('*');
+    } else {
+      userTyped = reader.readLine();
+    }
+
+    if (userTyped == null) {
+      // Propagate end of loading process
+      return false;
+    } else if (userTyped.isEmpty()) {
+      // Empty input in case that nothing was given
+      input.setEmpty();
+    } else {
+      // Set value that user has entered
+      input.setValue(userTyped);
+
+      // Check that it did not exceeds maximal allowance for given input
+      if(userTyped.length() > input.getMaxLength()) {
+        errorMessage("Size of input exceeds allowance for this input"
+          + " field. Maximal allowed size is " + input.getMaxLength());
+        return fillInputString(input, reader, bundle);
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Load boolean input from the user.
+   *
+   * @param input Input that we should load in
+   * @param reader Associated console reader
+   * @param bundle Resource bundle for this input
+   * @return
+   * @throws IOException
+   */
+  public static boolean fillInputBoolean(MBooleanInput input,
+                                         ConsoleReader reader,
+                                         ResourceBundle bundle)
+                                         throws IOException {
+    generatePrompt(reader, bundle, input);
+
+    // Fill already filled data when available
+    // However do not printout if this input contains sensitive information.
+    if(!input.isEmpty() && !input.isSensitive()) {
+      reader.putString(input.getValue().toString());
+    }
+
+    // Get the data
+    String userTyped;
+    if(input.isSensitive()) {
+       userTyped = reader.readLine('*');
+    } else {
+      userTyped = reader.readLine();
+    }
+
+    if (userTyped == null) {
+      // Propagate end of loading process
+      return false;
+    } else if (userTyped.isEmpty()) {
+      // Empty input in case that nothing was given
+      input.setEmpty();
+    } else {
+      // Set value that user has entered
+      input.setValue(Boolean.valueOf(userTyped));
+    }
+
+    return true;
+  }
+
+  public static void generatePrompt(ConsoleReader reader,
+                                    ResourceBundle bundle,
+                                    MInput input)
+                                    throws IOException {
+    reader.printString(bundle.getString(input.getLabelKey()) + ": ");
+    reader.flushConsole();
+  }
+
+  public static String getName(ConsoleReader reader,
+                               String name) throws IOException {
+    if(name == null) {
+      nameInput.setEmpty();
+    } else {
+      nameInput.setValue(name);
+    }
+
+    fillInputString(nameInput, reader, getResourceBundle());
+
+    return nameInput.getValue();
+  }
+
+  /**
+   * Print validation message in cases that it's not in state "FINE"
+   *
+   * @param element Validated element
+   */
+  public static void printValidationMessage(MValidatedElement element) {
+    switch (element.getValidationStatus()) {
+      case UNACCEPTABLE:
+        errorMessage(element.getValidationMessage());
+        break;
+      case ACCEPTABLE:
+        warningMessage(element.getValidationMessage());
+        break;
+      default:
+        // Simply ignore all other states for the moment
+        break;
+    }
+  }
+
+  public static void errorMessage(String message) {
+    println("Error message: @|red " + message + " |@");
+  }
+
+  public static void warningMessage(String message) {
+    println("Warning message: @|yellow " + message + " |@");
+  }
+
+  public static void errorIntroduction() {
+    println();
+    println("@|red There are issues with entered data, please revise your input:|@");
+  }
+
+  private FormFiller() {
+    // Do not instantiate
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/utils/SubmissionDisplayer.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/SubmissionDisplayer.java b/shell/src/main/java/org/apache/sqoop/shell/utils/SubmissionDisplayer.java
new file mode 100644
index 0000000..1f61fb2
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/SubmissionDisplayer.java
@@ -0,0 +1,148 @@
+/**
+ * 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.apache.sqoop.shell.utils;
+
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.shell.core.Constants;
+import org.apache.sqoop.submission.SubmissionStatus;
+import org.apache.sqoop.submission.counter.Counter;
+import org.apache.sqoop.submission.counter.CounterGroup;
+import org.apache.sqoop.submission.counter.Counters;
+
+import java.text.SimpleDateFormat;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+
+/**
+ * Class used for displaying or printing the submission details
+ */
+public final class SubmissionDisplayer {
+
+  private final static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
+
+  /**
+   * On job submission, displays the initial job info
+   * @param submission
+   */
+  public static void displayHeader(MSubmission submission) {
+    println("@|bold "+ resourceString(Constants.RES_SUBMISSION_SUBMISSION_DETAIL) +"|@");
+
+    print(resourceString(Constants.RES_SUBMISSION_JOB_ID)+": ");
+    println(submission.getJobId());
+
+    print(resourceString(Constants.RES_SUBMISSION_SERVER_URL)+": ");
+    println(getServerUrl());
+
+    print(resourceString(Constants.RES_SUBMISSION_CREATION_DATE)+": ");
+    println(dateFormat.format(submission.getCreationDate()));
+
+    String externalId = submission.getExternalId();
+    if(externalId != null) {
+      print(resourceString(Constants.RES_SUBMISSION_EXTERNAL_ID)+": ");
+      println(externalId);
+
+      String externalLink = submission.getExternalLink();
+      if(externalLink != null) {
+        println("\t" + externalLink);
+      }
+    }
+
+    if(isVerbose() && submission.getConnectorSchema() != null) {
+      print(resourceString(Constants.RES_CONNECTOR_SCHEMA)+": ");
+      println(submission.getConnectorSchema());
+    }
+
+    if(isVerbose() && submission.getHioSchema() != null) {
+      print(resourceString(Constants.RES_HIO_SCHEMA)+": ");
+      println(submission.getHioSchema());
+    }
+  }
+
+  /**
+   * Displays the progress of the executing job
+   * @param submission
+   */
+  public static void displayProgress(MSubmission submission) {
+    StringBuilder sb = new StringBuilder();
+    if(submission.getStatus().isRunning()) {
+      sb.append(dateFormat.format(submission.getLastUpdateDate())+": @|green "+submission.getStatus()+ " |@");
+      double progress = submission.getProgress();
+      sb.append(" - ");
+      if(progress == -1) {
+        sb.append(resourceString(Constants.RES_SUBMISSION_PROGRESS_NOT_AVAIL));
+      } else {
+        sb.append(String.format("%.2f %%", progress * 100));
+      }
+    } else {
+      sb.append(dateFormat.format(submission.getLastUpdateDate())+": "+submission.getStatus());
+    }
+
+    println(sb.toString());
+  }
+
+  /**
+   * On successfull or error, method is invoked
+   * @param submission
+   */
+  public static void displayFooter(MSubmission submission) {
+    if (submission.getStatus().toString().equals(SubmissionStatus.SUCCEEDED.toString())) {
+      println(dateFormat.format(submission.getLastUpdateDate())+": @|green "+submission.getStatus()+ " |@");
+      Counters counters = submission.getCounters();
+      if (counters != null) {
+        println(resourceString(Constants.RES_SUBMISSION_COUNTERS) + ":");
+        for (CounterGroup group : counters) {
+          print("\t");
+          println(group.getName());
+          for (Counter counter : group) {
+            print("\t\t");
+            print(counter.getName());
+            print(": ");
+            println(counter.getValue());
+          }
+        }
+        println(resourceString(Constants.RES_SUBMISSION_EXECUTED_SUCCESS));
+      }
+    } else {
+      if (submission.getStatus().isFailure()) {
+        println(dateFormat.format(submission.getLastUpdateDate())+": @|red "+submission.getStatus()+ " |@");
+      } else {
+        println(dateFormat.format(submission.getLastUpdateDate())+": "+submission.getStatus());
+      }
+      // Exception handling
+      if (submission.getExceptionInfo() != null) {
+        print("@|red Exception: |@");
+        println(submission.getExceptionInfo());
+
+        if (isVerbose() && submission.getExceptionStackTrace() != null) {
+          print("@|bold Stack trace: |@");
+          println(submission.getExceptionStackTrace());
+        }
+      }
+    }
+  }
+
+  public static void displaySubmission(MSubmission submission) {
+    if(submission.getStatus().isFailure() || submission.getStatus().equals(SubmissionStatus.SUCCEEDED)) {
+      SubmissionDisplayer.displayHeader(submission);
+      SubmissionDisplayer.displayFooter(submission);
+    } else {
+      SubmissionDisplayer.displayHeader(submission);
+      SubmissionDisplayer.displayProgress(submission);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/21c1207b/shell/src/main/java/org/apache/sqoop/shell/utils/TableDisplayer.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/TableDisplayer.java b/shell/src/main/java/org/apache/sqoop/shell/utils/TableDisplayer.java
new file mode 100644
index 0000000..51030d0
--- /dev/null
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/TableDisplayer.java
@@ -0,0 +1,141 @@
+/**
+ * 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.apache.sqoop.shell.utils;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.apache.sqoop.shell.ShellEnvironment.*;
+
+/**
+ * Display table based data
+ */
+public class TableDisplayer {
+
+  /**
+   * Display given columns in nice table structure to given IO object.
+   *
+   * @param headers List of headers
+   * @param columns Array of columns
+   */
+  public static void display(List<String> headers, List<String> ...columns) {
+    assert headers != null;
+    assert columns != null;
+    assert headers.size() == columns.length;
+
+    // Count of columns
+    int columnCount = headers.size();
+
+    // List of all maximal widths of each column
+    List<Integer> widths = new LinkedList<Integer>();
+    for(int i = 0; i < columnCount; i++) {
+      widths.add(getMaximalWidth(headers.get(i), columns[i]));
+    }
+
+    // First line is border
+    drawLine(widths);
+
+    // Print out header (text is centralised)
+    print("| ");
+    for(int i = 0 ; i < columnCount; i++) {
+      print(StringUtils.center(headers.get(i), widths.get(i), ' '));
+      print((i == columnCount -1) ? " |" : " | ");
+    }
+    println();
+
+    // End up header by border
+    drawLine(widths);
+
+    // Number of rows in the table
+    int rows = getMaximalRows(columns);
+
+    // Print out each row
+    for(int row = 0 ; row < rows; row++) {
+      print("| ");
+      for(int i = 0 ; i < columnCount; i++) {
+        print(StringUtils.rightPad(columns[i].get(row), widths.get(i), ' '));
+        print((i == columnCount -1) ? " |" : " | ");
+      }
+      println();
+    }
+
+    // End table by final border
+    drawLine(widths);
+  }
+
+  /**
+   * Draw border line
+   *
+   * @param widths List of widths of each column
+   */
+  private static void drawLine(List<Integer> widths) {
+    int last = widths.size() - 1;
+    print("+-");
+    for(int i = 0; i < widths.size(); i++) {
+      print(StringUtils.repeat("-", widths.get(i)));
+      print((i == last) ? "-+" : "-+-");
+    }
+    println();
+  }
+
+  /**
+   * Get maximal width for given column with it's associated header.
+   *
+   * @param header Associated header
+   * @param column All column values
+   * @return Maximal
+   */
+  private static int getMaximalWidth(String header, List<String> column) {
+    assert header != null;
+    assert column != null;
+
+    int max = header.length();
+
+    for(String value : column) {
+      if(value != null && value.length() > max) {
+        max = value.length();
+      }
+    }
+
+    return max;
+  }
+
+  /**
+   * Get maximal number of rows available in the column list
+   *
+   * @param columns Array with all column values
+   * @return
+   */
+  private static int getMaximalRows(List<String>... columns) {
+    int max = 0;
+
+    for(List<String> column : columns) {
+      if(column.size() > max) {
+        max = column.size();
+      }
+    }
+
+    return max;
+  }
+
+  private TableDisplayer() {
+    // Instantiation is prohibited
+  }
+}