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/06/12 08:01:36 UTC

[2/2] incubator-lens git commit: LENS-531 : Add cli command to show all queryable fields of cube or dimension

LENS-531 : Add cli command to show all queryable fields of cube or dimension


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

Branch: refs/heads/master
Commit: ff31ad96b928850f4d549ebcde7e79f260b025e7
Parents: 7a7bdec
Author: Rajat Khandelwal <pr...@apache.org>
Authored: Fri Jun 12 11:31:19 2015 +0530
Committer: Amareshwari Sriramadasu <am...@apache.org>
Committed: Fri Jun 12 11:31:19 2015 +0530

----------------------------------------------------------------------
 lens-api/pom.xml                                |   5 +
 lens-api/src/main/resources/cube-0.1.xsd        | 611 ++++++++++---------
 .../LensCRUDStoragePartitionCommand.java        | 114 ----
 .../lens/cli/commands/LensCubeCommands.java     |  21 +-
 .../cli/commands/LensDimensionCommands.java     |  19 +-
 .../commands/LensDimensionTableCommands.java    |   2 +-
 .../lens/cli/commands/LensFactCommands.java     |   2 +-
 .../lens/cli/commands/LensQueryCommands.java    |   3 +-
 .../cli/commands/LogicalTableCrudCommand.java   |  31 +
 .../cli/commands/PhysicalTableCrudCommand.java  | 114 ++++
 .../org/apache/lens/cli/skel/LensBanner.java    |   5 +
 .../lens/cli/skel/LensHistoryFileProvider.java  |   2 +-
 .../lens/cli/skel/LensPromptProvider.java       |   2 +-
 .../apache/lens/cli/table/CollectionTable.java  |  59 ++
 .../lens/cli/table/CollectionTableFactory.java  | 158 +++++
 .../lens/cli/table/XFlattenedColumnTable.java   |  97 +++
 .../apache/lens/cli/table/XJoinChainTable.java  |  77 +++
 .../apache/lens/cli/TestLensCubeCommands.java   |  40 +-
 .../lens/cli/TestLensDimensionCommands.java     |  26 +-
 .../apache/lens/cli/TestLensQueryCommands.java  |  15 +-
 .../java/org/apache/lens/client/LensClient.java |   7 +
 .../apache/lens/client/LensMetadataClient.java  |  35 +-
 .../api/metastore/CubeMetastoreService.java     |   6 +-
 .../metastore/CubeMetastoreServiceImpl.java     |  80 ++-
 .../server/metastore/MetastoreResource.java     |  36 +-
 pom.xml                                         |   7 +-
 src/site/apt/user/cli.apt                       |  10 +-
 27 files changed, 1109 insertions(+), 475 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-api/pom.xml
----------------------------------------------------------------------
diff --git a/lens-api/pom.xml b/lens-api/pom.xml
index adc464a..184f8a8 100644
--- a/lens-api/pom.xml
+++ b/lens-api/pom.xml
@@ -66,6 +66,10 @@
       <groupId>com.typesafe</groupId>
       <artifactId>config</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.jvnet.jaxb2_commons</groupId>
+      <artifactId>jaxb2-basics-runtime</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
@@ -85,6 +89,7 @@
           <args>
             <arg>-extension</arg>
             <arg>-Xinheritance</arg>
+            <arg>-XtoString</arg>
           </args>
           <plugins>
             <plugin>

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-api/src/main/resources/cube-0.1.xsd
----------------------------------------------------------------------
diff --git a/lens-api/src/main/resources/cube-0.1.xsd b/lens-api/src/main/resources/cube-0.1.xsd
index 719d10d..2ae606f 100644
--- a/lens-api/src/main/resources/cube-0.1.xsd
+++ b/lens-api/src/main/resources/cube-0.1.xsd
@@ -18,18 +18,53 @@
   under the License.
 
 -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified"
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
+  attributeFormDefault="unqualified" elementFormDefault="qualified"
   targetNamespace="uri:lens:cube:0.1" xmlns="uri:lens:cube:0.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
   jaxb:version="2.1">
+
   <xs:annotation>
     <xs:appinfo>
       <jaxb:schemaBindings>
-        <jaxb:package name="org.apache.lens.api.metastore" />
+        <jaxb:package name="org.apache.lens.api.metastore"/>
       </jaxb:schemaBindings>
     </xs:appinfo>
   </xs:annotation>
 
-  <xs:element name="x_cube" abstract="true" type="x_cube" />
+  <xs:element name="x_field" abstract="true" type="x_field"/>
+
+  <xs:complexType name="x_field" abstract="true">
+    <xs:annotation>
+      <xs:documentation>
+        some documentation
+      </xs:documentation>
+    </xs:annotation>
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="display_string">
+      <xs:annotation>
+        <xs:documentation>
+          Display string that should be shown to end users. Can be space separated. It gives UI systems
+          built on top to use this value to show the field to end user.
+        </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute type="xs:string" name="description"/>
+  </xs:complexType>
+
+  <xs:element name="x_fields" type="x_fields"/>
+
+  <xs:complexType name="x_fields">
+    <xs:annotation>
+      <xs:documentation>
+        Set of fields.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element type="x_field" name="fields" maxOccurs="unbounded" minOccurs="1"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="x_cube" abstract="true" type="x_cube"/>
 
   <xs:complexType name="x_cube" abstract="true">
     <xs:annotation>
@@ -65,44 +100,44 @@
             Additional properties:
 
             1. cube.timedim.relation.{time_dim1}: time_dim2+[timediff1,timediff2]. It's assumed that
-              timediff1 is smaller than timediff2. Means that time_dim1 can be expected to be between
-              [time_dim2+timediff1 and time_dim2+timediff2]. One use case would be the following:
+            timediff1 is smaller than timediff2. Means that time_dim1 can be expected to be between
+            [time_dim2+timediff1 and time_dim2+timediff2]. One use case would be the following:
 
-              1.1. if a query is on range of time_dim1 and
-                time_dim1 has no partitioning column in some fact, then partitions for time_dim2 can be looked at.
-                Let's say time_dim2's part col is part_col2, then for a query asking for time_dim1 between [a,b) can
-                be answered by looking at partitions of part_col2 in range [a-timediff2, b-timediff1).
+            1.1. if a query is on range of time_dim1 and
+            time_dim1 has no partitioning column in some fact, then partitions for time_dim2 can be looked at.
+            Let's say time_dim2's part col is part_col2, then for a query asking for time_dim1 between [a,b) can
+            be answered by looking at partitions of part_col2 in range [a-timediff2, b-timediff1).
 
-              This property is first looked into fact properties, then cube properties and if that's a derived cube,
-              then next in base cube properties. Wherever found first, that will be considered as the final relation
-              between time dimensions.
+            This property is first looked into fact properties, then cube properties and if that's a derived cube,
+            then next in base cube properties. Wherever found first, that will be considered as the final relation
+            between time dimensions.
 
-              Time dimension relations are transitive, but not reversible. i.e.
-              cube.timedim.relation.time_dim1 = time_dim2 + [a, b]
-              cube.timedim.relation.time_dim2 = time_dim3 + [c, d]
+            Time dimension relations are transitive, but not reversible. i.e.
+            cube.timedim.relation.time_dim1 = time_dim2 + [a, b]
+            cube.timedim.relation.time_dim2 = time_dim3 + [c, d]
 
-              implies:
+            implies:
 
-              cube.timedim.relation.time_dim1 = time_dim3 + [a+c, b+d]
+            cube.timedim.relation.time_dim1 = time_dim3 + [a+c, b+d]
 
-              but not:
+            but not:
 
-              cube.timedim.relation.time_dim2 = time_dim1 + [-b, -a]
+            cube.timedim.relation.time_dim2 = time_dim1 + [-b, -a]
 
-              Reverse relations have to be defined explicitly.
+            Reverse relations have to be defined explicitly.
 
-              Timediff syntax is sign, quantity and unit. Spaces in between can be present. e.g. -4 days, +4days, +4 day
-              etc all are valid.
+            Timediff syntax is sign, quantity and unit. Spaces in between can be present. e.g. -4 days, +4days, +4 day
+            etc all are valid.
 
           </xs:documentation>
         </xs:annotation>
       </xs:element>
     </xs:sequence>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="description" />
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="description"/>
   </xs:complexType>
 
-  <xs:element name="x_base_cube" type="x_base_cube" />
+  <xs:element name="x_base_cube" type="x_base_cube"/>
   <xs:complexType name="x_base_cube">
     <xs:annotation>
       <xs:documentation>
@@ -113,16 +148,16 @@
     <xs:complexContent>
       <xs:extension base="x_cube">
         <xs:sequence>
-          <xs:element type="x_measures" name="measures" maxOccurs="1" minOccurs="1" />
-          <xs:element type="x_dim_attributes" name="dim_attributes" maxOccurs="1" minOccurs="0" />
-          <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0" />
-          <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0" />
+          <xs:element type="x_measures" name="measures" maxOccurs="1" minOccurs="1"/>
+          <xs:element type="x_dim_attributes" name="dim_attributes" maxOccurs="1" minOccurs="0"/>
+          <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0"/>
+          <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0"/>
         </xs:sequence>
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
 
-  <xs:element name="x_derived_cube" type="x_derived_cube" />
+  <xs:element name="x_derived_cube" type="x_derived_cube"/>
   <xs:complexType name="x_derived_cube">
     <xs:annotation>
       <xs:documentation>
@@ -134,10 +169,10 @@
     <xs:complexContent>
       <xs:extension base="x_cube">
         <xs:sequence>
-          <xs:element type="x_measure_names" name="measure_names" maxOccurs="1" minOccurs="0" />
-          <xs:element type="x_dim_attr_names" name="dim_attr_names" maxOccurs="1" minOccurs="0" />
+          <xs:element type="x_measure_names" name="measure_names" maxOccurs="1" minOccurs="0"/>
+          <xs:element type="x_dim_attr_names" name="dim_attr_names" maxOccurs="1" minOccurs="0"/>
         </xs:sequence>
-        <xs:attribute type="xs:string" name="parent" use="required" />
+        <xs:attribute type="xs:string" name="parent" use="required"/>
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
@@ -151,13 +186,13 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element type="x_dim_attributes" name="attributes" maxOccurs="1" minOccurs="0" />
-      <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0" />
-      <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0" />
-      <xs:element type="x_properties" name="properties" maxOccurs="1" minOccurs="0" />
+      <xs:element type="x_dim_attributes" name="attributes" maxOccurs="1" minOccurs="0"/>
+      <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0"/>
+      <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0"/>
+      <xs:element type="x_properties" name="properties" maxOccurs="1" minOccurs="0"/>
     </xs:sequence>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="description" />
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="description"/>
   </xs:complexType>
 
   <xs:complexType name="x_property">
@@ -166,8 +201,8 @@
         A key-value pair for storing property's name and its value.
       </xs:documentation>
     </xs:annotation>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="value" use="required" />
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="value" use="required"/>
   </xs:complexType>
 
   <xs:complexType name="x_properties">
@@ -187,72 +222,68 @@
         A cube measure.
       </xs:documentation>
     </xs:annotation>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="x_measure_type" name="type" use="required" />
-    <xs:attribute type="xs:string" name="description" />
-    <xs:attribute type="xs:string" name="display_string">
-      <xs:annotation>
-        <xs:documentation>
-          Display string that should be shown to end users. Can be comma separated. It gives UI systems
-          built on top to use this value to show the field to end user.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:string" name="default_aggr">
-      <xs:annotation>
-        <xs:documentation>
-          The aggregate for the measure that is used to rollup in aggregated facts.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:string" name="format_string">
-      <xs:annotation>
-        <xs:documentation>
-          The string format that can should be used to format the number shown to user. For example:
-          formatting with respect to precision upto 3 decimals, can be specified as
-          format_number(%s,"##################.###")
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:dateTime" name="start_time">
-      <xs:annotation>
-        <xs:documentation>
-          The start time from when the measure is available for querying
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:dateTime" name="end_time">
-      <xs:annotation>
-        <xs:documentation>
-          The end time till when the measure is available for querying
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:string" name="unit">
-      <xs:annotation>
-        <xs:documentation>
-          Specify the unit of the measure. For example, currency in dollars or rupees.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:double" name="min">
-      <xs:annotation>
-        <xs:documentation>
-          The minimum value the measure can take. This is only indicative value for user to know what
-          vaues it can take. Lens does not do any validation based on this value.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:double" name="max">
-      <xs:annotation>
-        <xs:documentation>
-          The maximum value the measure can take. This is only indicative value for user to know what
-          vaues it can take. Lens does not do any validation based on this value.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
+    <xs:complexContent>
+      <xs:extension base="x_field">
+        <xs:attribute type="x_measure_type" name="type" use="required"/>
+        <xs:attribute type="xs:string" name="default_aggr">
+          <xs:annotation>
+            <xs:documentation>
+              The aggregate for the measure that is used to rollup in aggregated facts.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:string" name="format_string">
+          <xs:annotation>
+            <xs:documentation>
+              The string format that can should be used to format the number shown to user. For example:
+              formatting with respect to precision upto 3 decimals, can be specified as
+              format_number(%s,"##################.###")
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:dateTime" name="start_time">
+          <xs:annotation>
+            <xs:documentation>
+              The start time from when the measure is available for querying
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:dateTime" name="end_time">
+          <xs:annotation>
+            <xs:documentation>
+              The end time till when the measure is available for querying
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:string" name="unit">
+          <xs:annotation>
+            <xs:documentation>
+              Specify the unit of the measure. For example, currency in dollars or rupees.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:double" name="min">
+          <xs:annotation>
+            <xs:documentation>
+              The minimum value the measure can take. This is only indicative value for user to know what
+              vaues it can take. Lens does not do any validation based on this value.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:double" name="max">
+          <xs:annotation>
+            <xs:documentation>
+              The maximum value the measure can take. This is only indicative value for user to know what
+              vaues it can take. Lens does not do any validation based on this value.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
   </xs:complexType>
 
+  <xs:element name="x_measures" type="x_measures"/>
+
   <xs:complexType name="x_measures">
     <xs:annotation>
       <xs:documentation>
@@ -281,35 +312,29 @@
         An expression column
       </xs:documentation>
     </xs:annotation>
-    <xs:sequence>
-      <xs:annotation>
-        <xs:documentation>
-          All the expressions associated with expression column.
-        </xs:documentation>
-      </xs:annotation>
-      <xs:element type="x_expr_spec" name="expr_spec" maxOccurs="unbounded" minOccurs="1"/>
-    </xs:sequence>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="type" use="required">
-      <xs:annotation>
-        <xs:documentation>
-          The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN, TINYINT,
-          SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP,
-          STRUCT, UNION
-          See hive represenation for specifying complex types -
-          https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:string" name="description" />
-    <xs:attribute type="xs:string" name="display_string">
-      <xs:annotation>
-        <xs:documentation>
-          Display string that should be shown to end users. Can be comma separated. It gives UI systems
-          built on top to use this value to show the field to end user.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
+    <xs:complexContent>
+      <xs:extension base="x_field">
+        <xs:sequence>
+          <xs:annotation>
+            <xs:documentation>
+              All the expressions associated with expression column.
+            </xs:documentation>
+          </xs:annotation>
+          <xs:element type="x_expr_spec" name="expr_spec" maxOccurs="unbounded" minOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute type="xs:string" name="type" use="required">
+          <xs:annotation>
+            <xs:documentation>
+              The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN, TINYINT,
+              SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP,
+              STRUCT, UNION
+              See hive represenation for specifying complex types -
+              https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
   </xs:complexType>
 
   <xs:complexType name="x_expr_spec">
@@ -345,6 +370,8 @@
     </xs:attribute>
   </xs:complexType>
 
+  <xs:element name="x_expressions" type="x_expressions"/>
+
   <xs:complexType name="x_expressions">
     <xs:annotation>
       <xs:documentation>
@@ -362,81 +389,78 @@
         A dim attribute.
       </xs:documentation>
     </xs:annotation>
-    <xs:sequence>
-      <xs:element name="ref_spec" maxOccurs="1" minOccurs="0">
-        <xs:annotation>
-          <xs:documentation>
-            Reference specifiction needs to be specified if the attribute is a reference attribute. It
-            can either be table reference or a chained column
-
-            ref_spec can be specified as a list of table references to
-            which the attribute is refering to.
-            For ex : userid refers user.id, xuser.id, yuser.id, zuser.id.
-
-            Alternately, ref_spec could be a chained column specifed with chain name and column name.
-          </xs:documentation>
-        </xs:annotation>
-        <xs:complexType>
-          <xs:choice maxOccurs="1" minOccurs="1">
-            <xs:element type="x_table_references" name="table_references" maxOccurs="1" minOccurs="1" />
-            <xs:element type="x_chain_column" name="chain_ref_column" maxOccurs="1" minOccurs="1" />
-          </xs:choice>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="type" use="required">
-      <xs:annotation>
-        <xs:documentation>
-          The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN,TINYINT,
-          SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP,
-          STRUCT, UNION
-          See hive represenation for specifying complex types -
-          https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:string" name="description" />
-    <xs:attribute type="xs:string" name="display_string">
-      <xs:annotation>
-        <xs:documentation>
-          Display string that should be shown to end users. Can be comma separated. It gives UI systems
-          built on top to use this value to show the field to end user.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:dateTime" name="start_time">
-      <xs:annotation>
-        <xs:documentation>
-          The start time from when the attribute is available for querying.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:dateTime" name="end_time">
-      <xs:annotation>
-        <xs:documentation>
-          The end time till when the attribute is available for querying.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:long" name="num_distinct_values" use="optional">
-      <xs:annotation>
-        <xs:documentation>
-          Specifies an indicative value of how many distinct values the dim attribute can take.
-          This would give an idea of how big the grouping will be when an attribute is chosen for groupby expressions.
-          This is just an approximate value.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
-    <xs:attribute type="xs:boolean" name="join_key" default="false">
-      <xs:annotation>
-        <xs:documentation>
-          This flag will tell whether the attribute can be used as a join key or not
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
+    <xs:complexContent>
+      <xs:extension base="x_field">
+        <xs:sequence>
+          <xs:element name="ref_spec" maxOccurs="1" minOccurs="0">
+            <xs:annotation>
+              <xs:documentation>
+                Reference specifiction needs to be specified if the attribute is a reference attribute. It
+                can either be table reference or a chained column
+
+                ref_spec can be specified as a list of table references to
+                which the attribute is refering to.
+                For ex : userid refers user.id, xuser.id, yuser.id, zuser.id.
+
+                Alternately, ref_spec could be a chained column specifed with chain name and column name.
+              </xs:documentation>
+            </xs:annotation>
+            <xs:complexType>
+              <xs:choice maxOccurs="1" minOccurs="1">
+                <xs:element type="x_table_references" name="table_references" maxOccurs="1" minOccurs="1"/>
+                <xs:element type="x_chain_column" name="chain_ref_column" maxOccurs="1" minOccurs="1"/>
+              </xs:choice>
+            </xs:complexType>
+          </xs:element>
+        </xs:sequence>
+        <xs:attribute type="xs:string" name="type" use="required">
+          <xs:annotation>
+            <xs:documentation>
+              The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN,TINYINT,
+              SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP,
+              STRUCT, UNION
+              See hive represenation for specifying complex types -
+              https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:dateTime" name="start_time">
+          <xs:annotation>
+            <xs:documentation>
+              The start time from when the attribute is available for querying.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:dateTime" name="end_time">
+          <xs:annotation>
+            <xs:documentation>
+              The end time till when the attribute is available for querying.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:long" name="num_distinct_values" use="optional">
+          <xs:annotation>
+            <xs:documentation>
+              Specifies an indicative value of how many distinct values the dim attribute can take.
+              This would give an idea of how big the grouping will be when an attribute is chosen for groupby
+              expressions.
+              This is just an approximate value.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute type="xs:boolean" name="join_key" default="false">
+          <xs:annotation>
+            <xs:documentation>
+              This flag will tell whether the attribute can be used as a join key or not
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
   </xs:complexType>
 
+  <xs:element name="x_dim_attributes" type="x_dim_attributes"/>
+
   <xs:complexType name="x_dim_attributes">
     <xs:annotation>
       <xs:documentation>
@@ -460,8 +484,8 @@
   </xs:complexType>
 
   <xs:complexType name="x_chain_column">
-    <xs:attribute type="xs:string" name="chain_name" use="required" />
-    <xs:attribute type="xs:string" name="ref_col" use="required" />
+    <xs:attribute type="xs:string" name="chain_name" use="required"/>
+    <xs:attribute type="xs:string" name="ref_col" use="required"/>
     <xs:attribute type="xs:string" name="dest_table">
       <xs:annotation>
         <xs:documentation>
@@ -472,8 +496,8 @@
   </xs:complexType>
 
   <xs:complexType name="x_table_reference">
-    <xs:attribute type="xs:string" name="table" use="required" />
-    <xs:attribute type="xs:string" name="column" use="required" />
+    <xs:attribute type="xs:string" name="table" use="required"/>
+    <xs:attribute type="xs:string" name="column" use="required"/>
   </xs:complexType>
 
   <xs:complexType name="x_table_references">
@@ -487,6 +511,8 @@
     </xs:sequence>
   </xs:complexType>
 
+  <xs:element name="x_join_chains" type="x_join_chains"/>
+
   <xs:complexType name="x_join_chains">
     <xs:annotation>
       <xs:documentation>
@@ -513,19 +539,20 @@
         SalesCube.productionStateid -> State.id, State.countryid ->Country.id will be named differently.
       </xs:documentation>
     </xs:annotation>
-    <xs:sequence>
-      <xs:element type="x_join_paths" name="paths" maxOccurs="1" minOccurs="1" />
-    </xs:sequence>
-    <xs:attribute type="xs:string" name="name" use="required" />
-    <xs:attribute type="xs:string" name="description" />
-    <xs:attribute type="xs:string" name="display_string" />
-    <xs:attribute type="xs:string" name="dest_table">
-      <xs:annotation>
-        <xs:documentation>
-          This will be the destination table of the chain. LENS will set and return, need not be set by end-user.
-        </xs:documentation>
-      </xs:annotation>
-    </xs:attribute>
+    <xs:complexContent>
+      <xs:extension base="x_field">
+        <xs:sequence>
+          <xs:element type="x_join_paths" name="paths" maxOccurs="1" minOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute type="xs:string" name="dest_table">
+          <xs:annotation>
+            <xs:documentation>
+              This will be the destination table of the chain. LENS will set and return, need not be set by end-user.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
   </xs:complexType>
 
   <xs:complexType name="x_join_path">
@@ -535,7 +562,7 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element type="x_join_edges" name="edges" maxOccurs="1" minOccurs="1" />
+      <xs:element type="x_join_edges" name="edges" maxOccurs="1" minOccurs="1"/>
     </xs:sequence>
   </xs:complexType>
 
@@ -557,8 +584,8 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element type="x_table_reference" name="from" maxOccurs="1" minOccurs="1" />
-      <xs:element type="x_table_reference" name="to" maxOccurs="1" minOccurs="1" />
+      <xs:element type="x_table_reference" name="from" maxOccurs="1" minOccurs="1"/>
+      <xs:element type="x_table_reference" name="to" maxOccurs="1" minOccurs="1"/>
     </xs:sequence>
   </xs:complexType>
 
@@ -596,10 +623,10 @@
         <xs:annotation>
           <xs:documentation>
             Dimension table properties. The properties that should be set are:
-            1.  dimtable.{dim_table_name}.part.cols = comma separated list of partition columns of this dimtable.
-                This would basically be union of all partition columns of all storage tables of the dimtable.
-                Setting this makes that partition column queryable.
-                Time part columns can be skipped as they will generally not be queried.
+            1. dimtable.{dim_table_name}.part.cols = comma separated list of partition columns of this dimtable.
+            This would basically be union of all partition columns of all storage tables of the dimtable.
+            Setting this makes that partition column queryable.
+            Time part columns can be skipped as they will generally not be queried.
           </xs:documentation>
         </xs:annotation>
       </xs:element>
@@ -659,7 +686,7 @@
         Column in table.
       </xs:documentation>
     </xs:annotation>
-    <xs:attribute name="name" type="xs:string" use="required" />
+    <xs:attribute name="name" type="xs:string" use="required"/>
     <xs:attribute type="xs:string" name="type" use="required">
       <xs:annotation>
         <xs:documentation>
@@ -670,8 +697,8 @@
           https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes
         </xs:documentation>
       </xs:annotation>
-      </xs:attribute>
-    <xs:attribute name="comment" type="xs:string" />
+    </xs:attribute>
+    <xs:attribute name="comment" type="xs:string"/>
   </xs:complexType>
 
   <xs:simpleType name="x_measure_type">
@@ -681,13 +708,13 @@
       </xs:documentation>
     </xs:annotation>
     <xs:restriction base="xs:string">
-      <xs:enumeration value="TINYINT" />
-      <xs:enumeration value="SMALLINT" />
-      <xs:enumeration value="INT" />
-      <xs:enumeration value="BIGINT" />
-      <xs:enumeration value="FLOAT" />
-      <xs:enumeration value="DOUBLE" />
-      <xs:enumeration value="DECIMAL" />
+      <xs:enumeration value="TINYINT"/>
+      <xs:enumeration value="SMALLINT"/>
+      <xs:enumeration value="INT"/>
+      <xs:enumeration value="BIGINT"/>
+      <xs:enumeration value="FLOAT"/>
+      <xs:enumeration value="DOUBLE"/>
+      <xs:enumeration value="DECIMAL"/>
     </xs:restriction>
   </xs:simpleType>
 
@@ -698,18 +725,18 @@
       </xs:documentation>
     </xs:annotation>
     <xs:restriction base="xs:string">
-      <xs:enumeration value="SECONDLY" />
-      <xs:enumeration value="MINUTELY" />
-      <xs:enumeration value="HOURLY" />
-      <xs:enumeration value="DAILY" />
-      <xs:enumeration value="WEEKLY" />
-      <xs:enumeration value="MONTHLY" />
-      <xs:enumeration value="QUARTERLY" />
-      <xs:enumeration value="YEARLY" />
+      <xs:enumeration value="SECONDLY"/>
+      <xs:enumeration value="MINUTELY"/>
+      <xs:enumeration value="HOURLY"/>
+      <xs:enumeration value="DAILY"/>
+      <xs:enumeration value="WEEKLY"/>
+      <xs:enumeration value="MONTHLY"/>
+      <xs:enumeration value="QUARTERLY"/>
+      <xs:enumeration value="YEARLY"/>
     </xs:restriction>
   </xs:simpleType>
 
-  <xs:element name="x_storage" type="x_storage" />
+  <xs:element name="x_storage" type="x_storage"/>
   <xs:complexType name="x_storage">
     <xs:annotation>
       <xs:documentation>
@@ -725,7 +752,7 @@
         </xs:annotation>
       </xs:element>
     </xs:sequence>
-    <xs:attribute name="name" type="xs:string" use="required" />
+    <xs:attribute name="name" type="xs:string" use="required"/>
     <xs:attribute name="classname" type="xs:string" use="required">
       <xs:annotation>
         <xs:documentation>
@@ -738,7 +765,7 @@
     </xs:attribute>
   </xs:complexType>
 
-  <xs:element name="x_storage_table_desc" type="x_storage_table_desc" />
+  <xs:element name="x_storage_table_desc" type="x_storage_table_desc"/>
   <xs:complexType name="x_storage_table_desc">
     <xs:annotation>
       <xs:documentation>
@@ -907,9 +934,9 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="col_names" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
-      <xs:element name="col_values" type="x_skew_col_list" maxOccurs="unbounded" minOccurs="0" />
-      <xs:element name="value_location_map" type="x_skewed_value_location" maxOccurs="unbounded" minOccurs="0" />
+      <xs:element name="col_names" type="xs:string" maxOccurs="unbounded" minOccurs="0"/>
+      <xs:element name="col_values" type="x_skew_col_list" maxOccurs="unbounded" minOccurs="0"/>
+      <xs:element name="value_location_map" type="x_skewed_value_location" maxOccurs="unbounded" minOccurs="0"/>
     </xs:sequence>
   </xs:complexType>
 
@@ -920,7 +947,7 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="elements" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
+      <xs:element name="elements" type="xs:string" maxOccurs="unbounded" minOccurs="0"/>
     </xs:sequence>
   </xs:complexType>
 
@@ -931,12 +958,12 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="value" type="x_skew_col_list" minOccurs="1" maxOccurs="1" />
+      <xs:element name="value" type="x_skew_col_list" minOccurs="1" maxOccurs="1"/>
     </xs:sequence>
-    <xs:attribute type="xs:string" name="location" use="required" />
+    <xs:attribute type="xs:string" name="location" use="required"/>
   </xs:complexType>
 
-  <xs:element name="x_storage_table_element" type="x_storage_table_element" />
+  <xs:element name="x_storage_table_element" type="x_storage_table_element"/>
 
   <xs:complexType name="x_storage_table_element">
     <xs:annotation>
@@ -945,9 +972,9 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="update_periods" type="x_update_periods" maxOccurs="1" minOccurs="0" />
-      <xs:element name="storage_name" type="xs:string" />
-      <xs:element type="x_storage_table_desc" name="table_desc" />
+      <xs:element name="update_periods" type="x_update_periods" maxOccurs="1" minOccurs="0"/>
+      <xs:element name="storage_name" type="xs:string"/>
+      <xs:element type="x_storage_table_desc" name="table_desc"/>
     </xs:sequence>
   </xs:complexType>
 
@@ -958,11 +985,11 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="storage_table" minOccurs="1" maxOccurs="unbounded" type="x_storage_table_element" />
+      <xs:element name="storage_table" minOccurs="1" maxOccurs="unbounded" type="x_storage_table_element"/>
     </xs:sequence>
   </xs:complexType>
 
-  <xs:element name="x_partition_list" type="x_partition_list" />
+  <xs:element name="x_partition_list" type="x_partition_list"/>
   <xs:complexType name="x_partition_list">
     <xs:annotation>
       <xs:documentation>
@@ -970,11 +997,11 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="partition" type="x_partition" maxOccurs="unbounded" minOccurs="0" />
+      <xs:element name="partition" type="x_partition" maxOccurs="unbounded" minOccurs="0"/>
     </xs:sequence>
   </xs:complexType>
 
-  <xs:element name="x_partition" type="x_partition" />
+  <xs:element name="x_partition" type="x_partition"/>
 
   <xs:complexType name="x_partition">
     <xs:annotation>
@@ -983,21 +1010,21 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="non_time_partition_spec" maxOccurs="1" minOccurs="0" type ="x_part_spec" >
+      <xs:element name="non_time_partition_spec" maxOccurs="1" minOccurs="0" type="x_part_spec">
         <xs:annotation>
           <xs:documentation>
             Non time partition specification with partition columns and values.
           </xs:documentation>
         </xs:annotation>
       </xs:element>
-      <xs:element name="time_partition_spec" maxOccurs="1" minOccurs="0" type = "x_time_part_spec" >
+      <xs:element name="time_partition_spec" maxOccurs="1" minOccurs="0" type="x_time_part_spec">
         <xs:annotation>
           <xs:documentation>
             Time partition specification with partition columns and date values.
           </xs:documentation>
         </xs:annotation>
       </xs:element>
-      <xs:element name="full_partition_spec" maxOccurs="1" minOccurs="0" type ="x_part_spec" >
+      <xs:element name="full_partition_spec" maxOccurs="1" minOccurs="0" type="x_part_spec">
         <xs:annotation>
           <xs:documentation>
             LENS would use this type to retun the specification elements. Should not be used directly by end-user.
@@ -1078,8 +1105,8 @@
         Partition column name and its value.
       </xs:documentation>
     </xs:annotation>
-    <xs:attribute type="xs:string" name="key" use="required" />
-    <xs:attribute type="xs:string" name="value" use="required" />
+    <xs:attribute type="xs:string" name="key" use="required"/>
+    <xs:attribute type="xs:string" name="value" use="required"/>
   </xs:complexType>
 
   <xs:complexType name="x_part_spec">
@@ -1094,8 +1121,8 @@
         Time partition column name and its value as date-time.
       </xs:documentation>
     </xs:annotation>
-    <xs:attribute type="xs:string" name="key" use="required" />
-    <xs:attribute type="xs:dateTime" name="value" use="required" />
+    <xs:attribute type="xs:string" name="key" use="required"/>
+    <xs:attribute type="xs:dateTime" name="value" use="required"/>
   </xs:complexType>
 
   <xs:complexType name="x_time_part_spec">
@@ -1104,7 +1131,7 @@
     </xs:sequence>
   </xs:complexType>
 
-  <xs:element name="x_fact_table" type="x_fact_table" />
+  <xs:element name="x_fact_table" type="x_fact_table"/>
 
   <xs:complexType name="x_fact_table">
     <xs:annotation>
@@ -1127,26 +1154,26 @@
             Properties that can be set for a fact are
 
             1. cube.fact.{fact-name}.valid.columns.size : This should be set to number of
-              cube.fact.{fact-name}.valid.columns strings.
+            cube.fact.{fact-name}.valid.columns strings.
             2. cube.fact.{fact-name}.valid.columns{i} : This should be set to comma separated column names which are
-              valid in the fact, such that 0 &lt;= i &lt; cube.fact.{fact-name}.valid.columns.size and each of
-              cube.fact.{fact-name}.valid.columns{i} has maximum length of 3999.
+            valid in the fact, such that 0 &lt;= i &lt; cube.fact.{fact-name}.valid.columns.size and each of
+            cube.fact.{fact-name}.valid.columns{i} has maximum length of 3999.
             3. cube.fact.is.aggregated : Defaults to true. If the fact is a raw fact, this should be set to false,
-              otherwise true.
+            otherwise true.
             4. cube.timedim.relation.{time_dim1}: See the same property in cube. Fact tables can override the property.
             5. cube.fact.absolute.start.time: start time of the fact. For queries that ask for time before this,
-              this fact is not a candidate. Time format can be as you would specify in the time_range_in clause.
-              i.e. yyyy[-mm[-dd[-hh[:MM[:ss[,SSS]]]]]]
+            this fact is not a candidate. Time format can be as you would specify in the time_range_in clause.
+            i.e. yyyy[-mm[-dd[-hh[:MM[:ss[,SSS]]]]]]
             6. cube.fact.relative.start.time: Here you can specify fact's relative validity relative to current time.
-              Useful if you want to specify e.g. this fact is valid for today - 90 days. Can be specified as just
-              a time difference e.g. "-90 days". Or can be specified in relative syntax.
-              e.g. now.year or now.day - 6 hour etc.
+            Useful if you want to specify e.g. this fact is valid for today - 90 days. Can be specified as just
+            a time difference e.g. "-90 days". Or can be specified in relative syntax.
+            e.g. now.year or now.day - 6 hour etc.
             7. cube.fact.absolute.end.time: If you're deprecating this fact, put the final date till which the data of
-              the fact will be valid here. Format same as absolute start time.
+            the fact will be valid here. Format same as absolute start time.
           </xs:documentation>
         </xs:annotation>
       </xs:element>
-      <xs:element name="storage_tables" type = "x_storage_tables" maxOccurs="1" minOccurs="0"/>
+      <xs:element name="storage_tables" type="x_storage_tables" maxOccurs="1" minOccurs="0"/>
     </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required">
       <xs:annotation>
@@ -1177,7 +1204,7 @@
     </xs:attribute>
   </xs:complexType>
 
-  <xs:element name="x_native_table" type="x_native_table" />
+  <xs:element name="x_native_table" type="x_native_table"/>
   <xs:complexType name="x_native_table">
     <xs:annotation>
       <xs:documentation>
@@ -1246,7 +1273,7 @@
     </xs:attribute>
   </xs:complexType>
 
-  <xs:element name="x_flattened_columns" type="x_flattened_columns" />
+  <xs:element name="x_flattened_columns" type="x_flattened_columns"/>
   <xs:complexType name="x_flattened_columns">
     <xs:annotation>
       <xs:documentation>
@@ -1255,16 +1282,16 @@
       </xs:documentation>
     </xs:annotation>
     <xs:sequence>
-      <xs:element name="flattened_column" type="x_flattened_column" maxOccurs="unbounded" minOccurs="0" />
+      <xs:element name="flattened_column" type="x_flattened_column" maxOccurs="unbounded" minOccurs="0"/>
     </xs:sequence>
   </xs:complexType>
   <xs:complexType name="x_flattened_column">
     <xs:choice maxOccurs="1" minOccurs="1">
-      <xs:element name="measure" type="x_measure" />
-      <xs:element name="expression" type="x_expr_column" />
-      <xs:element name="dim_attribute" type="x_dim_attribute" />
+      <xs:element name="measure" type="x_measure"/>
+      <xs:element name="expression" type="x_expr_column"/>
+      <xs:element name="dim_attribute" type="x_dim_attribute"/>
     </xs:choice>
-    <xs:attribute name="table_name" type="xs:string" use="required" />
+    <xs:attribute name="table_name" type="xs:string" use="required"/>
     <xs:attribute name="chain_name" type="xs:string">
       <xs:annotation>
         <xs:documentation>

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/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
deleted file mode 100644
index 208081d..0000000
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * 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, false, true)).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, false, true)).toString().toLowerCase();
-  }
-
-  public String addPartitions(String tableName, String storageName, String path) {
-    return doAddPartitions(tableName, storageName, getValidPath(path, false, true)).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/ff31ad96/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 d05d7a5..6ba702f 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
@@ -35,7 +35,7 @@ import org.springframework.stereotype.Component;
 @Component
 @UserDocumentation(title = "OLAP Data cube metadata management",
   description = "These commands provide CRUD for cubes")
-public class LensCubeCommands extends LensCRUDCommand<XCube> {
+public class LensCubeCommands extends LogicalTableCrudCommand<XCube> {
 
   /**
    * Show cubes.
@@ -106,12 +106,29 @@ public class LensCubeCommands extends LensCRUDCommand<XCube> {
     help = "get latest date of data available in cube <cube_name> for time dimension <time_dimension_name>. "
       + " Instead of time dimension, partition column can be directly passed as <time_dimension>")
   public String getLatest(
-    @CliOption(key = {"", "cube"}, mandatory = true, help = "<cube_name>") String cube,
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String cube,
     @CliOption(key = {"", "time_dimension"}, mandatory = true, help = "<time_dimension>") String timeDim) {
     Date dt = getClient().getLatestDateOfCube(cube, timeDim);
     return dt == null ? "No Data Available" : formatDate(dt);
   }
 
+  @CliCommand(value = "cube show fields",
+    help = "Show queryable fields of the given cube <cube_name>. "
+      + "Optionally specify <flattened> to include chained fields")
+  public String showQueryableFields(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String table,
+    @CliOption(key = {"flattened"}, mandatory = false, unspecifiedDefaultValue = "false",
+      specifiedDefaultValue = "true", help = "<flattened>") boolean flattened) {
+    return getAllFields(table, flattened);
+  }
+
+  @CliCommand(value = "cube show joinchains",
+    help = "Show joinchains of the given cube <cube_name>. ")
+  public String showJoinChains(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String table) {
+    return getAllJoinChains(table);
+  }
+
   @Override
   public List<String> getAll() {
     return getClient().getAllCubes();

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/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 84ae6c3..de022c1 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
@@ -34,7 +34,7 @@ import org.springframework.stereotype.Component;
  */
 @Component
 @UserDocumentation(title = "Dimension Management", description = "These commands provide CRUD for Dimensions")
-public class LensDimensionCommands extends LensCRUDCommand<XDimension> {
+public class LensDimensionCommands extends LogicalTableCrudCommand<XDimension> {
 
   /**
    * Show dimensions.
@@ -103,6 +103,23 @@ public class LensDimensionCommands extends LensCRUDCommand<XDimension> {
     return drop(name, false);
   }
 
+  @CliCommand(value = "dimension show fields",
+    help = "Show queryable fields of the given dimension <dimension_name>. "
+      + "Optionally specify <flattened> to include chained fields")
+  public String showQueryableFields(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension_name>") String table,
+    @CliOption(key = {"flattened"}, mandatory = false, unspecifiedDefaultValue = "false",
+      specifiedDefaultValue = "true", help = "<flattened>") boolean flattened) {
+    return getAllFields(table, flattened);
+  }
+
+  @CliCommand(value = "dimension show joinchains",
+    help = "Show joinchains of the given dimension <dimension_name>. ")
+  public String showJoinChains(
+    @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension_name>") String table) {
+    return getAllJoinChains(table);
+  }
+
   @Override
   public List<String> getAll() {
     return getClient().getAllDimensions();

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/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 40380b7..6a93393 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
@@ -37,7 +37,7 @@ import org.springframework.stereotype.Component;
 @Component
 @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>
+public class LensDimensionTableCommands extends PhysicalTableCrudCommand<XDimensionTable>
   implements CommandMarker {
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/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 24992b9..bdb9c38 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
@@ -36,7 +36,7 @@ import org.springframework.stereotype.Component;
 @Component
 @UserDocumentation(title = "Management of Facts",
   description = "These command provide CRUD for facts, associated storages, and fact partitions")
-public class LensFactCommands extends LensCRUDStoragePartitionCommand<XFactTable> {
+public class LensFactCommands extends PhysicalTableCrudCommand<XFactTable> {
 
   /**
    * Show facts.

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java
index 1eb7ed6..928531e 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java
@@ -271,7 +271,7 @@ public class LensQueryCommands extends BaseLensCommand {
     @CliOption(key = {"", "query_handle"}, mandatory = true, help = "<query_handle>") String qh,
     @CliOption(key = {"save_location"}, mandatory = false, help = "<save_location>") String location,
     @CliOption(key = {"async"}, mandatory = false, unspecifiedDefaultValue = "true",
-    help = "<async>") boolean async) {
+      help = "<async>") boolean async) {
     QueryHandle queryHandle = new QueryHandle(UUID.fromString(qh));
     LensClient.LensClientResultSetWithStats results;
     try {
@@ -459,5 +459,4 @@ public class LensQueryCommands extends BaseLensCommand {
     planStr.append("\n").append("Prepare handle:").append(plan.getPrepareHandle());
     return planStr.toString();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java
new file mode 100644
index 0000000..3c78e43
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java
@@ -0,0 +1,31 @@
+/**
+ * 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 org.apache.lens.cli.table.XFlattenedColumnTable;
+import org.apache.lens.cli.table.XJoinChainTable;
+
+public abstract class LogicalTableCrudCommand<T> extends LensCRUDCommand<T> {
+  public String getAllFields(String table, boolean flattened) {
+    return new XFlattenedColumnTable(getClient().getQueryableFields(table, flattened), table).toString();
+  }
+  public String getAllJoinChains(String table) {
+    return new XJoinChainTable(getClient().getJoinChains(table)).toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java
new file mode 100644
index 0000000..a479c14
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.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 PhysicalTableCrudCommand<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, false, true)).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, false, true)).toString().toLowerCase();
+  }
+
+  public String addPartitions(String tableName, String storageName, String path) {
+    return doAddPartitions(tableName, storageName, getValidPath(path, false, true)).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/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java
index 86099d3..f577509 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java
@@ -47,4 +47,9 @@ public class LensBanner extends DefaultBannerProvider {
   public String getWelcomeMessage() {
     return "Welcome to Lens Client";
   }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getImplementationVersion() + " built with spring shell " + super.getVersion();
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java
index b599d6e..905a019 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java
@@ -40,7 +40,7 @@ public class LensHistoryFileProvider extends DefaultHistoryFileNameProvider {
    * @see org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider#name()
    */
   @Override
-  public String name() {
+  public String getProviderName() {
     return "lens client history provider";
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java
index e5524bd..3729bc7 100644
--- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java
+++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java
@@ -41,7 +41,7 @@ public class LensPromptProvider extends DefaultPromptProvider {
    * @see org.springframework.shell.plugin.support.DefaultPromptProvider#name()
    */
   @Override
-  public String name() {
+  public String getProviderName() {
     return "lens prompt provider";
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java
new file mode 100644
index 0000000..2f46c3b
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java
@@ -0,0 +1,59 @@
+/**
+ * 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.table;
+
+
+import java.util.Collection;
+
+import org.springframework.shell.support.table.Table;
+import org.springframework.shell.support.table.TableHeader;
+import org.springframework.shell.support.table.TableRenderer;
+
+import lombok.Data;
+
+@Data
+public class CollectionTable<T> {
+  private final Collection<T> collection;
+  private final RowProvider<T> provider;
+  private final String[] header;
+
+  public CollectionTable(Collection<T> collection, RowProvider<T> provider, String... header) {
+    this.collection = collection;
+    this.provider = provider;
+    this.header = header;
+  }
+
+  interface RowProvider<T> {
+    String[][] getRows(T element);
+  }
+
+  @Override
+  public String toString() {
+    Table table = new Table();
+    for (int i = 0; i < header.length; i++) {
+      table.addHeader(i + 1, new TableHeader(header[i]));
+    }
+    for (T element : collection) {
+      for (String[] row : provider.getRows(element)) {
+        table.addRow(row);
+      }
+    }
+    return TableRenderer.renderTextTable(table);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java
new file mode 100644
index 0000000..bcc44a6
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java
@@ -0,0 +1,158 @@
+/**
+ * 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.table;
+
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.lens.api.metastore.*;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+public class CollectionTableFactory {
+  private CollectionTableFactory() {}
+
+  public static CollectionTable<XFlattenedColumn> getCollectionTable(Class<? extends XField> claz, final String table) {
+    if (claz == XExprColumn.class) {
+      return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() {
+        @Override
+        public int compare(XFlattenedColumn o1, XFlattenedColumn o2) {
+          return o1.getExpression().getName().compareTo(o2.getExpression().getName());
+        }
+      }),
+        new CollectionTable.RowProvider<XFlattenedColumn>() {
+          @Override
+          public String[][] getRows(XFlattenedColumn element) {
+            return new String[][]{
+              {
+                nulltoBlank(element.getExpression().getName()),
+                nulltoBlank(element.getExpression().getDisplayString()),
+                nulltoBlank(element.getExpression().getDescription()),
+                expressionsAsString(element.getExpression().getExprSpec()),
+              },
+            };
+          }
+
+          private String expressionsAsString(List<XExprSpec> exprSpec) {
+            StringBuilder sb = new StringBuilder();
+            String sep = "";
+            for (XExprSpec spec : exprSpec) {
+              sb.append(sep);
+              sep = ", ";
+              List<String> clauses = Lists.newArrayList();
+              if (spec.getStartTime() != null) {
+                clauses.add("after " + spec.getStartTime());
+              }
+              if (spec.getEndTime() != null) {
+                clauses.add("before " + spec.getEndTime());
+              }
+              String sep1 = "";
+              if (clauses.isEmpty()) {
+                clauses.add("always valid");
+              }
+              for (String clause : clauses) {
+                sb.append(sep1).append(clause);
+                sep1 = " and ";
+              }
+              sb.append(": ");
+              sb.append(spec.getExpr());
+            }
+            return sb.toString();
+          }
+        }, "Name", "Display String", "Description", "Expr Specs");
+    } else if (claz == XDimAttribute.class) {
+      return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() {
+        @Override
+        public int compare(XFlattenedColumn o1, XFlattenedColumn o2) {
+          if (o1 == null || o1.getDimAttribute() == null) {
+            return -1;
+          } else if (o2 == null || o2.getDimAttribute() == null) {
+            return 1;
+          } else if (table.equals(o1.getTableName()) && !table.equals(o2.getTableName())) {
+            return -1;
+          } else if (table.equals(o2.getTableName()) && !table.equals(o1.getTableName())) {
+            return 1;
+          } else {
+            if (o1.getTableName() == null) {
+              o1.setTableName("");
+            }
+            if (o2.getTableName() == null) {
+              o2.setTableName("");
+            }
+            if (o1.getChainName() == null) {
+              o1.setChainName("");
+            }
+            if (o2.getChainName() == null) {
+              o2.setChainName("");
+            }
+            int cmp = o1.getTableName().compareTo(o2.getTableName());
+            if (cmp != 0) {
+              return cmp;
+            }
+            cmp = o1.getChainName().compareTo(o2.getChainName());
+            if (cmp != 0) {
+              return cmp;
+            }
+            return o1.getDimAttribute().getName().compareTo(o2.getDimAttribute().getName());
+          }
+        }
+      }),
+        new CollectionTable.RowProvider<XFlattenedColumn>() {
+          @Override
+          public String[][] getRows(XFlattenedColumn element) {
+            String prefix = XFlattenedColumnTable.firstNonNull(element.getChainName(), element.getTableName());
+            return new String[][]{
+              {
+                (prefix == null || prefix.isEmpty() || prefix.equalsIgnoreCase(table) ? "" : (prefix + "."))
+                  + nulltoBlank(element.getDimAttribute().getName()),
+                nulltoBlank(element.getDimAttribute().getDisplayString()),
+                nulltoBlank(element.getDimAttribute().getDescription()),
+              },
+            };
+          }
+        }, "Name", "Display String", "Description");
+    } else if (claz == XMeasure.class) {
+      return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() {
+        @Override
+        public int compare(XFlattenedColumn o1, XFlattenedColumn o2) {
+          return o1.getMeasure().getName().compareTo(o2.getMeasure().getName());
+        }
+      }),
+        new CollectionTable.RowProvider<XFlattenedColumn>() {
+          @Override
+          public String[][] getRows(XFlattenedColumn element) {
+            return new String[][]{
+              {
+                nulltoBlank(element.getMeasure().getName()),
+                nulltoBlank(element.getMeasure().getDisplayString()),
+                nulltoBlank(element.getMeasure().getDescription()),
+              },
+            };
+          }
+        }, "Name", "Display String", "Description");
+    } else {
+      return null;
+    }
+  }
+
+  public static String nulltoBlank(String s) {
+    return s == null ? "" : s;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java
new file mode 100644
index 0000000..d4208c1
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.lens.cli.table;
+
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.lens.api.metastore.XField;
+import org.apache.lens.api.metastore.XFlattenedColumn;
+import org.apache.lens.api.metastore.XFlattenedColumns;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public class XFlattenedColumnTable {
+  private final String table;
+  Map<Class<? extends XField>, CollectionTable<XFlattenedColumn>> tables = Maps.newLinkedHashMap();
+  List<String> chainNames = Lists.newArrayList();
+  List<String> tableNames = Lists.newArrayList();
+
+  public XFlattenedColumnTable(XFlattenedColumns flattenedColumns, String table) {
+    this.table = table;
+    for (XFlattenedColumn column : flattenedColumns.getFlattenedColumn()) {
+      XField field = firstNonNull(column.getDimAttribute(), column.getMeasure(), column.getExpression());
+      if (field != null) {
+        if (!tables.containsKey(field.getClass())) {
+          tables.put(field.getClass(), CollectionTableFactory.getCollectionTable(field.getClass(), table));
+        }
+        tables.get(field.getClass()).getCollection().add(column);
+      } else {
+        if (column.getChainName() != null) {
+          chainNames.add(column.getChainName());
+        }
+        if (column.getTableName() != null) {
+          tableNames.add(column.getTableName());
+        }
+      }
+    }
+  }
+
+  public static <T> T firstNonNull(T... args) {
+    for (T arg : args) {
+      if (arg != null) {
+        return arg;
+      }
+    }
+    return null;
+  }
+
+
+  @Override
+  public String toString() {
+    String sep = "=============================";
+    StringBuilder sb = new StringBuilder();
+    for (Map.Entry<Class<? extends XField>, CollectionTable<XFlattenedColumn>> entry : tables.entrySet()) {
+      String title =
+        entry.getKey().getAnnotation(XmlType.class).name().replaceAll("^x_", "").replaceAll("_", " ") + "s";
+      sb.append(title).append("\n").append(sep).append("\n").append(entry.getValue()).append("\n");
+    }
+    String sep1 = "";
+    if (!chainNames.isEmpty()) {
+      sb.append("Accessible Join Chains\n").append(sep).append("\n");
+      for (String chain : chainNames) {
+        sb.append(sep1).append(chain);
+        sep1 = "\n";
+      }
+    }
+    sep1 = "";
+    if (!tableNames.isEmpty()) {
+      sb.append("Accessible Tables\n").append(sep).append("\n");
+      for (String table : tableNames) {
+        sb.append(sep1).append(table);
+        sep1 = "\n";
+      }
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java
new file mode 100644
index 0000000..8082215
--- /dev/null
+++ b/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java
@@ -0,0 +1,77 @@
+/**
+ * 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.table;
+
+
+import static org.apache.lens.cli.table.CollectionTableFactory.nulltoBlank;
+
+import org.apache.lens.api.metastore.*;
+
+public class XJoinChainTable {
+
+  private XJoinChains xJoinChains;
+
+  public XJoinChainTable(XJoinChains xJoinChains) {
+    this.xJoinChains = xJoinChains;
+  }
+
+  @Override
+  public String toString() {
+    return new CollectionTable<>(xJoinChains.getJoinChain(), new CollectionTable.RowProvider<XJoinChain>() {
+      @Override
+      public String[][] getRows(XJoinChain element) {
+        int size = element.getPaths().getPath().size();
+        String[][] ret = new String[size][5];
+        for (int i = 0; i < size; i++) {
+          if (i == 0) {
+            ret[i][0] = nulltoBlank(element.getName());
+            ret[i][1] = nulltoBlank(element.getDisplayString());
+            ret[i][2] = nulltoBlank(element.getDescription());
+            ret[i][3] = nulltoBlank(element.getDestTable());
+          } else {
+            ret[i][0] = "";
+            ret[i][1] = "";
+            ret[i][2] = "";
+            ret[i][3] = "";
+          }
+          ret[i][4] = pathAsString(element.getPaths().getPath().get(i));
+        }
+        return ret;
+      }
+
+      private String pathAsString(XJoinPath path) {
+        StringBuilder sb = new StringBuilder();
+        String sep1 = "";
+        for (XJoinEdge edge : path.getEdges().getEdge()) {
+          sb.append(sep1)
+            .append(edge.getFrom().getTable()).append(".").append(edge.getFrom().getColumn())
+            .append("=")
+            .append(edge.getTo().getTable()).append(".").append(edge.getTo().getColumn());
+          sep1 = "->";
+        }
+        return sb.toString();
+      }
+    }
+
+      , "Name", "Display String", "Description", "Destination Table", "Path").
+
+      toString();
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java
----------------------------------------------------------------------
diff --git a/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java b/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java
index ae39a2a..73661e1 100644
--- a/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java
+++ b/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java
@@ -18,15 +18,19 @@
  */
 package org.apache.lens.cli;
 
+import static org.testng.Assert.*;
+
 import java.io.*;
 import java.net.URL;
+import java.util.Arrays;
 
+import org.apache.lens.api.metastore.XJoinChains;
 import org.apache.lens.cli.commands.LensCubeCommands;
+import org.apache.lens.cli.table.XJoinChainTable;
 import org.apache.lens.client.LensClient;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 /**
@@ -51,22 +55,38 @@ public class TestLensCubeCommands extends LensCliApplicationTest {
     LOG.debug("Starting to test cube commands");
     URL cubeSpec = TestLensCubeCommands.class.getClassLoader().getResource("sample-cube.xml");
     String cubeList = command.showCubes();
-    Assert.assertFalse(cubeList.contains("sample_cube"));
+    assertFalse(cubeList.contains("sample_cube"));
     command.createCube(new File(cubeSpec.toURI()).getAbsolutePath());
     cubeList = command.showCubes();
-    Assert.assertEquals(command.getLatest("sample_cube", "dt"), "No Data Available");
-    Assert.assertTrue(cubeList.contains("sample_cube"));
-
+    assertEquals(command.getLatest("sample_cube", "dt"), "No Data Available");
+    assertTrue(cubeList.contains("sample_cube"));
+    testJoinChains(command);
+    testFields(command);
     testUpdateCommand(new File(cubeSpec.toURI()), command);
     command.dropCube("sample_cube");
     try {
       command.getLatest("sample_cube", "dt");
-      Assert.fail("should have failed as cube doesn't exist");
+      fail("should have failed as cube doesn't exist");
     } catch (Exception e) {
       //pass
     }
     cubeList = command.showCubes();
-    Assert.assertFalse(cubeList.contains("sample_cube"));
+    assertFalse(cubeList.contains("sample_cube"));
+  }
+
+  private void testJoinChains(LensCubeCommands command) {
+    String joinChains = command.showJoinChains("sample_cube");
+    assertEquals(joinChains, new XJoinChainTable(new XJoinChains()).toString());
+  }
+
+  private void testFields(LensCubeCommands command) {
+    String fields = command.showQueryableFields("sample_cube", true);
+    for (String field : Arrays
+      .asList("dim1", "dim2", "dim3", "measure1", "measure2", "measure3", "measure4", "expr_msr5")) {
+      assertTrue(fields.contains(field));
+    }
+    assertTrue(fields.contains("measure3 + measure4 + 0.01"));
+    assertTrue(fields.replace("measure3 + measure4 + 0.01", "blah").contains("measure3 + measure4"));
   }
 
   /**
@@ -105,13 +125,13 @@ public class TestLensCubeCommands extends LensCliApplicationTest {
       String propString = "name : sample_cube.prop  value : sample";
       String propString1 = "name : sample_cube.prop1  value : sample1";
 
-      Assert.assertTrue(desc.contains(propString));
+      assertTrue(desc.contains(propString));
 
       command.updateCube("sample_cube", "/tmp/sample_cube1.xml");
       desc = command.describeCube("sample_cube");
       LOG.debug(desc);
-      Assert.assertTrue(desc.contains(propString));
-      Assert.assertTrue(desc.contains(propString1));
+      assertTrue(desc.contains(propString));
+      assertTrue(desc.contains(propString1));
     } finally {
       newFile.delete();
     }