You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2017/01/09 06:14:01 UTC

ambari git commit: AMBARI-19379. Hive View 2.0: Ability to delete a table from UI. (dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 d346558c1 -> 1e2fe429b


AMBARI-19379. Hive View 2.0: Ability to delete a table from UI. (dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1e2fe429
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1e2fe429
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1e2fe429

Branch: refs/heads/branch-2.5
Commit: 1e2fe429b88e1963d1cf40285dd5cf248fc556fd
Parents: d346558
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Mon Jan 9 11:43:36 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Mon Jan 9 11:43:36 2017 +0530

----------------------------------------------------------------------
 .../ambari/view/hive20/ConnectionSystem.java    |   4 +
 .../view/hive20/actor/DatabaseManager.java      |  44 ++++-
 .../ambari/view/hive20/actor/JdbcConnector.java |   6 +
 .../view/hive20/actor/MetaDataManager.java      |   3 +
 .../view/hive20/actor/MetaDataRetriever.java    |  12 +-
 .../ambari/view/hive20/actor/message/Ping.java  |  10 +
 .../hive20/resources/browser/DDLService.java    |   4 +-
 .../utils/MetaDataManagerEventSubmitter.java    |  43 +++++
 .../src/main/resources/ui/app/adapters/table.js |   7 +-
 .../ui/app/routes/databases/database/tables.js  |   5 +
 .../app/routes/databases/database/tables/new.js |  25 ++-
 .../routes/databases/database/tables/table.js   |  53 ++++-
 .../resources/ui/app/services/create-table.js   | 182 -----------------
 .../ui/app/services/table-operations.js         | 193 +++++++++++++++++++
 .../app/templates/components/jobs-browser.hbs   |   2 +-
 .../databases/database/tables/table.hbs         |  20 +-
 .../databases/database/tables/table/details.hbs |   2 +-
 .../databases/database/tables/table/storage.hbs |   2 +-
 18 files changed, 411 insertions(+), 206 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/ConnectionSystem.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/ConnectionSystem.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/ConnectionSystem.java
index 40b4c04..a6c7334 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/ConnectionSystem.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/ConnectionSystem.java
@@ -124,6 +124,10 @@ public class ConnectionSystem {
     return metaDataManager;
   }
 
+  public synchronized Optional<ActorRef> getMetaDataManagerIfPresent(String instanceName) {
+    return Optional.fromNullable(metaDataManagerMap.get(instanceName));
+  }
+
   private ActorRef createMetaDataManager(SafeViewContext safeViewContext) {
     return actorSystem.actorOf(MetaDataManager.props(safeViewContext));
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/DatabaseManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/DatabaseManager.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/DatabaseManager.java
index 6dc4ad9..bd7c6bd 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/DatabaseManager.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/DatabaseManager.java
@@ -75,7 +75,7 @@ public class DatabaseManager extends HiveActor {
 
     Object message = hiveMessage.getMessage();
     if (message instanceof Refresh) {
-      handleRefresh();
+      handleRefresh((Refresh) message);
     } else if (message instanceof SelfRefresh) {
       handleSelfRefresh();
     } else if (message instanceof MetaDataRetriever.DBRefreshed) {
@@ -83,7 +83,7 @@ public class DatabaseManager extends HiveActor {
     } else if (message instanceof MetaDataRetriever.TableRefreshed) {
       handleTableRefreshed((MetaDataRetriever.TableRefreshed) message);
     } else if (message instanceof MetaDataRetriever.AllTableRefreshed) {
-      handleAllTableRefeshed((MetaDataRetriever.AllTableRefreshed) message);
+      handleAllTableRefreshed((MetaDataRetriever.AllTableRefreshed) message);
     } else if (message instanceof GetDatabases) {
       handleGetDatabases((GetDatabases) message);
     }
@@ -96,11 +96,11 @@ public class DatabaseManager extends HiveActor {
           getSelf(), new SelfRefresh(), getContext().dispatcher(), getSelf());
     } else {
       selfRefreshQueued = false;
-      refresh();
+      refresh(true);
     }
   }
 
-  private void handleRefresh() {
+  private void handleRefresh(Refresh message) {
     if (refreshInProgress && selfRefreshQueued) {
       return; // We will not honor refresh message when a refresh is going on and another self refresh is queued in mailbox
     } else if (refreshInProgress) {
@@ -108,7 +108,7 @@ public class DatabaseManager extends HiveActor {
       getContext().system().scheduler().scheduleOnce(Duration.create(500, TimeUnit.MILLISECONDS),
           getSelf(), new SelfRefresh(), getContext().dispatcher(), getSelf());
     } else {
-      refresh();
+      refresh(message.initiateScheduler());
     }
   }
 
@@ -157,8 +157,9 @@ public class DatabaseManager extends HiveActor {
     databaseChangeNotifier.tell(new DatabaseChangeNotifier.TableUpdated(message.getTable()), getSelf());
   }
 
-  private void handleAllTableRefeshed(MetaDataRetriever.AllTableRefreshed message) {
+  private void handleAllTableRefreshed(MetaDataRetriever.AllTableRefreshed message) {
     ActorRef databaseChangeNotifier = getDatabaseChangeNotifier(message.getDatabase());
+    updateRemovedTables(message.getDatabase(), message.getCurrentTableNames());
     databaseChangeNotifier.tell(new DatabaseChangeNotifier.AllTablesUpdated(message.getDatabase()), getSelf());
     if (checkIfAllTablesOfAllDatabaseRefeshed(message)) {
       refreshInProgress = false;
@@ -193,12 +194,14 @@ public class DatabaseManager extends HiveActor {
     return databaseChangeNotifier;
   }
 
-  private void refresh() {
+  private void refresh(boolean initiateScheduler) {
     LOG.info("Received refresh for user");
     refreshInProgress = true;
     metaDataRetriever.tell(new MetaDataRetriever.RefreshDB(), getSelf());
 
-    scheduleRefreshAfter(1, TimeUnit.MINUTES);
+    if (initiateScheduler) {
+      scheduleRefreshAfter(1, TimeUnit.MINUTES);
+    }
   }
 
   private void scheduleRefreshAfter(long time, TimeUnit timeUnit) {
@@ -220,6 +223,20 @@ public class DatabaseManager extends HiveActor {
     }
   }
 
+  private void updateRemovedTables(String database, Set<String> currentTableNames) {
+    DatabaseWrapper wrapper = databases.get(database);
+    HashSet<TableInfo> notRemovedTables = new HashSet<>();
+    if (wrapper != null) {
+      DatabaseInfo info = wrapper.getDatabase();
+      for (TableInfo tableInfo : info.getTables()) {
+        if (currentTableNames.contains(tableInfo.getName())) {
+          notRemovedTables.add(tableInfo);
+        }
+      }
+      info.setTables(notRemovedTables);
+    }
+  }
+
   public static Props props(ViewContext context) {
     ConnectionConfig config = ConnectionFactory.create(context);
     Connectable connectable = new HiveConnectionWrapper(config.getJdbcUrl(), config.getUsername(), config.getPassword(), new AuthParams(context));
@@ -228,14 +245,25 @@ public class DatabaseManager extends HiveActor {
 
   public static class Refresh {
     private final String username;
+    private final boolean initiateScheduler;
+
 
     public Refresh(String username) {
+      this(username, true);
+    }
+
+    public Refresh(String username, boolean initiateScheduler) {
       this.username = username;
+      this.initiateScheduler = initiateScheduler;
     }
 
     public String getUsername() {
       return username;
     }
+
+    public boolean initiateScheduler() {
+      return initiateScheduler;
+    }
   }
 
   private static class SelfRefresh {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/JdbcConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/JdbcConnector.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/JdbcConnector.java
index ce58c8c..1855afc 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/JdbcConnector.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/JdbcConnector.java
@@ -57,6 +57,7 @@ import org.apache.ambari.view.hive20.persistence.utils.ItemNotFound;
 import org.apache.ambari.view.hive20.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive20.resources.jobs.viewJobs.JobImpl;
 import org.apache.ambari.view.hive20.utils.HiveActorConfiguration;
+import org.apache.ambari.view.hive20.utils.MetaDataManagerEventSubmitter;
 import org.apache.ambari.view.utils.hdfs.HdfsApi;
 import org.apache.hive.jdbc.HiveConnection;
 import org.slf4j.Logger;
@@ -132,6 +133,7 @@ public class JdbcConnector extends HiveActor {
    */
   private final HiveActorConfiguration actorConfiguration;
   private String username;
+  private String instanceName;
   private Optional<String> jobId = Optional.absent();
   private Optional<String> logFile = Optional.absent();
   private int statementsCount = 0;
@@ -157,6 +159,7 @@ public class JdbcConnector extends HiveActor {
     this.storage = storage;
     this.lastActivityTimestamp = System.currentTimeMillis();
     resultSetIterator = null;
+    this.instanceName = viewContext.getInstanceName();
 
     authParams = new AuthParams(viewContext);
     actorConfiguration = new HiveActorConfiguration(viewContext);
@@ -287,6 +290,9 @@ public class JdbcConnector extends HiveActor {
     LOG.info("Finished processing SQL statements for Job id : {}", jobId.or("SYNC JOB"));
     if (isAsync() && jobId.isPresent()) {
       updateJobStatus(jobId.get(), Job.JOB_STATE_FINISHED);
+
+      LOG.info("Sending event to refresh meta information for user {} and instance {}", username, instanceName);
+      MetaDataManagerEventSubmitter.sendDBRefresh(username, instanceName);
     }
 
     if (resultSetOptional.isPresent()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
index d63b3a0..43733e4 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
@@ -72,6 +72,9 @@ public class MetaDataManager extends HiveActor {
       databaseManagers.put(context.getUsername(), databaseManager);
       databaseManager.tell(new DatabaseManager.Refresh(context.getUsername()), getSelf());
     } else {
+      if(message.isImmediate()) {
+        databaseManager.tell(new DatabaseManager.Refresh(context.getUsername(), false), getSelf());
+      }
       cancelTerminationScheduler(message.getUsername());
     }
     scheduleTermination(context.getUsername());

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataRetriever.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataRetriever.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataRetriever.java
index 7323a0a..64cd69c 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataRetriever.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataRetriever.java
@@ -91,13 +91,15 @@ public class MetaDataRetriever extends HiveActor {
 
   private void refreshTablesInfo(String database) throws ConnectionException, SQLException {
     HiveConnection connection = getHiveConnection();
+    Set<String> currentTableNames = new HashSet<>();
     try (ResultSet tables = connection.getMetaData().getTables("", database, null, null)) {
       while (tables.next()) {
         TableInfo info = new TableInfo(tables.getString(3), tables.getString(4));
+        currentTableNames.add(info.getName());
         getSender().tell(new TableRefreshed(info, database), getSelf());
       }
     }
-    getSender().tell(new AllTableRefreshed(database), getSelf());
+    getSender().tell(new AllTableRefreshed(database, currentTableNames), getSelf());
   }
 
   public static  Props props(Connectable connectable) {
@@ -153,13 +155,19 @@ public class MetaDataRetriever extends HiveActor {
 
   public static class AllTableRefreshed {
     private final String database;
+    private final Set<String> currentTableNames;
 
-    public AllTableRefreshed(String database) {
+    public AllTableRefreshed(String database, Set<String> currentTableNames) {
       this.database = database;
+      this.currentTableNames = currentTableNames;
     }
 
     public String getDatabase() {
       return database;
     }
+
+    public Set<String> getCurrentTableNames() {
+      return currentTableNames;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/message/Ping.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/message/Ping.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/message/Ping.java
index c8449dc..61df87a 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/message/Ping.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/message/Ping.java
@@ -24,10 +24,16 @@ package org.apache.ambari.view.hive20.actor.message;
 public class Ping {
   private final String username;
   private final String instanceName;
+  private final boolean immediate;
 
   public Ping(String username, String instanceName) {
+    this(username, instanceName, false);
+  }
+
+  public Ping(String username, String instanceName, boolean immediate) {
     this.username = username;
     this.instanceName = instanceName;
+    this.immediate = immediate;
   }
 
   public String getUsername() {
@@ -37,4 +43,8 @@ public class Ping {
   public String getInstanceName() {
     return instanceName;
   }
+
+  public boolean isImmediate() {
+    return immediate;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java
index b278983..65647ee 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java
@@ -114,7 +114,7 @@ public class DDLService extends BaseService {
       Job job = proxy.createTable(databaseName, request.tableInfo, getResourceManager());
       JSONObject response = new JSONObject();
       response.put("job", job);
-      return Response.status(Response.Status.ACCEPTED).entity(job).build();
+      return Response.status(Response.Status.ACCEPTED).entity(response).build();
     } catch (ServiceException e) {
       LOG.error("Exception occurred while creatint table for db {} with details : {}", databaseName, request.tableInfo, e);
       throw new ServiceFormattedException(e);
@@ -192,7 +192,7 @@ public class DDLService extends BaseService {
       Job job = proxy.alterTable(context, hiveConnectionConfig, databaseName, oldTableName, tableMetaRequest.tableInfo, getResourceManager());
       JSONObject response = new JSONObject();
       response.put("job", job);
-      return Response.status(Response.Status.ACCEPTED).entity(job).build();
+      return Response.status(Response.Status.ACCEPTED).entity(response).build();
     } catch (ServiceException e) {
       LOG.error("Exception occurred while creatint table for db {} with details : {}", databaseName, tableMetaRequest.tableInfo, e);
       throw new ServiceFormattedException(e);

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/MetaDataManagerEventSubmitter.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/MetaDataManagerEventSubmitter.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/MetaDataManagerEventSubmitter.java
new file mode 100644
index 0000000..b23e06e
--- /dev/null
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/MetaDataManagerEventSubmitter.java
@@ -0,0 +1,43 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view.hive20.utils;
+
+import akka.actor.ActorRef;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.hive20.ConnectionSystem;
+import org.apache.ambari.view.hive20.actor.message.Ping;
+
+/**
+ * Static class to submit event to the MetaData Manager.
+ */
+public final class MetaDataManagerEventSubmitter {
+
+  /**
+   * Send a ping message to the MetaDataManager Actor for that instance
+   * @param username Logged-in username
+   * @param instanceName current instance name
+   */
+  public static void sendDBRefresh(String username, String instanceName) {
+    Optional<ActorRef> metaDataManagerOptional = ConnectionSystem.getInstance().getMetaDataManagerIfPresent(instanceName);
+    if(metaDataManagerOptional.isPresent()) {
+      ActorRef metaDataManager = metaDataManagerOptional.get();
+      metaDataManager.tell(new Ping(username, instanceName, true), ActorRef.noSender());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
index f4d1615..9a4692d 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
@@ -41,8 +41,11 @@ export default DDLAdapter.extend({
 
   createTable(tableMetaInfo) {
     let postURL = this.buildURL('table', null, null, 'query', {databaseId: tableMetaInfo.database});
-    console.log(postURL);
-    console.log(tableMetaInfo);
     return this.ajax(postURL, 'POST', { data: {tableInfo: tableMetaInfo} });
+  },
+
+  deleteTable(database, tableName) {
+    let deletURL = this.buildURL('table', null, null, 'query', {databaseId: database, tableName: tableName});
+    return this.ajax(deletURL, 'DELETE');
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables.js
index a121b88..92f483f 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables.js
@@ -44,4 +44,9 @@ export default Ember.Route.extend({
       this.transitionTo('databases.database.tables.table', table.get('name'));
     }
   }
+
+
+
+
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new.js
index f648ef6..6dfdf29 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new.js
@@ -20,7 +20,7 @@ import Ember from 'ember';
 import tabs from '../../../../configs/create-table-tabs';
 
 export default Ember.Route.extend({
-  createTable: Ember.inject.service(),
+  tableOperations: Ember.inject.service(),
 
   setupController(controller, model) {
     this._super(controller, model);
@@ -34,20 +34,21 @@ export default Ember.Route.extend({
     },
 
     create(settings) {
-      debugger;
       this.controller.set('showCreateTableModal', true);
       this.controller.set('createTableMessage', 'Submitting request to create table');
       let databaseModel = this.controllerFor('databases.database').get('model');
-      this.get('createTable').submitCreateTable(databaseModel.get('name'), settings)
+      this.get('tableOperations').submitCreateTable(databaseModel.get('name'), settings)
         .then((job) => {
           console.log('Created job: ', job.get('id'));
           this.controller.set('createTableMessage', 'Waiting for the table to be created');
-          this.get('createTable').waitForJobToComplete(job.get('id'), 5 * 1000)
+          this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000)
             .then((status) => {
               this.controller.set('createTableMessage', "Successfully created table");
               Ember.run.later(() => {
                 this.controller.set('showCreateTableModal', false);
                 this.controller.set('createTableMessage');
+                this._addTableToStoreLocally(databaseModel, settings.name);
+                this._resetModelInTablesController(databaseModel.get('tables'));
                 this._transitionToCreatedTable(databaseModel.get('name'), settings.name);
               }, 2 * 1000);
             }, (error) => {
@@ -67,5 +68,21 @@ export default Ember.Route.extend({
 
   _transitionToCreatedTable(database, table) {
     this.transitionTo('databases.database.tables.table', database, table);
+  },
+
+  _addTableToStoreLocally(database, table) {
+    this.store.createRecord('table', {
+      id: `${database.get('name')}/${table}`,
+      name: `${table}`,
+      type: 'TABLE',
+      selected: true,
+      database: database
+    });
+  },
+
+  _resetModelInTablesController(tables) {
+    let tablesController = this.controllerFor('databases.database.tables');
+    tablesController.get('model').setEach('selected', false);
+    tablesController.set('model', tables);
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table.js
index 5a88bd2..88f1e7e 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table.js
@@ -20,6 +20,7 @@ import Ember from 'ember';
 import tabs from '../../../../configs/table-level-tabs';
 
 export default Ember.Route.extend({
+  tableOperations: Ember.inject.service(),
   model(params) {
     let database = this.modelFor('databases.database').get('name');
     let table = params.name;
@@ -40,5 +41,55 @@ export default Ember.Route.extend({
     controller.set('tabs', newTabs);
   },
 
-  actions: {}
+  actions: {
+    deleteTable(table) {
+      this.deleteTable(table);
+    },
+
+    editTable(table) {
+      console.log("Edit table");
+    }
+  },
+
+  deleteTable(tableInfo) {
+    this.controller.set('showDeleteTableModal', true);
+    this.controller.set('deleteTableMessage', 'Submitting request to delete table');
+    let databaseModel = this.controllerFor('databases.database').get('model');
+    this.get('tableOperations').deleteTable(databaseModel.get('name'), tableInfo.get('table'))
+      .then((job) => {
+        this.controller.set('deleteTableMessage', 'Waiting for the table to be deleted');
+        this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000)
+          .then((status) => {
+            this.controller.set('deleteTableMessage', "Successfully Deleted table");
+            Ember.run.later(() => {
+              this.controller.set('showDeleteTableModal', false);
+              this.controller.set('deleteTableMessage');
+              this._removeTableLocally(databaseModel.get('name'), tableInfo.get('table'));
+              this._resetModelInTablesController(databaseModel.get('name'), tableInfo.get('table'));
+              this.transitionTo('databases.database', databaseModel.get('name'));
+            }, 2 * 1000);
+          }, (error) => {
+            // TODO: handle error
+            Ember.run.later(() => {
+              this.controller.set('showDeleteTableModal', false);
+              this.controller.set('deleteTableMessage');
+              this.transitionTo('databases.database', databaseModel.get('name'));
+            }, 2 * 1000);
+          });
+      }, (error) => {
+        console.log("Error encountered", error);
+        this.controller.set('showDeleteTableModal', true);
+      });
+  },
+
+  _removeTableLocally(database, table) {
+    let tableToBeRemoved = this.store.peekRecord('table', `${database}/${table}`);
+    this.store.deleteRecord(tableToBeRemoved);
+  },
+
+  _resetModelInTablesController(database, tables) {
+    let tablesController = this.controllerFor('databases.database.tables');
+    let currentTables = this.store.peekRecord('database', database).get('tables');
+    tablesController.set('model', currentTables);
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/services/create-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/create-table.js b/contrib/views/hive20/src/main/resources/ui/app/services/create-table.js
deleted file mode 100644
index 135f96a..0000000
--- a/contrib/views/hive20/src/main/resources/ui/app/services/create-table.js
+++ /dev/null
@@ -1,182 +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.
- */
-
-import Ember from 'ember';
-
-export default Ember.Service.extend({
-  store: Ember.inject.service(),
-
-  submitCreateTable(database, settings) {
-    let detailedInfo = this._getDetailedInfo(settings);
-    let storageInfo = this._getStorageInfo(settings);
-    let columns = this._getColumns(settings);
-    let partitionColumns = this._getPartitionColumns(settings);
-
-    let tableInfo = Ember.Object.create({
-      database: database,
-      table: settings.name,
-      columns: columns,
-      partitionInfo: { columns: partitionColumns },
-      detailedInfo: detailedInfo,
-      storageInfo: storageInfo
-    });
-    return new Promise((resolve, reject) => {
-      this.get('store').adapterFor('table').createTable(tableInfo).then((data) => {
-        this.get('store').pushPayload({job: data});
-        resolve(this.get('store').peekRecord('job', data.id));
-      }, (err) => {
-        reject(err);
-      });
-    });
-  },
-
-  waitForJobToComplete(jobId, after) {
-    return new Ember.RSVP.Promise((resolve, reject) => {
-      Ember.run.later(() => {
-        this.get('store').findRecord('job', jobId, {reload: true})
-          .then((job) => {
-            let status = job.get('status').toLowerCase();
-            if (status === 'succeeded') {
-              this._fetchDummyResult(jobId);
-              resolve();
-            } else if (status === 'error') {
-              reject()
-            } else {
-              resolve(this.waitForJobToComplete(jobId, after));
-            }
-          }, (error) => {
-            reject(error);
-          });
-      }, after);
-    });
-  },
-
-  _fetchDummyResult(jobId) {
-    this.get('store').adapterFor('job').fetchResult(jobId);
-  },
-
-  _getDetailedInfo(settings) {
-    let detailedInfo = {};
-    detailedInfo['parameters'] = this._getTableProperties(settings);
-
-    if (!Ember.isEmpty(settings.settings.location)) {
-      detailedInfo['location'] = settings.settings.location;
-    }
-
-    return detailedInfo;
-
-  },
-
-  _getStorageInfo(settings) {
-    const storageSettings = settings.settings;
-    let storageInfo = {};
-    let parameters = {};
-
-
-
-    if (!(Ember.isEmpty(storageSettings.fileFormat) || Ember.isEmpty(storageSettings.fileFormat.type))) {
-      storageInfo.fileFormat = storageSettings.fileFormat.type;
-      if (storageSettings.fileFormat.type === 'CUSTOM Serde') {
-        storageInfo.inputFormat = storageSettings.inputFormat;
-        storageInfo.outputFormat = storageSettings.outputFormat;
-      }
-    }
-
-    if (!Ember.isEmpty(storageSettings.rowFormat)) {
-      let addParameters = false;
-      if (!Ember.isEmpty(storageSettings.rowFormat.fieldTerminatedBy)) {
-        parameters['field.delim'] = String.fromCharCode(storageSettings.rowFormat.fieldTerminatedBy.id);
-        addParameters = true;
-      }
-
-      if (!Ember.isEmpty(storageSettings.rowFormat.linesTerminatedBy)) {
-        parameters['line.delim'] = String.fromCharCode(storageSettings.rowFormat.linesTerminatedBy.id);
-        addParameters = true;
-      }
-
-      if (!Ember.isEmpty(storageSettings.rowFormat.nullDefinedAs)) {
-        parameters['serialization.null.format'] = String.fromCharCode(storageSettings.rowFormat.fieldTerminatedBy.id);
-        addParameters = true;
-      }
-
-      if (!Ember.isEmpty(storageSettings.rowFormat.escapeDefinedAs)) {
-        parameters['escape.delim'] = String.fromCharCode(storageSettings.rowFormat.linesTerminatedBy.id);
-        addParameters = true;
-      }
-
-      if (addParameters) {
-        storageInfo.parameters = parameters;
-      }
-    }
-
-    if (!Ember.isEmpty(settings.settings.numBuckets)) {
-      storageInfo['numBuckets'] = settings.settings.numBuckets;
-    }
-
-    let clusteredColumnNames =  settings.columns.filterBy('isClustered', true).map((column) => {
-      return column.get('name');
-    });
-
-    if (clusteredColumnNames.length > 0) {
-      storageInfo['bucketCols'] = clusteredColumnNames;
-    }
-
-    return storageInfo;
-  },
-
-  _getColumns(settings) {
-    return settings.columns.filterBy('isPartitioned', false).map((column) => {
-      return {
-        name: column.get('name'),
-        type: column.get('type.label'),
-        comment: column.get('comment'),
-        precision: column.get('precision'),
-        scale: column.get('scale')
-      }
-    });
-  },
-
-  _getPartitionColumns(settings) {
-    return settings.columns.filterBy('isPartitioned', true).map((column) => {
-      return {
-        name: column.get('name'),
-        type: column.get('type.label'),
-        comment: column.get('comment'),
-        precision: column.get('precision'),
-        scale: column.get('scale')
-      }
-    });
-  },
-
-  _getTableProperties(settings) {
-    let properties = {};
-    settings.properties.forEach(function (property) {
-      properties[property.key] = property.value;
-    });
-
-    if (settings.settings.transactional) {
-      if (Ember.isEmpty(properties['transactional'])) {
-        properties['transactional'] = true;
-      }
-    }
-
-    return properties;
-  }
-
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
new file mode 100644
index 0000000..81b0430
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
@@ -0,0 +1,193 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+  store: Ember.inject.service(),
+
+  submitCreateTable(database, settings) {
+    let detailedInfo = this._getDetailedInfo(settings);
+    let storageInfo = this._getStorageInfo(settings);
+    let columns = this._getColumns(settings);
+    let partitionColumns = this._getPartitionColumns(settings);
+
+    let tableInfo = Ember.Object.create({
+      database: database,
+      table: settings.name,
+      columns: columns,
+      partitionInfo: { columns: partitionColumns },
+      detailedInfo: detailedInfo,
+      storageInfo: storageInfo
+    });
+    return new Promise((resolve, reject) => {
+      this.get('store').adapterFor('table').createTable(tableInfo).then((data) => {
+        this.get('store').pushPayload(data);
+        resolve(this.get('store').peekRecord('job', data.job.id));
+      }, (err) => {
+        reject(err);
+      });
+    });
+  },
+
+  deleteTable(database, table) {
+    return new Promise((resolve, reject) => {
+      this.get('store').adapterFor('table').deleteTable(database, table).then((data) => {
+        this.get('store').pushPayload(data);
+        resolve(this.get('store').peekRecord('job', data.job.id));
+      }, (err) => {
+        reject(err);
+      });
+    })
+  },
+
+  waitForJobToComplete(jobId, after) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      Ember.run.later(() => {
+        this.get('store').findRecord('job', jobId, {reload: true})
+          .then((job) => {
+            let status = job.get('status').toLowerCase();
+            if (status === 'succeeded') {
+              this._fetchDummyResult(jobId);
+              resolve();
+            } else if (status === 'error') {
+              reject()
+            } else {
+              resolve(this.waitForJobToComplete(jobId, after));
+            }
+          }, (error) => {
+            reject(error);
+          });
+      }, after);
+    });
+  },
+
+  _fetchDummyResult(jobId) {
+    this.get('store').adapterFor('job').fetchResult(jobId);
+  },
+
+  _getDetailedInfo(settings) {
+    let detailedInfo = {};
+    detailedInfo['parameters'] = this._getTableProperties(settings);
+
+    if (!Ember.isEmpty(settings.settings.location)) {
+      detailedInfo['location'] = settings.settings.location;
+    }
+
+    return detailedInfo;
+
+  },
+
+  _getStorageInfo(settings) {
+    const storageSettings = settings.settings;
+    let storageInfo = {};
+    let parameters = {};
+
+
+
+    if (!(Ember.isEmpty(storageSettings.fileFormat) || Ember.isEmpty(storageSettings.fileFormat.type))) {
+      storageInfo.fileFormat = storageSettings.fileFormat.type;
+      if (storageSettings.fileFormat.type === 'CUSTOM Serde') {
+        storageInfo.inputFormat = storageSettings.inputFormat;
+        storageInfo.outputFormat = storageSettings.outputFormat;
+      }
+    }
+
+    if (!Ember.isEmpty(storageSettings.rowFormat)) {
+      let addParameters = false;
+      if (!Ember.isEmpty(storageSettings.rowFormat.fieldTerminatedBy)) {
+        parameters['field.delim'] = String.fromCharCode(storageSettings.rowFormat.fieldTerminatedBy.id);
+        addParameters = true;
+      }
+
+      if (!Ember.isEmpty(storageSettings.rowFormat.linesTerminatedBy)) {
+        parameters['line.delim'] = String.fromCharCode(storageSettings.rowFormat.linesTerminatedBy.id);
+        addParameters = true;
+      }
+
+      if (!Ember.isEmpty(storageSettings.rowFormat.nullDefinedAs)) {
+        parameters['serialization.null.format'] = String.fromCharCode(storageSettings.rowFormat.fieldTerminatedBy.id);
+        addParameters = true;
+      }
+
+      if (!Ember.isEmpty(storageSettings.rowFormat.escapeDefinedAs)) {
+        parameters['escape.delim'] = String.fromCharCode(storageSettings.rowFormat.linesTerminatedBy.id);
+        addParameters = true;
+      }
+
+      if (addParameters) {
+        storageInfo.parameters = parameters;
+      }
+    }
+
+    if (!Ember.isEmpty(settings.settings.numBuckets)) {
+      storageInfo['numBuckets'] = settings.settings.numBuckets;
+    }
+
+    let clusteredColumnNames =  settings.columns.filterBy('isClustered', true).map((column) => {
+      return column.get('name');
+    });
+
+    if (clusteredColumnNames.length > 0) {
+      storageInfo['bucketCols'] = clusteredColumnNames;
+    }
+
+    return storageInfo;
+  },
+
+  _getColumns(settings) {
+    return settings.columns.filterBy('isPartitioned', false).map((column) => {
+      return {
+        name: column.get('name'),
+        type: column.get('type.label'),
+        comment: column.get('comment'),
+        precision: column.get('precision'),
+        scale: column.get('scale')
+      }
+    });
+  },
+
+  _getPartitionColumns(settings) {
+    return settings.columns.filterBy('isPartitioned', true).map((column) => {
+      return {
+        name: column.get('name'),
+        type: column.get('type.label'),
+        comment: column.get('comment'),
+        precision: column.get('precision'),
+        scale: column.get('scale')
+      }
+    });
+  },
+
+  _getTableProperties(settings) {
+    let properties = {};
+    settings.properties.forEach(function (property) {
+      properties[property.key] = property.value;
+    });
+
+    if (settings.settings.transactional) {
+      if (Ember.isEmpty(properties['transactional'])) {
+        properties['transactional'] = true;
+      }
+    }
+
+    return properties;
+  }
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/templates/components/jobs-browser.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/jobs-browser.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/jobs-browser.hbs
index 84f16a7..47b499a 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/jobs-browser.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/jobs-browser.hbs
@@ -45,7 +45,7 @@
       <thead>
         <tr>
           <th width="10%">Job Id</th>
-          <th width="30%">Title <span class="pull-right">Dipayan</span> </th>
+          <th width="30%">Title</th>
           <th width="10%">status</th>
           <th width="25%">Start time</th>
           <th width="20%" >Duration</th>

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
index 258f687..2d1d075 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
@@ -25,12 +25,26 @@
           {{fa-icon "navicon"}}
         </button>
         <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
-          <li><a href="#" class="text-uppercase">{{fa-icon "edit"}} Edit</a></li>
-          <li><a href="#" class="text-uppercase">{{fa-icon "trash"}} Delete</a></li>
+          <li><a href="#" class="text-uppercase" {{action "editTable" model}}>{{fa-icon "edit"}} Edit</a></li>
+          <li><a href="#" class="text-uppercase" {{action "deleteTable" model}}>{{fa-icon "trash"}} Delete</a></li>
         </ul>
       </div>
     </div>
   </div>
+  {{#if showDeleteTableModal}}
+    {{#modal-dialog
+      translucentOverlay=true
+      container-class="modal-dialog modal-sm"}}
+      <div class="modal-content">
+        <div class="modal-header text-danger">
+          <p class="modal-title">{{fa-icon "minus"}}&nbsp;&nbsp;&nbsp; Delete table</p>
+        </div>
+        <div class="modal-body text-center text-primary">
+          <p>{{deleteTableMessage}}</p>
+        </div>
+      </div><!-- /.modal-content -->
+    {{/modal-dialog}}
+  {{/if}}
   <div class="table-body">
     {{#tabs-pane tabs=tabs inverse= true as |tab|}}
       {{tabs-item tab=tab tabs=tabs}}
@@ -39,4 +53,6 @@
   </div>
 
 
+
+
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/details.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/details.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/details.hbs
index 1577fec..225b6eb 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/details.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/details.hbs
@@ -56,7 +56,7 @@
         </tr>
         <tr>
           <th>Parameters</th>
-          <td><pre class="table-info-json">{{toJson info.parameters}}</pre></td>
+          <td><pre class="table-info-json">{{to-json info.parameters}}</pre></td>
         </tr>
       </tbody>
     {{/with}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/1e2fe429/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/storage.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/storage.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/storage.hbs
index 6e76741..52209ac 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/storage.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/storage.hbs
@@ -56,7 +56,7 @@
       </tr>
       <tr>
         <th>Parameters</th>
-        <td><pre class="table-info-json">{{toJson info.parameters}}</pre></td>
+        <td><pre class="table-info-json">{{to-json info.parameters}}</pre></td>
       </tr>
       </tbody>
     {{/with}}