Repository: sqoop
Updated Branches:
  refs/heads/sqoop2 66989a6ec -> 9f69badd9


SQOOP-2462: Sqoop2: Provide List type for configuration objects

(Dian Fu via Jarek Jarcec Cecho)


Project: http://git-wip-us.apache.org/repos/asf/sqoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/sqoop/commit/9f69badd
Tree: http://git-wip-us.apache.org/repos/asf/sqoop/tree/9f69badd
Diff: http://git-wip-us.apache.org/repos/asf/sqoop/diff/9f69badd

Branch: refs/heads/sqoop2
Commit: 9f69badd9625adbfdbc8c719906f58de888bf54a
Parents: 66989a6
Author: Jarek Jarcec Cecho <[email protected]>
Authored: Wed Sep 9 15:49:02 2015 +0200
Committer: Jarek Jarcec Cecho <[email protected]>
Committed: Wed Sep 9 15:49:02 2015 +0200

----------------------------------------------------------------------
 .../json/util/ConfigInputSerialization.java     |   5 +
 .../org/apache/sqoop/model/ConfigUtils.java     |   2 +
 .../java/org/apache/sqoop/model/MConfig.java    |   4 +
 .../org/apache/sqoop/model/MConfigList.java     |   4 +
 .../java/org/apache/sqoop/model/MInputType.java |   3 +
 .../java/org/apache/sqoop/model/MListInput.java | 116 +++++++++++++++++++
 .../json/util/TestConfigSerialization.java      |   9 ++
 .../org/apache/sqoop/model/TestMConfig.java     |   3 +
 .../org/apache/sqoop/model/TestMConfigList.java |   3 +
 .../org/apache/sqoop/model/TestMListInput.java  | 116 +++++++++++++++++++
 .../common/CommonRepositoryHandler.java         |   7 ++
 .../sqoop/shell/utils/ConfigDisplayer.java      |  17 +++
 .../apache/sqoop/shell/utils/ConfigFiller.java  | 102 ++++++++++++++++
 13 files changed, 391 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/json/util/ConfigInputSerialization.java
----------------------------------------------------------------------
diff --git 
a/common/src/main/java/org/apache/sqoop/json/util/ConfigInputSerialization.java 
b/common/src/main/java/org/apache/sqoop/json/util/ConfigInputSerialization.java
index 0d40715..e2e5b67 100644
--- 
a/common/src/main/java/org/apache/sqoop/json/util/ConfigInputSerialization.java
+++ 
b/common/src/main/java/org/apache/sqoop/json/util/ConfigInputSerialization.java
@@ -29,6 +29,7 @@ import org.apache.sqoop.model.MConfigType;
 import org.apache.sqoop.model.MInput;
 import org.apache.sqoop.model.MInputType;
 import org.apache.sqoop.model.MIntegerInput;
+import org.apache.sqoop.model.MListInput;
 import org.apache.sqoop.model.MLongInput;
 import org.apache.sqoop.model.MMapInput;
 import org.apache.sqoop.model.MStringInput;
@@ -182,6 +183,10 @@ public final class ConfigInputSerialization {
         mInput = new MEnumInput(name, sensitive.booleanValue(), editable, 
overrides, values.split(","));
         break;
       }
+      case LIST: {
+        mInput = new MListInput(name, sensitive.booleanValue(), editable, 
overrides);
+        break;
+      }
       default:
         // do nothing
         break;

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java 
b/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
index b4146a7..5d53437 100644
--- a/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
+++ b/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
@@ -167,6 +167,8 @@ public class  ConfigUtils {
         } else if (type.isEnum()) {
           input = new MEnumInput(inputName, sensitive, editable, overrides,
               ClassUtils.getEnumStrings(type));
+        } else if (type.isAssignableFrom(List.class)) {
+          input = new MListInput(inputName, sensitive, editable, overrides);
         } else {
           throw new SqoopException(ModelError.MODEL_004, "Unsupported type "
               + type.getName() + " for input " + fieldName);

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/model/MConfig.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/MConfig.java 
b/common/src/main/java/org/apache/sqoop/model/MConfig.java
index 9e12979..6f11d92 100644
--- a/common/src/main/java/org/apache/sqoop/model/MConfig.java
+++ b/common/src/main/java/org/apache/sqoop/model/MConfig.java
@@ -98,6 +98,10 @@ public final class MConfig extends MValidatedElement 
implements MClonable {
     return (MMapInput)getInput(inputName);
   }
 
+  public MListInput getListInput(String inputName) {
+    return (MListInput)getInput(inputName);
+  }
+
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder("config-").append(getName());

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/model/MConfigList.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/MConfigList.java 
b/common/src/main/java/org/apache/sqoop/model/MConfigList.java
index d09434a..2a3c3e4 100644
--- a/common/src/main/java/org/apache/sqoop/model/MConfigList.java
+++ b/common/src/main/java/org/apache/sqoop/model/MConfigList.java
@@ -89,6 +89,10 @@ public class MConfigList implements MClonable {
     return (MBooleanInput) getInput(name);
   }
 
+  public MListInput getListInput(String name) {
+    return (MListInput) getInput(name);
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/model/MInputType.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/MInputType.java 
b/common/src/main/java/org/apache/sqoop/model/MInputType.java
index 7e6b90a..0f1fe0a 100644
--- a/common/src/main/java/org/apache/sqoop/model/MInputType.java
+++ b/common/src/main/java/org/apache/sqoop/model/MInputType.java
@@ -48,5 +48,8 @@ public enum MInputType {
   /** Long input type */
   LONG,
 
+  /** List input type */
+  LIST,
+
   ;
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/main/java/org/apache/sqoop/model/MListInput.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/MListInput.java 
b/common/src/main/java/org/apache/sqoop/model/MListInput.java
new file mode 100644
index 0000000..04dbaf2
--- /dev/null
+++ b/common/src/main/java/org/apache/sqoop/model/MListInput.java
@@ -0,0 +1,116 @@
+/**
+ * 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.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sqoop.classification.InterfaceAudience;
+import org.apache.sqoop.classification.InterfaceStability;
+import org.apache.sqoop.utils.UrlSafeUtils;
+
[email protected]
[email protected]
+public class MListInput extends MInput<List<String>> {
+
+  public MListInput(String name, boolean sensitive, InputEditable editable, 
String overrides) {
+    super(name, sensitive, editable, overrides);
+  }
+
+  @Override
+  public String getUrlSafeValueString() {
+    List<String> valueList = getValue();
+    if (valueList == null) {
+      return null;
+    }
+    boolean first = true;
+    StringBuilder vsb = new StringBuilder();
+    for (String element : valueList) {
+      if (first) {
+        first = false;
+      } else {
+        vsb.append("&");
+      }
+      vsb.append(UrlSafeUtils.urlEncode(element));
+    }
+    return vsb.toString();
+  }
+
+  @Override
+  public void restoreFromUrlSafeValueString(String valueString) {
+    if (valueString == null) {
+      setValue(null);
+    } else {
+      List<String> valueList = new LinkedList<String>();
+      if (valueString.trim().length() > 0) {
+        for (String element : valueString.split("&")) {
+          valueList.add(UrlSafeUtils.urlDecode(element));
+        }
+      }
+      setValue(valueList);
+    }
+  }
+
+  @Override
+  public MInputType getType() {
+    return MInputType.LIST;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == this) {
+      return true;
+    }
+
+    if (!(other instanceof MListInput)) {
+      return false;
+    }
+
+    MListInput mli = (MListInput) other;
+    return getName().equals(mli.getName());
+  }
+
+  @Override
+  public int hashCode() {
+    return 23 + 31 * getName().hashCode();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return getValue() == null;
+  }
+
+  @Override
+  public void setEmpty() {
+    setValue(null);
+  }
+
+  @Override
+  public Object clone(boolean cloneWithValue) {
+    MListInput copy = new MListInput(getName(), isSensitive(), getEditable(), 
getOverrides());
+    copy.setPersistenceId(getPersistenceId());
+    if(cloneWithValue && this.getValue() != null) {
+      List<String> copyList = new LinkedList<String>();
+      for(String element : this.getValue()) {
+        copyList.add(element);
+      }
+      copy.setValue(copyList);
+    }
+    return copy;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/test/java/org/apache/sqoop/json/util/TestConfigSerialization.java
----------------------------------------------------------------------
diff --git 
a/common/src/test/java/org/apache/sqoop/json/util/TestConfigSerialization.java 
b/common/src/test/java/org/apache/sqoop/json/util/TestConfigSerialization.java
index d2989d3..2a2cfe8 100644
--- 
a/common/src/test/java/org/apache/sqoop/json/util/TestConfigSerialization.java
+++ 
b/common/src/test/java/org/apache/sqoop/json/util/TestConfigSerialization.java
@@ -36,6 +36,7 @@ import org.apache.sqoop.model.MConfigType;
 import org.apache.sqoop.model.MEnumInput;
 import org.apache.sqoop.model.MInput;
 import org.apache.sqoop.model.MIntegerInput;
+import org.apache.sqoop.model.MListInput;
 import org.apache.sqoop.model.MLongInput;
 import org.apache.sqoop.model.MMapInput;
 import org.apache.sqoop.model.MStringInput;
@@ -126,6 +127,9 @@ public class TestConfigSerialization {
     Map<String, String> map = new HashMap<String, String>();
     map.put("A", "B");
 
+    List<String> list = new LinkedList<String>();
+    list.add("C");
+
     // Fill config with all values
     MConfig config = getConfig();
     config.getStringInput("String").setValue("A");
@@ -133,6 +137,7 @@ public class TestConfigSerialization {
     config.getIntegerInput("Integer").setValue(1);
     config.getBooleanInput("Boolean").setValue(true);
     config.getEnumInput("Enum").setValue("YES");
+    config.getListInput("List").setValue(list);
 
     // Serialize that into JSON
     JSONObject jsonObject = ConfigInputSerialization.extractConfig(config, 
MConfigType.JOB,  false);
@@ -168,6 +173,7 @@ public class TestConfigSerialization {
     assertEquals(1, (int)retrieved.getIntegerInput("Integer").getValue());
     assertEquals(true, 
retrieved.getBooleanInput("Boolean").getValue().booleanValue());
     assertEquals("YES", retrieved.getEnumInput("Enum").getValue());
+    assertEquals(list, retrieved.getListInput("List").getValue());
   }
 
   protected MConfig getMapConfig() {
@@ -211,6 +217,9 @@ public class TestConfigSerialization {
     input = new MEnumInput("Enum", false, InputEditable.ANY, 
StringUtils.EMPTY, new String[] {"YES", "NO"});
     inputs.add(input);
 
+    input = new MListInput("List", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    inputs.add(input);
+
     return new MConfig("c", inputs);
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/test/java/org/apache/sqoop/model/TestMConfig.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/sqoop/model/TestMConfig.java 
b/common/src/test/java/org/apache/sqoop/model/TestMConfig.java
index 2b47c13..2cb3989 100644
--- a/common/src/test/java/org/apache/sqoop/model/TestMConfig.java
+++ b/common/src/test/java/org/apache/sqoop/model/TestMConfig.java
@@ -74,6 +74,7 @@ public class TestMConfig {
         StringUtils.EMPTY, (short) 3);
     MEnumInput enumInput = new MEnumInput("Config.D", false, 
InputEditable.ANY, StringUtils.EMPTY,
         new String[] { "I", "V" });
+    MListInput listInput = new MListInput("Config.E", false, 
InputEditable.ANY, StringUtils.EMPTY );
 
     List<MInput<?>> inputs = new ArrayList<MInput<?>>();
     inputs.add(intInput);
@@ -81,6 +82,7 @@ public class TestMConfig {
     inputs.add(mapInput);
     inputs.add(stringInput);
     inputs.add(enumInput);
+    inputs.add(listInput);
 
     MConfig config = new MConfig("Config", inputs);
     assertEquals(intInput, config.getIntegerInput("Config.A"));
@@ -88,5 +90,6 @@ public class TestMConfig {
     assertEquals(mapInput, config.getMapInput("Config.B"));
     assertEquals(stringInput, config.getStringInput("Config.C"));
     assertEquals(enumInput, config.getEnumInput("Config.D"));
+    assertEquals(listInput, config.getListInput("Config.E"));
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/test/java/org/apache/sqoop/model/TestMConfigList.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/sqoop/model/TestMConfigList.java 
b/common/src/test/java/org/apache/sqoop/model/TestMConfigList.java
index 3dfc33a..fd100b1 100644
--- a/common/src/test/java/org/apache/sqoop/model/TestMConfigList.java
+++ b/common/src/test/java/org/apache/sqoop/model/TestMConfigList.java
@@ -43,10 +43,12 @@ public class TestMConfigList {
         StringUtils.EMPTY, (short) 3);
     MEnumInput enumInput = new MEnumInput("Config2.D", false, 
InputEditable.ANY, StringUtils.EMPTY,
         new String[] { "I", "V" });
+    MListInput listInput = new MListInput("Config2.E", false, 
InputEditable.ANY, StringUtils.EMPTY);
 
     inputs = new ArrayList<MInput<?>>();
     inputs.add(stringInput);
     inputs.add(enumInput);
+    inputs.add(listInput);
     configs.add(new MConfig("Config2", inputs));
 
     MConfigList config = new MConfigList(configs, MConfigType.JOB);
@@ -54,5 +56,6 @@ public class TestMConfigList {
     assertEquals(mapInput, config.getMapInput("Config1.B"));
     assertEquals(stringInput, config.getStringInput("Config2.C"));
     assertEquals(enumInput, config.getEnumInput("Config2.D"));
+    assertEquals(listInput, config.getListInput("Config2.E"));
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/common/src/test/java/org/apache/sqoop/model/TestMListInput.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/sqoop/model/TestMListInput.java 
b/common/src/test/java/org/apache/sqoop/model/TestMListInput.java
new file mode 100644
index 0000000..decf927
--- /dev/null
+++ b/common/src/test/java/org/apache/sqoop/model/TestMListInput.java
@@ -0,0 +1,116 @@
+/**
+ * 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.model;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.testng.annotations.Test;
+
+/**
+ * Test class for org.apache.sqoop.model.MListInput
+ */
+public class TestMListInput {
+  /**
+   * Test for class initialization
+   */
+  @Test
+  public void testInitialization() {
+    MListInput input = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    assertEquals("sqoopsqoop", input.getName());
+    assertEquals(MInputType.LIST, input.getType());
+  }
+
+  /**
+   * Test for equals() method
+   */
+  @Test
+  public void testEquals() {
+    // Positive test
+    MListInput input1 = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    MListInput input2 = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    assertTrue(input1.equals(input2));
+
+    // Negative test
+    MListInput input3 = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    MListInput input4 = new MListInput("sqoopsqoop1", false, 
InputEditable.ANY, StringUtils.EMPTY);
+    assertFalse(input3.equals(input4));
+  }
+
+  /**
+   * Test for value
+   */
+  @Test
+  public void testValue() {
+    MListInput input1 = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    List<String> list = new LinkedList<String>();
+    input1.setValue(list);
+    assertEquals(list, input1.getValue());
+    input1.setEmpty();
+    assertNull(input1.getValue());
+  }
+
+  /**
+   * Test for getUrlSafeValueString() and restoreFromUrlSafeValueString()
+   */
+  @Test
+  public void testUrlSafe() {
+    MListInput input1 = new MListInput("sqoopsqoop", false, InputEditable.ANY, 
StringUtils.EMPTY);
+    List<String> list = new LinkedList<String>();
+    input1.setValue(list);
+    // Getting URL safe string
+    String tmp = input1.getUrlSafeValueString();
+    // Restore to actual value
+    input1.restoreFromUrlSafeValueString(tmp);
+    assertNotNull(input1.getValue());
+    assertEquals(0, input1.getValue().size());
+
+    input1.setValue(null);
+    tmp = input1.getUrlSafeValueString();
+    input1.restoreFromUrlSafeValueString(tmp);
+    assertNull(input1.getValue());
+  }
+
+  /**
+   * Test case for MNamedElement.getLabelKey() and MNamedElement.getHelpKey()
+   */
+  @Test
+  public void testNamedElement() {
+    MListInput input1 = new MListInput("sqoopsqoop", true, InputEditable.ANY, 
StringUtils.EMPTY);
+    assertEquals("sqoopsqoop.label", input1.getLabelKey());
+    assertEquals("sqoopsqoop.help", input1.getHelpKey());
+  }
+
+  /**
+   * Test for sensitivity
+   */
+  @Test
+  public void testSensitivity() {
+    MListInput input1 = new MListInput("NAME", false, InputEditable.ANY, 
StringUtils.EMPTY );
+    MListInput input2 = new MListInput("NAME", true, InputEditable.ANY, 
StringUtils.EMPTY );
+    assertFalse(input1.isSensitive());
+    assertTrue(input2.isSensitive());
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/repository/repository-common/src/main/java/org/apache/sqoop/repository/common/CommonRepositoryHandler.java
----------------------------------------------------------------------
diff --git 
a/repository/repository-common/src/main/java/org/apache/sqoop/repository/common/CommonRepositoryHandler.java
 
b/repository/repository-common/src/main/java/org/apache/sqoop/repository/common/CommonRepositoryHandler.java
index 46235be..6d303c8 100644
--- 
a/repository/repository-common/src/main/java/org/apache/sqoop/repository/common/CommonRepositoryHandler.java
+++ 
b/repository/repository-common/src/main/java/org/apache/sqoop/repository/common/CommonRepositoryHandler.java
@@ -59,6 +59,7 @@ import org.apache.sqoop.model.MIntegerInput;
 import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
 import org.apache.sqoop.model.MLinkConfig;
+import org.apache.sqoop.model.MListInput;
 import org.apache.sqoop.model.MLongInput;
 import org.apache.sqoop.model.MMapInput;
 import org.apache.sqoop.model.MStringInput;
@@ -1978,6 +1979,9 @@ public abstract class CommonRepositoryHandler extends 
JdbcRepositoryHandler {
               case ENUM:
                 input = new MEnumInput(inputName, inputSensitivity, 
editableEnum, overrides, inputEnumValues.split(","));
                 break;
+              case LIST:
+                input = new MListInput(inputName, inputSensitivity, 
editableEnum, overrides);
+                break;
               default:
                 throw new SqoopException(CommonRepositoryError.COMMON_0003,
                         "input-" + inputName + ":" + inputId + ":"
@@ -2121,6 +2125,9 @@ public abstract class CommonRepositoryHandler extends 
JdbcRepositoryHandler {
                 input = new MEnumInput(inputName, inputSensitivity, 
editableEnum, overrides,
                         inputEnumValues.split(","));
                 break;
+              case LIST:
+                input = new MListInput(inputName, inputSensitivity, 
editableEnum, overrides);
+                break;
               default:
                 throw new SqoopException(CommonRepositoryError.COMMON_0003, 
"input-" + inputName + ":"
                         + inputId + ":" + "config-" + inputConfig + ":" + 
mit.name());

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigDisplayer.java
----------------------------------------------------------------------
diff --git 
a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigDisplayer.java 
b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigDisplayer.java
index 6540a52..ab442fe 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigDisplayer.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigDisplayer.java
@@ -40,6 +40,7 @@ import org.apache.sqoop.model.MInputType;
 import org.apache.sqoop.model.MIntegerInput;
 import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
+import org.apache.sqoop.model.MListInput;
 import org.apache.sqoop.model.MLongInput;
 import org.apache.sqoop.model.MMapInput;
 import org.apache.sqoop.model.MStringInput;
@@ -202,6 +203,9 @@ public final class ConfigDisplayer {
             case ENUM:
               displayInputEnum((MEnumInput) input);
               break;
+            case LIST:
+              displayInputList((MListInput) input);
+              break;
             default:
               print("\n%s " + input.getType(), 
resourceString(Constants.RES_CONFIG_DISPLAYER_UNSUPPORTED_DATATYPE));
               return;
@@ -272,6 +276,19 @@ public final class ConfigDisplayer {
     print(input.getValue());
   }
 
+  /**
+   * Display content of List input
+   *
+   * @param input List input
+   */
+  private static void displayInputList(MListInput input) {
+    for (String element : input.getValue()) {
+      println();
+      print("      ");
+      print(element);
+    }
+  }
+
   private ConfigDisplayer() {
     // Do not instantiate
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/9f69badd/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java 
b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java
index 8b5f380..b45d8df 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java
@@ -29,6 +29,7 @@ import org.apache.sqoop.model.MEnumInput;
 import org.apache.sqoop.model.MConfig;
 import org.apache.sqoop.model.MInput;
 import org.apache.sqoop.model.MIntegerInput;
+import org.apache.sqoop.model.MListInput;
 import org.apache.sqoop.model.MLongInput;
 import org.apache.sqoop.model.MMapInput;
 import org.apache.sqoop.model.MJob;
@@ -39,6 +40,7 @@ import org.apache.sqoop.validation.Message;
 import org.apache.sqoop.validation.Status;
 
 import java.io.IOException;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
@@ -197,6 +199,9 @@ public final class ConfigFiller {
     case ENUM:
       assert input instanceof MEnumInput;
       return fillInputEnum(prefix, (MEnumInput) input, line);
+    case LIST:
+      assert input instanceof MListInput;
+      return fillInputList(prefix, (MListInput) input, line);
     default:
       println("Unsupported data type " + input.getType());
       return true;
@@ -204,6 +209,35 @@ public final class ConfigFiller {
   }
 
   /**
+   * Load CLI options for list type.
+   *
+   * Parses elements that take the config "<element1>&<element2>&...".
+   *
+   * @param prefix placed at the beginning of the CLI option key
+   * @param input Input that we should read or edit
+   * @param line CLI options container
+   * @return
+   * @throws IOException
+   */
+  private static boolean fillInputList(String prefix,
+                                       MListInput input,
+                                       CommandLine line)
+                                       throws IOException {
+    String opt = ConfigOptions.getOptionKey(prefix, input);
+    if (line.hasOption(opt)) {
+      String value = line.getOptionValue(opt);
+      List<String> values = new LinkedList<String>();
+      for (String element : value.split("&")) {
+        values.add(element);
+      }
+      input.setValue(values);
+    } else {
+      input.setEmpty();
+    }
+    return true;
+  }
+
+  /**
    * Load CLI option for enum type.
    *
    * Currently only supports numeric values.
@@ -503,6 +537,8 @@ public final class ConfigFiller {
         return fillInputMapWithBundle((MMapInput) input, reader, bundle);
       case ENUM:
         return fillInputEnumWithBundle((MEnumInput) input, reader, bundle);
+      case LIST:
+        return fillInputListWithBundle((MListInput) input, reader, bundle);
       default:
         println("Unsupported data type " + input.getType());
         return true;
@@ -510,6 +546,72 @@ public final class ConfigFiller {
   }
 
   /**
+   * Load user input for list type.
+   *
+   * This implementation will load one element at a time. If user did not
+   * enter anything (empty input) finish loading and return from function.
+   *
+   * @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 fillInputListWithBundle(MListInput input,
+                                       ConsoleReader reader,
+                                       ResourceBundle bundle)
+                                       throws IOException {
+    // Special prompt in List case
+    println(bundle.getString(input.getLabelKey()) + ": ");
+
+    // Internal loading list
+    List<String> values = input.getValue();
+    if(values == null) {
+      values = new LinkedList<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 list:");
+      if (!input.isSensitive()) {
+        for(String value : values) {
+          println(value);
+        }
+      }
+
+      // Special prompt for List element
+      reader.printString("element# ");
+      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 List input, either set input empty
+        // if there are no elements or propagate elements to the input
+        if(values.size() == 0) {
+          input.setEmpty();
+        } else {
+          input.setValue(values);
+        }
+        return true;
+      } else {
+        values.add(userTyped);
+      }
+
+    }
+  }
+
+  /**
    * Load user input for enum type.
    *
    * Print out numbered list of all available options and let user choose one

Reply via email to