You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lens.apache.org by am...@apache.org on 2015/05/07 07:45:05 UTC

[2/2] incubator-lens git commit: LENS-256 : lens-cli should not use single parameter for two values (Rajat Khandelwal via amareshwari)

LENS-256 : lens-cli should not use single parameter for two values (Rajat Khandelwal via amareshwari)


Project: http://git-wip-us.apache.org/repos/asf/incubator-lens/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-lens/commit/10917c25
Tree: http://git-wip-us.apache.org/repos/asf/incubator-lens/tree/10917c25
Diff: http://git-wip-us.apache.org/repos/asf/incubator-lens/diff/10917c25

Branch: refs/heads/master
Commit: 10917c25e4bd1ddaceef242836a25bb555e3e95e
Parents: 9b51b46
Author: Rajat Khandelwal <pr...@apache.org>
Authored: Thu May 7 11:14:26 2015 +0530
Committer: Amareshwari Sriramadasu <am...@apache.org>
Committed: Thu May 7 11:14:26 2015 +0530

----------------------------------------------------------------------
 .../lens/cli/commands/BaseLensCommand.java      |  47 +-
 .../lens/cli/commands/LensCRUDCommand.java      |  75 +++
 .../LensCRUDStoragePartitionCommand.java        | 114 +++++
 .../cli/commands/LensConnectionCommands.java    |  92 ++--
 .../lens/cli/commands/LensCubeCommands.java     | 145 +++---
 .../lens/cli/commands/LensDatabaseCommands.java |  73 +--
 .../cli/commands/LensDimensionCommands.java     | 131 +++---
 .../commands/LensDimensionTableCommands.java    | 459 ++++++++-----------
 .../lens/cli/commands/LensFactCommands.java     | 427 ++++++++---------
 .../cli/commands/LensNativeTableCommands.java   |  55 ++-
 .../lens/cli/commands/LensQueryCommands.java    | 180 ++++----
 .../lens/cli/commands/LensStorageCommands.java  | 111 ++---
 .../commands/annotations/UserDocumentation.java |  29 ++
 .../META-INF/spring/spring-shell-plugin.xml     |  24 +-
 .../apache/lens/cli/TestLensCubeCommands.java   |   6 +-
 .../lens/cli/TestLensDatabaseCommands.java      |   2 +-
 .../lens/cli/TestLensDimensionCommands.java     |   2 +-
 .../cli/TestLensDimensionTableCommands.java     |  51 ++-
 .../apache/lens/cli/TestLensFactCommands.java   |  40 +-
 .../apache/lens/cli/TestLensQueryCommands.java  |  10 +-
 .../lens/cli/TestLensStorageCommands.java       |   2 +-
 .../lens/cli/doc/TestGenerateCLIUserDoc.java    | 126 +++++
 lens-cli/src/test/resources/cli-intro.apt       |  78 ++++
 src/site/apt/user/cli.apt                       | 289 ++++++++----
 tools/scripts/generate-site-public.sh           |   2 +-
 25 files changed, 1540 insertions(+), 1030 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/BaseLensCommand.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/BaseLensCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/BaseLensCommand.java
index bf90cdc..8707fec 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/BaseLensCommand.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/BaseLensCommand.java
@@ -18,6 +18,7 @@
  */
 package org.apache.lens.cli.commands;
 
+import java.io.File;
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -35,11 +36,15 @@ import org.codehaus.jackson.impl.Indenter;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
 import org.codehaus.jackson.util.DefaultPrettyPrinter;
+import org.springframework.shell.core.ExecutionProcessor;
+import org.springframework.shell.event.ParseResult;
+
+import com.google.common.collect.Sets;
 
 /**
  * The Class BaseLensCommand.
  */
-public class BaseLensCommand {
+public class BaseLensCommand implements ExecutionProcessor {
 
   /** The mapper. */
   protected ObjectMapper mapper;
@@ -134,4 +139,44 @@ public class BaseLensCommand {
     return json.replaceAll("\\[ \\{", "\n\n ").replaceAll("\\{", "").replaceAll("}", "").replaceAll("\\[", "")
       .replaceAll("]", "\n").replaceAll(",", "").replaceAll("\"", "").replaceAll("\n\n", "\n");
   }
+
+  public String getValidPath(String path) {
+    if (path.startsWith("~")) {
+      path = path.replaceFirst("~", System.getProperty("user.home"));
+    }
+    File f = new File(path);
+    if (!f.exists()) {
+      throw new RuntimeException("Path " + path + " doesn't exist.");
+    }
+    return f.getAbsolutePath();
+  }
+
+
+  /**
+   * This Code piece allows lens cli to be able to parse list arguments. It can already parse keyword args.
+   * More details at https://github.com/spring-projects/spring-shell/issues/72
+   * @param parseResult
+   * @return
+   */
+  @Override
+  public ParseResult beforeInvocation(ParseResult parseResult) {
+    Object[] args = parseResult.getArguments();
+    if (args != null && Sets.newHashSet(args).size() == 1) {
+      if (args[0] instanceof String) {
+        String[] split = ((String) args[0]).split("\\s+");
+        Object[] newArgs = new String[args.length];
+        System.arraycopy(split, 0, newArgs, 0, split.length);
+        parseResult = new ParseResult(parseResult.getMethod(), parseResult.getInstance(), newArgs);
+      }
+    }
+    return parseResult;
+  }
+
+  @Override
+  public void afterReturningInvocation(ParseResult parseResult, Object o) {
+  }
+
+  @Override
+  public void afterThrowingInvocation(ParseResult parseResult, Throwable throwable) {
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDCommand.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDCommand.java
new file mode 100644
index 0000000..05922e3
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDCommand.java
@@ -0,0 +1,75 @@
+/**
+ * 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.lens.cli.commands;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.lens.api.APIResult;
+
+import com.google.common.base.Joiner;
+
+public abstract class LensCRUDCommand<T> extends BaseLensCommand {
+
+  // Template methods. overriding classes need a binding to commands so
+  // they can call them directly from their own methods.
+  public String showAll() {
+    List<String> all = getAll();
+    if (all == null || all.isEmpty()) {
+      return "No " + getSingleObjectName() + " found";
+    }
+    return Joiner.on("\n").join(all);
+  }
+
+  public String create(String path, boolean ignoreIfExists) {
+    return doCreate(getValidPath(path), ignoreIfExists).getStatus().toString().toLowerCase();
+  }
+
+  public String describe(String name) {
+    try {
+      return formatJson(mapper.writer(pp).writeValueAsString(doRead(name)));
+    } catch (IOException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  public String update(String entity, String path) {
+    return doUpdate(entity, getValidPath(path)).getStatus().toString().toLowerCase();
+  }
+
+  public String drop(String name, boolean cascade) {
+    return doDelete(name, cascade).getStatus().toString().toLowerCase();
+  }
+
+  public String getSingleObjectName() {
+    return getClass().getSimpleName().substring(4, getClass().getSimpleName().indexOf("Command")).toLowerCase();
+  }
+
+  // Actual operations. Need to be overridden by overriding classes
+
+  public abstract List<String> getAll();
+
+  protected abstract APIResult doCreate(String path, boolean ignoreIfExists);
+
+  protected abstract T doRead(String name);
+
+  public abstract APIResult doUpdate(String name, String path);
+
+  protected abstract APIResult doDelete(String name, boolean cascade);
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java
new file mode 100644
index 0000000..0d53e21
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java
@@ -0,0 +1,114 @@
+/**
+ * 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.lens.cli.commands;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.lens.api.APIResult;
+import org.apache.lens.api.metastore.XPartition;
+import org.apache.lens.api.metastore.XStorageTableElement;
+
+import com.google.common.base.Joiner;
+
+public abstract class LensCRUDStoragePartitionCommand<T> extends LensCRUDCommand<T> {
+  public String showAll(String filter) {
+    List<String> all = getAll(filter);
+    if (all == null || all.isEmpty()) {
+      return "No " + getSingleObjectName() + " found" + (filter == null ? "" : " for " + filter);
+    }
+    return Joiner.on("\n").join(all);
+  }
+
+  public String showAllStorages(String tableName) {
+    String sep = "";
+    StringBuilder sb = new StringBuilder();
+    List<String> storages = getAllStorages(tableName);
+    if (storages != null) {
+      for (String storage : storages) {
+        if (!storage.isEmpty()) {
+          sb.append(sep).append(storage);
+          sep = "\n";
+        }
+      }
+    }
+    String ret = sb.toString();
+    return ret.isEmpty() ? "No storage found for " + tableName : ret;
+  }
+
+  public String addStorage(String tableName, String path) {
+    return doAddStorage(tableName, getValidPath(path)).toString().toLowerCase();
+  }
+
+  public String getStorage(String tableName, String storage) {
+    try {
+      return formatJson(mapper.writer(pp).writeValueAsString(readStorage(tableName, storage)));
+    } catch (IOException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  public String dropStorage(String tableName, String storageName) {
+    return doDropStorage(tableName, storageName).toString().toLowerCase();
+  }
+
+  public String dropAllStorages(String tableName) {
+    return doDropAllStorages(tableName).toString();
+  }
+
+  public String getAllPartitions(String tableName, String storageName, String filter) {
+    try {
+      return formatJson(mapper.writer(pp).writeValueAsString(readAllPartitions(tableName, storageName, filter)));
+    } catch (IOException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  public String addPartition(String tableName, String storageName, String path) {
+    return doAddPartition(tableName, storageName, getValidPath(path)).toString().toLowerCase();
+  }
+
+  public String addPartitions(String tableName, String storageName, String path) {
+    return doAddPartitions(tableName, storageName, getValidPath(path)).toString().toLowerCase();
+  }
+
+  public String dropPartitions(String tableName, String storageName, String filter) {
+    return doDropPartitions(tableName, storageName, filter).toString().toLowerCase();
+  }
+
+  protected abstract List<String> getAll(String filter);
+
+  public abstract List<String> getAllStorages(String name);
+
+  public abstract APIResult doAddStorage(String name, String path);
+
+  protected abstract XStorageTableElement readStorage(String tableName, String storage);
+
+  public abstract APIResult doDropStorage(String tableName, String storageName);
+
+  public abstract APIResult doDropAllStorages(String name);
+
+  protected abstract List<XPartition> readAllPartitions(String tableName, String storageName, String filter);
+
+  protected abstract APIResult doAddPartition(String tableName, String storageName, String path);
+
+  protected abstract APIResult doAddPartitions(String tableName, String storageName, String path);
+
+  protected abstract APIResult doDropPartitions(String tableName, String storageName, String filter);
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensConnectionCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensConnectionCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensConnectionCommands.java
index b6be2e0..d727ecc 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensConnectionCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensConnectionCommands.java
@@ -20,9 +20,11 @@ package org.apache.lens.cli.commands;
 
 import java.util.List;
 
+import javax.ws.rs.ProcessingException;
+
 import org.apache.lens.api.APIResult;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
-import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.ExitShellRequest;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
@@ -34,7 +36,10 @@ import com.google.common.base.Joiner;
  * The Class LensConnectionCommands.
  */
 @Component
-public class LensConnectionCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "Session management",
+  description = "Opening the lens CLI shell is equivalent to open a session with lens server."
+    + "This section provides all the commands available for in shell which are applicable for the full session.")
+public class LensConnectionCommands extends BaseLensCommand {
 
   /**
    * Sets the param.
@@ -42,8 +47,8 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
    * @param keyval the keyval
    * @return the string
    */
-  @CliCommand(value = "set", help = "sets a session parameter.")
-  public String setParam(@CliOption(key = {"", "param"}, mandatory = true, help = "key=val") String keyval) {
+  @CliCommand(value = "set", help = "Assign <value> to session parameter specified with <key> on lens server")
+  public String setParam(@CliOption(key = {""}, mandatory = true, help = "<key>=<value>") String keyval) {
     String[] pair = keyval.split("=");
     if (pair.length != 2) {
       return "Error: Pass parameter as <key>=<value>";
@@ -53,39 +58,25 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
   }
 
   /**
-   * Show parameters.
+   * Gets the param.
    *
-   * @return the string
+   * @param param the param
+   * @return the param
    */
-  @CliCommand(value = "show params", help = "list of all session parameter")
-  public String showParameters() {
-    List<String> params = getClient().getConnectionParam();
-    return Joiner.on("\n").skipNulls().join(params);
+  @CliCommand(value = "get", help = "Fetches and prints session parameter specified with name <key> from lens server")
+  public String getParam(@CliOption(key = {"", "key"}, mandatory = true, help = "<key>") String param) {
+    return Joiner.on("\n").skipNulls().join(getClient().getConnectionParam(param));
   }
 
   /**
-   * List resources.
+   * Show parameters.
    *
    * @return the string
    */
-  @CliCommand(value = "list resources", help = "list all resources from session")
-  public String listResources(@CliOption(key = {"", "type"}, mandatory = false, help = "jar/file") String type) {
-    List<String> resources = getClient().listResources(type);
-    if (resources == null) {
-      return "No resources found";
-    }
-    return Joiner.on("\n").skipNulls().join(resources);
-  }
-
-  /**
-   * Gets the param.
-   *
-   * @param param the param
-   * @return the param
-   */
-  @CliCommand(value = "get", help = "gets value of session parameter")
-  public String getParam(@CliOption(key = {"", "param"}, mandatory = true, help = "param name") String param) {
-    return Joiner.on("\n").skipNulls().join(getClient().getConnectionParam(param));
+  @CliCommand(value = "show params", help = "Fetches and prints all session parameter from lens server")
+  public String showParameters() {
+    List<String> params = getClient().getConnectionParam();
+    return Joiner.on("\n").skipNulls().join(params);
   }
 
   /**
@@ -94,9 +85,9 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
    * @param path the path
    * @return the string
    */
-  @CliCommand(value = "add jar", help = "adds a jar resource to session")
+  @CliCommand(value = "add jar", help = "Adds jar resource to the session")
   public String addJar(
-    @CliOption(key = {"", "param"}, mandatory = true, help = "path to jar on serverside") String path) {
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-jar-on-server-side>") String path) {
     APIResult result = getClient().addJarResource(path);
     return result.getMessage();
   }
@@ -107,9 +98,9 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
    * @param path the path
    * @return the string
    */
-  @CliCommand(value = "remove jar", help = "removes a jar resource from session")
+  @CliCommand(value = "remove jar", help = "Removes a jar resource from session")
   public String removeJar(
-    @CliOption(key = {"", "param"}, mandatory = true, help = "path to jar on serverside") String path) {
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-jar-on-server-side>") String path) {
     APIResult result = getClient().removeJarResource(path);
     return result.getMessage();
   }
@@ -120,9 +111,9 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
    * @param path the path
    * @return the string
    */
-  @CliCommand(value = "add file", help = "adds a file resource to session")
+  @CliCommand(value = "add file", help = "Adds a file resource to session")
   public String addFile(
-    @CliOption(key = {"", "param"}, mandatory = true, help = "path to file on serverside") String path) {
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-file-on-server-side>") String path) {
     APIResult result = getClient().addFileResource(path);
     return result.getMessage();
   }
@@ -135,19 +126,42 @@ public class LensConnectionCommands extends BaseLensCommand implements CommandMa
    */
   @CliCommand(value = "remove file", help = "removes a file resource from session")
   public String removeFile(
-    @CliOption(key = {"", "param"}, mandatory = true, help = "path to file on serverside") String path) {
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-file-on-server-side>") String path) {
     APIResult result = getClient().removeFileResource(path);
     return result.getMessage();
   }
 
   /**
+   * List resources.
+   *
+   * @return the string
+   */
+  @CliCommand(value = "list resources",
+    help = "list all resources from session. If type is provided, "
+      + " lists resources of type <resource-type>. Valid values for type are jar and file.")
+  public String listResources(@CliOption(key = {"", "type"}, mandatory = false,
+    help = "<resource-type>") String type) {
+    List<String> resources = getClient().listResources(type);
+    if (resources == null) {
+      return "No resources found";
+    }
+    return Joiner.on("\n").skipNulls().join(resources);
+  }
+
+  /**
    * Quit shell.
    *
    * @return the exit shell request
    */
-  @CliCommand(value = {"close"}, help = "Exits the shell")
+  @CliCommand(value = {"close", "bye"}, help = "Releases all resources of the server session and exits the shell")
   public ExitShellRequest quitShell() {
-    closeClientConnection();
-    return ExitShellRequest.NORMAL_EXIT;
+    try {
+      closeClientConnection();
+      return ExitShellRequest.NORMAL_EXIT;
+    } catch (ProcessingException e) {
+      System.out.println(e.getMessage());
+      LOG.error(e);
+      return ExitShellRequest.FATAL_EXIT;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java
index 675e830..095d70d 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java
@@ -18,145 +18,122 @@
  */
 package org.apache.lens.cli.commands;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 
 import org.apache.lens.api.APIResult;
+import org.apache.lens.api.metastore.XCube;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
-import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.springframework.stereotype.Component;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
 /**
  * The Class LensCubeCommands.
  */
 @Component
-public class LensCubeCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "OLAP Data cube metadata management",
+  description = "These commands provide CRUD for cubes")
+public class LensCubeCommands extends LensCRUDCommand<XCube> {
 
   /**
    * Show cubes.
    *
    * @return the string
    */
-  @CliCommand(value = "show cubes", help = "show list of cubes in database")
+  @CliCommand(value = "show cubes", help = "show list of cubes in current database")
   public String showCubes() {
-    List<String> cubes = getClient().getAllCubes();
-    if (cubes != null) {
-      return Joiner.on("\n").join(cubes);
-    } else {
-      return "No Cubes found";
-    }
+    return showAll();
   }
 
   /**
    * Creates the cube.
    *
-   * @param cubeSpec the cube spec
+   * @param path the cube spec
    * @return the string
    */
-  @CliCommand(value = "create cube", help = "Create a new Cube")
+  @CliCommand(value = "create cube", help = "Create a new Cube, taking spec from <path-to-cube-spec-file>")
   public String createCube(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<path to cube-spec file>") String cubeSpec) {
-    File f = new File(cubeSpec);
-
-    if (!f.exists()) {
-      return "cube spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-    APIResult result = getClient().createCube(cubeSpec);
-
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "create cube succeeded";
-    } else {
-      return "create cube failed";
-    }
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-cube-spec-file>") String path) {
+    return create(path, false);
   }
 
   /**
-   * Drop cube.
+   * Describe cube.
    *
-   * @param cube the cube
+   * @param name the cube name
    * @return the string
    */
-  @CliCommand(value = "drop cube", help = "drop cube")
-  public String dropCube(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "cube name to be dropped") String cube) {
-    APIResult result = getClient().dropCube(cube);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped " + cube + "!!!";
-    } else {
-      return "Dropping cube failed";
-    }
+  @CliCommand(value = "describe cube", help = "describe cube with name <cube-name>")
+  public String describeCube(@CliOption(key = {"", "name"}, mandatory = true, help = "<cube-name>") String name) {
+    return describe(name);
   }
 
   /**
    * Update cube.
    *
-   * @param specPair the spec pair
+   * @param name     cube name
+   * @param path path to new spec file
    * @return the string
    */
-  @CliCommand(value = "update cube", help = "update cube")
+  @CliCommand(value = "update cube", help = "update cube <cube-name> with spec from <path-to-cube-spec-file>")
   public String updateCube(
-    @CliOption(key = {"", "cube"}, mandatory = true, help =
-      "<cube-name> <path to cube-spec file>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. create fact <fact spec path> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-
-    if (!f.exists()) {
-      return "Fact spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().updateCube(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Update of " + pair[0] + " succeeded";
-    } else {
-      return "Update of " + pair[0] + " failed";
-    }
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<cube-name>") String name,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-cube-spec-file>") String path) {
+    return update(name, path);
   }
 
   /**
-   * Describe cube.
+   * Drop cube.
    *
-   * @param cubeName the cube name
+   * @param name the cube
    * @return the string
    */
-  @CliCommand(value = "describe cube", help = "describe cube")
-  public String describeCube(@CliOption(key = {"", "cube"}, mandatory = true, help = "<cube-name>") String cubeName) {
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getCube(cubeName)));
-
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-
-    }
+  @CliCommand(value = "drop cube", help = "drop cube <cube-name>")
+  public String dropCube(@CliOption(key = {"", "name"}, mandatory = true, help = "<cube-name>") String name) {
+    return drop(name, false);
   }
 
   /**
-   * Describe cube.
+   * Cube latest date
    *
-   * @param specPair &lt;cube name, timePartition&gt;
+   * @param cube cube name
+   * @param timeDim time dimension name
    * @return the string
    */
-  @CliCommand(value = "cube latestdate", help = "cube get latest")
+  @CliCommand(value = "cube latestdate",
+    help = "get latest date of data available in cube <cube-name> for time dimension <time-dimension-name>")
   public String getLatest(
-    @CliOption(key = {"", "cube"}, mandatory = true, help = "<cube-name> <timePartition>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. cube get latest <cubeName> <timePartition>";
-    }
-    Date dt = getClient().getLatestDateOfCube(pair[0], pair[1]);
+    @CliOption(key = {"", "cube"}, mandatory = true, help = "<cube-name>") String cube,
+    @CliOption(key = {"", "timeDimension"}, mandatory = true, help = "<time-dimension-name>") String timeDim) {
+    Date dt = getClient().getLatestDateOfCube(cube, timeDim);
     return dt == null ? "No Data Available" : formatDate(dt);
   }
+
+  @Override
+  public List<String> getAll() {
+    return getClient().getAllCubes();
+  }
+
+  @Override
+  protected APIResult doCreate(String path, boolean ignoreIfExists) {
+    return getClient().createCube(path);
+  }
+
+  @Override
+  protected APIResult doDelete(String name, boolean cascade) {
+    return getClient().dropCube(name);
+  }
+
+  @Override
+  public APIResult doUpdate(String name, String path) {
+    return getClient().updateCube(name, path);
+  }
+
+  @Override
+  protected XCube doRead(String name) {
+    return getClient().getCube(name);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDatabaseCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDatabaseCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDatabaseCommands.java
index f030d0d..800c0b5 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDatabaseCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDatabaseCommands.java
@@ -21,19 +21,18 @@ package org.apache.lens.cli.commands;
 import java.util.List;
 
 import org.apache.lens.api.APIResult;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
-import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.springframework.stereotype.Component;
 
-import com.google.common.base.Joiner;
-
 /**
  * The Class LensDatabaseCommands.
  */
 @Component
-public class LensDatabaseCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "Database management commands", description = "These commands provide CRUD for databases")
+public class LensDatabaseCommands extends LensCRUDCommand {
 
   /**
    * Show all databases.
@@ -42,12 +41,7 @@ public class LensDatabaseCommands extends BaseLensCommand implements CommandMark
    */
   @CliCommand(value = "show databases", help = "displays list of all databases")
   public String showAllDatabases() {
-    List<String> databases = getClient().getAllDatabases();
-    if (databases != null) {
-      return Joiner.on("\n").join(databases);
-    } else {
-      return "No Dabases found";
-    }
+    return showAll();
   }
 
   /**
@@ -58,7 +52,7 @@ public class LensDatabaseCommands extends BaseLensCommand implements CommandMark
    */
   @CliCommand(value = "use", help = "change to new database")
   public String switchDatabase(
-    @CliOption(key = {"", "db"}, mandatory = true, help = "Database to change to") String database) {
+    @CliOption(key = {"", "db"}, mandatory = true, help = "<database-name>") String database) {
     boolean status = getClient().setDatabase(database);
     if (status) {
       return "Successfully switched to " + database;
@@ -70,20 +64,19 @@ public class LensDatabaseCommands extends BaseLensCommand implements CommandMark
   /**
    * Creates the database.
    *
-   * @param database the database
-   * @param ignore   the ignore
+   * @param database       the database
+   * @param ignoreIfExists the ignore
    * @return the string
    */
-  @CliCommand(value = "create database", help = "create a database with specified name")
+  @CliCommand(value = "create database",
+    help = "create a database with specified name. if <ignore-if-exists> is true, "
+      + "create will not be tried if already exists. Default is false")
   public String createDatabase(
-    @CliOption(key = {"", "db"}, mandatory = true, help = "Database to create") String database,
-    @CliOption(key = {"ignore"}, mandatory = false, unspecifiedDefaultValue = "false") boolean ignore) {
-    APIResult result = getClient().createDatabase(database, ignore);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return ("Create database " + database + " successful");
-    } else {
-      return result.getMessage();
-    }
+    @CliOption(key = {"", "db"}, mandatory = true, help = "<database-name>") String database,
+    @CliOption(key = {"ignoreIfExists"}, mandatory = false, unspecifiedDefaultValue = "false",
+      help = "<ignore-if-exists>") boolean ignoreIfExists) {
+    // first arg is not file. LensCRUDCommand.create expects file path as first arg. So calling method directly here.
+    return doCreate(database, ignoreIfExists).toString().toLowerCase();
   }
 
   /**
@@ -94,13 +87,35 @@ public class LensDatabaseCommands extends BaseLensCommand implements CommandMark
    */
   @CliCommand(value = "drop database", help = "drop a database with specified name")
   public String dropDatabase(@CliOption(key = {"", "db"}, mandatory = true,
-    help = "Database to drop") String database) {
-    APIResult result = getClient().dropDatabase(database);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return ("drop database " + database + " successful");
-    } else {
-      return result.getMessage();
-    }
+    help = "<database-name>") String database) {
+    return drop(database, false);
   }
 
+  @Override
+  public List<String> getAll() {
+    return getClient().getAllDatabases();
+  }
+
+  // Create is directly implemented
+  @Override
+  protected APIResult doCreate(String database, boolean ignoreIfExists) {
+    return getClient().createDatabase(database, ignoreIfExists);
+  }
+
+  // Doesn't make sense for database
+  @Override
+  protected Object doRead(String name) {
+    return null;
+  }
+
+  // Also, doesn't make sense
+  @Override
+  public APIResult doUpdate(String name, String path) {
+    return null;
+  }
+
+  @Override
+  protected APIResult doDelete(String name, boolean cascade) {
+    return getClient().dropDatabase(name);
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java
index 7539ea9..dc44f80 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java
@@ -18,126 +18,113 @@
  */
 package org.apache.lens.cli.commands;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.List;
 
 import org.apache.lens.api.APIResult;
+import org.apache.lens.api.metastore.XDimension;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
-import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.springframework.stereotype.Component;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
 /**
  * The Class LensDimensionCommands.
  */
 @Component
-public class LensDimensionCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "Dimension Management", description = "These commands provide CRUD for Dimensions")
+public class LensDimensionCommands extends LensCRUDCommand<XDimension> {
 
   /**
    * Show dimensions.
    *
    * @return the string
    */
-  @CliCommand(value = "show dimensions", help = "show list of dimensions in database")
+  @CliCommand(value = "show dimensions", help = "show list of all dimensions in current database")
   public String showDimensions() {
-    List<String> dimensions = getClient().getAllDimensions();
-    if (dimensions != null) {
-      return Joiner.on("\n").join(dimensions);
-    } else {
-      return "No Dimensions found";
-    }
+    return showAll();
   }
 
   /**
    * Creates the dimension.
    *
-   * @param dimensionSpec the dimension spec
+   * @param path the dimension spec
    * @return the string
    */
-  @CliCommand(value = "create dimension", help = "Create a new Dimension")
+  @CliCommand(value = "create dimension",
+    help = "Create a new Dimension, taking spec from <path-to-dimension-spec file>")
   public String createDimension(
-    @CliOption(key = {"", "table"}, mandatory = true, help =
-      "<path to dimension-spec file>") String dimensionSpec) {
-    File f = new File(dimensionSpec);
-
-    if (!f.exists()) {
-      return "dimension spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-    APIResult result = getClient().createDimension(dimensionSpec);
-
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "create dimension succeeded";
-    } else {
-      return "create dimension failed";
-    }
+    @CliOption(key = {"", "path"}, mandatory = true, help =
+      "<path-to-dimension-spec file>") String path) {
+    return create(path, false);
   }
 
   /**
-   * Drop dimension.
+   * Describe dimension.
    *
-   * @param dimension the dimension
+   * @param name the dimension name
    * @return the string
    */
-  @CliCommand(value = "drop dimension", help = "drop dimension")
-  public String dropDimension(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "dimension name to be dropped") String dimension) {
-    APIResult result = getClient().dropDimension(dimension);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped " + dimension + "!!!";
-    } else {
-      return "Dropping dimension failed";
+  @CliCommand(value = "describe dimension", help = "describe dimension <dimension-name>")
+  public String describeDimension(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension-name>") String name) {
+    try {
+      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getDimension(name)));
+    } catch (IOException e) {
+      throw new IllegalArgumentException(e);
     }
   }
 
   /**
    * Update dimension.
    *
-   * @param specPair the spec pair
+   * @param name the dimension to be updated
+   * @param path  path to spec fild
    * @return the string
    */
-  @CliCommand(value = "update dimension", help = "update dimension")
+  @CliCommand(value = "update dimension",
+    help = "update dimension <dimension-name>, taking spec from <path-to-dimension-spec file>")
   public String updateDimension(
-    @CliOption(key = {"", "dimension"}, mandatory = true, help
-      = "<dimension-name> <path to dimension-spec file>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. create fact <fact spec path> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-
-    if (!f.exists()) {
-      return "Fact spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().updateDimension(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Update of " + pair[0] + " succeeded";
-    } else {
-      return "Update of " + pair[0] + " failed";
-    }
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension-name>") String name,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-dimension-spec-file>") String path) {
+    return update(name, path);
   }
 
   /**
-   * Describe dimension.
+   * Drop dimension.
    *
-   * @param dimensionName the dimension name
+   * @param name the dimension
    * @return the string
    */
-  @CliCommand(value = "describe dimension", help = "describe dimension")
-  public String describeDimension(
-    @CliOption(key = {"", "dimension"}, mandatory = true, help = "<dimension-name>") String dimensionName) {
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getDimension(dimensionName)));
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-    }
+  @CliCommand(value = "drop dimension", help = "drop dimension <dimension-name>")
+  public String dropDimension(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension-name>") String name) {
+    return drop(name, false);
+  }
+
+  @Override
+  public List<String> getAll() {
+    return getClient().getAllDimensions();
+  }
+
+  @Override
+  protected APIResult doCreate(String path, boolean ignoreIfExists) {
+    return getClient().createDimension(path);
+  }
+
+  @Override
+  protected XDimension doRead(String name) {
+    return getClient().getDimension(name);
+  }
+
+  @Override
+  public APIResult doUpdate(String name, String path) {
+    return getClient().updateDimension(name, path);
+  }
+
+  @Override
+  protected APIResult doDelete(String name, boolean cascade) {
+    return getClient().dropDimension(name);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java
index c3b7f37..d4b7418 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java
@@ -18,375 +18,312 @@
  */
 package org.apache.lens.cli.commands;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.List;
 
 import org.apache.lens.api.APIResult;
+import org.apache.lens.api.metastore.XDimensionTable;
+import org.apache.lens.api.metastore.XPartition;
+import org.apache.lens.api.metastore.XStorageTableElement;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
 import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.springframework.stereotype.Component;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
 /**
  * The Class LensDimensionTableCommands.
  */
 @Component
-public class LensDimensionTableCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "Commands for Dimension Tables",
+  description = "These commands provide CRUD for dimension tables, associated storages, and fact partitions")
+public class LensDimensionTableCommands extends LensCRUDStoragePartitionCommand<XDimensionTable>
+  implements CommandMarker {
 
   /**
    * Show dimension tables.
    *
    * @return the string
    */
-  @CliCommand(value = "show dimtables", help = "show list of dimension tables in database")
+  @CliCommand(value = "show dimtables",
+    help = "display list of dimtables in current database. If optional <dimension-name> is supplied,"
+      + " only facts belonging to dimension <dimension-name> will be displayed")
   public String showDimensionTables(
-    @CliOption(key = {"", "dimension"}, mandatory = false, help = "<optional dimension name>") String dimensionName) {
-    List<String> dims = getClient().getAllDimensionTables(dimensionName);
-    if (dims != null) {
-      return Joiner.on("\n").join(dims);
-    } else {
-      return "No Dimensions Found";
-    }
+    @CliOption(key = {"", "dimension-name"}, mandatory = false, help = "<dimension-name>") String dimensionName) {
+    return showAll(dimensionName);
   }
 
   /**
    * Creates the dimension table.
    *
-   * @param dimSpec Path to dim spec
+   * @param path Path to dim spec
    * @return the string
    */
-  @CliCommand(value = "create dimtable", help = "Create a new dimension table")
+  @CliCommand(value = "create dimtable",
+    help = "Create a new dimension table taking spec from <path-to-dimtable-spec-file>")
   public String createDimensionTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<path to dim-spec>") String dimSpec) {
-
-    File f = new File(dimSpec);
-    if (!f.exists()) {
-      return "dimtable spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().createDimensionTable(dimSpec);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "create dimension table succeeded";
-    } else {
-      return "create dimension table failed";
-    }
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-dimtable-spec-file>") String path) {
+    return create(path, false);
   }
 
   /**
-   * Drop dimension table.
+   * Describe dimension table.
    *
-   * @param dim     the dim
-   * @param cascade the cascade
+   * @param name the dim
    * @return the string
    */
-  @CliCommand(value = "drop dimtable", help = "drop dimension table")
-  public String dropDimensionTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "dimension table name to be dropped") String dim,
-    @CliOption(key = {"cascade"}, mandatory = false, unspecifiedDefaultValue = "false") boolean cascade) {
-    APIResult result = getClient().dropDimensionTable(dim, cascade);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped " + dim + "!!!";
-    } else {
-      return "Dropping " + dim + " table failed";
-    }
+  @CliCommand(value = "describe dimtable", help = "describe dimtable <dimtable-name>")
+  public String describeDimensionTable(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String name) {
+    return describe(name);
   }
 
   /**
    * Update dimension table.
    *
-   * @param specPair the spec pair
+   * @param name the dimtable name
+   * @param path the path to spec file
    * @return the string
    */
-  @CliCommand(value = "update dimtable", help = "update dimension table")
+  @CliCommand(value = "update dimtable",
+    help = "update dimtable <dimtable-name> taking spec from <path-to-dimtable-spec>")
   public String updateDimensionTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<dimension-table-name> <path to table-spec>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following "
-        + "format. create dimtable <dimtable spec path> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-
-    if (!f.exists()) {
-      return "Fact spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().updateDimensionTable(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Update of " + pair[0] + " succeeded";
-    } else {
-      return "Update of " + pair[0] + " failed";
-    }
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String name,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-dimtable-spec>") String path) {
+    return update(name, path);
   }
 
+
   /**
-   * Describe dimension table.
+   * Drop dimension table.
    *
-   * @param dim the dim
+   * @param name    the dim
+   * @param cascade the cascade
    * @return the string
    */
-  @CliCommand(value = "describe dimtable", help = "describe a dimension table")
-  public String describeDimensionTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "dimension table name to be described") String dim) {
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getDimensionTable(dim)));
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-    }
+  @CliCommand(value = "drop dimtable",
+    help = "drop dimtable <dimtable-name>. "
+      + " If <cascade> is true, all the storage tables associated with the dimtable <dimtable-name> are also dropped."
+      + " By default <cascade> is false")
+  public String dropDimensionTable(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String name,
+    @CliOption(key = {"cascade"}, mandatory = false, unspecifiedDefaultValue = "false", help = "<cascade>")
+    boolean cascade) {
+    return drop(name, cascade);
   }
 
   /**
    * Gets the dim storages.
    *
-   * @param dim the dim
+   * @param table the dim
    * @return the dim storages
    */
-  @CliCommand(value = "dimtable list storage", help = "display list of storage associated to dimension table")
+  @CliCommand(value = "dimtable list storages", help = "display list of storage associated to dimtable <dimtable-name>")
   public String getDimStorages(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<table-name> for listing storages") String dim) {
-    List<String> storages = getClient().getDimStorages(dim);
-    StringBuilder sb = new StringBuilder();
-    if (storages != null && !storages.isEmpty()) {
-      for (String storage : storages) {
-        if (!storage.isEmpty()) {
-          sb.append(storage).append("\n");
-        }
-      }
-    }
-
-    if (sb.toString().isEmpty()) {
-      return "No storages found for " + dim;
-    }
-    return sb.toString().substring(0, sb.toString().length() - 1);
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String table) {
+    return showAllStorages(table);
   }
 
   /**
-   * Drop all dim storages.
+   * Adds the new dim storage.
    *
-   * @param table the table
+   * @param tableName dimtable name
+   * @param path      path to storage spec
    * @return the string
    */
-  @CliCommand(value = "dimtable drop-all storages", help = "drop all storages associated to dimension table")
-  public String dropAllDimStorages(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<table-name> for which all storage should be dropped") String table) {
-    APIResult result = getClient().dropAllStoragesOfDim(table);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "All storages of " + table + " dropped successfully";
-    } else {
-      return "Error dropping storages of " + table;
-    }
+  @CliCommand(value = "dimtable add storage",
+    help = "adds a new storage to dimtable <dimtable-name>, taking storage spec from <path-to-storage-spec>")
+  public String addNewDimStorage(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-storage-spec>") String path) {
+    return addStorage(tableName, path);
   }
 
   /**
-   * Adds the new dim storage.
+   * Gets the storage from dim.
    *
-   * @param tablepair the tablepair
-   * @return the string
+   * @param tableName dimtable name
+   * @return path storage spec path
    */
-  @CliCommand(value = "dimtable add storage", help = "adds a new storage to dimension")
-  public String addNewDimStorage(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<dim-table-name> <path to storage-spec>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following "
-        + "format. create dimtable <dimtable spec path> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-    if (!f.exists()) {
-      return "Storage spech path " + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().addStorageToDim(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Dim table storage addition completed";
-    } else {
-      return "Dim table storage addition failed";
-    }
+  @CliCommand(value = "dimtable get storage", help = "describe storage <storage-name> of dimtable <dimtable-name>")
+  public String getStorageFromDim(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storage) {
+    return getStorage(tableName, storage);
   }
 
   /**
    * Drop storage from dim.
    *
-   * @param tablepair the tablepair
+   * @param tableName   dimtable name
+   * @param storageName storage name
    * @return the string
    */
-  @CliCommand(value = "dimtable drop storage", help = "drop storage to dimension table")
+  @CliCommand(value = "dimtable drop storage", help = "drop storage <storage-name> from dimtable <dimtable-name>")
   public String dropStorageFromDim(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<dimension-table-name> <storage-name>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following "
-        + "format. create dimtable <dimtable spec path> <storage spec path>";
-    }
-    APIResult result = getClient().dropStorageFromDim(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Dim table storage removal successful";
-    } else {
-      return "Dim table storage removal failed";
-    }
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName) {
+    return dropStorage(tableName, storageName);
   }
 
   /**
-   * Gets the storage from dim.
+   * Drop all dim storages.
    *
-   * @param tablepair the tablepair
-   * @return the storage from dim
+   * @param tableName the table
+   * @return the string
    */
-  @CliCommand(value = "dimtable get storage", help = "describe storage of dimension table")
-  public String getStorageFromDim(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<dimension-table-name> <storage-name>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following "
-        + "format. create dimtable <dimtable spec path> <storage spec path>";
-    }
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getStorageFromDim(pair[0], pair[1])));
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-    }
+  @CliCommand(value = "dimtable drop all storages", help = "drop all storages associated to dimension table")
+  public String dropAllDimStorages(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName) {
+    return dropAllStorages(tableName);
   }
 
   /**
    * Gets the all partitions of dim.
    *
-   * @param specPair the spec pair
+   * @param tableName   dimtable name
+   * @param storageName storage name
+   * @param filter      partition filter
    * @return the all partitions of dim
    */
-  @CliCommand(value = "dimtable list partitions", help = "get all partitions associated with dimension table")
+  @CliCommand(value = "dimtable list partitions",
+    help = "get all partitions associated with dimtable <dimtable-name>, "
+      + "storage <storage-name> filtered by <partition-filter>")
   public String getAllPartitionsOfDim(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<dimension-table-name> <storageName> "
-      + "[optional <partition query filter> to get]") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length == 2) {
-      try {
-        return formatJson(mapper.writer(pp).writeValueAsString(getClient().getAllPartitionsOfDim(pair[0], pair[1])));
-      } catch (IOException e) {
-        throw new IllegalArgumentException(e);
-      }
-    }
-
-    if (pair.length == 3) {
-      try {
-        return formatJson(mapper.writer(pp).writeValueAsString(
-          getClient().getAllPartitionsOfDim(pair[0], pair[1], pair[2])));
-      } catch (IOException e) {
-        throw new IllegalArgumentException(e);
-      }
-    }
-
-    return "Syntax error, please try in following "
-      + "format. dim list partitions <table> <storage> [partition values]";
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "filter"}, mandatory = false, help = "<partition-filter>") String filter) {
+    return getAllPartitions(tableName, storageName, filter);
   }
 
   /**
    * Drop all partitions of dim.
    *
-   * @param specPair the spec pair
+   * @param tableName   dimtable name
+   * @param storageName storage name
+   * @param filter      partition query filter
    * @return the string
    */
-  @CliCommand(value = "dimtable drop partitions", help = "drop all partitions associated with dimension table")
+  @CliCommand(value = "dimtable drop partitions",
+    help = "drop all partitions associated with dimtable "
+      + "<dimtable-name>, storage <storage-name> filtered by <partition-filter>")
   public String dropAllPartitionsOfDim(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<dimension-table-name> <storageName> "
-      + "[optional <partition query filter> to drop]") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length == 2) {
-      result = getClient().dropAllPartitionsOfDim(pair[0], pair[1]);
-    }
-    if (pair.length == 3) {
-      result = getClient().dropAllPartitionsOfDim(pair[0], pair[1], pair[3]);
-    } else {
-      return "Syntax error, please try in following "
-        + "format. dimtable drop partitions <table> <storage> [partition values]";
-    }
-
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped partition of " + pair[0];
-    } else {
-      return "failure in  dropping partition of " + pair[0];
-    }
-
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "filter"}, mandatory = false, help = "<partition-filter>") String filter) {
+    return dropPartitions(tableName, storageName, filter);
   }
 
   /**
    * Adds the partition to dim table.
    *
-   * @param specPair the spec pair
+   * @param tableName   dimtable name
+   * @param storageName storage name
+   * @param path        partition spec path
    * @return the string
    */
-  @CliCommand(value = "dimtable add single-partition", help = "add a partition to dim table")
-  public String addPartitionToDimTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<dimension-table-name> <storage-name>"
-      + " <path to partition specification>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length != 3) {
-      return "Syntax error, please try in following "
-        + "format. dimtable add single-partition <table> <storage> <partition spec>";
-    }
-
-    File f = new File(pair[2]);
-    if (!f.exists()) {
-      return "Partition spec does not exist";
-    }
-
-    result = getClient().addPartitionToDim(pair[0], pair[1], pair[2]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully added partition to " + pair[0];
-    } else {
-      return "failure in  addition of partition to " + pair[0];
-    }
+  @CliCommand(value = "dimtable add single-partition",
+    help = "add single partition to dimtable <dimtable-name>'s"
+      + " storage <storage-name>, reading spec from <partition-spec-path>")
+  public String addPartitionToDimtable(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<partition-spec-path>") String path) {
+    return addPartition(tableName, storageName, path);
   }
 
   /**
-   * Adds  partitions to dim table.
+   * Adds the partitions to dim table.
    *
-   * @param specPair the spec pair
+   * @param tableName   dimtable name
+   * @param storageName storage name
+   * @param path        partition spec path
    * @return the string
    */
-  @CliCommand(value = "dimtable add partitions", help = "add partitions to dim table")
-  public String addPartitionsToDimTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<dimension-table-name> <storage-name>"
-      + " <path to partitions specification>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length != 3) {
-      return "Syntax error, please try in following "
-        + "format. dimtable add partitions <table> <storage> <partition spec>";
-    }
-
-    File f = new File(pair[2]);
-    if (!f.exists()) {
-      return "Partition spec does not exist";
-    }
-
-    result = getClient().addPartitionsToDim(pair[0], pair[1], pair[2]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully added partition to " + pair[0];
-    } else {
-      return "failure in  addition of partition to " + pair[0];
-    }
+
+  @CliCommand(value = "dimtable add partitions",
+    help = "add multiple partition to dimtable <dimtable-name>'s"
+      + " storage <storage-name>, reading partition list spec from <partition-list-spec-path>")
+  public String addPartitionsToDimtable(
+    @CliOption(key = {"", "dimtable-name"}, mandatory = true, help = "<dimtable-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<partition-list-spec-path>") String path) {
+    return addPartitions(tableName, storageName, path);
+  }
+
+  @Override
+  protected XStorageTableElement readStorage(String tableName, String storage) {
+    return getClient().getStorageFromDim(tableName, storage);
+  }
+
+  @Override
+  public APIResult doDropStorage(String tableName, String storageName) {
+    return getClient().dropStorageFromDim(tableName, storageName);
+  }
+
+
+  @Override
+  public List<String> getAllStorages(String name) {
+    return getClient().getDimStorages(name);
+  }
+
+  @Override
+  public APIResult doAddStorage(String name, String path) {
+    return getClient().addStorageToDim(name, path);
+  }
+
+  @Override
+  public APIResult doDropAllStorages(String name) {
+    return getClient().dropAllStoragesOfDim(name);
+  }
+
+  @Override
+  protected List<XPartition> readAllPartitions(String tableName, String storageName, String filter) {
+    return getClient().getAllPartitionsOfDim(tableName, storageName, filter);
+  }
+
+  @Override
+  protected APIResult doAddPartition(String tableName, String storageName, String path) {
+    return getClient().addPartitionToDim(tableName, storageName, path);
+  }
+
+  @Override
+  protected APIResult doAddPartitions(String tableName, String storageName, String path) {
+    return getClient().addPartitionsToDim(tableName, storageName, path);
+  }
+
+  @Override
+  protected APIResult doDropPartitions(String tableName, String storageName, String filter) {
+    return getClient().dropAllPartitionsOfDim(tableName, storageName, filter);
+  }
+
+  @Override
+  public List<String> getAll() {
+    return getClient().getAllDimensionTables();
+  }
+
+  @Override
+  public List<String> getAll(String dimesionName) {
+    return getClient().getAllDimensionTables(dimesionName);
+  }
+
+  @Override
+  protected APIResult doCreate(String path, boolean ignoreIfExists) {
+    return getClient().createDimensionTable(path);
+  }
+
+  @Override
+  protected XDimensionTable doRead(String name) {
+    return getClient().getDimensionTable(name);
+  }
+
+  @Override
+  public APIResult doUpdate(String name, String path) {
+    return getClient().updateDimensionTable(name, path);
+  }
+
+  @Override
+  protected APIResult doDelete(String name, boolean cascade) {
+    return getClient().dropDimensionTable(name, cascade);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/10917c25/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java
index 1e8abf9..818bd99 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java
@@ -18,352 +18,297 @@
  */
 package org.apache.lens.cli.commands;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.List;
 
 import org.apache.lens.api.APIResult;
+import org.apache.lens.api.metastore.XFactTable;
+import org.apache.lens.api.metastore.XPartition;
+import org.apache.lens.api.metastore.XStorageTableElement;
+import org.apache.lens.cli.commands.annotations.UserDocumentation;
 
-import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.springframework.stereotype.Component;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
 /**
  * The Class LensFactCommands.
  */
 @Component
-public class LensFactCommands extends BaseLensCommand implements CommandMarker {
+@UserDocumentation(title = "Management of Facts",
+  description = "These command provide CRUD for facts, associated storages, and fact partitions")
+public class LensFactCommands extends LensCRUDStoragePartitionCommand<XFactTable> {
 
   /**
    * Show facts.
    *
    * @return the string
    */
-  @CliCommand(value = "show facts", help = "display list of fact tables in database")
+  @CliCommand(value = "show facts",
+    help = "display list of fact tables in current database. "
+      + "If optional <cube-name> is supplied, only facts belonging to cube <cube-name> will be displayed")
   public String showFacts(
-    @CliOption(key = {"", "cube"}, mandatory = false, help = "<optional cube name>") String cubeName) {
-    List<String> facts = getClient().getAllFactTables(cubeName);
-    if (facts != null) {
-      return Joiner.on("\n").join(facts);
-    } else {
-      return "No Facts Found";
-    }
+    @CliOption(key = {"", "cube-name"}, mandatory = false, help = "<cube-name>") String cubeName) {
+    return showAll(cubeName);
   }
 
   /**
    * Creates the fact.
    *
-   * @param factSpecFileName Path to fact spec
+   * @param path Path to fact spec
    * @return the string
    */
-  @CliCommand(value = "create fact", help = "create a fact table")
+  @CliCommand(value = "create fact", help = "create a fact table with spec from <path-to-fact-spec-file>")
   public String createFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<fact spec path>") String factSpecFileName) {
-    File f = new File(factSpecFileName);
-
-    if (!f.exists()) {
-      return "Fact spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-    APIResult result = getClient().createFactTable(factSpecFileName);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Fact table Successfully completed";
-    } else {
-      return "Fact table creation failed";
-    }
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-fact-spec-file>") String path) {
+    return create(path, false);
   }
 
   /**
-   * Drop fact.
+   * Describe fact table.
    *
-   * @param fact    the fact
-   * @param cascade the cascade
+   * @param name the fact
    * @return the string
    */
-  @CliCommand(value = "drop fact", help = "drop fact table")
-  public String dropFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "table name to be dropped") String fact,
-    @CliOption(key = {"cascade"}, mandatory = false, unspecifiedDefaultValue = "false") boolean cascade) {
-    APIResult result = getClient().dropFactTable(fact, cascade);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped " + fact + "!!!";
-    } else {
-      return "Dropping " + fact + " table failed";
-    }
+  @CliCommand(value = "describe fact", help = "describe fact <fact-name>")
+  public String describeFactTable(
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String name) {
+    return describe(name);
   }
 
   /**
    * Update fact table.
    *
-   * @param specPair the spec pair
+   * @param name     fact name to be updated
+   * @param specPath path to the file containing new spec of the fact
    * @return the string
    */
-  @CliCommand(value = "update fact", help = "update fact table")
+  @CliCommand(value = "update fact", help = "update fact <fact-name> taking spec from <path-to-fact-spec>")
   public String updateFactTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<table-name> <path to table-spec>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. create fact <fact spec path> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-
-    if (!f.exists()) {
-      return "Fact spec path" + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().updateFactTable(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Update of " + pair[0] + " succeeded";
-    } else {
-      return "Update of " + pair[0] + " failed";
-    }
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String name,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-fact-spec>") String specPath) {
+    return update(name, specPath);
   }
 
   /**
-   * Describe fact table.
+   * Drop fact.
    *
-   * @param fact the fact
+   * @param fact    the fact
+   * @param cascade the cascade
    * @return the string
    */
-  @CliCommand(value = "describe fact", help = "describe a fact table")
-  public String describeFactTable(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "tablename to be described") String fact) {
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getFactTable(fact)));
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-    }
+  @CliCommand(value = "drop fact",
+    help = "drops fact <fact-name>."
+      + " If <cascade> is true, all the storage tables associated with the fact <fact-name> are also dropped."
+      + " By default <cascade> is false")
+  public String dropFact(
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String fact,
+    @CliOption(key = {"cascade"}, mandatory = false, unspecifiedDefaultValue = "false", help = "<cascade>")
+    boolean cascade) {
+    return drop(fact, cascade);
   }
 
   /**
    * Gets the fact storages.
    *
-   * @param fact the fact
+   * @param tableName the fact
    * @return the fact storages
    */
-  @CliCommand(value = "fact list storage", help = "display list of storages associated to fact table")
+  @CliCommand(value = "fact list storage", help = "display list of storages associated to fact <fact-name>")
   public String getFactStorages(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "tablename for getting storages") String fact) {
-    List<String> storages = getClient().getFactStorages(fact);
-    if (storages == null || storages.isEmpty()) {
-      return "No storages found for " + fact;
-    }
-    return Joiner.on("\n").join(storages);
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName) {
+    return showAllStorages(tableName);
   }
 
   /**
-   * Drop all fact storages.
+   * Adds the new fact storage.
    *
-   * @param table the table
+   * @param tableName the fact name
+   * @param path      the path to storage spec
    * @return the string
    */
-  @CliCommand(value = "fact dropall storages", help = "drop all storages associated to fact table")
-  public String dropAllFactStorages(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "tablename for dropping all storages") String table) {
-    APIResult result = getClient().dropAllStoragesOfFact(table);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "All storages of " + table + " dropped successfully";
-    } else {
-      return "Error dropping storages of " + table;
-    }
+  @CliCommand(value = "fact add storage",
+    help = "adds a new storage to fact <fact-name>, taking storage spec from <path-to-storage-spec>")
+  public String addNewFactStorage(
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<path-to-storage-spec>") String path) {
+    return addStorage(tableName, path);
   }
 
   /**
-   * Adds the new fact storage.
+   * Gets the storage from fact.
    *
-   * @param tablepair the tablepair
-   * @return the string
+   * @param tableName fact table name
+   * @param storage      storage spec path
+   * @return the storage from fact
    */
-  @CliCommand(value = "fact add storage", help = "adds a new storage to fact")
-  public String addNewFactStorage(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<table> <path to storage-spec>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. fact add storage <table> <storage spec path>";
-    }
-
-    File f = new File(pair[1]);
-    if (!f.exists()) {
-      return "Storage spech path " + f.getAbsolutePath() + " does not exist. Please check the path";
-    }
-
-    APIResult result = getClient().addStorageToFact(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Fact table storage addition completed";
-    } else {
-      return "Fact table storage addition failed";
-    }
+  @CliCommand(value = "fact get storage", help = "describe storage <storage-name> of fact <fact-name>")
+  public String getStorageFromFact(
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<path-to-storage-spec>") String storage) {
+    return getStorage(tableName, storage);
   }
 
   /**
    * Drop storage from fact.
    *
-   * @param tablepair the tablepair
+   * @param tableName   the table name
+   * @param storageName the storage name
    * @return the string
    */
-  @CliCommand(value = "fact drop storage", help = "drop a storage from fact")
+  @CliCommand(value = "fact drop storage", help = "drop storage <storage-name> from fact <fact-name>")
   public String dropStorageFromFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<table-name> <storage-name>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. fact drop storage <table> <storage>";
-    }
-
-    APIResult result = getClient().dropStorageFromFact(pair[0], pair[1]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Fact table storage removal successful";
-    } else {
-      return "Fact table storage removal failed";
-    }
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage-name"}, mandatory = true, help = "<storage-name>") String storageName) {
+    return dropStorage(tableName, storageName);
   }
 
   /**
-   * Gets the storage from fact.
+   * Drop all fact storages.
    *
-   * @param tablepair the tablepair
-   * @return the storage from fact
+   * @param name the table
+   * @return the string
    */
-  @CliCommand(value = "fact get storage", help = "get storage of fact table")
-  public String getStorageFromFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help = "<table-name> <storage-name>") String tablepair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(tablepair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length != 2) {
-      return "Syntax error, please try in following " + "format. fact get storage <table> <storage>";
-    }
-    try {
-      return formatJson(mapper.writer(pp).writeValueAsString(getClient().getStorageFromFact(pair[0], pair[1])));
-    } catch (IOException e) {
-      throw new IllegalArgumentException(e);
-    }
+  @CliCommand(value = "fact drop all storages", help = "drop all storages associated to fact <fact-name>")
+  public String dropAllFactStorages(
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String name) {
+    return dropAllStorages(name);
   }
 
   /**
    * Gets the all partitions of fact.
    *
-   * @param specPair the spec pair
+   * @param tableName   fact name
+   * @param storageName storage name
+   * @param filter      partition filter
    * @return the all partitions of fact
    */
-  @CliCommand(value = "fact list partitions", help = "get all partitions associated with fact")
+  @CliCommand(value = "fact list partitions",
+    help = "get all partitions associated with fact <fact-name>, storage <storage-name> filtered by <partition-filter>")
   public String getAllPartitionsOfFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<table-name> <storageName> [optional <partition query filter> to get]") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    if (pair.length == 2) {
-      try {
-        return formatJson(mapper.writer(pp).writeValueAsString(getClient().getAllPartitionsOfFact(pair[0], pair[1])));
-      } catch (IOException e) {
-        throw new IllegalArgumentException(e);
-      }
-    }
-    if (pair.length == 3) {
-      try {
-        return formatJson(mapper.writer(pp).writeValueAsString(
-          getClient().getAllPartitionsOfFact(pair[0], pair[1], pair[2])));
-      } catch (IOException e) {
-        throw new IllegalArgumentException(e);
-      }
-    }
-    return "Syntax error, please try in following "
-      + "format. fact list partitions <table> <storage> [partition values]";
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "filter"}, mandatory = false, help = "<partition-filter>") String filter) {
+    return getAllPartitions(tableName, storageName, filter);
   }
 
   /**
    * Drop all partitions of fact.
    *
-   * @param specPair the spec pair
+   * @param tableName   fact name
+   * @param storageName storage name
+   * @param filter      partition query filter
    * @return the string
    */
-  @CliCommand(value = "fact drop partitions", help = "drop all partitions associated with fact")
+  @CliCommand(value = "fact drop partitions",
+    help = "drop all partitions associated with fact <fact-name>, "
+      + "storage <storage-name> filtered by <partition-filter>")
   public String dropAllPartitionsOfFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<tablename> <storageName> [optional <partition query filter> to drop]") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length == 2) {
-      result = getClient().dropAllPartitionsOfFact(pair[0], pair[1]);
-    } else if (pair.length == 3) {
-      result = getClient().dropAllPartitionsOfFact(pair[0], pair[1], pair[2]);
-    } else {
-      return "Syntax error, please try in following "
-        + "format. fact drop partitions <table> <storage> [partition values]";
-    }
-
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully dropped partition of " + pair[0];
-    } else {
-      return "failure in  dropping partition of " + pair[0];
-    }
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "filter"}, mandatory = false, help = "<partition-filter>") String filter) {
+    return dropPartitions(tableName, storageName, filter);
   }
 
   /**
    * Adds the partition to fact.
    *
-   * @param specPair the spec pair
+   * @param tableName   fact name
+   * @param storageName storage name
+   * @param path        partition spec path
    * @return the string
    */
-  @CliCommand(value = "fact add single-partition", help = "add a partition to fact table")
+  @CliCommand(value = "fact add single-partition",
+    help = "add single partition to fact <fact-name>'s"
+      + " storage <storage-name>, reading spec from <partition-spec-path>")
   public String addPartitionToFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<table> <storage> <path to partition spec>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length != 3) {
-      return "Syntax error, please try in following " + "format. fact add single-partition "
-        + "<table> <storage> <partition spec>";
-    }
-
-    File f = new File(pair[2]);
-    if (!f.exists()) {
-      return "Partition spec does not exist";
-    }
-
-    result = getClient().addPartitionToFact(pair[0], pair[1], pair[2]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully added partition to " + pair[0];
-    } else {
-      return "failure in  addition of partition to " + pair[0];
-    }
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<partition-spec-path>") String path) {
+    return addPartition(tableName, storageName, path);
   }
 
-  /**
-   * Adds the partitions to fact.
-   *
-   * @param specPair the spec pair
-   * @return the string
-   */
-  @CliCommand(value = "fact add partitions", help = "add a partitions to fact table")
+  @CliCommand(value = "fact add partitions",
+    help = "add multiple partition to fact <fact-name>'s"
+      + " storage <storage-name>, reading partition list spec from <partition-list-spec-path>")
   public String addPartitionsToFact(
-    @CliOption(key = {"", "table"}, mandatory = true, help
-      = "<table> <storage> <path to partitions spec>") String specPair) {
-    Iterable<String> parts = Splitter.on(' ').trimResults().omitEmptyStrings().split(specPair);
-    String[] pair = Iterables.toArray(parts, String.class);
-    APIResult result;
-    if (pair.length != 3) {
-      return "Syntax error, please try in following "
-        + "format. fact add partitions <table> <storage> <partitions spec>";
-    }
-
-    File f = new File(pair[2]);
-    if (!f.exists()) {
-      return "Partition spec does not exist";
-    }
-    result = getClient().addPartitionsToFact(pair[0], pair[1], pair[2]);
-    if (result.getStatus() == APIResult.Status.SUCCEEDED) {
-      return "Successfully added partition to " + pair[0];
-    } else {
-      return "failure in  addition of partition to " + pair[0];
-    }
+    @CliOption(key = {"", "fact-name"}, mandatory = true, help = "<fact-name>") String tableName,
+    @CliOption(key = {"", "storage"}, mandatory = true, help = "<storage-name>") String storageName,
+    @CliOption(key = {"", "path"}, mandatory = true, help = "<partition-list-spec-path>") String path) {
+    return addPartitions(tableName, storageName, path);
+  }
+
+  @Override
+  protected XStorageTableElement readStorage(String tableName, String storage) {
+    return getClient().getStorageFromFact(tableName, storage);
+  }
+
+  @Override
+  public APIResult doDropStorage(String tableName, String storageName) {
+    return getClient().dropStorageFromFact(tableName, storageName);
+  }
+
+  @Override
+  public List<String> getAllStorages(String name) {
+    return getClient().getFactStorages(name);
+  }
+
+  @Override
+  public APIResult doAddStorage(String name, String path) {
+    return getClient().addStorageToFact(name, path);
+  }
+
+  @Override
+  public APIResult doDropAllStorages(String name) {
+    return getClient().dropAllStoragesOfFact(name);
+  }
+
+  @Override
+  protected List<XPartition> readAllPartitions(String tableName, String storageName, String filter) {
+    return getClient().getAllPartitionsOfFact(tableName, storageName, filter);
+  }
+
+  @Override
+  protected APIResult doAddPartition(String tableName, String storageName, String path) {
+    return getClient().addPartitionToFact(tableName, storageName, path);
+  }
+
+  @Override
+  protected APIResult doAddPartitions(String tableName, String storageName, String path) {
+    return getClient().addPartitionsToFact(tableName, storageName, path);
+  }
+
+  @Override
+  protected APIResult doDropPartitions(String tableName, String storageName, String filter) {
+    return getClient().dropAllPartitionsOfFact(tableName, storageName, filter);
+  }
+
+  @Override
+  public List<String> getAll() {
+    return getClient().getAllFactTables();
+  }
+
+  @Override
+  public List<String> getAll(String cubeName) {
+    return getClient().getAllFactTables(cubeName);
+  }
+
+  @Override
+  protected APIResult doCreate(String path, boolean ignoreIfExists) {
+    return getClient().createFactTable(path);
+  }
+
+  @Override
+  protected XFactTable doRead(String name) {
+    return getClient().getFactTable(name);
+  }
+
+  @Override
+  public APIResult doUpdate(String name, String path) {
+    return getClient().updateFactTable(name, path);
+  }
+
+  @Override
+  protected APIResult doDelete(String name, boolean cascade) {
+    return getClient().dropFactTable(name, cascade);
   }
 }