You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sr...@apache.org on 2016/07/12 20:06:14 UTC

[1/4] sentry git commit: SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS notification logs

Repository: sentry
Updated Branches:
  refs/heads/sentry-ha-redesign de7c26a8a -> ff7823b66


http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDBNotificationListenerInBuiltDeserializer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDBNotificationListenerInBuiltDeserializer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDBNotificationListenerInBuiltDeserializer.java
new file mode 100644
index 0000000..56e19c4
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDBNotificationListenerInBuiltDeserializer.java
@@ -0,0 +1,353 @@
+/**
+ * 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.sentry.tests.e2e.metastore;
+
+import com.google.common.collect.Lists;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.api.*;
+import org.apache.hive.hcatalog.messaging.CreateDatabaseMessage;
+import org.apache.hive.hcatalog.messaging.HCatEventMessage;
+import org.apache.hive.hcatalog.messaging.MessageDeserializer;
+import org.apache.hive.hcatalog.messaging.MessageFactory;
+import org.apache.hive.hcatalog.messaging.CreateTableMessage;
+import org.apache.hive.hcatalog.messaging.DropTableMessage;
+import org.apache.hive.hcatalog.messaging.AlterTableMessage;
+import org.apache.hive.hcatalog.messaging.AlterPartitionMessage;
+import org.apache.hive.hcatalog.messaging.DropDatabaseMessage;
+import org.apache.hive.hcatalog.messaging.AddPartitionMessage;
+import org.apache.hive.hcatalog.messaging.DropPartitionMessage;
+import org.apache.sentry.tests.e2e.hive.StaticUserGroup;
+import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.hamcrest.text.IsEqualIgnoringCase;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.*;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * Make sure NotificationLog is capturing the information correctly for the commands which change <Obj,Location> mapping
+ * This test class is using Hive's DbNotificationListener and Hive's Notification log JSON deserializer.
+ */
+
+public class TestDBNotificationListenerInBuiltDeserializer extends AbstractMetastoreTestWithStaticConfiguration {
+
+  protected static HiveMetaStoreClient client;
+  protected static MessageDeserializer deserializer;
+  protected static Random random = new Random();
+  private static String testDB;
+
+  @BeforeClass
+  public static void setupTestStaticConfiguration() throws Exception {
+    setMetastoreListener = true;
+    useDbNotificationListener = true;
+    beforeClass();
+  }
+
+  protected static void beforeClass() throws Exception {
+    AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration();
+    client = context.getMetaStoreClient(ADMIN1);
+    deserializer = MessageFactory.getDeserializer("json", "");
+    writePolicyFile(setAdminOnServer1(ADMINGROUP).setUserGroupMapping(StaticUserGroup.getStaticMapping()));
+  }
+
+  @AfterClass
+  public static void cleanupAfterClass() throws Exception {
+    if (client != null) {
+      client.close();
+    }
+  }
+
+  @After
+  public void dropDBAfterTest() throws Exception {
+    if(client != null && testDB != null) {
+      dropMetastoreDBIfExists(client, testDB);
+    }
+  }
+
+  @Test
+  public void testCreateDropDatabase() throws Exception {
+    CurrentNotificationEventId latestID, previousID;
+    NotificationEventResponse response;
+
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+
+    // Create database
+    // We need:
+    // - Dbname
+    // - location
+    createMetastoreDB(client, testDB);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    CreateDatabaseMessage createDatabaseMessage = deserializer.getCreateDatabaseMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_DATABASE, createDatabaseMessage.getEventType()); //Validate EventType
+    assertEquals(testDB, createDatabaseMessage.getDB()); //dbName
+    //Location information is not available
+
+    //Alter database location and rename are not supported. See HIVE-4847
+
+    //Drop database
+    // We need:
+    // - dbName
+    // - location
+    client.dropDatabase(testDB);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId()); //Validate monotonically increasing eventID
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    DropDatabaseMessage dropDatabaseMessage = deserializer.getDropDatabaseMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_DATABASE, dropDatabaseMessage.getEventType()); //Event type
+    assertThat(dropDatabaseMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); // dbName
+    //Location information is not available, but we might not really need it as we can drop all paths associated with
+    //the object when we drop
+  }
+
+  @Test
+  public void testCreateDropTableWithPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    // We need:
+    // - dbname
+    // - tablename
+    // - location
+    createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    CreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
+    assertEquals(testDB, createTableMessage.getDB()); //dbName
+    assertEquals(testTable, createTableMessage.getTable()); //tableName
+    //Location information is not available
+
+    //Drop table
+    // We need:
+    // - dbName
+    // - tableName
+    // - location
+    client.dropTable(testDB, testTable);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    DropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
+    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    //Location information is not available, but we might not really need it as we can drop all paths associated with
+    //the object when we drop
+  }
+
+  @Test
+  public void testCreateDropTableWithoutPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    // We need:
+    // - dbname
+    // - tablename
+    // - location
+    createMetastoreTable(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")));
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    CreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
+    assertEquals(testDB, createTableMessage.getDB()); //dbName
+    assertEquals(testTable, createTableMessage.getTable()); //tableName
+    //Location information is not available
+
+    //Drop table
+    // We need:
+    // - dbName
+    // - tableName
+    // - location
+    client.dropTable(testDB, testTable);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    DropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
+    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    //Location information is not available, but we might not really need it as we can drop all paths associated with
+    //the object when we drop
+  }
+
+  @Test
+  public void testAddDropPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database and table
+    createMetastoreDB(client, testDB);
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+
+    ArrayList<String> partVals1 = Lists.newArrayList("part1");
+
+    //Add partition
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    addPartition(client, testDB, testTable, partVals1, tbl1);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    AddPartitionMessage addPartitionMessage = deserializer.getAddPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ADD_PARTITION, addPartitionMessage.getEventType());
+    assertThat(addPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName (returns lowered version)
+    assertThat(addPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName (returns lowered version)
+    //Location information is not available
+
+    //Drop partition
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    dropPartition(client, testDB, testTable, partVals1);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    DropPartitionMessage dropPartitionMessage = deserializer.getDropPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_PARTITION, dropPartitionMessage.getEventType());
+    assertThat(dropPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); //dbName
+    assertThat(dropPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable)); //tableName
+    //Location information is not available
+
+  }
+
+  @Ignore("Needs Hive >= 1.1.2")
+  @Test
+  public void testAlterTableWithPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+
+    //Alter table location
+    // We need:
+    // - dbName
+    // - tableName
+    // - old location
+    // - new location
+    String tabDir1 = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR)
+        + File.separator + random.nextInt(Integer.SIZE - 1);
+    alterTableWithLocation(client, tbl1, tabDir1);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    AlterTableMessage alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
+    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    //Old location is not available: This information is lost if not captured at the time of event.
+    //New location is not available
+
+    //Alter table rename managed table - location also changes
+    // We need:
+    // - oldDbName
+    // - newDbName
+    // - oldTableName
+    // - newTableName
+    // - old location
+    // - new location
+    String newDBName = testDB + random.nextInt(Integer.SIZE - 1);
+    String newTableName = testTable + random.nextInt(Integer.SIZE - 1);
+    String newLocation = tabDir1 + random.nextInt(Integer.SIZE - 1);
+    createMetastoreDB(client, newDBName);
+    alterTableRename(client, tbl1, newDBName, newTableName, newLocation);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
+    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//oldDbName
+    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//oldTableName
+    assertThat(response.getEvents().get(0).getDbName(), IsEqualIgnoringCase.equalToIgnoringCase(newDBName));//newDbName
+    assertThat(response.getEvents().get(0).getTableName(), IsEqualIgnoringCase.equalToIgnoringCase(newTableName));//newTableName
+    //Old location: This information is lost if not captured at the time of event.
+    //New location: Not sure how can we get this? Refresh all paths for every alter table add partition?
+  }
+
+  @Ignore("Needs Hive >= 1.1.2")
+  @Test
+  public void testAlterPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+    ArrayList<String> partVals1 = Lists.newArrayList("part1");
+    Partition partition = addPartition(client, testDB, testTable, partVals1, tbl1);
+
+
+    String warehouseDir = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR);
+    //Alter partition with location
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    alterPartitionWithLocation(client, partition, warehouseDir + File.separator + "newpart");
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    AlterPartitionMessage alterPartitionMessage = deserializer.getAlterPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_PARTITION, alterPartitionMessage.getEventType());
+    assertThat(alterPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName
+    assertThat(alterPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName
+    //Location information, not sure how can we get this? Refresh all paths for every alter table add partition?
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDbNotificationListenerSentryDeserializer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDbNotificationListenerSentryDeserializer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDbNotificationListenerSentryDeserializer.java
new file mode 100644
index 0000000..8e588b1
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestDbNotificationListenerSentryDeserializer.java
@@ -0,0 +1,39 @@
+/**
+ * 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.sentry.tests.e2e.metastore;
+
+import org.junit.BeforeClass;
+
+
+/**
+ * Make sure we are able to capture all HMS object and path changes using Hive's DbNotificationListener and
+ * Sentry's JSON deserializer. This would make sure Sentry is able to read the Notification logs written by
+ * Hive's DBNotificationListener
+ */
+public class TestDbNotificationListenerSentryDeserializer extends TestSentryListenerSentryDeserializer {
+
+  @BeforeClass
+  public static void setupTestStaticConfiguration() throws Exception {
+    setMetastoreListener = true;
+    useDbNotificationListener = true;
+    AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration();
+    setupClass();
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestHMSNotificationLogUsingDBNotificationListener.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestHMSNotificationLogUsingDBNotificationListener.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestHMSNotificationLogUsingDBNotificationListener.java
deleted file mode 100644
index 0b328d4..0000000
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestHMSNotificationLogUsingDBNotificationListener.java
+++ /dev/null
@@ -1,351 +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
- * <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.sentry.tests.e2e.metastore;
-
-import com.google.common.collect.Lists;
-import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
-import org.apache.hadoop.hive.metastore.api.*;
-import org.apache.hive.hcatalog.messaging.CreateDatabaseMessage;
-import org.apache.hive.hcatalog.messaging.HCatEventMessage;
-import org.apache.hive.hcatalog.messaging.MessageDeserializer;
-import org.apache.hive.hcatalog.messaging.MessageFactory;
-import org.apache.hive.hcatalog.messaging.CreateTableMessage;
-import org.apache.hive.hcatalog.messaging.DropTableMessage;
-import org.apache.hive.hcatalog.messaging.AlterTableMessage;
-import org.apache.hive.hcatalog.messaging.AlterPartitionMessage;
-import org.apache.hive.hcatalog.messaging.DropDatabaseMessage;
-import org.apache.hive.hcatalog.messaging.AddPartitionMessage;
-import org.apache.hive.hcatalog.messaging.DropPartitionMessage;
-import org.apache.sentry.provider.file.PolicyFile;
-import org.apache.sentry.tests.e2e.hive.StaticUserGroup;
-import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
-import org.hamcrest.text.IsEqualIgnoringCase;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import org.junit.*;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Random;
-
-/**
- * Make sure NotificationLog is capturing the information correctly for the commands which change <Obj,Location> mapping
- */
-public class TestHMSNotificationLogUsingDBNotificationListener extends AbstractMetastoreTestWithStaticConfiguration {
-
-  private PolicyFile policyFile;
-
-  private static HiveMetaStoreClient client;
-  private static MessageDeserializer deserializer;
-  private static Random random = new Random();
-
-
-  @BeforeClass
-  public static void setupTestStaticConfiguration() throws Exception {
-    setMetastoreListener = true;
-    useDbNotificationListener = true;
-    AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration();
-    client = context.getMetaStoreClient(ADMIN1);
-    deserializer = MessageFactory.getDeserializer("json", "");
-  }
-
-  @AfterClass
-  public static void cleanupAfterClass() throws Exception {
-    if (client != null) {
-      client.close();
-    }
-  }
-
-  @Override
-  @Before
-  public void setup() throws Exception {
-    policyFile = setAdminOnServer1(ADMINGROUP);
-    policyFile.setUserGroupMapping(StaticUserGroup.getStaticMapping());
-    writePolicyFile(policyFile);
-    super.setup();
-  }
-
-  @Test
-  public void testCreateDropDatabase() throws Exception {
-    CurrentNotificationEventId latestID, previousID;
-    NotificationEventResponse response;
-
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-
-    // Create database
-    // We need:
-    // - Dbname
-    // - location
-    createMetastoreDB(client, testDB);
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    CreateDatabaseMessage createDatabaseMessage = deserializer.getCreateDatabaseMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.CREATE_DATABASE, createDatabaseMessage.getEventType()); //Validate EventType
-    assertEquals(testDB, createDatabaseMessage.getDB()); //dbName
-    //Location information is not available
-
-    //Alter database location and rename are not supported. See HIVE-4847
-
-    //Drop database
-    // We need:
-    // - dbName
-    // - location
-    client.dropDatabase(testDB);
-    previousID = latestID;
-    latestID = client.getCurrentNotificationEventId();
-    assertEquals(previousID.getEventId() + 1, latestID.getEventId()); //Validate monotonically increasing eventID
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    DropDatabaseMessage dropDatabaseMessage = deserializer.getDropDatabaseMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.DROP_DATABASE, dropDatabaseMessage.getEventType()); //Event type
-    assertThat(dropDatabaseMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); // dbName
-    //Location information is not available, but we might not really need it as we can drop all paths associated with
-    //the object when we drop
-  }
-
-  @Test
-  public void testCreateDropTableWithPartition() throws Exception {
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
-
-    NotificationEventResponse response;
-    CurrentNotificationEventId latestID, previousID;
-    // Create database
-    createMetastoreDB(client, testDB);
-
-    // Create table with partition
-    // We need:
-    // - dbname
-    // - tablename
-    // - location
-    createMetastoreTableWithPartition(client, testDB,
-        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
-        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    CreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
-    assertEquals(testDB, createTableMessage.getDB()); //dbName
-    assertEquals(testTable, createTableMessage.getTable()); //tableName
-    //Location information is not available
-
-    //Drop table
-    // We need:
-    // - dbName
-    // - tableName
-    // - location
-    client.dropTable(testDB, testTable);
-    previousID = latestID;
-    latestID = client.getCurrentNotificationEventId();
-    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    DropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
-    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
-    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
-    //Location information is not available, but we might not really need it as we can drop all paths associated with
-    //the object when we drop
-  }
-
-  @Test
-  public void testCreateDropTableWithoutPartition() throws Exception {
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
-
-    NotificationEventResponse response;
-    CurrentNotificationEventId latestID, previousID;
-    // Create database
-    createMetastoreDB(client, testDB);
-
-    // Create table with partition
-    // We need:
-    // - dbname
-    // - tablename
-    // - location
-    createMetastoreTable(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")));
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    CreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
-    assertEquals(testDB, createTableMessage.getDB()); //dbName
-    assertEquals(testTable, createTableMessage.getTable()); //tableName
-    //Location information is not available
-
-    //Drop table
-    // We need:
-    // - dbName
-    // - tableName
-    // - location
-    client.dropTable(testDB, testTable);
-    previousID = latestID;
-    latestID = client.getCurrentNotificationEventId();
-    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    DropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
-    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
-    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
-    //Location information is not available, but we might not really need it as we can drop all paths associated with
-    //the object when we drop
-  }
-
-  @Test
-  public void testAddDropPartition() throws Exception {
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
-
-    NotificationEventResponse response;
-    CurrentNotificationEventId latestID, previousID;
-    // Create database and table
-    createMetastoreDB(client, testDB);
-    Table tbl1 = createMetastoreTableWithPartition(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
-        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
-
-    ArrayList<String> partVals1 = Lists.newArrayList("part1");
-
-    //Add partition
-    // We need:
-    // - dbName
-    // - tableName
-    // - partition location
-    addPartition(client, testDB, testTable, partVals1, tbl1);
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    AddPartitionMessage addPartitionMessage = deserializer.getAddPartitionMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.ADD_PARTITION, addPartitionMessage.getEventType());
-    assertThat(addPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName (returns lowered version)
-    assertThat(addPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName (returns lowered version)
-    //Location information is not available
-
-    //Drop partition
-    // We need:
-    // - dbName
-    // - tableName
-    // - partition location
-    dropPartition(client, testDB, testTable, partVals1);
-    previousID = latestID;
-    latestID = client.getCurrentNotificationEventId();
-    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
-    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
-    DropPartitionMessage dropPartitionMessage = deserializer.getDropPartitionMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.DROP_PARTITION, dropPartitionMessage.getEventType());
-    assertThat(dropPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); //dbName
-    assertThat(dropPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable)); //tableName
-    //Location information is not available
-
-  }
-
-  @Ignore("Needs Hive >= 1.1.2")
-  @Test
-  public void testAlterTableWithPartition() throws Exception {
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
-
-    NotificationEventResponse response;
-    CurrentNotificationEventId latestID, previousID;
-    // Create database
-    createMetastoreDB(client, testDB);
-
-    // Create table with partition
-    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
-        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
-        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
-
-    //Alter table location
-    // We need:
-    // - dbName
-    // - tableName
-    // - old location
-    // - new location
-    String tabDir1 = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR)
-        + File.separator + random.nextInt(Integer.SIZE - 1);
-    alterTableWithLocation(client, tbl1, tabDir1);
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
-    AlterTableMessage alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
-    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
-    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
-    //Old location is not available: This information is lost if not captured at the time of event.
-    //New location is not available
-
-    //Alter table rename managed table - location also changes
-    // We need:
-    // - oldDbName
-    // - newDbName
-    // - oldTableName
-    // - newTableName
-    // - old location
-    // - new location
-    String newDBName = testDB + random.nextInt(Integer.SIZE - 1);
-    String newTableName = testTable + random.nextInt(Integer.SIZE - 1);
-    String newLocation = tabDir1 + random.nextInt(Integer.SIZE - 1);
-    createMetastoreDB(client, newDBName);
-    alterTableRename(client, tbl1, newDBName, newTableName, newLocation);
-    previousID = latestID;
-    latestID = client.getCurrentNotificationEventId();
-    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
-    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
-    alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
-    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//oldDbName
-    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//oldTableName
-    assertThat(response.getEvents().get(0).getDbName(), IsEqualIgnoringCase.equalToIgnoringCase(newDBName));//newDbName
-    assertThat(response.getEvents().get(0).getTableName(), IsEqualIgnoringCase.equalToIgnoringCase(newTableName));//newTableName
-    //Old location: This information is lost if not captured at the time of event.
-    //New location: Not sure how can we get this? Refresh all paths for every alter table add partition?
-  }
-
-  @Ignore("Needs Hive >= 1.1.2")
-  @Test
-  public void testAlterPartition() throws Exception {
-    String testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
-    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
-
-    NotificationEventResponse response;
-    CurrentNotificationEventId latestID;
-    // Create database
-    createMetastoreDB(client, testDB);
-
-    // Create table with partition
-    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
-        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
-        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
-    ArrayList<String> partVals1 = Lists.newArrayList("part1");
-    Partition partition = addPartition(client, testDB, testTable, partVals1, tbl1);
-
-
-    String warehouseDir = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR);
-    //Alter partition with location
-    // We need:
-    // - dbName
-    // - tableName
-    // - partition location
-    alterPartitionWithLocation(client, partition, warehouseDir + File.separator + "newpart");
-    latestID = client.getCurrentNotificationEventId();
-    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
-    AlterPartitionMessage alterPartitionMessage = deserializer.getAlterPartitionMessage(response.getEvents().get(0).getMessage());
-    assertEquals(HCatEventMessage.EventType.ALTER_PARTITION, alterPartitionMessage.getEventType());
-    assertThat(alterPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName
-    assertThat(alterPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName
-    //Location information, not sure how can we get this? Refresh all paths for every alter table add partition?
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerInBuiltDeserializer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerInBuiltDeserializer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerInBuiltDeserializer.java
new file mode 100644
index 0000000..c4be62d
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerInBuiltDeserializer.java
@@ -0,0 +1,37 @@
+/**
+ * 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.sentry.tests.e2e.metastore;
+
+import org.junit.BeforeClass;
+
+/**
+ * Make sure we are able to capture all HMS object and path changes using Sentry's SentryMetastorePostEventListener
+ * and Hive's inbuilt Notification log deserializer. This would make sure Sentry is not breaking other users of
+ * NotificationLog who might be using Hive's in built serializer
+ */
+public class TestSentryListenerInBuiltDeserializer extends TestDBNotificationListenerInBuiltDeserializer {
+
+  @BeforeClass
+  public static void setupTestStaticConfiguration() throws Exception {
+    setMetastoreListener = true;
+    useDbNotificationListener = false;
+    beforeClass();
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerSentryDeserializer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerSentryDeserializer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerSentryDeserializer.java
new file mode 100644
index 0000000..6f1886f
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestSentryListenerSentryDeserializer.java
@@ -0,0 +1,375 @@
+/**
+ * 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.sentry.tests.e2e.metastore;
+
+import com.google.common.collect.Lists;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.api.*;
+import org.apache.hive.hcatalog.messaging.HCatEventMessage;
+import org.apache.sentry.binding.metastore.messaging.json.*;
+import org.apache.sentry.tests.e2e.hive.StaticUserGroup;
+import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.hamcrest.text.IsEqualIgnoringCase;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.*;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * Make sure we are able to capture all HMS object and path changes using Sentry's SentryMetastorePostEventListener
+ * and Sentry Notification log deserializer. Can be removed if we move to using DBNotificationListener
+ */
+public class TestSentryListenerSentryDeserializer extends AbstractMetastoreTestWithStaticConfiguration {
+
+  protected static HiveMetaStoreClient client;
+  protected static SentryJSONMessageDeserializer deserializer;
+  protected static Random random = new Random();
+  private static String warehouseDir;
+  private static String testDB;
+
+
+  @BeforeClass
+  public static void setupTestStaticConfiguration() throws Exception {
+    setMetastoreListener = true;
+    useDbNotificationListener = false;
+    AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration();
+    setupClass();
+  }
+
+  protected static void setupClass() throws Exception{
+    client = context.getMetaStoreClient(ADMIN1);
+    deserializer = new SentryJSONMessageDeserializer();
+    warehouseDir = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR);
+    writePolicyFile(setAdminOnServer1(ADMINGROUP).setUserGroupMapping(StaticUserGroup.getStaticMapping()));
+
+  }
+
+  @AfterClass
+  public static void cleanupAfterClass() throws Exception {
+    if (client != null) {
+      client.close();
+    }
+  }
+
+  @After
+  public void dropDBAfterTest() throws Exception {
+    if(client != null && testDB != null) {
+      dropMetastoreDBIfExists(client, testDB);
+    }
+  }
+
+  @Test
+  public void testCreateDropDatabase() throws Exception {
+    CurrentNotificationEventId latestID, previousID;
+    NotificationEventResponse response;
+
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+
+    // Create database
+    // We need:
+    // - Dbname
+    // - location
+    createMetastoreDB(client, testDB);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONCreateDatabaseMessage createDatabaseMessage = deserializer.getCreateDatabaseMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_DATABASE, createDatabaseMessage.getEventType()); //Validate EventType
+    assertEquals(testDB, createDatabaseMessage.getDB()); //dbName
+    String expectedLocation = warehouseDir + "/" + testDB + ".db";
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), createDatabaseMessage.getLocation());
+    }
+
+    //Alter database location and rename are not supported. See HIVE-4847
+
+    //Drop database
+    // We need:
+    // - dbName
+    // - location
+    client.dropDatabase(testDB);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId()); //Validate monotonically increasing eventID
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONDropDatabaseMessage dropDatabaseMessage = deserializer.getDropDatabaseMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_DATABASE, dropDatabaseMessage.getEventType()); //Event type
+    assertThat(dropDatabaseMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); // dbName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), dropDatabaseMessage.getLocation()); //location
+    }
+  }
+
+  @Test
+  public void testCreateDropTableWithPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    // We need:
+    // - dbname
+    // - tablename
+    // - location
+    createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONCreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
+    assertEquals(testDB, createTableMessage.getDB()); //dbName
+    assertEquals(testTable, createTableMessage.getTable()); //tableName
+    String expectedLocation = warehouseDir + "/" + testDB + ".db/" + testTable;
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), createTableMessage.getLocation());
+    }
+
+
+    //Drop table
+    // We need:
+    // - dbName
+    // - tableName
+    // - location
+    client.dropTable(testDB, testTable);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONDropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
+    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), dropTableMessage.getLocation()); //location
+    }
+  }
+
+  @Test
+  public void testCreateDropTableWithoutPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    // We need:
+    // - dbname
+    // - tablename
+    // - location
+    createMetastoreTable(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")));
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONCreateTableMessage createTableMessage = deserializer.getCreateTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.CREATE_TABLE, createTableMessage.getEventType());
+    assertEquals(testDB, createTableMessage.getDB()); //dbName
+    assertEquals(testTable, createTableMessage.getTable()); //tableName
+    String expectedLocation = warehouseDir + "/" + testDB + ".db/" + testTable;
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), createTableMessage.getLocation());
+    }
+
+    //Drop table
+    // We need:
+    // - dbName
+    // - tableName
+    // - location
+    client.dropTable(testDB, testTable);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONDropTableMessage dropTableMessage = deserializer.getDropTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_TABLE, dropTableMessage.getEventType());
+    assertThat(dropTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(dropTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), dropTableMessage.getLocation()); //location
+    }
+  }
+
+  @Test
+  public void testAddDropPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database and table
+    createMetastoreDB(client, testDB);
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB, testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+
+    ArrayList<String> partVals1 = Lists.newArrayList("part1");
+
+    //Add partition
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    addPartition(client, testDB, testTable, partVals1, tbl1);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONAddPartitionMessage addPartitionMessage = deserializer.getAddPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ADD_PARTITION, addPartitionMessage.getEventType());
+    assertThat(addPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName (returns lowered version)
+    assertThat(addPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName (returns lowered version)
+    String expectedLocation = warehouseDir + "/" + testDB + ".db/" + testTable ; //TODO: SENTRY-1387: Tablelocation is stored instead of partition location
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), addPartitionMessage.getLocations().get(0));
+    }
+
+    //Drop partition
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    dropPartition(client, testDB, testTable, partVals1);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId() - 1, 1, null);
+    SentryJSONDropPartitionMessage dropPartitionMessage = deserializer.getDropPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.DROP_PARTITION, dropPartitionMessage.getEventType());
+    assertThat(dropPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB)); //dbName
+    assertThat(dropPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable)); //tableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(expectedLocation.toLowerCase(), dropPartitionMessage.getLocation());
+    }
+
+  }
+
+  @Test
+  public void testAlterTableWithPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID, previousID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+    String oldLocation = tbl1.getSd().getLocation();
+
+    //Alter table location
+    // We need:
+    // - dbName
+    // - tableName
+    // - old location
+    // - new location
+    String tabDir1 = hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR)
+        + File.separator + random.nextInt(Integer.SIZE - 1);
+    alterTableWithLocation(client, tbl1, tabDir1);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    SentryJSONAlterTableMessage alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
+    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//dbName
+    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//tableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(oldLocation, alterTableMessage.getOldLocation()); //oldLocation
+      Assert.assertEquals(tbl1.getSd().getLocation(), alterTableMessage.getLocation()); //newLocation
+    }
+
+    //Alter table rename managed table - location also changes
+    // We need:
+    // - oldDbName
+    // - newDbName
+    // - oldTableName
+    // - newTableName
+    // - old location
+    // - new location
+    oldLocation = tbl1.getSd().getLocation();
+    String newDBName = testDB + random.nextInt(Integer.SIZE - 1);
+    String newTableName = testTable + random.nextInt(Integer.SIZE - 1);
+    String newLocation = tabDir1 + random.nextInt(Integer.SIZE - 1);
+    createMetastoreDB(client, newDBName);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    alterTableRename(client, tbl1, newDBName, newTableName, newLocation);
+    previousID = latestID;
+    latestID = client.getCurrentNotificationEventId();
+    assertEquals(previousID.getEventId() + 1, latestID.getEventId());
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    alterTableMessage = deserializer.getAlterTableMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_TABLE, alterTableMessage.getEventType());
+    assertThat(alterTableMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));//oldDbName
+    assertThat(alterTableMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));//oldTableName
+    assertThat(response.getEvents().get(0).getDbName(), IsEqualIgnoringCase.equalToIgnoringCase(newDBName));//newDbName
+    assertThat(response.getEvents().get(0).getTableName(), IsEqualIgnoringCase.equalToIgnoringCase(newTableName));//newTableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(oldLocation, alterTableMessage.getOldLocation()); //oldLocation
+      Assert.assertEquals(tbl1.getSd().getLocation(), alterTableMessage.getLocation()); //newLocation
+    }
+  }
+
+  @Test
+  public void testAlterPartition() throws Exception {
+    testDB = "N_db" + random.nextInt(Integer.SIZE - 1);
+    String testTable = "N_table" + random.nextInt(Integer.SIZE - 1);
+
+    NotificationEventResponse response;
+    CurrentNotificationEventId latestID;
+    // Create database
+    createMetastoreDB(client, testDB);
+
+    // Create table with partition
+    Table tbl1 = createMetastoreTableWithPartition(client, testDB,
+        testTable, Lists.newArrayList(new FieldSchema("col1", "int", "")),
+        Lists.newArrayList(new FieldSchema("part_col1", "string", "")));
+    ArrayList<String> partVals1 = Lists.newArrayList("part1");
+    Partition partition = addPartition(client, testDB, testTable, partVals1, tbl1);
+
+    //Alter partition with location
+    // We need:
+    // - dbName
+    // - tableName
+    // - partition location
+    String oldLocation = tbl1.getSd().getLocation(); //TODO: SENTRY-1387: Tablelocation is stored instead of partition location
+    String newLocation = warehouseDir + File.separator + "newpart";
+    alterPartitionWithLocation(client, partition, newLocation);
+    latestID = client.getCurrentNotificationEventId();
+    response = client.getNextNotification(latestID.getEventId()-1, 1, null);
+    SentryJSONAlterPartitionMessage alterPartitionMessage = deserializer.getAlterPartitionMessage(response.getEvents().get(0).getMessage());
+    assertEquals(HCatEventMessage.EventType.ALTER_PARTITION, alterPartitionMessage.getEventType());
+    assertThat(alterPartitionMessage.getDB(), IsEqualIgnoringCase.equalToIgnoringCase(testDB));// dbName
+    assertThat(alterPartitionMessage.getTable(), IsEqualIgnoringCase.equalToIgnoringCase(testTable));// tableName
+    if(!useDbNotificationListener) {
+      Assert.assertEquals(oldLocation.toLowerCase(), alterPartitionMessage.getOldLocation());
+      Assert.assertEquals(newLocation.toLowerCase(), alterPartitionMessage.getLocation());
+    }
+  }
+}
+


[4/4] sentry git commit: SENTRY-1317: Implement fencing required for active/standby (Colin P. McCabe , Reviewed by: Hao Hao and Sravya Tirukkovalur)

Posted by sr...@apache.org.
SENTRY-1317: Implement fencing required for active/standby (Colin P. McCabe , Reviewed by: Hao Hao and Sravya Tirukkovalur)

New fencing and active/passive code
- Activator to store the state about whether the daemon is active or not, as well as manage fencing
- Create Fencer to implement SQL fencing.
- Add SqlAccessor to talk directly to SQL databases
LeaderStatus: generate shorter incarnation IDs by using base64.
LeaderStatusAdaptor: implement close()
Remove old code which is no longer used
- HAContext
- PluginCacheSyncUtil
- TestHAUpdateForwarder
- ServiceRegister
SentryStore
- move DataNucleus properties setup into a utility function
- Remove unused DEFAULT_DATA_DIR variable (it's not used anywhere in the code)
- SentryStore should maintain a reference to the Activator
Add SentryStandbyException to indicate that the daemon is currently standby
Move SENTRY_ZK_JAAS_NAME from HAContext to SentryConstants
DelegateSentryStore: make some fields final

Change-Id: Ic41711ecbc218bb21e3ca3120998866d65e16493


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

Branch: refs/heads/sentry-ha-redesign
Commit: ff7823b66f5fc6cb97b5b760ab091b217c38f7d4
Parents: 113c5ea
Author: Sravya Tirukkovalur <sr...@apache.org>
Authored: Tue Jul 12 13:03:23 2016 -0700
Committer: Sravya Tirukkovalur <sr...@apache.org>
Committed: Tue Jul 12 13:03:23 2016 -0700

----------------------------------------------------------------------
 .../exception/SentryStandbyException.java       |  33 ++
 .../core/common/utils/SentryConstants.java      |   3 +
 .../apache/sentry/hdfs/PluginCacheSyncUtil.java | 251 ---------------
 .../sentry/hdfs/SentryHdfsMetricsUtil.java      |   8 -
 .../sentry/hdfs/TestHAUpdateForwarder.java      |  66 ----
 .../provider/db/service/persistent/Fencer.java  | 242 +++++++++++++++
 .../db/service/persistent/HAContext.java        | 262 ----------------
 .../db/service/persistent/SentryStore.java      |  32 +-
 .../db/service/persistent/ServiceRegister.java  |  52 ----
 .../db/service/persistent/SqlAccessor.java      | 309 +++++++++++++++++++
 .../thrift/SentryPolicyStoreProcessor.java      |  31 +-
 .../apache/sentry/service/thrift/Activator.java | 112 +++++++
 .../sentry/service/thrift/Activators.java       |  69 +++++
 .../sentry/service/thrift/LeaderStatus.java     |  31 +-
 .../service/thrift/LeaderStatusAdaptor.java     |  41 ++-
 .../sentry/service/thrift/SentryService.java    |  33 +-
 .../sentry/service/thrift/ServiceConstants.java |   4 +
 .../persistent/SentryStoreIntegrationBase.java  |  15 +
 .../TestPrivilegeOperatePersistence.java        |  22 +-
 .../db/service/persistent/TestSentryStore.java  |  14 +
 .../persistent/TestSentryStoreImportExport.java |  16 +-
 .../service/persistent/TestSentryVersion.java   |  18 ++
 .../thrift/SentryServiceIntegrationBase.java    |   3 +-
 .../sentry/service/thrift/TestLeaderStatus.java |  26 ++
 24 files changed, 982 insertions(+), 711 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/exception/SentryStandbyException.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/exception/SentryStandbyException.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/exception/SentryStandbyException.java
new file mode 100644
index 0000000..73c7e4e
--- /dev/null
+++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/exception/SentryStandbyException.java
@@ -0,0 +1,33 @@
+/**
+ * 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.sentry.core.common.exception;
+
+/**
+ * An exception which indicates that the current server is standby.
+ */
+public class SentryStandbyException extends SentryUserException {
+  private static final long serialVersionUID = 2162010615815L;
+
+  public SentryStandbyException(String msg) {
+    super(msg);
+  }
+
+  public SentryStandbyException(String msg, String reason) {
+    super(msg, reason);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/SentryConstants.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/SentryConstants.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/SentryConstants.java
index 3da4906..c094058 100644
--- a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/SentryConstants.java
+++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/SentryConstants.java
@@ -40,4 +40,7 @@ public class SentryConstants {
   public static final String RESOURCE_WILDCARD_VALUE_ALL = "ALL";
   public static final String RESOURCE_WILDCARD_VALUE_SOME = "+";
   public static final String ACCESS_ALLOW_URI_PER_DB_POLICYFILE = "sentry.allow.uri.db.policyfile";
+
+  public static final String SENTRY_ZK_JAAS_NAME = "Sentry";
+  public static final String CURRENT_INCARNATION_ID_KEY = "current.incarnation.key";
 }

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/PluginCacheSyncUtil.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/PluginCacheSyncUtil.java b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/PluginCacheSyncUtil.java
deleted file mode 100644
index 4ce16c7..0000000
--- a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/PluginCacheSyncUtil.java
+++ /dev/null
@@ -1,251 +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.sentry.hdfs;
-
-import java.io.IOException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import com.codahale.metrics.Timer;
-import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
-import org.apache.curator.framework.recipes.cache.PathChildrenCache;
-import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
-import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
-import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
-import org.apache.curator.utils.ZKPaths;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.sentry.hdfs.ServiceConstants.ServerConfig;
-import org.apache.sentry.hdfs.Updateable.Update;
-import org.apache.sentry.provider.db.SentryPolicyStorePlugin.SentryPluginException;
-import org.apache.sentry.provider.db.service.persistent.HAContext;
-import org.apache.zookeeper.KeeperException.NoNodeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-
-/**
- * Utility class for handling the cache update syncup via Curator path cache It
- * creates the path cache, a distributed lock and counter. The updated API
- * updates the counter, creates a znode zpath/counter and writes the data to it.
- * The caller should provider the cache callback handler class that posts the
- * update object to the required cache
- */
-public class PluginCacheSyncUtil {
-  private static final Logger LOGGER = LoggerFactory
-      .getLogger(PluginCacheSyncUtil.class);
-  public static final long CACHE_GC_SIZE_THRESHOLD_HWM = 100;
-  public static final long CACHE_GC_SIZE_THRESHOLD_LWM = 50;
-  public static final long CACHE_GC_SIZE_MAX_CLEANUP = 1000;
-  public static final long ZK_COUNTER_INIT_VALUE = 4;
-  public static final long GC_COUNTER_INIT_VALUE = ZK_COUNTER_INIT_VALUE + 1;
-
-  private final String zkPath;
-  private final HAContext haContext;
-  private final PathChildrenCache cache;
-  private InterProcessSemaphoreMutex updatorLock, gcLock;
-  private int lockTimeout;
-  private DistributedAtomicLong updateCounter, gcCounter;
-  private final ScheduledExecutorService gcSchedulerForZk = Executors
-      .newScheduledThreadPool(1);
-
-  public PluginCacheSyncUtil(String zkPath, final Configuration conf,
-      PathChildrenCacheListener cacheListener) throws SentryPluginException {
-    this.zkPath = zkPath;
-    // Init ZK connection
-    try {
-      haContext = HAContext.getHAContext(conf);
-    } catch (Exception e) {
-      throw new SentryPluginException("Error creating HA context ", e);
-    }
-    haContext.startCuratorFramework();
-
-    // Init path cache
-    cache = new PathChildrenCache(haContext.getCuratorFramework(), zkPath
-        + "/cache", true);
-    // path cache callback
-    cache.getListenable().addListener(cacheListener);
-    try {
-      cache.start();
-    } catch (Exception e) {
-      throw new SentryPluginException("Error creating ZK PathCache ", e);
-    }
-    updatorLock = new InterProcessSemaphoreMutex(
-        haContext.getCuratorFramework(), zkPath + "/lock");
-    lockTimeout = conf.getInt(
-        ServerConfig.SENTRY_HDFS_INIT_UPDATE_RETRY_DELAY_MS,
-        ServerConfig.SENTRY_HDFS_INIT_UPDATE_RETRY_DELAY_DEFAULT);
-    gcLock = new InterProcessSemaphoreMutex(
-        haContext.getCuratorFramework(), zkPath + "/gclock");
-
-    updateCounter = new DistributedAtomicLong(haContext.getCuratorFramework(),
-        zkPath + "/counter", haContext.getRetryPolicy());
-    try {
-      updateCounter.initialize(ZK_COUNTER_INIT_VALUE);
-    } catch (Exception e) {
-      LOGGER.error("Error initializing  counter for zpath " + zkPath, e);
-    }
-
-    // GC setup
-    gcCounter = new DistributedAtomicLong(haContext.getCuratorFramework(),
-        zkPath + "/gccounter", haContext.getRetryPolicy());
-    try {
-      gcCounter.initialize(GC_COUNTER_INIT_VALUE);
-    } catch (Exception e) {
-      LOGGER.error("Error initializing  counter for zpath " + zkPath, e);
-    }
-    final Runnable gcRunner = new Runnable() {
-      public void run() {
-        gcPluginCache(conf);
-      }
-    };
-    gcSchedulerForZk.scheduleAtFixedRate(gcRunner, 10, 10, TimeUnit.MINUTES);
-  }
-
-  public void handleCacheUpdate(Update update) throws SentryPluginException {
-    final Timer.Context timerContext = SentryHdfsMetricsUtil.getCacheSyncToZKTimer.time();
-    // post message to ZK cache
-    try {
-      // Acquire ZK lock for update cache sync. This ensures that the counter
-      // increment and znode creation is atomic operation
-      if (!updatorLock.acquire(lockTimeout, TimeUnit.MILLISECONDS)) {
-        throw new SentryPluginException(
-            "Failed to get ZK lock for update cache syncup");
-      }
-    } catch (Exception e1) {
-      // Stop timer in advance
-      timerContext.stop();
-      SentryHdfsMetricsUtil.getFailedCacheSyncToZK.inc();
-      throw new SentryPluginException(
-          "Error getting ZK lock for update cache syncup" + e1, e1);
-    }
-    boolean failed = false;
-    try {
-      try {
-        // increment the global sequence counter if this is not a full update
-        if (!update.hasFullImage()) {
-          update.setSeqNum(updateCounter.increment().postValue());
-        } else {
-          if (updateCounter.get().preValue() < update.getSeqNum()) {
-            updateCounter.add(update.getSeqNum() - updateCounter.get().preValue());
-          }
-        }
-      } catch (Exception e1) {
-        failed = true;
-        throw new SentryPluginException(
-            "Error setting ZK counter for update cache syncup" + e1, e1);
-      }
-
-      // Create a new znode with the sequence number and write the update data
-      // into it
-      String updateSeq = String.valueOf(update.getSeqNum());
-      String newPath = ZKPaths.makePath(zkPath + "/cache", updateSeq);
-      try {
-        haContext.getCuratorFramework().create().creatingParentsIfNeeded()
-            .forPath(newPath, update.serialize());
-      } catch (Exception e) {
-        failed = true;
-        throw new SentryPluginException("error posting update to ZK ", e);
-      }
-    } finally {
-      // release the ZK lock
-      try {
-        updatorLock.release();
-      } catch (Exception e) {
-        // Stop timer in advance
-        timerContext.stop();
-        SentryHdfsMetricsUtil.getFailedCacheSyncToZK.inc();
-        throw new SentryPluginException(
-            "Error releasing ZK lock for update cache syncup" + e, e);
-      }
-      timerContext.stop();
-      if (failed) {
-        SentryHdfsMetricsUtil.getFailedCacheSyncToZK.inc();
-      }
-    }
-  }
-
-  public static void setUpdateFromChildEvent(PathChildrenCacheEvent cacheEvent,
-      Update update) throws IOException {
-    byte eventData[] = cacheEvent.getData().getData();
-    update.deserialize(eventData);
-    String seqNum = ZKPaths.getNodeFromPath(cacheEvent.getData().getPath());
-    update.setSeqNum(Integer.valueOf(seqNum));
-  }
-
-  public void close() throws IOException {
-    cache.close();
-  }
-
-  public long getUpdateCounter() throws Exception {
-    return updateCounter.get().preValue();
-  }
-
-  /**
-   * Cleanup old znode of the plugin cache. The last cleaned and last created
-   * node counters are stored in ZK. If the number of available nodes are more
-   * than the high water mark, then we delete the old nodes till we reach low
-   * water mark. The scheduler periodically runs the cleanup routine
-   * @param conf
-   */
-  @VisibleForTesting
-  public void gcPluginCache(Configuration conf) {
-    try {
-      // If we can acquire gc lock, then continue with znode cleanup
-      if (!gcLock.acquire(500, TimeUnit.MILLISECONDS)) {
-        return;
-      }
-
-      // If we have passed the High watermark, then start the cleanup
-      Long updCount = updateCounter.get().preValue();
-      Long gcCount = gcCounter.get().preValue();
-      if (updCount - gcCount > CACHE_GC_SIZE_THRESHOLD_HWM) {
-        Long numNodesToClean = Math.min(updCount - gcCount
-            - CACHE_GC_SIZE_THRESHOLD_LWM, CACHE_GC_SIZE_MAX_CLEANUP);
-        for (Long nodeNum = gcCount; nodeNum < gcCount + numNodesToClean; nodeNum++) {
-          String pathToDelete = ZKPaths.makePath(zkPath + "/cache",
-              Long.toString(nodeNum));
-          try {
-            haContext.getCuratorFramework().delete().forPath(pathToDelete);
-            gcCounter.increment();
-            LOGGER.debug("Deleted znode " + pathToDelete);
-          } catch (NoNodeException eN) {
-            // We might have endup with holes in the node counter due to network/ZK errors
-            // Ignore the delete error if the node doesn't exist and move on
-            gcCounter.increment();
-          } catch (Exception e) {
-            LOGGER.info("Error cleaning up node " + pathToDelete, e);
-            break;
-          }
-        }
-      }
-    } catch (Exception e) {
-      LOGGER.warn("Error cleaning the cache", e);
-    } finally {
-      if (gcLock.isAcquiredInThisProcess()) {
-        try {
-          gcLock.release();
-        } catch (Exception e) {
-          LOGGER.warn("Error releasing gc lock", e);
-        }
-      }
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryHdfsMetricsUtil.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryHdfsMetricsUtil.java b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryHdfsMetricsUtil.java
index 5bf2f6e..e68c708 100644
--- a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryHdfsMetricsUtil.java
+++ b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryHdfsMetricsUtil.java
@@ -91,14 +91,6 @@ public class SentryHdfsMetricsUtil {
       MetricRegistry.name(MetastorePlugin.class, "apply-local-update",
           "path-change-size"));
 
-  // Metrics for handleCacheUpdate to ZK in PluginCacheSyncUtil
-  // The time used for each handleCacheUpdate
-  public static final Timer getCacheSyncToZKTimer = sentryMetrics.getTimer(
-      MetricRegistry.name(PluginCacheSyncUtil.class, "cache-sync-to-zk"));
-  // The number of failed handleCacheUpdate
-  public static final Counter getFailedCacheSyncToZK = sentryMetrics.getCounter(
-      MetricRegistry.name(PluginCacheSyncUtil.class, "cache-sync-to-zk", "failed-num"));
-  
   private SentryHdfsMetricsUtil() {
     // Make constructor private to avoid instantiation
   }

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-hdfs/sentry-hdfs-service/src/test/java/org/apache/sentry/hdfs/TestHAUpdateForwarder.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-service/src/test/java/org/apache/sentry/hdfs/TestHAUpdateForwarder.java b/sentry-hdfs/sentry-hdfs-service/src/test/java/org/apache/sentry/hdfs/TestHAUpdateForwarder.java
deleted file mode 100644
index 5246e05..0000000
--- a/sentry-hdfs/sentry-hdfs-service/src/test/java/org/apache/sentry/hdfs/TestHAUpdateForwarder.java
+++ /dev/null
@@ -1,66 +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.sentry.hdfs;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.List;
-
-import org.apache.curator.test.TestingServer;
-import org.apache.sentry.hdfs.service.thrift.TRoleChanges;
-import org.apache.sentry.provider.db.service.persistent.HAContext;
-import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.common.collect.Lists;
-
-public class TestHAUpdateForwarder extends TestUpdateForwarder {
-
-  private TestingServer server;
-
-  @Before
-  public void setup() throws Exception {
-    server = new TestingServer();
-    server.start();
-    testConf.set(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
-        server.getConnectString());
-    testConf.setBoolean(ServerConfig.SENTRY_HA_ENABLED, true);
-  }
-
-  @Override
-  @After
-  public void cleanup() throws Exception {
-    super.cleanup();
-    server.stop();
-    HAContext.clearServerContext();
-  }
-
-  @Test
-  public void testThriftSerializer() throws Exception {
-    List<String> addGroups = Lists.newArrayList("g1", "g2", "g3");
-    List<String> delGroups = Lists.newArrayList("d1", "d2", "d3");
-    String roleName = "testRole1";
-
-    TRoleChanges roleUpdate = new TRoleChanges(roleName, addGroups, delGroups);
-    TRoleChanges newRoleUpdate = (TRoleChanges) ThriftSerializer.deserialize(
-        roleUpdate, ThriftSerializer.serialize(roleUpdate));
-    assertEquals(roleUpdate, newRoleUpdate);
-  }
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java
new file mode 100644
index 0000000..14cdde3
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java
@@ -0,0 +1,242 @@
+/**
+ * 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.sentry.provider.db.service.persistent;
+
+import java.util.List;
+
+import com.google.common.base.Joiner;
+
+import javax.jdo.JDOException;
+import javax.jdo.JDOFatalDataStoreException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Fences the SQL database.<p/>
+ *
+ * Fencing ensures that any SQL requests that were sent by a previously active
+ * (but now standby) sentry daemon will not be honored.  It also ensures that if
+ * users start up multiple non-HA sentry daemons, only one can become
+ * active.<p/>
+ *
+ * The fencer uses a special SQL table, the SENTRY_FENCE table.  When a sentry
+ * process becomes active, it renames this table so that the name contains the
+ * current "incarnation ID."  The incarnation ID is a randomly generated 128-bit
+ * ID, which changes each time the process is restarted.  From that point
+ * forward, the sentry process includes a SELECT query for the SENTRY_FENCE
+ * table in all update transactions.  This ensures that if the SENTRY_FENCE
+ * table is subsequently renamed again, those update transactions will not
+ * succeed.<p/>
+ *
+ * It is important to distinguish between fencing and leader election.
+ * ZooKeeper is responsible for leader election and ensures that there is only
+ * ever one active sentry daemon at any one time.  However, sentry exists in an
+ * asynchronous network where requests from a previously active daemon may be
+ * arbitrarily delayed before reaching the SQL databse.  There is also a delay
+ * between a process being "de-leadered" by ZooKeeper, and the process itself
+ * becoming aware of this situation.  Java's garbage collection pauses tend to
+ * expose these kinds of race conditions.  The SQL database must be prepared to
+ * reject these stale updates.<p/>
+ *
+ * Given that we need this SQL fencing, why bother with ZooKeeper at all?
+ * ZooKeeper detects when nodes have stopped responding, and elects a new
+ * leader.  The SQL fencing code cannot do that.<p/>
+ */
+public class Fencer {
+  private static final Logger LOGGER = LoggerFactory
+          .getLogger(Fencer.class);
+
+  /**
+   * The base name of the sentry fencer table.<p/>
+   *
+   * We will append the incarnation ID on to this base name to make the final
+   * table name.
+   */
+  private final static String SENTRY_FENCE_TABLE_BASE = "SENTRY_FENCE";
+
+  /**
+   * The update log table name, including the incarnation ID.
+   */
+  private final String tableIncarnationName;
+
+  /**
+   * The SQL accessor that we're using.
+   */
+  private final SqlAccessor sql;
+
+  /**
+   * Create an accessor for the update log.
+   *
+   * @param incarnationId     The ID of the current sentry daemon incarnation.
+   * @param pmf               The PersistenceManagerFactory to use.
+   */
+  public Fencer(String incarnationId, PersistenceManagerFactory pmf) {
+    this.tableIncarnationName = String.
+        format("%s_%s", SENTRY_FENCE_TABLE_BASE, incarnationId);
+    this.sql = SqlAccessor.get(pmf);
+  }
+
+  /**
+   * Finds the name of the fencing table.<p/>
+   *
+   * The name of the update log table will always begin with SENTRY_UPDATE_LOG,
+   * but it may have the ID of a previous sentry incarnation tacked on to it.
+   *
+   * @return the current name of the update log table, or null if there is none.
+   *
+   * @throws JDOFatalDataStoreException    If there is more than one sentry
+   *                                       fencing table.
+   *         JDOException                  If there was a JDO error.
+   */
+  private String findFencingTable(PersistenceManagerFactory pmf) {
+    // Perform a SQL query to find the name of the update log table.
+    PersistenceManager pm = pmf.getPersistenceManager();
+    Query query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE,
+        sql.getFindTableByPrefixSql(SENTRY_FENCE_TABLE_BASE));
+    Transaction tx = pm.currentTransaction();
+    try {
+      tx.begin();
+      List<Object> results = (List<Object>) query.execute();
+      if (results.isEmpty()) {
+        return null;
+      } else if (results.size() != 1) {
+        throw new JDOFatalDataStoreException(
+            "Found more than one table whose name begins with " +
+            "SENTRY_UPDATE_LOG: " + Joiner.on(",").join(results));
+      }
+      String tableName = (String)results.get(0);
+      if (!tableName.startsWith(SENTRY_FENCE_TABLE_BASE)) {
+        throw new JDOFatalDataStoreException(
+            "The result of our attempt to locate the update log table was " +
+            "a table name which did not begin with " +
+            SENTRY_FENCE_TABLE_BASE + ", named " + tableName);
+      }
+      LOGGER.info("Found sentry update log table named " + tableName);
+      tx.commit();
+      return tableName;
+    } finally {
+      if (tx.isActive()) {
+        tx.rollback();
+      }
+      query.closeAll();
+    }
+  }
+
+  /**
+   * Creates the fencing table.
+   *
+   * @param pmf                 The PersistenceManagerFactory to use.
+   *
+   * @throws  JDOException      If there was a JDO error.
+   */
+  private void createFenceTable(PersistenceManagerFactory pmf) {
+    PersistenceManager pm = pmf.getPersistenceManager();
+    Transaction tx = pm.currentTransaction();
+    Query query = null;
+    try {
+      tx.begin();
+      query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE,
+          sql.getCreateTableSql(tableIncarnationName));
+      query.execute();
+      tx.commit();
+    } finally {
+      if (query != null) {
+        query.closeAll();
+      }
+      if (tx.isActive()) {
+        tx.rollback();
+      }
+      pm.close();
+    }
+  }
+
+  /**
+   * Renames one table to another.
+   *
+   * @param pmf                 The PersistenceManagerFactory to use.
+   * @param src                 The table to rename
+   * @param dst                 The new name of the table.
+   *
+   * @throws  JDOException      If there was a JDO error.
+   */
+  private void renameTable(PersistenceManagerFactory pmf, String src,
+          String dst) {
+    boolean success = false;
+    PersistenceManager pm = pmf.getPersistenceManager();
+    Transaction tx = pm.currentTransaction();
+    Query query = null;
+    try {
+      tx.begin();
+      query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE,
+          sql.getRenameTableSql(src, dst));
+      query.execute();
+      tx.commit();
+      success = true;
+    } finally {
+      if (query != null) {
+        query.closeAll();
+      }
+      if (!success) {
+        LOGGER.info("Failed to rename table " + src + " to " + dst);
+        tx.rollback();
+      }
+      pm.close();
+    }
+  }
+
+  /**
+   * Renames the update log table so that only this incarnation can modify it.
+   *
+   * @param pmf                 The PersistenceManagerFactory to use.
+   *
+   * @throws  JDOException      If there was a JDO error.
+   */
+  public void fence(PersistenceManagerFactory pmf) {
+    String curTableName = findFencingTable(pmf);
+    if (curTableName == null) {
+      createFenceTable(pmf);
+      LOGGER.info("Created sentry fence table.");
+    } else if (curTableName.equals(tableIncarnationName)) {
+      LOGGER.info("Sentry fence table is already named " +
+          tableIncarnationName);
+    } else {
+      renameTable(pmf, curTableName, tableIncarnationName);
+      LOGGER.info("Renamed sentry fence table " + curTableName + " to " +
+          tableIncarnationName);
+    }
+  }
+
+  /**
+   * Attempt to append an UpdateLogEntry to the update log.
+   */
+  void verify(PersistenceManager pm) {
+    Query query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE,
+        sql.getFetchAllRowsSql(tableIncarnationName));
+    query.execute();
+  }
+
+  String getTableIncarnationName() {
+    return tableIncarnationName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
deleted file mode 100644
index cacc29f..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
+++ /dev/null
@@ -1,262 +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.sentry.provider.db.service.persistent;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.curator.RetryPolicy;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.framework.api.ACLProvider;
-import org.apache.curator.framework.imps.CuratorFrameworkState;
-import org.apache.curator.framework.imps.DefaultACLProvider;
-import org.apache.curator.retry.RetryNTimes;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.SecurityUtil;
-import org.apache.sentry.service.thrift.JaasConfiguration;
-import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
-import org.apache.zookeeper.ZooDefs.Perms;
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
-import org.apache.zookeeper.data.ACL;
-import org.apache.zookeeper.data.Id;
-import org.apache.zookeeper.data.Stat;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-
-/**
- * Stores the HA related context
- */
-public class HAContext {
-
-  private static final Logger LOGGER = LoggerFactory.getLogger(HAContext.class);
-  private static volatile HAContext serverHAContext = null;
-  private static boolean aclChecked = false;
-
-  public final static String SENTRY_SERVICE_REGISTER_NAMESPACE = "sentry-service";
-  public static final String SENTRY_ZK_JAAS_NAME = "SentryClient";
-  private final String zookeeperQuorum;
-  private final int retriesMaxCount;
-  private final int sleepMsBetweenRetries;
-  private final String namespace;
-
-  private final boolean zkSecure;
-  private List<ACL> saslACL;
-
-  private final CuratorFramework curatorFramework;
-  private final RetryPolicy retryPolicy;
-
-  protected HAContext(Configuration conf) throws Exception {
-    this.zookeeperQuorum = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM_DEFAULT);
-    this.retriesMaxCount = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT_DEFAULT);
-    this.sleepMsBetweenRetries = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS_DEFAULT);
-    this.namespace = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE_DEFAULT);
-    this.zkSecure = conf.getBoolean(ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY_DEFAULT);
-    ACLProvider aclProvider;
-    validateConf();
-    if (zkSecure) {
-      LOGGER.info("Connecting to ZooKeeper with SASL/Kerberos and using 'sasl' ACLs");
-      setJaasConfiguration(conf);
-      System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
-          SENTRY_ZK_JAAS_NAME);
-      saslACL = Lists.newArrayList();
-      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
-          ServerConfig.PRINCIPAL))));
-      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
-              ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL))));
-      aclProvider = new SASLOwnerACLProvider();
-      String allowConnect = conf.get(ServerConfig.ALLOW_CONNECT);
-
-      if (!Strings.isNullOrEmpty(allowConnect)) {
-        for (String principal : Arrays.asList(allowConnect.split("\\s*,\\s*"))) {
-          LOGGER.info("Adding acls for " + principal);
-          saslACL.add(new ACL(Perms.ALL, new Id("sasl", principal)));
-        }
-      }
-    } else {
-      LOGGER.info("Connecting to ZooKeeper without authentication");
-      aclProvider = new DefaultACLProvider();
-    }
-
-    retryPolicy = new RetryNTimes(retriesMaxCount, sleepMsBetweenRetries);
-    this.curatorFramework = CuratorFrameworkFactory.builder()
-        .namespace(this.namespace)
-        .connectString(this.zookeeperQuorum)
-        .retryPolicy(retryPolicy)
-        .aclProvider(aclProvider)
-        .build();
-    startCuratorFramework();
-  }
-
-  /**
-   * Use common HAContext (ie curator framework connection to ZK)
-   *
-   * @param conf
-   * @throws Exception
-   */
-  public static HAContext getHAContext(Configuration conf) throws Exception {
-    if (serverHAContext == null) {
-      serverHAContext = new HAContext(conf);
-      Runtime.getRuntime().addShutdownHook(new Thread() {
-        @Override
-        public void run() {
-          LOGGER.info("ShutdownHook closing curator framework");
-          try {
-            clearServerContext();
-          } catch (Throwable t) {
-            LOGGER.error("Error stopping SentryService", t);
-          }
-        }
-      });
-
-    }
-    return serverHAContext;
-  }
-
-  // HA context for server which verifies the ZK ACLs on namespace
-  public static HAContext getHAServerContext(Configuration conf) throws Exception {
-    HAContext serverContext = getHAContext(conf);
-    serverContext.checkAndSetACLs();
-    return serverContext;
-  }
-
-  @VisibleForTesting
-  public static synchronized void clearServerContext() {
-    if (serverHAContext != null) {
-      serverHAContext.getCuratorFramework().close();
-      serverHAContext = null;
-    }
-  }
-
-  public void startCuratorFramework() {
-    if (curatorFramework.getState() != CuratorFrameworkState.STARTED) {
-      curatorFramework.start();
-    }
-  }
-
-  public CuratorFramework getCuratorFramework() {
-    return this.curatorFramework;
-  }
-
-  public String getZookeeperQuorum() {
-    return zookeeperQuorum;
-  }
-
-  public static boolean isHaEnabled(Configuration conf) {
-    return conf.getBoolean(ServerConfig.SENTRY_HA_ENABLED, ServerConfig.SENTRY_HA_ENABLED_DEFAULT);
-  }
-
-  public String getNamespace() {
-    return namespace;
-  }
-
-  public RetryPolicy getRetryPolicy() {
-    return retryPolicy;
-  }
-
-  private void validateConf() {
-    Preconditions.checkNotNull(zookeeperQuorum, "Zookeeper Quorum should not be null.");
-    Preconditions.checkNotNull(namespace, "Zookeeper namespace should not be null.");
-  }
-
-  protected String getServicePrincipal(Configuration conf, String confProperty)
-      throws IOException {
-    String principal = conf.get(confProperty);
-    Preconditions.checkNotNull(principal);
-    Preconditions.checkArgument(principal.length() != 0, "Server principal is not right.");
-    return principal.split("[/@]")[0];
-  }
-
-  private void checkAndSetACLs() throws Exception {
-    if (zkSecure && !aclChecked) {
-      // If znodes were previously created without security enabled, and now it is, we need to go through all existing znodes
-      // and set the ACLs for them. This is done just once at the startup
-      // We can't get the namespace znode through curator; have to go through zk client
-      startCuratorFramework();
-      String newNamespace = "/" + curatorFramework.getNamespace();
-      if (curatorFramework.getZookeeperClient().getZooKeeper().exists(newNamespace, null) != null) {
-        List<ACL> acls = curatorFramework.getZookeeperClient().getZooKeeper().getACL(newNamespace, new Stat());
-        if (acls.isEmpty() || !acls.get(0).getId().getScheme().equals("sasl")) {
-          LOGGER.info("'sasl' ACLs not set; setting...");
-          List<String> children = curatorFramework.getZookeeperClient().getZooKeeper().getChildren(newNamespace, null);
-          for (String child : children) {
-            checkAndSetACLs("/" + child);
-          }
-          curatorFramework.getZookeeperClient().getZooKeeper().setACL(newNamespace, saslACL, -1);
-        }
-      }
-      aclChecked = true;
-
-    }
-  }
-
-  private void checkAndSetACLs(String path) throws Exception {
-      LOGGER.info("Setting acls on " + path);
-      List<String> children = curatorFramework.getChildren().forPath(path);
-      for (String child : children) {
-        checkAndSetACLs(path + "/" + child);
-      }
-      curatorFramework.setACL().withACL(saslACL).forPath(path);
-  }
-
-  // This gets ignored during most tests, see ZKXTestCaseWithSecurity#setupZKServer()
-  private void setJaasConfiguration(Configuration conf) throws IOException {
-    if ("false".equalsIgnoreCase(conf.get(
-          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE,
-          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE_DEFAULT))) {
-      String keytabFile = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_KEYTAB);
-      Preconditions.checkArgument(keytabFile.length() != 0, "Keytab File is not right.");
-      String principal = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL);
-      principal = SecurityUtil.getServerPrincipal(principal,
-        conf.get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT));
-      Preconditions.checkArgument(principal.length() != 0, "Kerberos principal is not right.");
-
-      // This is equivalent to writing a jaas.conf file and setting the system property, "java.security.auth.login.config", to
-      // point to it (but this way we don't have to write a file, and it works better for the tests)
-      JaasConfiguration.addEntryForKeytab(SENTRY_ZK_JAAS_NAME, principal, keytabFile);
-    } else {
-      // Create jaas conf for ticket cache
-      JaasConfiguration.addEntryForTicketCache(SENTRY_ZK_JAAS_NAME);
-    }
-    javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
-  }
-
-  public class SASLOwnerACLProvider implements ACLProvider {
-    @Override
-    public List<ACL> getDefaultAcl() {
-        return saslACL;
-    }
-
-    @Override
-    public List<ACL> getAclForPath(String path) {
-        return saslACL;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index 7dad496..6e367e5 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -71,6 +71,8 @@ import org.apache.sentry.provider.db.service.thrift.TSentryMappingData;
 import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
 import org.apache.sentry.provider.db.service.thrift.TSentryPrivilegeMap;
 import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
 import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope;
 import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
 import org.datanucleus.store.rdbms.exceptions.MissingTableException;
@@ -102,7 +104,6 @@ public class SentryStore {
   public static final String NULL_COL = "__NULL__";
   public static int INDEX_GROUP_ROLES_MAP = 0;
   public static int INDEX_USER_ROLES_MAP = 1;
-  static final String DEFAULT_DATA_DIR = "sentry_policy_db";
 
   private static final Set<String> ALL_ACTIONS = Sets.newHashSet(AccessConstants.ALL,
       AccessConstants.SELECT, AccessConstants.INSERT, AccessConstants.ALTER,
@@ -116,6 +117,11 @@ public class SentryStore {
       AccessConstants.ACTION_ALL.toLowerCase(), AccessConstants.SELECT, AccessConstants.INSERT);
 
   /**
+   * The activator object which tells us whether the current daemon is active.
+   */
+  private final Activator act;
+
+  /**
    * Commit order sequence id. This is used by notification handlers
    * to know the order in which events where committed to the database.
    * This instance variable is incremented in incrementGetSequenceId
@@ -128,10 +134,8 @@ public class SentryStore {
   private PrivCleaner privCleaner = null;
   private Thread privCleanerThread = null;
 
-  public SentryStore(Configuration conf) throws SentryNoSuchObjectException,
-  SentryAccessDeniedException, SentrySiteConfigurationException, IOException {
-    commitSequenceId = 0;
-    this.conf = conf;
+  public static Properties getDataNucleusProperties(Configuration conf)
+      throws SentrySiteConfigurationException, IOException {
     Properties prop = new Properties();
     prop.putAll(ServerConfig.SENTRY_STORE_DEFAULTS);
     String jdbcUrl = conf.get(ServerConfig.SENTRY_STORE_JDBC_URL, "").trim();
@@ -164,8 +168,19 @@ public class SentryStore {
         prop.setProperty(key, entry.getValue());
       }
     }
+    // Disallow operations outside of transactions
+    prop.setProperty("datanucleus.NontransactionalRead", "false");
+    prop.setProperty("datanucleus.NontransactionalWrite", "false");
+    return prop;
+  }
 
-
+  public SentryStore(Configuration conf)
+      throws SentryNoSuchObjectException, SentryAccessDeniedException,
+          SentrySiteConfigurationException, IOException {
+    this.act = Activators.INSTANCE.get(conf);
+    commitSequenceId = 0;
+    this.conf = conf;
+    Properties prop = getDataNucleusProperties(conf);
     boolean checkSchemaVersion = conf.get(
         ServerConfig.SENTRY_VERIFY_SCHEM_VERSION,
         ServerConfig.SENTRY_VERIFY_SCHEM_VERSION_DEFAULT).equalsIgnoreCase(
@@ -175,11 +190,6 @@ public class SentryStore {
       prop.setProperty("datanucleus.autoCreateSchema", "true");
       prop.setProperty("datanucleus.fixedDatastore", "false");
     }
-
-    // Disallow operations outside of transactions
-    prop.setProperty("datanucleus.NontransactionalRead", "false");
-    prop.setProperty("datanucleus.NontransactionalWrite", "false");
-
     pmf = JDOHelper.getPersistenceManagerFactory(prop);
     verifySentryStoreSchema(checkSchemaVersion);
 

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceRegister.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceRegister.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceRegister.java
deleted file mode 100644
index 79dfe48..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceRegister.java
+++ /dev/null
@@ -1,52 +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.sentry.provider.db.service.persistent;
-
-import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
-import org.apache.curator.x.discovery.ServiceInstance;
-import org.apache.curator.x.discovery.details.InstanceSerializer;
-
-public class ServiceRegister {
-
-  private HAContext haContext;
-
-  public ServiceRegister(HAContext haContext) {
-    this.haContext = haContext;
-  }
-
-  public void regService(String host, int port) throws Exception {
-
-    haContext.startCuratorFramework();
-    ServiceInstance<Void> serviceInstance = ServiceInstance.<Void>builder()
-        .address(host)
-        .port(port)
-        .name(HAContext.SENTRY_SERVICE_REGISTER_NAMESPACE)
-        .build();
-
-    InstanceSerializer<Void> instanceSerializer = new FixedJsonInstanceSerializer<Void>(Void.class);
-    ServiceDiscoveryBuilder.builder(Void.class)
-        .basePath(HAContext.SENTRY_SERVICE_REGISTER_NAMESPACE)
-        .client(haContext.getCuratorFramework())
-        .serializer(instanceSerializer)
-        .thisInstance(serviceInstance)
-        .build()
-        .start();
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java
new file mode 100644
index 0000000..9879e67
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java
@@ -0,0 +1,309 @@
+/**
+ * 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.sentry.provider.db.service.persistent;
+
+import java.sql.Connection;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.datastore.JDOConnection;
+
+/**
+ * An accessor for a SQL database.
+ *
+ * SqlAccessor objects generate raw SQL statements in a variety of dialects.
+ * We use this to do stuff that the DataNucleus architects didn't anticipate,
+ * like rename tables or search for tables by a prefix name.<p/>
+ *
+ * This class exists only to implement fencing.  While it's theoretically
+ * possible to do other things with it, it is almost always better to use the
+ * functionality provided by DataNucleus if it is at all possible.<p/>
+ *
+ * Note: do NOT pass any untrusted user input into these functions.  You must
+ * NOT create SQL statements from unsanitized user input because they may expose
+ * you to SQL injection attacks.  Use prepared statements if you need to do that
+ * (yes, it's possible via DataNucleus.)<p/>
+ */
+abstract class SqlAccessor {
+  /**
+   * The string which we can use with PersistenceManager#newQuery to perform raw
+   * SQL operations.
+   */
+  final static String JDO_SQL_ESCAPE = "javax.jdo.query.SQL";
+
+  /**
+   * Get an accessor for the SQL database that we're using.
+   *
+   * @return The singleton accessor instance for the SQL database we are using.
+   *
+   * @throws RuntimeException     If there was an error loading the SqlAccessor.
+   *                              This could happen because we don't know the
+   *                              type of database that we're using.  In theory
+   *                              it could also happen because JDO is being run
+   *                              against something that is not a SQL databse at
+   *                              all.
+   */
+  static SqlAccessor get(PersistenceManagerFactory pmf) {
+    String productName = getProductNameString(pmf).toLowerCase();
+    if (productName.contains("postgresql")) {
+      return PostgresSqlAccessor.INSTANCE;
+    } else if (productName.contains("mysql")) {
+      return MySqlSqlAccessor.INSTANCE;
+    } else if (productName.contains("oracle")) {
+      return OracleSqlAccessor.INSTANCE;
+    } else if (productName.contains("derby")) {
+      return DerbySqlAccessor.INSTANCE;
+    } else if (productName.contains("db2")) {
+      return Db2SqlAccessor.INSTANCE;
+    } else {
+      throw new RuntimeException("Unknown database type " +
+      "'" + productName + "'.  Supported database types are " +
+      "postgres, mysql, oracle, mssql, and derby.");
+    }
+  }
+
+  /**
+   * @return    An string describing the type of database that we're using.
+   */
+  static private String getProductNameString(PersistenceManagerFactory pmf) {
+    PersistenceManager pm = pmf.getPersistenceManager();
+    JDOConnection jdoConn = pm.getDataStoreConnection();
+    try {
+      return ((Connection)jdoConn.getNativeConnection()).getMetaData().
+          getDatabaseProductName();
+    } catch (Throwable t) {
+      throw new RuntimeException("Error retrieving database product " +
+          "name", t);
+    } finally {
+      // We must release the connection before we call other pm methods.
+      jdoConn.close();
+    }
+  }
+
+  /**
+   * Get the name of this database.
+   *
+   * @return          The name of this databse.
+   */
+  abstract String getDatabaseName();
+
+  /**
+   * Get the SQL for finding a table that starts with the given prefix.
+   *
+   * @param prefix    The prefix of the table to find.
+   * @return          The SQL.
+   */
+  abstract String getFindTableByPrefixSql(String prefix);
+
+  /**
+   * Get the SQL for creating a table with the given name.
+   *
+   * @param name      The name of the table to create.
+   * @return          The SQL.
+   */
+  abstract String getCreateTableSql(String name);
+
+  /**
+   * Get the SQL for renaming a table.
+   *
+   * @param src       The name of the table to rename.
+   * @param dst       The new name to give to the table.
+   * @return          The SQL.
+   */
+  abstract String getRenameTableSql(String src, String dst);
+
+  /**
+   * Get the SQL for fetching all rows from the given table.
+   *
+   * @param name      The table name.
+   * @return          The SQL.
+   */
+  abstract String getFetchAllRowsSql(String name);
+
+  /**
+   * The postgres database type.<p/>
+   *
+   * Postgres is case-senstitive, but will translate all identifiers to
+   * lowercase unless you quote them.  So we quote all identifiers when using
+   * postgres.
+   */
+  private static class PostgresSqlAccessor extends SqlAccessor {
+    static final PostgresSqlAccessor INSTANCE = new PostgresSqlAccessor();
+
+    @Override
+    String getDatabaseName() {
+      return "postgres";
+    }
+
+    @Override
+    String getFindTableByPrefixSql(String prefix) {
+      return "SELECT table_name FROM information_schema.tables " +
+          "WHERE table_name LIKE '" + prefix + "%'";
+    }
+
+    @Override
+    String getCreateTableSql(String name) {
+      return "CREATE TABLE \"" + name + "\" (\"VAL\" VARCHAR(512))";
+    }
+
+    @Override
+    String getRenameTableSql(String src, String dst) {
+      return "ALTER TABLE \"" + src + "\" RENAME TO \"" + dst + "\"";
+    }
+
+    @Override
+    String getFetchAllRowsSql(String tableName) {
+      return "SELECT * FROM \"" + tableName + "\"";
+    }
+  }
+
+  /**
+   * The MySQL database type.<p/>
+   *
+   * MySQL can't handle quotes unless specifically configured to accept them.
+   */
+  private static class MySqlSqlAccessor extends SqlAccessor {
+    static final MySqlSqlAccessor INSTANCE = new MySqlSqlAccessor();
+
+    @Override
+    String getDatabaseName() {
+      return "mysql";
+    }
+
+    @Override
+    String getFindTableByPrefixSql(String prefix) {
+      return "SELECT table_name FROM information_schema.tables " +
+          "WHERE table_name LIKE " + prefix + "%";
+    }
+
+    @Override
+    String getCreateTableSql(String name) {
+      return "CREATE TABLE " + name + " (VAL VARCHAR(512))";
+    }
+
+    @Override
+    String getRenameTableSql(String src, String dst) {
+      return "RENAME TABLE " + src + " TO " + dst;
+    }
+
+    @Override
+    String getFetchAllRowsSql(String tableName) {
+      return "SELECT * FROM " + tableName;
+    }
+  }
+
+  /**
+   * The Oracle database type.<p/>
+   */
+  private static class OracleSqlAccessor extends SqlAccessor {
+    static final OracleSqlAccessor INSTANCE = new OracleSqlAccessor();
+
+    @Override
+    String getDatabaseName() {
+      return "oracle";
+    }
+
+    @Override
+    String getFindTableByPrefixSql(String prefix) {
+      return "SELECT table_name FROM all_tables " +
+          "WHERE table_name LIKE " + prefix + "%";
+    }
+
+    @Override
+    String getCreateTableSql(String name) {
+      return "CREATE TABLE " + name + " (VAL VARCHAR(512))";
+    }
+
+    @Override
+    String getRenameTableSql(String src, String dst) {
+      return "RENAME TABLE " + src + " TO " + dst;
+    }
+
+    @Override
+    String getFetchAllRowsSql(String tableName) {
+      return "SELECT * FROM " + tableName;
+    }
+  }
+
+  /**
+   * The Derby database type.</p>
+   */
+  private static class DerbySqlAccessor extends SqlAccessor {
+    static final DerbySqlAccessor INSTANCE = new DerbySqlAccessor();
+
+    @Override
+    String getFindTableByPrefixSql(String prefix) {
+      return "SELECT tablename FROM SYS.SYSTABLES " +
+          "WHERE tablename LIKE '" + prefix + "%'";
+    }
+
+    @Override
+    String getCreateTableSql(String name) {
+      return "CREATE TABLE " + name + " (VAL VARCHAR(512))";
+    }
+
+    @Override
+    String getRenameTableSql(String src, String dst) {
+      return "RENAME TABLE " + src + " TO " + dst;
+    }
+
+    @Override
+    String getDatabaseName() {
+      return "derby";
+    }
+
+    @Override
+    String getFetchAllRowsSql(String tableName) {
+      return "SELECT * FROM " + tableName;
+    }
+  }
+
+  /**
+   * The DB2 database type.</p>
+   */
+  private static class Db2SqlAccessor extends SqlAccessor {
+    static final Db2SqlAccessor INSTANCE = new Db2SqlAccessor();
+
+    @Override
+    String getFindTableByPrefixSql(String prefix) {
+      return "SELECT tablename FROM SYS.SYSTABLES " +
+          "WHERE tablename LIKE '" + prefix + "%'";
+    }
+
+    @Override
+    String getCreateTableSql(String name) {
+      return "CREATE TABLE " + name + " (VAL VARCHAR(512))";
+    }
+
+    @Override
+    String getRenameTableSql(String src, String dst) {
+      return "RENAME TABLE " + src + " TO " + dst;
+    }
+
+    @Override
+    String getDatabaseName() {
+      return "db2";
+    }
+
+    @Override
+    String getFetchAllRowsSql(String tableName) {
+      return "SELECT * FROM " + tableName;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java
index 3de1f65..19daa75 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java
@@ -46,9 +46,7 @@ import org.apache.sentry.provider.db.log.entity.JsonLogEntity;
 import org.apache.sentry.provider.db.log.entity.JsonLogEntityFactory;
 import org.apache.sentry.provider.db.log.util.Constants;
 import org.apache.sentry.provider.db.service.persistent.CommitContext;
-import org.apache.sentry.provider.db.service.persistent.HAContext;
 import org.apache.sentry.provider.db.service.persistent.SentryStore;
-import org.apache.sentry.provider.db.service.persistent.ServiceRegister;
 import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants.PolicyStoreServerConfig;
 import org.apache.sentry.service.thrift.SentryServiceUtil;
 import org.apache.sentry.service.thrift.ServiceConstants;
@@ -84,30 +82,18 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
   private final SentryStore sentryStore;
   private final NotificationHandlerInvoker notificationHandlerInvoker;
   private final ImmutableSet<String> adminGroups;
-  private boolean isReady;
   SentryMetrics sentryMetrics;
-  private HAContext haContext;
 
   private List<SentryPolicyStorePlugin> sentryPlugins = new LinkedList<SentryPolicyStorePlugin>();
 
-  public SentryPolicyStoreProcessor(String name, Configuration conf) throws Exception {
+  public SentryPolicyStoreProcessor(String name,
+        Configuration conf) throws Exception {
     super();
     this.name = name;
     this.conf = conf;
     this.notificationHandlerInvoker = new NotificationHandlerInvoker(conf,
         createHandlers(conf));
-    isReady = false;
-    if (conf.getBoolean(ServerConfig.SENTRY_HA_ENABLED,
-        ServerConfig.SENTRY_HA_ENABLED_DEFAULT)) {
-      haContext = HAContext.getHAServerContext(conf);
-      sentryStore = new SentryStore(conf);
-      ServiceRegister reg = new ServiceRegister(haContext);
-      reg.regService(conf.get(ServerConfig.RPC_ADDRESS),
-          conf.getInt(ServerConfig.RPC_PORT,ServerConfig.RPC_PORT_DEFAULT));
-    } else {
-      sentryStore = new SentryStore(conf);
-    }
-    isReady = true;
+    sentryStore = new SentryStore(conf);
     adminGroups = ImmutableSet.copyOf(toTrimedLower(Sets.newHashSet(conf.getStrings(
         ServerConfig.ADMIN_GROUPS, new String[]{}))));
     Iterable<String> pluginClasses = ConfUtilties.CLASS_SPLITTER
@@ -149,16 +135,7 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
   }
 
   public void stop() {
-    if (isReady) {
-      sentryStore.stop();
-    }
-    if (haContext != null) {
-      try {
-        haContext.getCuratorFramework().close();
-      } catch (Exception e) {
-        LOGGER.warn("Error in stopping processor", e);
-      }
-    }
+    sentryStore.stop();
   }
 
   public void registerPlugin(SentryPolicyStorePlugin plugin) throws SentryPluginException {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activator.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activator.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activator.java
new file mode 100644
index 0000000..0b7ddf5
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activator.java
@@ -0,0 +1,112 @@
+/**
+ * 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.sentry.service.thrift;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.Fencer;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.PersistenceManagerFactory;
+
+/**
+ * The activator is used to access and modify the activation state of the sentry daemon.<p/>
+ */
+public class Activator implements Closeable {
+  private static final Logger LOGGER = LoggerFactory.getLogger(Activator.class);
+
+  /**
+   * The DataNucleus PersistenceManagerFactory to use.
+   */
+  private final PersistenceManagerFactory pmf;
+
+  /**
+   * The handler for LeaderStatus callbacks.
+   */
+  private final TransitionHandler handler;
+
+  /**
+   * LeaderStatus generates callbacks to let us know when we are active or
+   * standby.  When HA is enabled, it manages ZK sessions.
+   */
+  private final LeaderStatus leaderStatus;
+
+  /**
+   * The fencer object.
+   */
+  private final Fencer fencer;
+
+  /**
+   * True if the Activator is active.
+   */
+  private boolean active;
+
+  public Activator(Configuration conf) throws Exception {
+    Properties props = SentryStore.getDataNucleusProperties(conf);
+    this.pmf = JDOHelper.getPersistenceManagerFactory(props);
+    this.handler = new TransitionHandler();
+    this.leaderStatus = new LeaderStatus(handler, conf);
+    this.fencer = new Fencer(this.leaderStatus.getIncarnationId(), pmf);
+    this.active = false;
+    this.leaderStatus.start();
+  }
+
+  @Override
+  public void close() throws IOException {
+    this.leaderStatus.close();
+    this.pmf.close();
+  }
+
+  private class TransitionHandler implements LeaderStatus.Listener {
+    @Override
+    public void becomeActive() throws Exception {
+      synchronized (Activator.this) {
+        if (!active) {
+          LOGGER.info("Activating " + leaderStatus.getIncarnationId());
+          fencer.fence(pmf);
+          active = true;
+        }
+      }
+    }
+
+    @Override
+    public void becomeStandby() {
+      synchronized (Activator.this) {
+        if (active) {
+          LOGGER.info("Deactivating " + leaderStatus.getIncarnationId());
+          active = false;
+        }
+      }
+    }
+  }
+
+  synchronized boolean isActive() {
+    return active;
+  }
+
+  public synchronized String getIncarnationId() {
+    return leaderStatus.getIncarnationId();
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activators.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activators.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activators.java
new file mode 100644
index 0000000..37b0219
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Activators.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.service.thrift;
+
+import java.util.HashMap;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.core.common.utils.SentryConstants;
+
+/**
+ * A global map from incarnation IDs to Activator objects.<p/>
+ *
+ * This is used to access the current global Activator.  Normally there will
+ * only be one Activator used in a sentry process.  There may be multiple
+ * Activator objects in the case where we are running unit tests.
+ */
+public enum Activators {
+  INSTANCE;
+
+  private final HashMap<String, Activator> acts = new HashMap<String, Activator>();
+
+  Activators() {}
+
+  public synchronized void put(Activator act) {
+    acts.put(act.getIncarnationId(), act);
+  }
+
+  public Activator get(Configuration conf) {
+    String key = conf.get(SentryConstants.CURRENT_INCARNATION_ID_KEY);
+    if (key == null) {
+      throw new RuntimeException("No " +
+          SentryConstants.CURRENT_INCARNATION_ID_KEY + "set.");
+    }
+    return get(key);
+  }
+
+  public synchronized Activator get(String incarnationId) {
+    Activator act = acts.get(incarnationId);
+    if (act == null) {
+      throw new RuntimeException("No activator found with " +
+          "incarnationId " + incarnationId);
+    }
+    return act;
+  }
+
+  public synchronized void remove(Activator act) {
+    Activator removed = acts.remove(act.getIncarnationId());
+    if (removed == null) {
+      throw new RuntimeException("No activator found with " +
+          "incarnationId " + act.getIncarnationId());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatus.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatus.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatus.java
index e846766..e32e1db 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatus.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatus.java
@@ -16,10 +16,10 @@
  */
 package org.apache.sentry.service.thrift;
 
-import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
+import org.datanucleus.util.Base64;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -79,13 +79,36 @@ final class LeaderStatus implements Closeable {
   private final AtomicBoolean closed = new AtomicBoolean(false);
 
   /**
-   * Generate a 128-bit random ID.
+   * Generate a very long random ID.
+   *
+   * We want a name that doesn't start with a number, and which
+   * contains only letters and numbers.  This is important because
+   * the incarnation ID gets used in SQL databases to name a table.
    */
   static String generateIncarnationId() {
     SecureRandom srand = new SecureRandom();
-    byte[] buf = new byte[32];
+    byte[] buf = new byte[33];
     srand.nextBytes(buf);
-    return "sentry_" + Hex.encodeHexString(buf);
+    char[] cbuf = Base64.encode(buf);
+    StringBuilder bld = new StringBuilder();
+    for (int i = 0; i < cbuf.length; i++) {
+      boolean safe;
+      if (i == 0) {
+        // Some databases can't handle identiifers that start with numbers,
+        // so always start with a letter.  Also replace '+' or '/' with
+        // something safe.
+        safe = Character.isLetter(cbuf[i]);
+      } else {
+        // Replace '+' or '/' with something safe.
+        safe = Character.isLetterOrDigit(cbuf[i]);
+      }
+      if (!safe) {
+        bld.append((char)('a' + srand.nextInt(26)));
+      } else {
+        bld.append(cbuf[i]);
+      }
+    }
+    return bld.toString();
   }
 
   LeaderStatus(Listener listener, Configuration conf) throws Exception {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatusAdaptor.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatusAdaptor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatusAdaptor.java
index 80a6571..33a5e7b 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatusAdaptor.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/LeaderStatusAdaptor.java
@@ -81,6 +81,11 @@ final class LeaderStatusAdaptor
   private long becomeLeaderCount = 0;
 
   /**
+   * True only if this LeaderStatusAdaptor is closed.
+   */
+  private boolean isClosed = false;
+
+  /**
    * True only if this incarnation is currently active.
    */
   private boolean isActive = false;
@@ -112,9 +117,36 @@ final class LeaderStatusAdaptor
     this.leaderSelector.start();
   }
 
+  /**
+   * Shut down the LeaderStatusAdaptor and wait for it to transition to
+   * standby.
+   */
   @Override
   public void close() throws IOException {
+    // If the adaptor is already closed, calling close again is a no-op.
+    // Setting isClosed also prevents activation after this point.
+    lock.lock();
+    try {
+      if (isClosed) {
+        return;
+      }
+      isClosed = true;
+    } finally {
+      lock.unlock();
+    }
+
+    // Shut down our Curator hooks.
     leaderSelector.close();
+
+    // Wait for the adaptor to transition to standby state.
+    lock.lock();
+    try {
+      while (isActive) {
+        cond.awaitUninterruptibly();
+      }
+    } finally {
+      lock.unlock();
+    }
   }
 
   /**
@@ -148,9 +180,14 @@ final class LeaderStatusAdaptor
   public void takeLeadership(CuratorFramework client) throws Exception {
     lock.lock();
     try {
+      if (isClosed) {
+        LOG.info("LeaderStatusAdaptor: can't become active because the " +
+            "adaptor is closed.");
+        return;
+      }
       isActive = true;
       becomeLeaderCount++;
-      LOG.info("SentryLeaderSelectorClient: becoming active.  " +
+      LOG.info("LeaderStatusAdaptor: becoming active.  " +
           "becomeLeaderCount=" + becomeLeaderCount);
       listener.becomeActive();
       while (isActive) {
@@ -158,7 +195,7 @@ final class LeaderStatusAdaptor
       }
     } finally {
       isActive = false;
-      LOG.info("SentryLeaderSelectorClient: becoming standby");
+      LOG.info("LeaderStatusAdaptor: becoming standby");
       try {
         listener.becomeStandby();
       } catch (Throwable t) {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
index 809af06..531ab35 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
@@ -49,6 +49,7 @@ import org.apache.hadoop.security.SaslRpcServer;
 import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
 import org.apache.hadoop.security.SecurityUtil;
 import org.apache.sentry.Command;
+import org.apache.sentry.core.common.utils.SentryConstants;
 import org.apache.sentry.provider.db.service.thrift.SentryHealthCheckServletContextListener;
 import org.apache.sentry.provider.db.service.thrift.SentryMetrics;
 import org.apache.sentry.provider.db.service.thrift.SentryMetricsServletContextListener;
@@ -95,11 +96,10 @@ public class SentryService implements Callable {
   private SentryWebServer sentryWebServer;
   private long maxMessageSize;
   private final boolean isHA;
-  private volatile boolean isActive = false;
+  private final Activator act;
   SentryMetrics sentryMetrics;
-  private final LeaderStatus leaderStatus;
 
-  public SentryService(Configuration conf) {
+  public SentryService(Configuration conf) throws Exception {
     this.conf = conf;
     int port = conf
         .getInt(ServerConfig.RPC_PORT, ServerConfig.RPC_PORT_DEFAULT);
@@ -153,25 +153,10 @@ public class SentryService implements Callable {
             + (count++));
       }
     });
-    try {
-      leaderStatus = new LeaderStatus(
-          new LeaderStatus.Listener() {
-            @Override
-            public void becomeActive() throws Exception {
-              LOGGER.info("Activating " + leaderStatus.getIncarnationId());
-              isActive = true;
-            }
-
-            @Override
-            public void becomeStandby() {
-              LOGGER.info("Deactivating " + leaderStatus.getIncarnationId());
-              isActive = false;
-            }
-          }, conf);
-      leaderStatus.start(); // TODO: move this into call?
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
+    this.act = new Activator(conf);
+    conf.set(SentryConstants.CURRENT_INCARNATION_ID_KEY,
+        this.act.getIncarnationId());
+    Activators.INSTANCE.put(act);
     webServerPort = conf.getInt(ServerConfig.SENTRY_WEB_PORT, ServerConfig.SENTRY_WEB_PORT_DEFAULT);
     status = Status.NOT_STARTED;
   }
@@ -307,7 +292,7 @@ public class SentryService implements Callable {
   public synchronized void stop() throws Exception{
     MultiException exception = null;
     LOGGER.info("Attempting to stop...");
-    leaderStatus.close();
+    act.close();
     if (isRunning()) {
       LOGGER.info("Attempting to stop sentry thrift service...");
       try {
@@ -462,7 +447,7 @@ public class SentryService implements Callable {
     return new Gauge<Boolean>() {
       @Override
       public Boolean getValue() {
-        return isActive;
+        return act.isActive();
       }
     };
   }

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
index 0ab8192..abc3f58 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
@@ -141,6 +141,7 @@ public class ServiceConstants {
         .put("datanucleus.transactionIsolation", "read-committed")
         .put("datanucleus.cache.level2", "false")
         .put("datanucleus.cache.level2.type", "none")
+        .put("datanucleus.query.sql.allowAll", "true")
         .put("datanucleus.identifierFactory", "datanucleus1")
         .put("datanucleus.rdbms.useLegacyNativeValueStrategy", "true")
         .put("datanucleus.plugin.pluginRegistryBundleCheck", "LOG")
@@ -258,4 +259,7 @@ public class ServiceConstants {
     TABLE,
     COLUMN
   }
+
+  public static final String SENTRY_ZK_JAAS_NAME = "Sentry";
+  public static final String CURRENT_INCARNATION_ID_KEY = "current.incarnation.key";
 }

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
index f14b586..5999580 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
@@ -21,7 +21,11 @@ import java.io.File;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.IOUtils;
 import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
+import org.apache.sentry.service.thrift.ServiceConstants;
 import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -34,6 +38,7 @@ public abstract class SentryStoreIntegrationBase {
   private static File dataDir;
   private static File policyFilePath;
   protected static Configuration conf;
+  protected static Activator act;
   protected static DelegateSentryStore sentryStore;
   protected static PolicyFile policyFile;
 
@@ -57,6 +62,9 @@ public abstract class SentryStoreIntegrationBase {
     policyFilePath = new File(Files.createTempDir(), "local_policy_file.ini");
     conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE,
         policyFilePath.getPath());
+    act = new Activator(conf);
+		conf.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY, act.getIncarnationId());
+    Activators.INSTANCE.put(act);
   }
 
   @After
@@ -66,6 +74,9 @@ public abstract class SentryStoreIntegrationBase {
 
   @AfterClass
   public static void teardown() {
+    if (act != null) {
+      IOUtils.cleanup(null, act);
+    }
     if (sentryStore != null) {
       sentryStore.close();
     }
@@ -75,6 +86,10 @@ public abstract class SentryStoreIntegrationBase {
     if (policyFilePath != null) {
       FileUtils.deleteQuietly(policyFilePath);
     }
+    if (act != null) {
+      Activators.INSTANCE.remove(act);
+      act = null;
+    }
   }
 
   public static void addGroupsToUser(String user, String... groupNames) {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
index 799d5ef..7c66db4 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
@@ -37,6 +37,8 @@ import org.apache.sentry.core.model.sqoop.SqoopActionConstant;
 import org.apache.sentry.core.common.exception.SentryGrantDeniedException;
 import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder;
 import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
 import org.apache.sentry.service.thrift.ServiceConstants;
 import org.junit.Before;
 import org.junit.Test;
@@ -987,8 +989,14 @@ public class TestPrivilegeOperatePersistence extends SentryStoreIntegrationBase
     Configuration confCopy = new Configuration(conf);
     confCopy.set(String.format(ServiceConstants.ServerConfig.SENTRY_COMPONENT_ACTION_FACTORY_FORMAT, externalComponent),
                  InvalidActionFactory.class.getName());
-    SentryStoreLayer store = new DelegateSentryStore(confCopy);
+    Activator act = new Activator(confCopy);
+    confCopy.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+                 act.getIncarnationId());
+    Activators.INSTANCE.put(act);
+   SentryStoreLayer store = new DelegateSentryStore(confCopy);
     testGrantPrivilege(store, externalComponent);
+    act.close();
+    Activators.INSTANCE.remove(act);
   }
 
   @Test
@@ -997,8 +1005,14 @@ public class TestPrivilegeOperatePersistence extends SentryStoreIntegrationBase
     Configuration confCopy = new Configuration(conf);
     confCopy.set(String.format(ServiceConstants.ServerConfig.SENTRY_COMPONENT_ACTION_FACTORY_FORMAT, externalComponent),
                  MyComponentActionFactory.class.getName());
+    Activator act = new Activator(confCopy);
+    confCopy.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+                 act.getIncarnationId());
+    Activators.INSTANCE.put(act);
     SentryStoreLayer store = new DelegateSentryStore(confCopy);
     testGrantPrivilege(store, externalComponent);
+    act.close();
+    Activators.INSTANCE.remove(act);
   }
 
   @Test
@@ -1007,8 +1021,14 @@ public class TestPrivilegeOperatePersistence extends SentryStoreIntegrationBase
     Configuration confCopy = new Configuration(conf);
     confCopy.set(String.format(ServiceConstants.ServerConfig.SENTRY_COMPONENT_ACTION_FACTORY_FORMAT, "mycomponent"),
                  MyComponentActionFactory.class.getName());
+    Activator act = new Activator(confCopy);
+    confCopy.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+                 act.getIncarnationId());
+    Activators.INSTANCE.put(act);
     SentryStoreLayer store = new DelegateSentryStore(confCopy);
     testGrantPrivilege(store, externalComponent);
+    act.close();
+    Activators.INSTANCE.remove(act);
   }
 
   private void testGrantPrivilege(SentryStoreLayer sentryStore, String component) throws SentryUserException {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
index 3ef1cf7..6e00505 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
@@ -27,6 +27,7 @@ import java.util.Set;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.security.alias.CredentialProvider;
 import org.apache.hadoop.security.alias.CredentialProviderFactory;
 import org.apache.hadoop.security.alias.UserProvider;
@@ -44,6 +45,9 @@ import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
 import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
 import org.apache.sentry.provider.db.service.thrift.TSentryRole;
 import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
+import org.apache.sentry.service.thrift.ServiceConstants;
 import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -67,6 +71,7 @@ public class TestSentryStore extends org.junit.Assert {
   final long NUM_PRIVS = 60;  // > SentryStore.PrivCleaner.NOTIFY_THRESHOLD
   private static Configuration conf = null;
   private static char[] passwd = new char[] { '1', '2', '3'};
+  private static Activator act;
 
   @BeforeClass
   public static void setup() throws Exception {
@@ -89,6 +94,10 @@ public class TestSentryStore extends org.junit.Assert {
     policyFilePath = new File(dataDir, "local_policy_file.ini");
     conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE,
         policyFilePath.getPath());
+    act = new Activator(conf);
+    conf.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+             act.getIncarnationId());
+    Activators.INSTANCE.put(act);
     sentryStore = new SentryStore(conf);
   }
 
@@ -107,12 +116,17 @@ public class TestSentryStore extends org.junit.Assert {
 
   @AfterClass
   public static void teardown() {
+    IOUtils.cleanup(null, act);
     if (sentryStore != null) {
       sentryStore.stop();
     }
     if (dataDir != null) {
       FileUtils.deleteQuietly(dataDir);
     }
+    if (act != null) {
+      Activators.INSTANCE.remove(act);
+      act = null;
+    }
   }
 
   @Test


[3/4] sentry git commit: SENTRY-1317: Implement fencing required for active/standby (Colin P. McCabe , Reviewed by: Hao Hao and Sravya Tirukkovalur)

Posted by sr...@apache.org.
http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreImportExport.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreImportExport.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreImportExport.java
index 3ff97df..fc39658 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreImportExport.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStoreImportExport.java
@@ -28,6 +28,7 @@ import java.util.Set;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.IOUtils;
 import org.apache.sentry.core.model.db.AccessConstants;
 import org.apache.sentry.provider.db.service.model.MSentryGroup;
 import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
@@ -37,6 +38,9 @@ import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
 import org.apache.sentry.provider.db.service.thrift.TSentryMappingData;
 import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
 import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
+import org.apache.sentry.service.thrift.ServiceConstants;
 import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope;
 import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
 import org.junit.After;
@@ -52,10 +56,11 @@ import com.google.common.io.Files;
 public class TestSentryStoreImportExport {
 
   private static File dataDir;
-  private static SentryStore sentryStore;
   private static String[] adminGroups = { "adminGroup1" };
   private static PolicyFile policyFile;
   private static File policyFilePath;
+  private static Activator act;
+  private static SentryStore sentryStore;
   private TSentryPrivilege tSentryPrivilege1;
   private TSentryPrivilege tSentryPrivilege2;
   private TSentryPrivilege tSentryPrivilege3;
@@ -79,6 +84,10 @@ public class TestSentryStoreImportExport {
     policyFilePath = new File(dataDir, "local_policy_file.ini");
     conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE, policyFilePath.getPath());
     policyFile = new PolicyFile();
+    act = new Activator(conf);
+    conf.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+             act.getIncarnationId());
+    Activators.INSTANCE.put(act);
     sentryStore = new SentryStore(conf);
 
     String adminUser = "g1";
@@ -129,12 +138,17 @@ public class TestSentryStoreImportExport {
 
   @AfterClass
   public static void teardown() {
+    IOUtils.cleanup(null, act);
     if (sentryStore != null) {
       sentryStore.stop();
     }
     if (dataDir != null) {
       FileUtils.deleteQuietly(dataDir);
     }
+    if (act != null) {
+      Activators.INSTANCE.remove(act);
+      act = null;
+    }
   }
 
   protected static void addGroupsToUser(String user, String... groupNames) {

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryVersion.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryVersion.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryVersion.java
index a8e8a03..cf7ca8e 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryVersion.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryVersion.java
@@ -24,7 +24,11 @@ import java.io.File;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.sentry.core.common.exception.SentryNoSuchObjectException;
+import org.apache.sentry.service.thrift.Activator;
+import org.apache.sentry.service.thrift.Activators;
+import org.apache.sentry.service.thrift.ServiceConstants;
 import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -34,6 +38,7 @@ public class TestSentryVersion {
 
   private File dataDir;
   private Configuration conf;
+  private Activator act;
 
   @Before
   public void setup() throws Exception {
@@ -42,6 +47,19 @@ public class TestSentryVersion {
     conf.set(ServerConfig.SENTRY_STORE_JDBC_URL, "jdbc:derby:;databaseName="
         + dataDir.getPath() + ";create=true");
     conf.set(ServerConfig.SENTRY_STORE_JDBC_PASS, "dummy");
+    act = new Activator(conf);
+    conf.set(ServiceConstants.CURRENT_INCARNATION_ID_KEY,
+             act.getIncarnationId());
+    Activators.INSTANCE.put(act);
+  }
+
+  @After
+  public void shutdown() throws Exception {
+    if (act != null) {
+      act.close();
+      Activators.INSTANCE.remove(act);
+      act = null;
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
index cb2d9c9..4197e6d 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
@@ -31,7 +31,6 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.minikdc.MiniKdc;
 import org.apache.hadoop.net.NetUtils;
 import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.sentry.provider.db.service.persistent.HAContext;
 import org.apache.sentry.provider.db.service.thrift.SentryMiniKdcTestcase;
 import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
 import org.apache.sentry.provider.db.service.thrift.TSentryRole;
@@ -324,7 +323,7 @@ public abstract class SentryServiceIntegrationBase extends SentryMiniKdcTestcase
 
       JaasConfiguration.addEntryForKeytab("Server", ZK_SERVER_PRINCIPAL, ZKKeytabFile.getAbsolutePath());
       // Here's where we add the "Client" to the jaas configuration, even though we'd like not to
-      JaasConfiguration.addEntryForKeytab(HAContext.SENTRY_ZK_JAAS_NAME,
+      JaasConfiguration.addEntryForKeytab(ServiceConstants.SENTRY_ZK_JAAS_NAME,
           SERVER_KERBEROS_NAME, serverKeytab.getAbsolutePath());
       javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
 

http://git-wip-us.apache.org/repos/asf/sentry/blob/ff7823b6/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestLeaderStatus.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestLeaderStatus.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestLeaderStatus.java
index 434ac41..6d408ff 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestLeaderStatus.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestLeaderStatus.java
@@ -26,6 +26,7 @@ import org.junit.Test;
 
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -216,4 +217,29 @@ final public class TestLeaderStatus {
     Assert.assertTrue(null == active.getError());
     server.close();
   }
+
+  @Test(timeout = 60000)
+  public void testGenerateIncarnationIDs() throws Exception {
+    final int NUM_UNIQUE_IDS = 10000;
+    HashSet<String> ids = new HashSet<String>();
+    for (int i = 0; i < NUM_UNIQUE_IDS; i++) {
+      ids.add(LeaderStatus.generateIncarnationId());
+    }
+
+    // Assert that there were no ID collisions
+    Assert.assertEquals(NUM_UNIQUE_IDS, ids.size());
+
+    // Assert that all IDs are 44 characters long and begin with a letter.
+    for (String id : ids) {
+      Assert.assertEquals(44, id.length());
+      Assert.assertTrue(Character.isAlphabetic(id.charAt(0)));
+    }
+
+    // Assert that IDs contain only alphanumeric characters
+    for (String id : ids) {
+      for (int i = 0; i < id.length(); i++) {
+        Assert.assertTrue(Character.isLetterOrDigit(id.charAt(i)));
+      }
+    }
+  }
 }


Re: [2/4] sentry git commit: SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS notification logs

Posted by Sravya Tirukkovalur <sr...@apache.org>.
Sorry, pushed this change by mistake while pushing Sentry-1317. Fixed it
now.

Thanks!

On Tue, Jul 12, 2016 at 1:06 PM, <sr...@apache.org> wrote:

> SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS
> notification logs
>
> Also,
> 1. Implementing the SentryJSONMessageFactory to add custom information in
> the notification log entry message, which includes
>  1.1. Implementing Message class for each message type
>  1.2. Implementing a deserializer
> 2. Implementing JSONAlterPartitionMessage and JSONAlterTableMessage to
> work around the issue in Hive 1.1.0. These classes do not have required
> default constructor.
> 3. Testing:
>  3.1. Sentry functionality: TestSentryListenerSentryDeserializer to verify
> functionality using Sentry's SentryMetastorePostEventListener and Sentry
> Notification log deserializer.
>  3.2. TestDbNotificationListenerSentryDeserializer uses Hive's
> DbNotificationListener and Sentry's JSON deserializeri. This would make
> sure Sentry is able to read the Notification logs written by Hive's
> DBNotificationListener
>  3.3. TestSentryListenerInBuiltDeserializer uses Sentry's
> SentryMetastorePostEventListener and Hive's inbuilt Notification log
> deserializer: This would make sure Sentry is not breaking other users of
> NotificationLog who might be using Hive's in built serializer
>
> Change-Id: I680beb6db4e534bb0a9e6ee042ea0d4f33f0943f
>
>
> Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
> Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/113c5eae
> Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/113c5eae
> Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/113c5eae
>
> Branch: refs/heads/sentry-ha-redesign
> Commit: 113c5eae4ce9d3cb86ac7193731696d943fbea1f
> Parents: de7c26a
> Author: Sravya Tirukkovalur <sr...@apache.org>
> Authored: Tue Jun 14 16:30:51 2016 -0700
> Committer: Sravya Tirukkovalur <sr...@apache.org>
> Committed: Tue Jul 12 12:49:02 2016 -0700
>
> ----------------------------------------------------------------------
>  sentry-binding/sentry-binding-hive/pom.xml      |   6 +
>  .../SentryMetastorePostEventListener.java       | 518 +++++++++----------
>  .../json/JSONAlterPartitionMessage.java         |  78 +++
>  .../messaging/json/JSONAlterTableMessage.java   |  68 +++
>  .../json/SentryJSONAddPartitionMessage.java     |  49 ++
>  .../json/SentryJSONAlterPartitionMessage.java   |  53 ++
>  .../json/SentryJSONAlterTableMessage.java       |  50 ++
>  .../json/SentryJSONCreateDatabaseMessage.java   |  44 ++
>  .../json/SentryJSONCreateTableMessage.java      |  45 ++
>  .../json/SentryJSONDropDatabaseMessage.java     |  44 ++
>  .../json/SentryJSONDropPartitionMessage.java    |  49 ++
>  .../json/SentryJSONDropTableMessage.java        |  45 ++
>  .../json/SentryJSONMessageDeserializer.java     | 110 ++++
>  .../json/SentryJSONMessageFactory.java          | 177 +++++++
>  .../TestDbPrivilegeCleanupOnDrop.java           |   7 +-
>  .../AbstractTestWithStaticConfiguration.java    |   3 +-
>  ...actMetastoreTestWithStaticConfiguration.java |   5 +
>  ...NotificationListenerInBuiltDeserializer.java | 353 +++++++++++++
>  ...bNotificationListenerSentryDeserializer.java |  39 ++
>  ...ificationLogUsingDBNotificationListener.java | 351 -------------
>  .../TestSentryListenerInBuiltDeserializer.java  |  37 ++
>  .../TestSentryListenerSentryDeserializer.java   | 375 ++++++++++++++
>  22 files changed, 1886 insertions(+), 620 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/pom.xml
> ----------------------------------------------------------------------
> diff --git a/sentry-binding/sentry-binding-hive/pom.xml
> b/sentry-binding/sentry-binding-hive/pom.xml
> index 07aaae3..ca87836 100644
> --- a/sentry-binding/sentry-binding-hive/pom.xml
> +++ b/sentry-binding/sentry-binding-hive/pom.xml
> @@ -106,6 +106,12 @@ limitations under the License.
>        <scope>provided</scope>
>      </dependency>
>      <dependency>
> +      <groupId>org.apache.hive.hcatalog</groupId>
> +      <artifactId>hive-hcatalog-server-extensions</artifactId>
> +      <version>${hive.version}</version>
> +      <scope>compile</scope>
> +    </dependency>
> +    <dependency>
>        <groupId>org.mockito</groupId>
>        <artifactId>mockito-all</artifactId>
>        <scope>test</scope>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> index d12ac15..75190c1 100644
> ---
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> @@ -17,15 +17,16 @@
>   */
>  package org.apache.sentry.binding.metastore;
>
> -import java.io.IOException;
> -import java.util.ArrayList;
> -import java.util.List;
> +import java.util.concurrent.TimeUnit;
>
>  import org.apache.hadoop.conf.Configuration;
>  import org.apache.hadoop.hive.conf.HiveConf;
>  import org.apache.hadoop.hive.metastore.MetaStoreEventListener;
> +import org.apache.hadoop.hive.metastore.RawStore;
> +import org.apache.hadoop.hive.metastore.RawStoreProxy;
> +import org.apache.hadoop.hive.metastore.TableType;
>  import org.apache.hadoop.hive.metastore.api.MetaException;
> -import org.apache.hadoop.hive.metastore.api.Partition;
> +import org.apache.hadoop.hive.metastore.api.NotificationEvent;
>  import org.apache.hadoop.hive.metastore.events.AddPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.AlterPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.AlterTableEvent;
> @@ -34,371 +35,360 @@ import
> org.apache.hadoop.hive.metastore.events.CreateTableEvent;
>  import org.apache.hadoop.hive.metastore.events.DropDatabaseEvent;
>  import org.apache.hadoop.hive.metastore.events.DropPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.DropTableEvent;
> -import org.apache.hadoop.security.UserGroupInformation;
> -import org.apache.sentry.core.common.exception.SentryUserException;
> -import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
> -import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
> -import org.apache.sentry.core.common.Authorizable;
> -import org.apache.sentry.core.model.db.Database;
> -import org.apache.sentry.core.model.db.Server;
> -import org.apache.sentry.core.model.db.Table;
> +import org.apache.hive.hcatalog.common.HCatConstants;
> +import
> org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory;
>  import org.apache.sentry.provider.db.SentryMetastoreListenerPlugin;
> -import
> org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
> -import org.apache.sentry.service.thrift.SentryServiceClientFactory;
> -import org.apache.sentry.service.thrift.ServiceConstants.ConfUtilties;
> -import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
>  import org.slf4j.Logger;
>  import org.slf4j.LoggerFactory;
>
> +import org.apache.commons.lang3.builder.ToStringBuilder;
> +/*
> +A HMS listener class which should ideally go into the transaction which
> persists the Hive metadata.
> +This class writes all DDL events to the NotificationLog through
> rawstore.addNotificationEvent(event)
> +This class is very similar to DbNotificationListener, except:
> +1. It uses a custom SentryJSONMessageFactory which adds additional
> information to the message part of the event
> + to avoid another round trip from the clients
> +2. It handles the cases where actual operation has failed, and hence
> skips writing to the notification log.
> +3. Has additional validations to make sure event has the required
> information.
> +
> +This can be replaced with DbNotificationListener in future and sentry's
> message factory can be plugged in if:
> +- HIVE-14011 is fixed: Make MessageFactory truly pluggable
> +- 2 and 3 above are handled in DbNotificationListener
> +*/
> +
>  public class SentryMetastorePostEventListener extends
> MetaStoreEventListener {
>
>    private static final Logger LOGGER =
> LoggerFactory.getLogger(SentryMetastoreListenerPlugin.class);
> -  private final HiveAuthzConf authzConf;
> -  private final Server server;
> +  private RawStore rs;
> +  private HiveConf hiveConf;
> +  SentryJSONMessageFactory messageFactory;
>
> -  protected List<SentryMetastoreListenerPlugin> sentryPlugins = new
> ArrayList<SentryMetastoreListenerPlugin>();
> +  private static SentryMetastorePostEventListener.CleanerThread cleaner =
> null;
>
> -  public SentryMetastorePostEventListener(Configuration config) {
> -    super(config);
> -
> -    if (!(config instanceof HiveConf)) {
> -        String error = "Could not initialize Plugin - Configuration is
> not an instanceof HiveConf";
> -        LOGGER.error(error);
> -        throw new RuntimeException(error);
> +  //Same as DbNotificationListener to make the transition back easy
> +  private synchronized void init(HiveConf conf) {
> +    try {
> +      this.rs = RawStoreProxy.getProxy(conf, conf,
> conf.getVar(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL), 999999);
> +    } catch (MetaException var3) {
> +      LOGGER.error("Unable to connect to raw store, notifications will
> not be tracked", var3);
> +      this.rs = null;
>      }
>
> -    authzConf = HiveAuthzConf.getAuthzConf((HiveConf)config);
> -    server = new
> Server(authzConf.get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
> -    Iterable<String> pluginClasses = ConfUtilties.CLASS_SPLITTER
> -        .split(config.get(ServerConfig.SENTRY_METASTORE_PLUGINS,
> -            ServerConfig.SENTRY_METASTORE_PLUGINS_DEFAULT).trim());
> +    if(cleaner == null && this.rs != null) {
> +      cleaner = new SentryMetastorePostEventListener.CleanerThread(conf,
> this.rs);
> +      cleaner.start();
> +    }
> +  }
>
> -    try {
> -      for (String pluginClassStr : pluginClasses) {
> -        Class<?> clazz = config.getClassByName(pluginClassStr);
> -        if (!SentryMetastoreListenerPlugin.class.isAssignableFrom(clazz))
> {
> -          throw new IllegalArgumentException("Class ["
> -              + pluginClassStr + "] is not a "
> -              + SentryMetastoreListenerPlugin.class.getName());
> -        }
> -        SentryMetastoreListenerPlugin plugin =
> (SentryMetastoreListenerPlugin) clazz
> -            .getConstructor(Configuration.class, Configuration.class)
> -            .newInstance(config, authzConf);
> -        sentryPlugins.add(plugin);
> -      }
> -    } catch (Exception e) {
> -      LOGGER.error("Could not initialize Plugin !!", e);
> -      throw new RuntimeException(e);
> +  public SentryMetastorePostEventListener(Configuration config) {
> +    super(config);
> +    // The code in MetastoreUtils.getMetaStoreListeners() that calls this
> looks for a constructor
> +    // with a Configuration parameter, so we have to declare config as
> Configuration.  But it
> +    // actually passes a HiveConf, which we need.  So we'll do this ugly
> down cast.
> +    if (!(config instanceof HiveConf)) {
> +      String error = "Could not initialize Plugin - Configuration is not
> an instanceof HiveConf";
> +      LOGGER.error(error);
> +      throw new RuntimeException(error);
>      }
> +    hiveConf = (HiveConf)config;
> +    messageFactory = new SentryJSONMessageFactory();
> +    init(hiveConf);
>    }
>
>    @Override
> -  public void onCreateTable (CreateTableEvent tableEvent) throws
> MetaException {
> +  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
> +          throws MetaException {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip sync paths/privileges with Sentry server for
> onCreateTable event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!dbEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Create
> database event failed");
>        return;
>      }
>
> -    if (tableEvent.getTable().getSd().getLocation() != null) {
> -      String authzObj = tableEvent.getTable().getDbName() + "."
> -          + tableEvent.getTable().getTableName();
> -      String path = tableEvent.getTable().getSd().getLocation();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.addPath(authzObj, path);
> -      }
> +    String location = dbEvent.getDatabase().getLocationUri();
> +    if (location == null || location.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateDatabaseEvent has
> invalid location", dbEvent);
>      }
> -
> -    // drop the privileges on the given table, in case if anything was
> left
> -    // behind during the drop
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
> -      return;
> +    String dbName = dbEvent.getDatabase().getName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateDatabaseEvent has
> invalid dbName", dbEvent);
>      }
>
> -    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
> -        tableEvent.getTable().getTableName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_CREATE_DATABASE_EVENT,
> +
> messageFactory.buildCreateDatabaseMessage(dbEvent.getDatabase()).toString());
> +    event.setDbName(dbName);
> +    this.enqueue(event);
>    }
>
>    @Override
> -  public void onDropTable(DropTableEvent tableEvent) throws MetaException
> {
> -
> -    // don't sync paths/privileges if the operation has failed
> -    if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onDropTable event," +
> -        " since the operation failed. \n");
> -      return;
> -    }
> +  public void onDropDatabase(DropDatabaseEvent dbEvent) throws
> MetaException {
>
> -    if (tableEvent.getTable().getSd().getLocation() != null) {
> -      String authzObj = tableEvent.getTable().getDbName() + "."
> -          + tableEvent.getTable().getTableName();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.removeAllPaths(authzObj, null);
> -      }
> -    }
> -    // drop the privileges on the given table
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
> +    // do not write to Notification log if the operation has failed
> +    if (!dbEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop
> database event failed");
>        return;
>      }
>
> -    if (!tableEvent.getStatus()) {
> -      return;
> +    String dbName = dbEvent.getDatabase().getName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropDatabaseEvent has
> invalid dbName", dbEvent);
>      }
>
> -    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
> -        tableEvent.getTable().getTableName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_DATABASE_EVENT,
> +
> messageFactory.buildDropDatabaseMessage(dbEvent.getDatabase()).toString());
> +    event.setDbName(dbName);
> +    this.enqueue(event);
>    }
>
>    @Override
> -  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
> -      throws MetaException {
> +  public void onCreateTable (CreateTableEvent tableEvent) throws
> MetaException {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!dbEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onCreateDatabase event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!tableEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Create
> table event failed");
>        return;
>      }
>
> -    if (dbEvent.getDatabase().getLocationUri() != null) {
> -      String authzObj = dbEvent.getDatabase().getName();
> -      String path = dbEvent.getDatabase().getLocationUri();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.addPath(authzObj, path);
> -      }
> +    String dbName = tableEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateTableEvent has
> invalid dbName", tableEvent);
>      }
> -    // drop the privileges on the database, in case anything left behind
> during
> -    // last drop db
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
> -      return;
> +    String tableName = tableEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateTableEvent has
> invalid tableName", tableEvent);
>      }
> -
> -    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
> +    // Create table event should also contain a location.
> +    // But, Create view also generates a Create table event, but it does
> not have a location.
> +    // Create view is identified by the tableType. But turns out
> tableType is not set in some cases.
> +    // We assume that tableType is set for all create views.
> +    //TODO: Location can be null/empty, handle that in HMSFollower
> +    String tableType = tableEvent.getTable().getTableType();
> +    if(!(tableType != null && tableType.equals(
> TableType.VIRTUAL_VIEW.name()))) {
> +        if (tableType == null) {
> +        LOGGER.warn("TableType is null, assuming it is not
> TableType.VIRTUAL_VIEW: tableEvent", tableEvent);
> +      }
> +      String location = tableEvent.getTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("CreateTableEvent has
> invalid location", tableEvent);
> +      }
> +    }
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_CREATE_TABLE_EVENT,
> +
> messageFactory.buildCreateTableMessage(tableEvent.getTable()).toString());
> +    event.setDbName(dbName);
> +    event.setTableName(tableName);
> +    this.enqueue(event);
>    }
>
> -  /**
> -   * Drop the privileges on the database. Note that child tables will be
> -   * dropped individually by client, so we just need to handle the
> removing
> -   * the db privileges. The table drop should cleanup the table
> privileges.
> -   */
>    @Override
> -  public void onDropDatabase(DropDatabaseEvent dbEvent) throws
> MetaException {
> +  public void onDropTable(DropTableEvent tableEvent) throws MetaException
> {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!dbEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onDropDatabase event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!tableEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop table
> event failed");
>        return;
>      }
>
> -    String authzObj = dbEvent.getDatabase().getName();
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      List<String> tNames = dbEvent.getHandler().get_all_tables(authzObj);
> -      plugin.removeAllPaths(authzObj, tNames);
> +    String dbName = tableEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropTableEvent has invalid
> dbName", tableEvent);
>      }
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
> -      return;
> +    String tableName = tableEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropTableEvent has invalid
> tableName", tableEvent);
>      }
>
> -    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_TABLE_EVENT,
> +
> messageFactory.buildDropTableMessage(tableEvent.getTable()).toString());
> +    event.setDbName(dbName);
> +    event.setTableName(tableName);
> +    this.enqueue(event);
>    }
>
> -  /**
> -   * Adjust the privileges when table is renamed
> -   */
>    @Override
>    public void onAlterTable (AlterTableEvent tableEvent) throws
> MetaException {
>
> -    // don't sync privileges if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing privileges with Sentry server for
> onAlterTable event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Alter table
> event failed");
>        return;
>      }
>
> -    renameSentryTablePrivilege(tableEvent.getOldTable().getDbName(),
> -        tableEvent.getOldTable().getTableName(),
> -        tableEvent.getOldTable().getSd().getLocation(),
> -        tableEvent.getNewTable().getDbName(),
> -        tableEvent.getNewTable().getTableName(),
> -        tableEvent.getNewTable().getSd().getLocation());
> +    String dbName = tableEvent.getNewTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's newTable
> has invalid dbName", tableEvent);
> +    }
> +    String tableName = tableEvent.getNewTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's newTable
> has invalid tableName", tableEvent);
> +    }
> +    dbName = tableEvent.getOldTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's oldTable
> has invalid dbName", tableEvent);
> +    }
> +    tableName = tableEvent.getOldTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's oldTable
> has invalid tableName", tableEvent);
> +    }
> +    //Alter view also generates an alter table event, but it does not
> have a location
> +    //TODO: Handle this case in Sentry
> +    if(!tableEvent.getOldTable().getTableType().equals(
> TableType.VIRTUAL_VIEW.name())) {
> +      String location = tableEvent.getNewTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("AlterTableEvent's
> newTable has invalid location", tableEvent);
> +      }
> +      location = tableEvent.getOldTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("AlterTableEvent's
> oldTable has invalid location", tableEvent);
> +      }
> +    }
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ALTER_TABLE_EVENT,
> +
> messageFactory.buildAlterTableMessage(tableEvent.getOldTable(),
> tableEvent.getNewTable()).toString());
> +    event.setDbName(tableEvent.getNewTable().getDbName());
> +    event.setTableName(tableEvent.getNewTable().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onAlterPartition(AlterPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync privileges if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing privileges with Sentry server for
> onAlterPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Alter
> partition event failed");
>        return;
>      }
>
> -    String oldLoc = null, newLoc = null;
> -    if (partitionEvent.getOldPartition() != null) {
> -      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
> +    String dbName = partitionEvent.getNewPartition().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterPartitionEvent's
> newPartition has invalid dbName", partitionEvent);
>      }
> -    if (partitionEvent.getNewPartition() != null) {
> -      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
> +    String tableName = partitionEvent.getNewPartition().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterPartitionEvent's
> newPartition has invalid tableName", partitionEvent);
>      }
>
> -    if (oldLoc != null && newLoc != null && !oldLoc.equals(newLoc)) {
> -      String authzObj =
> -          partitionEvent.getOldPartition().getDbName() + "."
> -              + partitionEvent.getOldPartition().getTableName();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.renameAuthzObject(authzObj, oldLoc,
> -            authzObj, newLoc);
> -      }
> -    }
> +    //TODO: Need more validations, but it is tricky as there are many
> variations and validations change for each one
> +    // Alter partition Location
> +    // Alter partition property
> +    // Any more?
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ALTER_PARTITION_EVENT,
> +
> messageFactory.buildAlterPartitionMessage(partitionEvent.getOldPartition(),
> partitionEvent.getNewPartition()).toString());
> +
> +    event.setDbName(partitionEvent.getNewPartition().getDbName());
> +    event.setTableName(partitionEvent.getNewPartition().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onAddPartition(AddPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync path if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing path with Sentry server for
> onAddPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Add
> partition event failed");
>        return;
>      }
>
> -    for (Partition part : partitionEvent.getPartitions()) {
> -      if (part.getSd() != null && part.getSd().getLocation() != null) {
> -        String authzObj = part.getDbName() + "." + part.getTableName();
> -        String path = part.getSd().getLocation();
> -        for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -          plugin.addPath(authzObj, path);
> -        }
> -      }
> +    String dbName = partitionEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AddPartitionEvent has
> invalid dbName", partitionEvent);
> +    }
> +    String tableName = partitionEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AddPartitionEvent's
> newPartition has invalid tableName", partitionEvent);
>      }
> -    super.onAddPartition(partitionEvent);
> +
> +    //TODO: Need more validations?
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ADD_PARTITION_EVENT,
> +
> messageFactory.buildAddPartitionMessage(partitionEvent.getTable(),
> partitionEvent.getPartitions()).toString());
> +
> +    event.setDbName(partitionEvent.getTable().getDbName());
> +    event.setTableName(partitionEvent.getTable().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onDropPartition(DropPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync path if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing path with Sentry server for
> onDropPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop
> partition event failed");
>        return;
>      }
>
> -    String authzObj = partitionEvent.getTable().getDbName() + "."
> -        + partitionEvent.getTable().getTableName();
> -    String path = partitionEvent.getPartition().getSd().getLocation();
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      plugin.removePath(authzObj, path);
> -    }
> -    super.onDropPartition(partitionEvent);
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_PARTITION_EVENT,
> +
> messageFactory.buildDropPartitionMessage(partitionEvent.getTable(),
> partitionEvent.getPartition()).toString());
> +    //TODO: Why is this asymmetric with add partitions(s)?
> +    // Seems like adding multiple partitions generate a single event
> +    // where as single partition drop generated an event?
> +
> +    event.setDbName(partitionEvent.getTable().getDbName());
> +    event.setTableName(partitionEvent.getTable().getTableName());
> +    this.enqueue(event);
>    }
>
> -  private SentryPolicyServiceClient getSentryServiceClient()
> -      throws MetaException {
> -    try {
> -      return SentryServiceClientFactory.create(authzConf);
> -    } catch (Exception e) {
> -      throw new MetaException("Failed to connect to Sentry service "
> -          + e.getMessage());
> +  private int now() {
> +    long millis = System.currentTimeMillis();
> +    millis /= 1000;
> +    if (millis > Integer.MAX_VALUE) {
> +      LOGGER.warn("We've passed max int value in seconds since the epoch,
> " +
> +          "all notification times will be the same!");
> +      return Integer.MAX_VALUE;
>      }
> +    return (int)millis;
>    }
>
> -  private void dropSentryDbPrivileges(String dbName) throws MetaException
> {
> -    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
> -    authorizableTable.add(server);
> -    authorizableTable.add(new Database(dbName));
> -    try {
> -      dropSentryPrivileges(authorizableTable);
> -    } catch (SentryUserException e) {
> -      throw new MetaException("Failed to remove Sentry policies for drop
> DB "
> -          + dbName + " Error: " + e.getMessage());
> -    } catch (IOException e) {
> -      throw new MetaException("Failed to find local user " +
> e.getMessage());
> +  //Same as DbNotificationListener to make the transition back easy
> +  private void enqueue(NotificationEvent event) {
> +    if(this.rs != null) {
> +      this.rs.addNotificationEvent(event);
> +    } else {
> +      LOGGER.warn("Dropping event " + event + " since notification is not
> running.");
>      }
> -
>    }
>
> -  private void dropSentryTablePrivilege(String dbName, String tabName)
> -      throws MetaException {
> -    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
> -    authorizableTable.add(server);
> -    authorizableTable.add(new Database(dbName));
> -    authorizableTable.add(new Table(tabName));
> +  //Same as DbNotificationListener to make the transition back easy
> +  private static class CleanerThread extends Thread {
> +    private RawStore rs;
> +    private int ttl;
>
> -    try {
> -      dropSentryPrivileges(authorizableTable);
> -    } catch (SentryUserException e) {
> -      throw new MetaException(
> -          "Failed to remove Sentry policies for drop table " + dbName +
> "."
> -              + tabName + " Error: " + e.getMessage());
> -    } catch (IOException e) {
> -      throw new MetaException("Failed to find local user " +
> e.getMessage());
> +    CleanerThread(HiveConf conf, RawStore rs) {
> +      super("CleanerThread");
> +      this.rs = rs;
> +
> this.setTimeToLive(conf.getTimeVar(HiveConf.ConfVars.METASTORE_EVENT_DB_LISTENER_TTL,
> TimeUnit.SECONDS));
> +      this.setDaemon(true);
>      }
>
> -  }
> -  private void dropSentryPrivileges(
> -      List<? extends Authorizable> authorizableTable)
> -      throws SentryUserException, IOException, MetaException {
> -    String requestorUserName = UserGroupInformation.getCurrentUser()
> -        .getShortUserName();
> -    SentryPolicyServiceClient sentryClient = getSentryServiceClient();
> -    sentryClient.dropPrivileges(requestorUserName, authorizableTable);
> -
> -    // Close the connection after dropping privileges is done.
> -    sentryClient.close();
> -  }
> +    public void run() {
> +      while(true) {
> +        this.rs.cleanNotificationEvents(this.ttl);
>
> -  private void renameSentryTablePrivilege(String oldDbName, String
> oldTabName,
> -      String oldPath, String newDbName, String newTabName, String newPath)
> -      throws MetaException {
> -    List<Authorizable> oldAuthorizableTable = new
> ArrayList<Authorizable>();
> -    oldAuthorizableTable.add(server);
> -    oldAuthorizableTable.add(new Database(oldDbName));
> -    oldAuthorizableTable.add(new Table(oldTabName));
> -
> -    List<Authorizable> newAuthorizableTable = new
> ArrayList<Authorizable>();
> -    newAuthorizableTable.add(server);
> -    newAuthorizableTable.add(new Database(newDbName));
> -    newAuthorizableTable.add(new Table(newTabName));
> -
> -    if (!oldTabName.equalsIgnoreCase(newTabName)
> -        &&
> syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_ALTER_WITH_POLICY_STORE)) {
> -
> -      SentryPolicyServiceClient sentryClient = getSentryServiceClient();
> -
> -      try {
> -        String requestorUserName = UserGroupInformation.getCurrentUser()
> -            .getShortUserName();
> -        sentryClient.renamePrivileges(requestorUserName,
> oldAuthorizableTable, newAuthorizableTable);
> -      } catch (SentryUserException e) {
> -        throw new MetaException(
> -            "Failed to remove Sentry policies for rename table " +
> oldDbName
> -            + "." + oldTabName + "to " + newDbName + "." + newTabName
> -            + " Error: " + e.getMessage());
> -      } catch (IOException e) {
> -        throw new MetaException("Failed to find local user " +
> e.getMessage());
> -      } finally {
> -
> -        // Close the connection after renaming privileges is done.
> -        sentryClient.close();
> +        try {
> +          Thread.sleep(60000L);
> +        } catch (InterruptedException var2) {
> +          LOGGER.info("Cleaner thread sleep interupted", var2);
> +        }
>        }
>      }
> -    // The HDFS plugin needs to know if it's a path change (set location)
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      plugin.renameAuthzObject(oldDbName + "." + oldTabName, oldPath,
> -          newDbName + "." + newTabName, newPath);
> +
> +    public void setTimeToLive(long configTtl) {
> +      if(configTtl > 2147483647L) {
> +        this.ttl = 2147483647;
> +      } else {
> +        this.ttl = (int)configTtl;
> +      }
> +
>      }
>    }
> -
> -  private boolean syncWithPolicyStore(AuthzConfVars syncConfVar) {
> -    return "true"
> -        .equalsIgnoreCase(authzConf.get(syncConfVar.getVar(), "true"));
> +  private class SentryMalformedEventException extends MetaException {
> +    SentryMalformedEventException(String msg, Object event) {
> +      //toString is not implemented in Event classes,
> +      // hence using reflection to print the details of the Event object.
> +      super(msg + "Event: " + ToStringBuilder.reflectionToString(event));
> +    }
>    }
> -
> -}
> +}
> \ No newline at end of file
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> new file mode 100644
> index 0000000..890186b
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> @@ -0,0 +1,78 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.AlterPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +
> +/*
> +* This is only needed as corresponding class in Hive 1.1.0 does not have
> a default constructor
> + */
> +public class JSONAlterPartitionMessage extends AlterPartitionMessage {
> +    @JsonProperty
> +    String server;
> +    @JsonProperty
> +    String servicePrincipal;
> +    @JsonProperty
> +    String db;
> +    @JsonProperty
> +    String table;
> +    @JsonProperty
> +    Long timestamp;
> +    @JsonProperty
> +    List<String> values;
> +
> +    public JSONAlterPartitionMessage() {}
> +    public JSONAlterPartitionMessage(String server, String
> servicePrincipal, String db, String table, List<String> values, Long
> timestamp) {
> +        this.server = server;
> +        this.servicePrincipal = servicePrincipal;
> +        this.db = db;
> +        this.table = table;
> +        this.timestamp = timestamp;
> +        this.values = values;
> +        this.checkValid();
> +    }
> +
> +    public String getServer() {
> +        return this.server;
> +    }
> +
> +    public String getServicePrincipal() {
> +        return this.servicePrincipal;
> +    }
> +
> +    public String getDB() {
> +        return this.db;
> +    }
> +
> +    public Long getTimestamp() {
> +        return this.timestamp;
> +    }
> +
> +    public String getTable() {
> +        return this.table;
> +    }
> +
> +    public List<String> getValues() {
> +        return this.values;
> +    }
> +
> +}
> \ No newline at end of file
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> new file mode 100644
> index 0000000..76211c3
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> @@ -0,0 +1,68 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.AlterTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +/**
> + * This class is required as this class does not have a default
> contructor in Hive 1.1.0
> + */
> +public class JSONAlterTableMessage extends AlterTableMessage {
> +    @JsonProperty
> +    String server;
> +    @JsonProperty
> +    String servicePrincipal;
> +    @JsonProperty
> +    String db;
> +    @JsonProperty
> +    String table;
> +    @JsonProperty
> +    Long timestamp;
> +
> +    public JSONAlterTableMessage() {}
> +    public JSONAlterTableMessage(String server, String servicePrincipal,
> String db, String table, Long timestamp) {
> +        this.server = server;
> +        this.servicePrincipal = servicePrincipal;
> +        this.db = db;
> +        this.table = table;
> +        this.timestamp = timestamp;
> +        this.checkValid();
> +    }
> +
> +    public String getServer() {
> +        return this.server;
> +    }
> +
> +    public String getServicePrincipal() {
> +        return this.servicePrincipal;
> +    }
> +
> +    public String getDB() {
> +        return this.db;
> +    }
> +
> +    public Long getTimestamp() {
> +        return this.timestamp;
> +    }
> +
> +    public String getTable() {
> +        return this.table;
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> new file mode 100644
> index 0000000..c0c469c
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> @@ -0,0 +1,49 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONAddPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +import java.util.Map;
> +
> +public class SentryJSONAddPartitionMessage extends
> JSONAddPartitionMessage {
> +    @JsonProperty
> +    List<String> locations;
> +
> +    public SentryJSONAddPartitionMessage() {
> +    }
> +
> +    public SentryJSONAddPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                         List<Map<String, String>>
> partitions, Long timestamp, List<String> locations) {
> +        super(server, servicePrincipal, db, table, partitions, timestamp);
> +        this.locations = locations;
> +    }
> +
> +    public List<String> getLocations() {
> +        return locations;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> new file mode 100644
> index 0000000..99eb67a
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> @@ -0,0 +1,53 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +package org.apache.sentry.binding.metastore.messaging.json;
> +
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +
> +public class SentryJSONAlterPartitionMessage extends
> JSONAlterPartitionMessage{
> +    @JsonProperty
> +    String location;
> +    @JsonProperty
> +    String oldLocation;
> +
> +    public SentryJSONAlterPartitionMessage() {
> +    }
> +
> +    public SentryJSONAlterPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                           List<String> values, Long
> timestamp, String oldlocation, String newLocation) {
> +        super(server, servicePrincipal, db, table, values, timestamp);
> +        this.location = newLocation;
> +        this.oldLocation = oldlocation;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    public String getOldLocation() {
> +        return oldLocation;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> new file mode 100644
> index 0000000..6e59e25
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> @@ -0,0 +1,50 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONAlterTableMessage extends JSONAlterTableMessage {
> +    @JsonProperty
> +    String location; //newLocation
> +    @JsonProperty
> +    String oldLocation;
> +
> +    public SentryJSONAlterTableMessage() {
> +    }
> +
> +    public SentryJSONAlterTableMessage(String server, String
> servicePrincipal, String db, String table,
> +                                       Long timestamp, String
> oldLocation, String location) {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +        this.oldLocation = oldLocation;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +    public String getOldLocation() {
> +        return oldLocation;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> new file mode 100644
> index 0000000..ba19cbe
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> @@ -0,0 +1,44 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONCreateDatabaseMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONCreateDatabaseMessage extends
> JSONCreateDatabaseMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONCreateDatabaseMessage() {
> +    }
> +
> +    public SentryJSONCreateDatabaseMessage(String server, String
> servicePrincipal, String db, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> new file mode 100644
> index 0000000..57d11d2
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> @@ -0,0 +1,45 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONCreateTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONCreateTableMessage extends JSONCreateTableMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONCreateTableMessage() {
> +    }
> +
> +    public SentryJSONCreateTableMessage(String server, String
> servicePrincipal, String db, String table, Long timestamp, String location)
> {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> new file mode 100644
> index 0000000..05f83f7
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> @@ -0,0 +1,44 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropDatabaseMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONDropDatabaseMessage extends
> JSONDropDatabaseMessage{
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropDatabaseMessage() {
> +    }
> +
> +    public SentryJSONDropDatabaseMessage(String server, String
> servicePrincipal, String db, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> new file mode 100644
> index 0000000..2ab61f7
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> @@ -0,0 +1,49 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +import java.util.Map;
> +
> +public class SentryJSONDropPartitionMessage extends
> JSONDropPartitionMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropPartitionMessage() {
> +    }
> +
> +    public SentryJSONDropPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                          List<Map<String, String>>
> partitions, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, table, partitions, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> new file mode 100644
> index 0000000..7005776
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> @@ -0,0 +1,45 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +
> +public class SentryJSONDropTableMessage extends JSONDropTableMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropTableMessage() {
> +    }
> +
> +    public SentryJSONDropTableMessage(String server, String
> servicePrincipal, String db, String table, Long timestamp, String location)
> {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> new file mode 100644
> index 0000000..b645c45
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> @@ -0,0 +1,110 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.*;
> +import org.codehaus.jackson.map.DeserializationConfig;
> +import org.codehaus.jackson.map.ObjectMapper;
> +
> +public class SentryJSONMessageDeserializer extends MessageDeserializer {
> +    static ObjectMapper mapper = new ObjectMapper();
> +
> +    public SentryJSONMessageDeserializer() {
> +    }
> +
> +    /**
> +     * Method to de-serialize CreateDatabaseMessage instance.
> +     */
> +    public SentryJSONCreateDatabaseMessage
> getCreateDatabaseMessage(String messageBody) {
> +        try {
> +            return
> (SentryJSONCreateDatabaseMessage)mapper.readValue(messageBody,
> SentryJSONCreateDatabaseMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONCreateDatabaseMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropDatabaseMessage getDropDatabaseMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropDatabaseMessage)mapper.readValue(messageBody,
> SentryJSONDropDatabaseMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropDatabaseMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONCreateTableMessage getCreateTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONCreateTableMessage)mapper.readValue(messageBody,
> SentryJSONCreateTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONCreateTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAlterTableMessage getAlterTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONAlterTableMessage)mapper.readValue(messageBody,
> SentryJSONAlterTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAlterTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropTableMessage getDropTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropTableMessage)mapper.readValue(messageBody,
> SentryJSONDropTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAddPartitionMessage getAddPartitionMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONAddPartitionMessage)mapper.readValue(messageBody,
> SentryJSONAddPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAddPartitionMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAlterPartitionMessage
> getAlterPartitionMessage(String messageBody) {
> +        try {
> +            return
> (SentryJSONAlterPartitionMessage)mapper.readValue(messageBody,
> SentryJSONAlterPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAlterPartitionMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropPartitionMessage getDropPartitionMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropPartitionMessage)mapper.readValue(messageBody,
> SentryJSONDropPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropPartitionMessage.", var3);
> +        }
> +    }
> +
> +    static {
> +
> mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
> false);
> +    }
> +
> +    public static String serialize(Object object) {
> +        try {
> +            return mapper.writeValueAsString(object);
> +        }
> +        catch (Exception exception) {
> +            throw new IllegalArgumentException("Could not serialize: ",
> exception);
> +        }
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> new file mode 100644
> index 0000000..00e7db8
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> @@ -0,0 +1,177 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.commons.logging.LogFactory;
> +import org.apache.hadoop.hive.common.classification.InterfaceAudience;
> +import org.apache.hadoop.hive.common.classification.InterfaceStability;
> +import org.apache.hadoop.hive.metastore.api.Database;
> +import org.apache.hadoop.hive.metastore.api.FieldSchema;
> +import org.apache.hadoop.hive.metastore.api.Partition;
> +import org.apache.hadoop.hive.metastore.api.Table;
> +import org.apache.hadoop.hive.metastore.partition.spec.PartitionSpecProxy;
> +import org.apache.hive.hcatalog.messaging.*;
> +
> +import java.util.*;
> +
> +public class SentryJSONMessageFactory extends MessageFactory {
> +    private static final Log LOG =
> LogFactory.getLog(SentryJSONMessageFactory.class.getName());
> +    private static SentryJSONMessageDeserializer deserializer = new
> SentryJSONMessageDeserializer();
> +    public SentryJSONMessageFactory() {
> +        LOG.info("Using SentryJSONMessageFactory for building
> Notification log messages ");
> +
> +    }
> +    public MessageDeserializer getDeserializer() {
> +        return deserializer;
> +    }
> +
> +    public String getVersion() {
> +        return "0.1";
> +    }
> +
> +    public String getMessageFormat() {
> +        return "json";
> +    }
> +
> +    public SentryJSONCreateDatabaseMessage
> buildCreateDatabaseMessage(Database db) {
> +        return new SentryJSONCreateDatabaseMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, db.getName(),
> +                Long.valueOf(this.now()), db.getLocationUri());
> +    }
> +    public SentryJSONDropDatabaseMessage
> buildDropDatabaseMessage(Database db) {
> +        return new SentryJSONDropDatabaseMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, db.getName(),
> +                Long.valueOf(this.now()), db.getLocationUri());
> +    }
> +
> +    public SentryJSONCreateTableMessage buildCreateTableMessage(Table
> table) {
> +        return new SentryJSONCreateTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), Long.valueOf(this.now()),
> table.getSd().getLocation());
> +    }
> +
> +    public SentryJSONAlterTableMessage buildAlterTableMessage(Table
> before, Table after) {
> +        return new SentryJSONAlterTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, before.getDbName(),
> +                before.getTableName(), Long.valueOf(this.now()),
> before.getSd().getLocation(), after.getSd().getLocation());
> +    }
> +
> +    public SentryJSONDropTableMessage buildDropTableMessage(Table table) {
> +        return new SentryJSONDropTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), Long.valueOf(this.now()),
> table.getSd().getLocation());
> +    }
> +
> +    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table
> table, List<Partition> partitions) {
> +        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), getPartitionKeyValues(table,
> partitions), Long.valueOf(this.now()),
> +                getPartitionLocations(partitions));
> +    }
> +
> +    private List<String> getPartitionLocations(List<Partition>
> partitions) {
> +        List<String> paths = new ArrayList<String>();
> +        for(Partition partition:partitions) {
> +            paths.add(partition.getSd().getLocation());
> +        }
> +        return paths;
> +    }
> +
> +    //TODO: Not sure what is this used for. Need to investigate
> +    private List<String> getPartitionLocations(PartitionSpecProxy
> partitionSpec) {
> +        Iterator<Partition> iterator =
> partitionSpec.getPartitionIterator();
> +        List<String> locations = new ArrayList<String>();
> +        while(iterator.hasNext()) {
> +            locations.add(iterator.next().getSd().getLocation());
> +        }
> +        return locations;
> +    }
> +
> +    @InterfaceAudience.LimitedPrivate({"Hive"})
> +    @InterfaceStability.Evolving
> +    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table
> table, PartitionSpecProxy partitionSpec) {
> +        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), getPartitionKeyValues(table,
> partitionSpec), Long.valueOf(this.now()),
> +                getPartitionLocations(partitionSpec));
> +    }
> +
> +    public SentryJSONAlterPartitionMessage
> buildAlterPartitionMessage(Partition before, Partition after) {
> +        /*
> +     f (partitionEvent.getOldPartition() != null) {
> +      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
> +    }
> +    if (partitionEvent.getNewPartition() != null) {
> +      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
> +    }
> +
> +    if ((oldLoc != null) && (newLoc != null) && (!oldLoc.equals(newLoc)))
> {
> +      String authzObj =
> +              partitionEvent.getOldPartition().getDbName() + "."
> +                      + partitionEvent.getOldPartition().getTableName();
> +      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> +        plugin.renameAuthzObject(authzObj, oldLoc,
> +                authzObj, newLoc);
> +      }
> +    }
> +        * */
> +        return new SentryJSONAlterPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, before.getDbName(),
> +                before.getTableName(), before.getValues(),
> Long.valueOf(this.now()), before.getSd().getLocation(),
> +                after.getSd().getLocation());
> +    }
> +
> +    public SentryJSONDropPartitionMessage buildDropPartitionMessage(Table
> table, Partition partition) {
> +        return new SentryJSONDropPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, partition.getDbName(),
> +                partition.getTableName(),
> Arrays.asList(getPartitionKeyValues(table, partition)),
> +                Long.valueOf(this.now()),
> partition.getSd().getLocation());
> +    }
> +
> +    private static Map<String, String> getPartitionKeyValues(Table table,
> Partition partition) {
> +        LinkedHashMap partitionKeys = new LinkedHashMap();
> +
> +        for(int i = 0; i < table.getPartitionKeysSize(); ++i) {
> +
> partitionKeys.put(((FieldSchema)table.getPartitionKeys().get(i)).getName(),
> partition.getValues().get(i));
> +        }
> +
> +        return partitionKeys;
> +    }
> +
> +    private static List<Map<String, String>> getPartitionKeyValues(Table
> table, List<Partition> partitions) {
> +        ArrayList partitionList = new ArrayList(partitions.size());
> +        Iterator i$ = partitions.iterator();
> +
> +        while(i$.hasNext()) {
> +            Partition partition = (Partition)i$.next();
> +            partitionList.add(getPartitionKeyValues(table, partition));
> +        }
> +
> +        return partitionList;
> +    }
> +
> +    @InterfaceAudience.LimitedPrivate({"Hive"})
> +    @InterfaceStability.Evolving
> +    private static List<Map<String, String>> getPartitionKeyValues(Table
> table, PartitionSpecProxy partitionSpec) {
> +        ArrayList partitionList = new ArrayList();
> +        PartitionSpecProxy.PartitionIterator iterator =
> partitionSpec.getPartitionIterator();
> +
> +        while(iterator.hasNext()) {
> +            Partition partition = (Partition)iterator.next();
> +            partitionList.add(getPartitionKeyValues(table, partition));
> +        }
> +
> +        return partitionList;
> +    }
> +    //This is private in parent class
> +    private long now() {
> +        return System.currentTimeMillis() / 1000L;
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> index 767bcbe..439b9de 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> @@ -32,14 +32,13 @@ import java.util.ArrayList;
>  import java.util.List;
>
>  import
> org.apache.sentry.tests.e2e.hive.AbstractTestWithStaticConfiguration;
> -import org.junit.After;
> -import org.junit.Before;
> -import org.junit.BeforeClass;
> -import org.junit.Test;
> +import org.junit.*;
>
>  import com.google.common.collect.Lists;
>  import com.google.common.io.Resources;
>
> +
> +@Ignore("Ignoring until SENTRY-1321 is complete")
>  public class TestDbPrivilegeCleanupOnDrop extends
>      AbstractTestWithStaticConfiguration {
>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> index 2c4948e..7dc3d0f 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> @@ -515,7 +515,8 @@ public abstract class
> AbstractTestWithStaticConfiguration {
>        } else {
>
>  properties.put(HiveConf.ConfVars.METASTORE_EVENT_LISTENERS.varname,
>                  SentryMetastorePostEventListener.class.getName());
> -
> +        properties.put("hcatalog.message.factory.impl.json",
> +
> "org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory");
>        }
>      }
>    }
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> index b72e317..567b4c8 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> @@ -200,6 +200,11 @@ public abstract class
> AbstractMetastoreTestWithStaticConfiguration extends
>      client.createDatabase(db);
>    }
>
> +  public void dropMetastoreDBIfExists(HiveMetaStoreClient client, String
> dbName)
> +      throws Exception {
> +    client.dropDatabase(dbName, true, true, true);
> +  }
> +
>    public void execHiveSQLwithOverlay(final String sqlStmt,
>        final String userName, Map<String, String> overLay) throws
> Exception {
>      final HiveConf hiveConf = new HiveConf();
>
>

Re: [2/4] sentry git commit: SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS notification logs

Posted by Sravya Tirukkovalur <sr...@apache.org>.
Sorry, pushed this change by mistake while pushing Sentry-1317. Fixed it
now.

Thanks!

On Tue, Jul 12, 2016 at 1:06 PM, <sr...@apache.org> wrote:

> SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS
> notification logs
>
> Also,
> 1. Implementing the SentryJSONMessageFactory to add custom information in
> the notification log entry message, which includes
>  1.1. Implementing Message class for each message type
>  1.2. Implementing a deserializer
> 2. Implementing JSONAlterPartitionMessage and JSONAlterTableMessage to
> work around the issue in Hive 1.1.0. These classes do not have required
> default constructor.
> 3. Testing:
>  3.1. Sentry functionality: TestSentryListenerSentryDeserializer to verify
> functionality using Sentry's SentryMetastorePostEventListener and Sentry
> Notification log deserializer.
>  3.2. TestDbNotificationListenerSentryDeserializer uses Hive's
> DbNotificationListener and Sentry's JSON deserializeri. This would make
> sure Sentry is able to read the Notification logs written by Hive's
> DBNotificationListener
>  3.3. TestSentryListenerInBuiltDeserializer uses Sentry's
> SentryMetastorePostEventListener and Hive's inbuilt Notification log
> deserializer: This would make sure Sentry is not breaking other users of
> NotificationLog who might be using Hive's in built serializer
>
> Change-Id: I680beb6db4e534bb0a9e6ee042ea0d4f33f0943f
>
>
> Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
> Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/113c5eae
> Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/113c5eae
> Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/113c5eae
>
> Branch: refs/heads/sentry-ha-redesign
> Commit: 113c5eae4ce9d3cb86ac7193731696d943fbea1f
> Parents: de7c26a
> Author: Sravya Tirukkovalur <sr...@apache.org>
> Authored: Tue Jun 14 16:30:51 2016 -0700
> Committer: Sravya Tirukkovalur <sr...@apache.org>
> Committed: Tue Jul 12 12:49:02 2016 -0700
>
> ----------------------------------------------------------------------
>  sentry-binding/sentry-binding-hive/pom.xml      |   6 +
>  .../SentryMetastorePostEventListener.java       | 518 +++++++++----------
>  .../json/JSONAlterPartitionMessage.java         |  78 +++
>  .../messaging/json/JSONAlterTableMessage.java   |  68 +++
>  .../json/SentryJSONAddPartitionMessage.java     |  49 ++
>  .../json/SentryJSONAlterPartitionMessage.java   |  53 ++
>  .../json/SentryJSONAlterTableMessage.java       |  50 ++
>  .../json/SentryJSONCreateDatabaseMessage.java   |  44 ++
>  .../json/SentryJSONCreateTableMessage.java      |  45 ++
>  .../json/SentryJSONDropDatabaseMessage.java     |  44 ++
>  .../json/SentryJSONDropPartitionMessage.java    |  49 ++
>  .../json/SentryJSONDropTableMessage.java        |  45 ++
>  .../json/SentryJSONMessageDeserializer.java     | 110 ++++
>  .../json/SentryJSONMessageFactory.java          | 177 +++++++
>  .../TestDbPrivilegeCleanupOnDrop.java           |   7 +-
>  .../AbstractTestWithStaticConfiguration.java    |   3 +-
>  ...actMetastoreTestWithStaticConfiguration.java |   5 +
>  ...NotificationListenerInBuiltDeserializer.java | 353 +++++++++++++
>  ...bNotificationListenerSentryDeserializer.java |  39 ++
>  ...ificationLogUsingDBNotificationListener.java | 351 -------------
>  .../TestSentryListenerInBuiltDeserializer.java  |  37 ++
>  .../TestSentryListenerSentryDeserializer.java   | 375 ++++++++++++++
>  22 files changed, 1886 insertions(+), 620 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/pom.xml
> ----------------------------------------------------------------------
> diff --git a/sentry-binding/sentry-binding-hive/pom.xml
> b/sentry-binding/sentry-binding-hive/pom.xml
> index 07aaae3..ca87836 100644
> --- a/sentry-binding/sentry-binding-hive/pom.xml
> +++ b/sentry-binding/sentry-binding-hive/pom.xml
> @@ -106,6 +106,12 @@ limitations under the License.
>        <scope>provided</scope>
>      </dependency>
>      <dependency>
> +      <groupId>org.apache.hive.hcatalog</groupId>
> +      <artifactId>hive-hcatalog-server-extensions</artifactId>
> +      <version>${hive.version}</version>
> +      <scope>compile</scope>
> +    </dependency>
> +    <dependency>
>        <groupId>org.mockito</groupId>
>        <artifactId>mockito-all</artifactId>
>        <scope>test</scope>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> index d12ac15..75190c1 100644
> ---
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
> @@ -17,15 +17,16 @@
>   */
>  package org.apache.sentry.binding.metastore;
>
> -import java.io.IOException;
> -import java.util.ArrayList;
> -import java.util.List;
> +import java.util.concurrent.TimeUnit;
>
>  import org.apache.hadoop.conf.Configuration;
>  import org.apache.hadoop.hive.conf.HiveConf;
>  import org.apache.hadoop.hive.metastore.MetaStoreEventListener;
> +import org.apache.hadoop.hive.metastore.RawStore;
> +import org.apache.hadoop.hive.metastore.RawStoreProxy;
> +import org.apache.hadoop.hive.metastore.TableType;
>  import org.apache.hadoop.hive.metastore.api.MetaException;
> -import org.apache.hadoop.hive.metastore.api.Partition;
> +import org.apache.hadoop.hive.metastore.api.NotificationEvent;
>  import org.apache.hadoop.hive.metastore.events.AddPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.AlterPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.AlterTableEvent;
> @@ -34,371 +35,360 @@ import
> org.apache.hadoop.hive.metastore.events.CreateTableEvent;
>  import org.apache.hadoop.hive.metastore.events.DropDatabaseEvent;
>  import org.apache.hadoop.hive.metastore.events.DropPartitionEvent;
>  import org.apache.hadoop.hive.metastore.events.DropTableEvent;
> -import org.apache.hadoop.security.UserGroupInformation;
> -import org.apache.sentry.core.common.exception.SentryUserException;
> -import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
> -import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
> -import org.apache.sentry.core.common.Authorizable;
> -import org.apache.sentry.core.model.db.Database;
> -import org.apache.sentry.core.model.db.Server;
> -import org.apache.sentry.core.model.db.Table;
> +import org.apache.hive.hcatalog.common.HCatConstants;
> +import
> org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory;
>  import org.apache.sentry.provider.db.SentryMetastoreListenerPlugin;
> -import
> org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
> -import org.apache.sentry.service.thrift.SentryServiceClientFactory;
> -import org.apache.sentry.service.thrift.ServiceConstants.ConfUtilties;
> -import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
>  import org.slf4j.Logger;
>  import org.slf4j.LoggerFactory;
>
> +import org.apache.commons.lang3.builder.ToStringBuilder;
> +/*
> +A HMS listener class which should ideally go into the transaction which
> persists the Hive metadata.
> +This class writes all DDL events to the NotificationLog through
> rawstore.addNotificationEvent(event)
> +This class is very similar to DbNotificationListener, except:
> +1. It uses a custom SentryJSONMessageFactory which adds additional
> information to the message part of the event
> + to avoid another round trip from the clients
> +2. It handles the cases where actual operation has failed, and hence
> skips writing to the notification log.
> +3. Has additional validations to make sure event has the required
> information.
> +
> +This can be replaced with DbNotificationListener in future and sentry's
> message factory can be plugged in if:
> +- HIVE-14011 is fixed: Make MessageFactory truly pluggable
> +- 2 and 3 above are handled in DbNotificationListener
> +*/
> +
>  public class SentryMetastorePostEventListener extends
> MetaStoreEventListener {
>
>    private static final Logger LOGGER =
> LoggerFactory.getLogger(SentryMetastoreListenerPlugin.class);
> -  private final HiveAuthzConf authzConf;
> -  private final Server server;
> +  private RawStore rs;
> +  private HiveConf hiveConf;
> +  SentryJSONMessageFactory messageFactory;
>
> -  protected List<SentryMetastoreListenerPlugin> sentryPlugins = new
> ArrayList<SentryMetastoreListenerPlugin>();
> +  private static SentryMetastorePostEventListener.CleanerThread cleaner =
> null;
>
> -  public SentryMetastorePostEventListener(Configuration config) {
> -    super(config);
> -
> -    if (!(config instanceof HiveConf)) {
> -        String error = "Could not initialize Plugin - Configuration is
> not an instanceof HiveConf";
> -        LOGGER.error(error);
> -        throw new RuntimeException(error);
> +  //Same as DbNotificationListener to make the transition back easy
> +  private synchronized void init(HiveConf conf) {
> +    try {
> +      this.rs = RawStoreProxy.getProxy(conf, conf,
> conf.getVar(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL), 999999);
> +    } catch (MetaException var3) {
> +      LOGGER.error("Unable to connect to raw store, notifications will
> not be tracked", var3);
> +      this.rs = null;
>      }
>
> -    authzConf = HiveAuthzConf.getAuthzConf((HiveConf)config);
> -    server = new
> Server(authzConf.get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
> -    Iterable<String> pluginClasses = ConfUtilties.CLASS_SPLITTER
> -        .split(config.get(ServerConfig.SENTRY_METASTORE_PLUGINS,
> -            ServerConfig.SENTRY_METASTORE_PLUGINS_DEFAULT).trim());
> +    if(cleaner == null && this.rs != null) {
> +      cleaner = new SentryMetastorePostEventListener.CleanerThread(conf,
> this.rs);
> +      cleaner.start();
> +    }
> +  }
>
> -    try {
> -      for (String pluginClassStr : pluginClasses) {
> -        Class<?> clazz = config.getClassByName(pluginClassStr);
> -        if (!SentryMetastoreListenerPlugin.class.isAssignableFrom(clazz))
> {
> -          throw new IllegalArgumentException("Class ["
> -              + pluginClassStr + "] is not a "
> -              + SentryMetastoreListenerPlugin.class.getName());
> -        }
> -        SentryMetastoreListenerPlugin plugin =
> (SentryMetastoreListenerPlugin) clazz
> -            .getConstructor(Configuration.class, Configuration.class)
> -            .newInstance(config, authzConf);
> -        sentryPlugins.add(plugin);
> -      }
> -    } catch (Exception e) {
> -      LOGGER.error("Could not initialize Plugin !!", e);
> -      throw new RuntimeException(e);
> +  public SentryMetastorePostEventListener(Configuration config) {
> +    super(config);
> +    // The code in MetastoreUtils.getMetaStoreListeners() that calls this
> looks for a constructor
> +    // with a Configuration parameter, so we have to declare config as
> Configuration.  But it
> +    // actually passes a HiveConf, which we need.  So we'll do this ugly
> down cast.
> +    if (!(config instanceof HiveConf)) {
> +      String error = "Could not initialize Plugin - Configuration is not
> an instanceof HiveConf";
> +      LOGGER.error(error);
> +      throw new RuntimeException(error);
>      }
> +    hiveConf = (HiveConf)config;
> +    messageFactory = new SentryJSONMessageFactory();
> +    init(hiveConf);
>    }
>
>    @Override
> -  public void onCreateTable (CreateTableEvent tableEvent) throws
> MetaException {
> +  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
> +          throws MetaException {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip sync paths/privileges with Sentry server for
> onCreateTable event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!dbEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Create
> database event failed");
>        return;
>      }
>
> -    if (tableEvent.getTable().getSd().getLocation() != null) {
> -      String authzObj = tableEvent.getTable().getDbName() + "."
> -          + tableEvent.getTable().getTableName();
> -      String path = tableEvent.getTable().getSd().getLocation();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.addPath(authzObj, path);
> -      }
> +    String location = dbEvent.getDatabase().getLocationUri();
> +    if (location == null || location.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateDatabaseEvent has
> invalid location", dbEvent);
>      }
> -
> -    // drop the privileges on the given table, in case if anything was
> left
> -    // behind during the drop
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
> -      return;
> +    String dbName = dbEvent.getDatabase().getName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateDatabaseEvent has
> invalid dbName", dbEvent);
>      }
>
> -    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
> -        tableEvent.getTable().getTableName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_CREATE_DATABASE_EVENT,
> +
> messageFactory.buildCreateDatabaseMessage(dbEvent.getDatabase()).toString());
> +    event.setDbName(dbName);
> +    this.enqueue(event);
>    }
>
>    @Override
> -  public void onDropTable(DropTableEvent tableEvent) throws MetaException
> {
> -
> -    // don't sync paths/privileges if the operation has failed
> -    if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onDropTable event," +
> -        " since the operation failed. \n");
> -      return;
> -    }
> +  public void onDropDatabase(DropDatabaseEvent dbEvent) throws
> MetaException {
>
> -    if (tableEvent.getTable().getSd().getLocation() != null) {
> -      String authzObj = tableEvent.getTable().getDbName() + "."
> -          + tableEvent.getTable().getTableName();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.removeAllPaths(authzObj, null);
> -      }
> -    }
> -    // drop the privileges on the given table
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
> +    // do not write to Notification log if the operation has failed
> +    if (!dbEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop
> database event failed");
>        return;
>      }
>
> -    if (!tableEvent.getStatus()) {
> -      return;
> +    String dbName = dbEvent.getDatabase().getName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropDatabaseEvent has
> invalid dbName", dbEvent);
>      }
>
> -    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
> -        tableEvent.getTable().getTableName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_DATABASE_EVENT,
> +
> messageFactory.buildDropDatabaseMessage(dbEvent.getDatabase()).toString());
> +    event.setDbName(dbName);
> +    this.enqueue(event);
>    }
>
>    @Override
> -  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
> -      throws MetaException {
> +  public void onCreateTable (CreateTableEvent tableEvent) throws
> MetaException {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!dbEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onCreateDatabase event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!tableEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Create
> table event failed");
>        return;
>      }
>
> -    if (dbEvent.getDatabase().getLocationUri() != null) {
> -      String authzObj = dbEvent.getDatabase().getName();
> -      String path = dbEvent.getDatabase().getLocationUri();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.addPath(authzObj, path);
> -      }
> +    String dbName = tableEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateTableEvent has
> invalid dbName", tableEvent);
>      }
> -    // drop the privileges on the database, in case anything left behind
> during
> -    // last drop db
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
> -      return;
> +    String tableName = tableEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("CreateTableEvent has
> invalid tableName", tableEvent);
>      }
> -
> -    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
> +    // Create table event should also contain a location.
> +    // But, Create view also generates a Create table event, but it does
> not have a location.
> +    // Create view is identified by the tableType. But turns out
> tableType is not set in some cases.
> +    // We assume that tableType is set for all create views.
> +    //TODO: Location can be null/empty, handle that in HMSFollower
> +    String tableType = tableEvent.getTable().getTableType();
> +    if(!(tableType != null && tableType.equals(
> TableType.VIRTUAL_VIEW.name()))) {
> +        if (tableType == null) {
> +        LOGGER.warn("TableType is null, assuming it is not
> TableType.VIRTUAL_VIEW: tableEvent", tableEvent);
> +      }
> +      String location = tableEvent.getTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("CreateTableEvent has
> invalid location", tableEvent);
> +      }
> +    }
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_CREATE_TABLE_EVENT,
> +
> messageFactory.buildCreateTableMessage(tableEvent.getTable()).toString());
> +    event.setDbName(dbName);
> +    event.setTableName(tableName);
> +    this.enqueue(event);
>    }
>
> -  /**
> -   * Drop the privileges on the database. Note that child tables will be
> -   * dropped individually by client, so we just need to handle the
> removing
> -   * the db privileges. The table drop should cleanup the table
> privileges.
> -   */
>    @Override
> -  public void onDropDatabase(DropDatabaseEvent dbEvent) throws
> MetaException {
> +  public void onDropTable(DropTableEvent tableEvent) throws MetaException
> {
>
> -    // don't sync paths/privileges if the operation has failed
> -    if (!dbEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing paths/privileges with Sentry server for
> onDropDatabase event," +
> -        " since the operation failed. \n");
> +    // do not write to Notification log if the operation has failed
> +    if (!tableEvent.getStatus()) {
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop table
> event failed");
>        return;
>      }
>
> -    String authzObj = dbEvent.getDatabase().getName();
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      List<String> tNames = dbEvent.getHandler().get_all_tables(authzObj);
> -      plugin.removeAllPaths(authzObj, tNames);
> +    String dbName = tableEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropTableEvent has invalid
> dbName", tableEvent);
>      }
> -    if
> (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
> -      return;
> +    String tableName = tableEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("DropTableEvent has invalid
> tableName", tableEvent);
>      }
>
> -    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_TABLE_EVENT,
> +
> messageFactory.buildDropTableMessage(tableEvent.getTable()).toString());
> +    event.setDbName(dbName);
> +    event.setTableName(tableName);
> +    this.enqueue(event);
>    }
>
> -  /**
> -   * Adjust the privileges when table is renamed
> -   */
>    @Override
>    public void onAlterTable (AlterTableEvent tableEvent) throws
> MetaException {
>
> -    // don't sync privileges if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!tableEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing privileges with Sentry server for
> onAlterTable event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Alter table
> event failed");
>        return;
>      }
>
> -    renameSentryTablePrivilege(tableEvent.getOldTable().getDbName(),
> -        tableEvent.getOldTable().getTableName(),
> -        tableEvent.getOldTable().getSd().getLocation(),
> -        tableEvent.getNewTable().getDbName(),
> -        tableEvent.getNewTable().getTableName(),
> -        tableEvent.getNewTable().getSd().getLocation());
> +    String dbName = tableEvent.getNewTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's newTable
> has invalid dbName", tableEvent);
> +    }
> +    String tableName = tableEvent.getNewTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's newTable
> has invalid tableName", tableEvent);
> +    }
> +    dbName = tableEvent.getOldTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's oldTable
> has invalid dbName", tableEvent);
> +    }
> +    tableName = tableEvent.getOldTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterTableEvent's oldTable
> has invalid tableName", tableEvent);
> +    }
> +    //Alter view also generates an alter table event, but it does not
> have a location
> +    //TODO: Handle this case in Sentry
> +    if(!tableEvent.getOldTable().getTableType().equals(
> TableType.VIRTUAL_VIEW.name())) {
> +      String location = tableEvent.getNewTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("AlterTableEvent's
> newTable has invalid location", tableEvent);
> +      }
> +      location = tableEvent.getOldTable().getSd().getLocation();
> +      if (location == null || location.isEmpty()) {
> +        throw new SentryMalformedEventException("AlterTableEvent's
> oldTable has invalid location", tableEvent);
> +      }
> +    }
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ALTER_TABLE_EVENT,
> +
> messageFactory.buildAlterTableMessage(tableEvent.getOldTable(),
> tableEvent.getNewTable()).toString());
> +    event.setDbName(tableEvent.getNewTable().getDbName());
> +    event.setTableName(tableEvent.getNewTable().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onAlterPartition(AlterPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync privileges if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing privileges with Sentry server for
> onAlterPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Alter
> partition event failed");
>        return;
>      }
>
> -    String oldLoc = null, newLoc = null;
> -    if (partitionEvent.getOldPartition() != null) {
> -      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
> +    String dbName = partitionEvent.getNewPartition().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterPartitionEvent's
> newPartition has invalid dbName", partitionEvent);
>      }
> -    if (partitionEvent.getNewPartition() != null) {
> -      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
> +    String tableName = partitionEvent.getNewPartition().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AlterPartitionEvent's
> newPartition has invalid tableName", partitionEvent);
>      }
>
> -    if (oldLoc != null && newLoc != null && !oldLoc.equals(newLoc)) {
> -      String authzObj =
> -          partitionEvent.getOldPartition().getDbName() + "."
> -              + partitionEvent.getOldPartition().getTableName();
> -      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -        plugin.renameAuthzObject(authzObj, oldLoc,
> -            authzObj, newLoc);
> -      }
> -    }
> +    //TODO: Need more validations, but it is tricky as there are many
> variations and validations change for each one
> +    // Alter partition Location
> +    // Alter partition property
> +    // Any more?
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ALTER_PARTITION_EVENT,
> +
> messageFactory.buildAlterPartitionMessage(partitionEvent.getOldPartition(),
> partitionEvent.getNewPartition()).toString());
> +
> +    event.setDbName(partitionEvent.getNewPartition().getDbName());
> +    event.setTableName(partitionEvent.getNewPartition().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onAddPartition(AddPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync path if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing path with Sentry server for
> onAddPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Add
> partition event failed");
>        return;
>      }
>
> -    for (Partition part : partitionEvent.getPartitions()) {
> -      if (part.getSd() != null && part.getSd().getLocation() != null) {
> -        String authzObj = part.getDbName() + "." + part.getTableName();
> -        String path = part.getSd().getLocation();
> -        for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -          plugin.addPath(authzObj, path);
> -        }
> -      }
> +    String dbName = partitionEvent.getTable().getDbName();
> +    if (dbName == null || dbName.isEmpty()) {
> +      throw new SentryMalformedEventException("AddPartitionEvent has
> invalid dbName", partitionEvent);
> +    }
> +    String tableName = partitionEvent.getTable().getTableName();
> +    if (tableName == null || tableName.isEmpty()) {
> +      throw new SentryMalformedEventException("AddPartitionEvent's
> newPartition has invalid tableName", partitionEvent);
>      }
> -    super.onAddPartition(partitionEvent);
> +
> +    //TODO: Need more validations?
> +
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_ADD_PARTITION_EVENT,
> +
> messageFactory.buildAddPartitionMessage(partitionEvent.getTable(),
> partitionEvent.getPartitions()).toString());
> +
> +    event.setDbName(partitionEvent.getTable().getDbName());
> +    event.setTableName(partitionEvent.getTable().getTableName());
> +    this.enqueue(event);
>    }
>
>    @Override
>    public void onDropPartition(DropPartitionEvent partitionEvent)
> -      throws MetaException {
> +          throws MetaException {
>
> -    // don't sync path if the operation has failed
> +    // do not write to Notification log if the operation has failed
>      if (!partitionEvent.getStatus()) {
> -      LOGGER.debug("Skip syncing path with Sentry server for
> onDropPartition event," +
> -        " since the operation failed. \n");
> +      LOGGER.info("Skipping writing to NotificationLog as the Drop
> partition event failed");
>        return;
>      }
>
> -    String authzObj = partitionEvent.getTable().getDbName() + "."
> -        + partitionEvent.getTable().getTableName();
> -    String path = partitionEvent.getPartition().getSd().getLocation();
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      plugin.removePath(authzObj, path);
> -    }
> -    super.onDropPartition(partitionEvent);
> +    NotificationEvent event = new NotificationEvent(0L, now(),
> HCatConstants.HCAT_DROP_PARTITION_EVENT,
> +
> messageFactory.buildDropPartitionMessage(partitionEvent.getTable(),
> partitionEvent.getPartition()).toString());
> +    //TODO: Why is this asymmetric with add partitions(s)?
> +    // Seems like adding multiple partitions generate a single event
> +    // where as single partition drop generated an event?
> +
> +    event.setDbName(partitionEvent.getTable().getDbName());
> +    event.setTableName(partitionEvent.getTable().getTableName());
> +    this.enqueue(event);
>    }
>
> -  private SentryPolicyServiceClient getSentryServiceClient()
> -      throws MetaException {
> -    try {
> -      return SentryServiceClientFactory.create(authzConf);
> -    } catch (Exception e) {
> -      throw new MetaException("Failed to connect to Sentry service "
> -          + e.getMessage());
> +  private int now() {
> +    long millis = System.currentTimeMillis();
> +    millis /= 1000;
> +    if (millis > Integer.MAX_VALUE) {
> +      LOGGER.warn("We've passed max int value in seconds since the epoch,
> " +
> +          "all notification times will be the same!");
> +      return Integer.MAX_VALUE;
>      }
> +    return (int)millis;
>    }
>
> -  private void dropSentryDbPrivileges(String dbName) throws MetaException
> {
> -    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
> -    authorizableTable.add(server);
> -    authorizableTable.add(new Database(dbName));
> -    try {
> -      dropSentryPrivileges(authorizableTable);
> -    } catch (SentryUserException e) {
> -      throw new MetaException("Failed to remove Sentry policies for drop
> DB "
> -          + dbName + " Error: " + e.getMessage());
> -    } catch (IOException e) {
> -      throw new MetaException("Failed to find local user " +
> e.getMessage());
> +  //Same as DbNotificationListener to make the transition back easy
> +  private void enqueue(NotificationEvent event) {
> +    if(this.rs != null) {
> +      this.rs.addNotificationEvent(event);
> +    } else {
> +      LOGGER.warn("Dropping event " + event + " since notification is not
> running.");
>      }
> -
>    }
>
> -  private void dropSentryTablePrivilege(String dbName, String tabName)
> -      throws MetaException {
> -    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
> -    authorizableTable.add(server);
> -    authorizableTable.add(new Database(dbName));
> -    authorizableTable.add(new Table(tabName));
> +  //Same as DbNotificationListener to make the transition back easy
> +  private static class CleanerThread extends Thread {
> +    private RawStore rs;
> +    private int ttl;
>
> -    try {
> -      dropSentryPrivileges(authorizableTable);
> -    } catch (SentryUserException e) {
> -      throw new MetaException(
> -          "Failed to remove Sentry policies for drop table " + dbName +
> "."
> -              + tabName + " Error: " + e.getMessage());
> -    } catch (IOException e) {
> -      throw new MetaException("Failed to find local user " +
> e.getMessage());
> +    CleanerThread(HiveConf conf, RawStore rs) {
> +      super("CleanerThread");
> +      this.rs = rs;
> +
> this.setTimeToLive(conf.getTimeVar(HiveConf.ConfVars.METASTORE_EVENT_DB_LISTENER_TTL,
> TimeUnit.SECONDS));
> +      this.setDaemon(true);
>      }
>
> -  }
> -  private void dropSentryPrivileges(
> -      List<? extends Authorizable> authorizableTable)
> -      throws SentryUserException, IOException, MetaException {
> -    String requestorUserName = UserGroupInformation.getCurrentUser()
> -        .getShortUserName();
> -    SentryPolicyServiceClient sentryClient = getSentryServiceClient();
> -    sentryClient.dropPrivileges(requestorUserName, authorizableTable);
> -
> -    // Close the connection after dropping privileges is done.
> -    sentryClient.close();
> -  }
> +    public void run() {
> +      while(true) {
> +        this.rs.cleanNotificationEvents(this.ttl);
>
> -  private void renameSentryTablePrivilege(String oldDbName, String
> oldTabName,
> -      String oldPath, String newDbName, String newTabName, String newPath)
> -      throws MetaException {
> -    List<Authorizable> oldAuthorizableTable = new
> ArrayList<Authorizable>();
> -    oldAuthorizableTable.add(server);
> -    oldAuthorizableTable.add(new Database(oldDbName));
> -    oldAuthorizableTable.add(new Table(oldTabName));
> -
> -    List<Authorizable> newAuthorizableTable = new
> ArrayList<Authorizable>();
> -    newAuthorizableTable.add(server);
> -    newAuthorizableTable.add(new Database(newDbName));
> -    newAuthorizableTable.add(new Table(newTabName));
> -
> -    if (!oldTabName.equalsIgnoreCase(newTabName)
> -        &&
> syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_ALTER_WITH_POLICY_STORE)) {
> -
> -      SentryPolicyServiceClient sentryClient = getSentryServiceClient();
> -
> -      try {
> -        String requestorUserName = UserGroupInformation.getCurrentUser()
> -            .getShortUserName();
> -        sentryClient.renamePrivileges(requestorUserName,
> oldAuthorizableTable, newAuthorizableTable);
> -      } catch (SentryUserException e) {
> -        throw new MetaException(
> -            "Failed to remove Sentry policies for rename table " +
> oldDbName
> -            + "." + oldTabName + "to " + newDbName + "." + newTabName
> -            + " Error: " + e.getMessage());
> -      } catch (IOException e) {
> -        throw new MetaException("Failed to find local user " +
> e.getMessage());
> -      } finally {
> -
> -        // Close the connection after renaming privileges is done.
> -        sentryClient.close();
> +        try {
> +          Thread.sleep(60000L);
> +        } catch (InterruptedException var2) {
> +          LOGGER.info("Cleaner thread sleep interupted", var2);
> +        }
>        }
>      }
> -    // The HDFS plugin needs to know if it's a path change (set location)
> -    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> -      plugin.renameAuthzObject(oldDbName + "." + oldTabName, oldPath,
> -          newDbName + "." + newTabName, newPath);
> +
> +    public void setTimeToLive(long configTtl) {
> +      if(configTtl > 2147483647L) {
> +        this.ttl = 2147483647;
> +      } else {
> +        this.ttl = (int)configTtl;
> +      }
> +
>      }
>    }
> -
> -  private boolean syncWithPolicyStore(AuthzConfVars syncConfVar) {
> -    return "true"
> -        .equalsIgnoreCase(authzConf.get(syncConfVar.getVar(), "true"));
> +  private class SentryMalformedEventException extends MetaException {
> +    SentryMalformedEventException(String msg, Object event) {
> +      //toString is not implemented in Event classes,
> +      // hence using reflection to print the details of the Event object.
> +      super(msg + "Event: " + ToStringBuilder.reflectionToString(event));
> +    }
>    }
> -
> -}
> +}
> \ No newline at end of file
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> new file mode 100644
> index 0000000..890186b
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
> @@ -0,0 +1,78 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.AlterPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +
> +/*
> +* This is only needed as corresponding class in Hive 1.1.0 does not have
> a default constructor
> + */
> +public class JSONAlterPartitionMessage extends AlterPartitionMessage {
> +    @JsonProperty
> +    String server;
> +    @JsonProperty
> +    String servicePrincipal;
> +    @JsonProperty
> +    String db;
> +    @JsonProperty
> +    String table;
> +    @JsonProperty
> +    Long timestamp;
> +    @JsonProperty
> +    List<String> values;
> +
> +    public JSONAlterPartitionMessage() {}
> +    public JSONAlterPartitionMessage(String server, String
> servicePrincipal, String db, String table, List<String> values, Long
> timestamp) {
> +        this.server = server;
> +        this.servicePrincipal = servicePrincipal;
> +        this.db = db;
> +        this.table = table;
> +        this.timestamp = timestamp;
> +        this.values = values;
> +        this.checkValid();
> +    }
> +
> +    public String getServer() {
> +        return this.server;
> +    }
> +
> +    public String getServicePrincipal() {
> +        return this.servicePrincipal;
> +    }
> +
> +    public String getDB() {
> +        return this.db;
> +    }
> +
> +    public Long getTimestamp() {
> +        return this.timestamp;
> +    }
> +
> +    public String getTable() {
> +        return this.table;
> +    }
> +
> +    public List<String> getValues() {
> +        return this.values;
> +    }
> +
> +}
> \ No newline at end of file
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> new file mode 100644
> index 0000000..76211c3
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
> @@ -0,0 +1,68 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.AlterTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +/**
> + * This class is required as this class does not have a default
> contructor in Hive 1.1.0
> + */
> +public class JSONAlterTableMessage extends AlterTableMessage {
> +    @JsonProperty
> +    String server;
> +    @JsonProperty
> +    String servicePrincipal;
> +    @JsonProperty
> +    String db;
> +    @JsonProperty
> +    String table;
> +    @JsonProperty
> +    Long timestamp;
> +
> +    public JSONAlterTableMessage() {}
> +    public JSONAlterTableMessage(String server, String servicePrincipal,
> String db, String table, Long timestamp) {
> +        this.server = server;
> +        this.servicePrincipal = servicePrincipal;
> +        this.db = db;
> +        this.table = table;
> +        this.timestamp = timestamp;
> +        this.checkValid();
> +    }
> +
> +    public String getServer() {
> +        return this.server;
> +    }
> +
> +    public String getServicePrincipal() {
> +        return this.servicePrincipal;
> +    }
> +
> +    public String getDB() {
> +        return this.db;
> +    }
> +
> +    public Long getTimestamp() {
> +        return this.timestamp;
> +    }
> +
> +    public String getTable() {
> +        return this.table;
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> new file mode 100644
> index 0000000..c0c469c
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
> @@ -0,0 +1,49 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONAddPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +import java.util.Map;
> +
> +public class SentryJSONAddPartitionMessage extends
> JSONAddPartitionMessage {
> +    @JsonProperty
> +    List<String> locations;
> +
> +    public SentryJSONAddPartitionMessage() {
> +    }
> +
> +    public SentryJSONAddPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                         List<Map<String, String>>
> partitions, Long timestamp, List<String> locations) {
> +        super(server, servicePrincipal, db, table, partitions, timestamp);
> +        this.locations = locations;
> +    }
> +
> +    public List<String> getLocations() {
> +        return locations;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> new file mode 100644
> index 0000000..99eb67a
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
> @@ -0,0 +1,53 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +package org.apache.sentry.binding.metastore.messaging.json;
> +
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +
> +public class SentryJSONAlterPartitionMessage extends
> JSONAlterPartitionMessage{
> +    @JsonProperty
> +    String location;
> +    @JsonProperty
> +    String oldLocation;
> +
> +    public SentryJSONAlterPartitionMessage() {
> +    }
> +
> +    public SentryJSONAlterPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                           List<String> values, Long
> timestamp, String oldlocation, String newLocation) {
> +        super(server, servicePrincipal, db, table, values, timestamp);
> +        this.location = newLocation;
> +        this.oldLocation = oldlocation;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    public String getOldLocation() {
> +        return oldLocation;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> new file mode 100644
> index 0000000..6e59e25
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
> @@ -0,0 +1,50 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONAlterTableMessage extends JSONAlterTableMessage {
> +    @JsonProperty
> +    String location; //newLocation
> +    @JsonProperty
> +    String oldLocation;
> +
> +    public SentryJSONAlterTableMessage() {
> +    }
> +
> +    public SentryJSONAlterTableMessage(String server, String
> servicePrincipal, String db, String table,
> +                                       Long timestamp, String
> oldLocation, String location) {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +        this.oldLocation = oldLocation;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +    public String getOldLocation() {
> +        return oldLocation;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> new file mode 100644
> index 0000000..ba19cbe
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
> @@ -0,0 +1,44 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONCreateDatabaseMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONCreateDatabaseMessage extends
> JSONCreateDatabaseMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONCreateDatabaseMessage() {
> +    }
> +
> +    public SentryJSONCreateDatabaseMessage(String server, String
> servicePrincipal, String db, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> new file mode 100644
> index 0000000..57d11d2
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
> @@ -0,0 +1,45 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONCreateTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONCreateTableMessage extends JSONCreateTableMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONCreateTableMessage() {
> +    }
> +
> +    public SentryJSONCreateTableMessage(String server, String
> servicePrincipal, String db, String table, Long timestamp, String location)
> {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> new file mode 100644
> index 0000000..05f83f7
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
> @@ -0,0 +1,44 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropDatabaseMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +public class SentryJSONDropDatabaseMessage extends
> JSONDropDatabaseMessage{
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropDatabaseMessage() {
> +    }
> +
> +    public SentryJSONDropDatabaseMessage(String server, String
> servicePrincipal, String db, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> new file mode 100644
> index 0000000..2ab61f7
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
> @@ -0,0 +1,49 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropPartitionMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +import java.util.List;
> +import java.util.Map;
> +
> +public class SentryJSONDropPartitionMessage extends
> JSONDropPartitionMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropPartitionMessage() {
> +    }
> +
> +    public SentryJSONDropPartitionMessage(String server, String
> servicePrincipal, String db, String table,
> +                                          List<Map<String, String>>
> partitions, Long timestamp, String location) {
> +        super(server, servicePrincipal, db, table, partitions, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> new file mode 100644
> index 0000000..7005776
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
> @@ -0,0 +1,45 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.json.JSONDropTableMessage;
> +import org.codehaus.jackson.annotate.JsonProperty;
> +
> +
> +public class SentryJSONDropTableMessage extends JSONDropTableMessage {
> +    @JsonProperty
> +    String location;
> +
> +    public SentryJSONDropTableMessage() {
> +    }
> +
> +    public SentryJSONDropTableMessage(String server, String
> servicePrincipal, String db, String table, Long timestamp, String location)
> {
> +        super(server, servicePrincipal, db, table, timestamp);
> +        this.location = location;
> +    }
> +
> +    public String getLocation() {
> +        return location;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return SentryJSONMessageDeserializer.serialize(this);
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> new file mode 100644
> index 0000000..b645c45
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
> @@ -0,0 +1,110 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.hive.hcatalog.messaging.*;
> +import org.codehaus.jackson.map.DeserializationConfig;
> +import org.codehaus.jackson.map.ObjectMapper;
> +
> +public class SentryJSONMessageDeserializer extends MessageDeserializer {
> +    static ObjectMapper mapper = new ObjectMapper();
> +
> +    public SentryJSONMessageDeserializer() {
> +    }
> +
> +    /**
> +     * Method to de-serialize CreateDatabaseMessage instance.
> +     */
> +    public SentryJSONCreateDatabaseMessage
> getCreateDatabaseMessage(String messageBody) {
> +        try {
> +            return
> (SentryJSONCreateDatabaseMessage)mapper.readValue(messageBody,
> SentryJSONCreateDatabaseMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONCreateDatabaseMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropDatabaseMessage getDropDatabaseMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropDatabaseMessage)mapper.readValue(messageBody,
> SentryJSONDropDatabaseMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropDatabaseMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONCreateTableMessage getCreateTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONCreateTableMessage)mapper.readValue(messageBody,
> SentryJSONCreateTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONCreateTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAlterTableMessage getAlterTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONAlterTableMessage)mapper.readValue(messageBody,
> SentryJSONAlterTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAlterTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropTableMessage getDropTableMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropTableMessage)mapper.readValue(messageBody,
> SentryJSONDropTableMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropTableMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAddPartitionMessage getAddPartitionMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONAddPartitionMessage)mapper.readValue(messageBody,
> SentryJSONAddPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAddPartitionMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONAlterPartitionMessage
> getAlterPartitionMessage(String messageBody) {
> +        try {
> +            return
> (SentryJSONAlterPartitionMessage)mapper.readValue(messageBody,
> SentryJSONAlterPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONAlterPartitionMessage.", var3);
> +        }
> +    }
> +
> +    public SentryJSONDropPartitionMessage getDropPartitionMessage(String
> messageBody) {
> +        try {
> +            return
> (SentryJSONDropPartitionMessage)mapper.readValue(messageBody,
> SentryJSONDropPartitionMessage.class);
> +        } catch (Exception var3) {
> +            throw new IllegalArgumentException("Could not construct
> SentryJSONDropPartitionMessage.", var3);
> +        }
> +    }
> +
> +    static {
> +
> mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
> false);
> +    }
> +
> +    public static String serialize(Object object) {
> +        try {
> +            return mapper.writeValueAsString(object);
> +        }
> +        catch (Exception exception) {
> +            throw new IllegalArgumentException("Could not serialize: ",
> exception);
> +        }
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> new file mode 100644
> index 0000000..00e7db8
> --- /dev/null
> +++
> b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
> @@ -0,0 +1,177 @@
> +/**
> + * 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.sentry.binding.metastore.messaging.json;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.commons.logging.LogFactory;
> +import org.apache.hadoop.hive.common.classification.InterfaceAudience;
> +import org.apache.hadoop.hive.common.classification.InterfaceStability;
> +import org.apache.hadoop.hive.metastore.api.Database;
> +import org.apache.hadoop.hive.metastore.api.FieldSchema;
> +import org.apache.hadoop.hive.metastore.api.Partition;
> +import org.apache.hadoop.hive.metastore.api.Table;
> +import org.apache.hadoop.hive.metastore.partition.spec.PartitionSpecProxy;
> +import org.apache.hive.hcatalog.messaging.*;
> +
> +import java.util.*;
> +
> +public class SentryJSONMessageFactory extends MessageFactory {
> +    private static final Log LOG =
> LogFactory.getLog(SentryJSONMessageFactory.class.getName());
> +    private static SentryJSONMessageDeserializer deserializer = new
> SentryJSONMessageDeserializer();
> +    public SentryJSONMessageFactory() {
> +        LOG.info("Using SentryJSONMessageFactory for building
> Notification log messages ");
> +
> +    }
> +    public MessageDeserializer getDeserializer() {
> +        return deserializer;
> +    }
> +
> +    public String getVersion() {
> +        return "0.1";
> +    }
> +
> +    public String getMessageFormat() {
> +        return "json";
> +    }
> +
> +    public SentryJSONCreateDatabaseMessage
> buildCreateDatabaseMessage(Database db) {
> +        return new SentryJSONCreateDatabaseMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, db.getName(),
> +                Long.valueOf(this.now()), db.getLocationUri());
> +    }
> +    public SentryJSONDropDatabaseMessage
> buildDropDatabaseMessage(Database db) {
> +        return new SentryJSONDropDatabaseMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, db.getName(),
> +                Long.valueOf(this.now()), db.getLocationUri());
> +    }
> +
> +    public SentryJSONCreateTableMessage buildCreateTableMessage(Table
> table) {
> +        return new SentryJSONCreateTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), Long.valueOf(this.now()),
> table.getSd().getLocation());
> +    }
> +
> +    public SentryJSONAlterTableMessage buildAlterTableMessage(Table
> before, Table after) {
> +        return new SentryJSONAlterTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, before.getDbName(),
> +                before.getTableName(), Long.valueOf(this.now()),
> before.getSd().getLocation(), after.getSd().getLocation());
> +    }
> +
> +    public SentryJSONDropTableMessage buildDropTableMessage(Table table) {
> +        return new SentryJSONDropTableMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), Long.valueOf(this.now()),
> table.getSd().getLocation());
> +    }
> +
> +    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table
> table, List<Partition> partitions) {
> +        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), getPartitionKeyValues(table,
> partitions), Long.valueOf(this.now()),
> +                getPartitionLocations(partitions));
> +    }
> +
> +    private List<String> getPartitionLocations(List<Partition>
> partitions) {
> +        List<String> paths = new ArrayList<String>();
> +        for(Partition partition:partitions) {
> +            paths.add(partition.getSd().getLocation());
> +        }
> +        return paths;
> +    }
> +
> +    //TODO: Not sure what is this used for. Need to investigate
> +    private List<String> getPartitionLocations(PartitionSpecProxy
> partitionSpec) {
> +        Iterator<Partition> iterator =
> partitionSpec.getPartitionIterator();
> +        List<String> locations = new ArrayList<String>();
> +        while(iterator.hasNext()) {
> +            locations.add(iterator.next().getSd().getLocation());
> +        }
> +        return locations;
> +    }
> +
> +    @InterfaceAudience.LimitedPrivate({"Hive"})
> +    @InterfaceStability.Evolving
> +    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table
> table, PartitionSpecProxy partitionSpec) {
> +        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, table.getDbName(),
> +                table.getTableName(), getPartitionKeyValues(table,
> partitionSpec), Long.valueOf(this.now()),
> +                getPartitionLocations(partitionSpec));
> +    }
> +
> +    public SentryJSONAlterPartitionMessage
> buildAlterPartitionMessage(Partition before, Partition after) {
> +        /*
> +     f (partitionEvent.getOldPartition() != null) {
> +      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
> +    }
> +    if (partitionEvent.getNewPartition() != null) {
> +      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
> +    }
> +
> +    if ((oldLoc != null) && (newLoc != null) && (!oldLoc.equals(newLoc)))
> {
> +      String authzObj =
> +              partitionEvent.getOldPartition().getDbName() + "."
> +                      + partitionEvent.getOldPartition().getTableName();
> +      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
> +        plugin.renameAuthzObject(authzObj, oldLoc,
> +                authzObj, newLoc);
> +      }
> +    }
> +        * */
> +        return new SentryJSONAlterPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, before.getDbName(),
> +                before.getTableName(), before.getValues(),
> Long.valueOf(this.now()), before.getSd().getLocation(),
> +                after.getSd().getLocation());
> +    }
> +
> +    public SentryJSONDropPartitionMessage buildDropPartitionMessage(Table
> table, Partition partition) {
> +        return new SentryJSONDropPartitionMessage(HCAT_SERVER_URL,
> HCAT_SERVICE_PRINCIPAL, partition.getDbName(),
> +                partition.getTableName(),
> Arrays.asList(getPartitionKeyValues(table, partition)),
> +                Long.valueOf(this.now()),
> partition.getSd().getLocation());
> +    }
> +
> +    private static Map<String, String> getPartitionKeyValues(Table table,
> Partition partition) {
> +        LinkedHashMap partitionKeys = new LinkedHashMap();
> +
> +        for(int i = 0; i < table.getPartitionKeysSize(); ++i) {
> +
> partitionKeys.put(((FieldSchema)table.getPartitionKeys().get(i)).getName(),
> partition.getValues().get(i));
> +        }
> +
> +        return partitionKeys;
> +    }
> +
> +    private static List<Map<String, String>> getPartitionKeyValues(Table
> table, List<Partition> partitions) {
> +        ArrayList partitionList = new ArrayList(partitions.size());
> +        Iterator i$ = partitions.iterator();
> +
> +        while(i$.hasNext()) {
> +            Partition partition = (Partition)i$.next();
> +            partitionList.add(getPartitionKeyValues(table, partition));
> +        }
> +
> +        return partitionList;
> +    }
> +
> +    @InterfaceAudience.LimitedPrivate({"Hive"})
> +    @InterfaceStability.Evolving
> +    private static List<Map<String, String>> getPartitionKeyValues(Table
> table, PartitionSpecProxy partitionSpec) {
> +        ArrayList partitionList = new ArrayList();
> +        PartitionSpecProxy.PartitionIterator iterator =
> partitionSpec.getPartitionIterator();
> +
> +        while(iterator.hasNext()) {
> +            Partition partition = (Partition)iterator.next();
> +            partitionList.add(getPartitionKeyValues(table, partition));
> +        }
> +
> +        return partitionList;
> +    }
> +    //This is private in parent class
> +    private long now() {
> +        return System.currentTimeMillis() / 1000L;
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> index 767bcbe..439b9de 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
> @@ -32,14 +32,13 @@ import java.util.ArrayList;
>  import java.util.List;
>
>  import
> org.apache.sentry.tests.e2e.hive.AbstractTestWithStaticConfiguration;
> -import org.junit.After;
> -import org.junit.Before;
> -import org.junit.BeforeClass;
> -import org.junit.Test;
> +import org.junit.*;
>
>  import com.google.common.collect.Lists;
>  import com.google.common.io.Resources;
>
> +
> +@Ignore("Ignoring until SENTRY-1321 is complete")
>  public class TestDbPrivilegeCleanupOnDrop extends
>      AbstractTestWithStaticConfiguration {
>
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> index 2c4948e..7dc3d0f 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
> @@ -515,7 +515,8 @@ public abstract class
> AbstractTestWithStaticConfiguration {
>        } else {
>
>  properties.put(HiveConf.ConfVars.METASTORE_EVENT_LISTENERS.varname,
>                  SentryMetastorePostEventListener.class.getName());
> -
> +        properties.put("hcatalog.message.factory.impl.json",
> +
> "org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory");
>        }
>      }
>    }
>
>
> http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> ----------------------------------------------------------------------
> diff --git
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> index b72e317..567b4c8 100644
> ---
> a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> +++
> b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
> @@ -200,6 +200,11 @@ public abstract class
> AbstractMetastoreTestWithStaticConfiguration extends
>      client.createDatabase(db);
>    }
>
> +  public void dropMetastoreDBIfExists(HiveMetaStoreClient client, String
> dbName)
> +      throws Exception {
> +    client.dropDatabase(dbName, true, true, true);
> +  }
> +
>    public void execHiveSQLwithOverlay(final String sqlStmt,
>        final String userName, Map<String, String> overLay) throws
> Exception {
>      final HiveConf hiveConf = new HiveConf();
>
>

[2/4] sentry git commit: SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS notification logs

Posted by sr...@apache.org.
SENTRY-1329: Adapt SentryMetaStorePostEventListener to write HMS notification logs

Also,
1. Implementing the SentryJSONMessageFactory to add custom information in the notification log entry message, which includes
 1.1. Implementing Message class for each message type
 1.2. Implementing a deserializer
2. Implementing JSONAlterPartitionMessage and JSONAlterTableMessage to work around the issue in Hive 1.1.0. These classes do not have required default constructor.
3. Testing:
 3.1. Sentry functionality: TestSentryListenerSentryDeserializer to verify functionality using Sentry's SentryMetastorePostEventListener and Sentry Notification log deserializer.
 3.2. TestDbNotificationListenerSentryDeserializer uses Hive's DbNotificationListener and Sentry's JSON deserializeri. This would make sure Sentry is able to read the Notification logs written by Hive's DBNotificationListener
 3.3. TestSentryListenerInBuiltDeserializer uses Sentry's SentryMetastorePostEventListener and Hive's inbuilt Notification log deserializer: This would make sure Sentry is not breaking other users of NotificationLog who might be using Hive's in built serializer

Change-Id: I680beb6db4e534bb0a9e6ee042ea0d4f33f0943f


Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/113c5eae
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/113c5eae
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/113c5eae

Branch: refs/heads/sentry-ha-redesign
Commit: 113c5eae4ce9d3cb86ac7193731696d943fbea1f
Parents: de7c26a
Author: Sravya Tirukkovalur <sr...@apache.org>
Authored: Tue Jun 14 16:30:51 2016 -0700
Committer: Sravya Tirukkovalur <sr...@apache.org>
Committed: Tue Jul 12 12:49:02 2016 -0700

----------------------------------------------------------------------
 sentry-binding/sentry-binding-hive/pom.xml      |   6 +
 .../SentryMetastorePostEventListener.java       | 518 +++++++++----------
 .../json/JSONAlterPartitionMessage.java         |  78 +++
 .../messaging/json/JSONAlterTableMessage.java   |  68 +++
 .../json/SentryJSONAddPartitionMessage.java     |  49 ++
 .../json/SentryJSONAlterPartitionMessage.java   |  53 ++
 .../json/SentryJSONAlterTableMessage.java       |  50 ++
 .../json/SentryJSONCreateDatabaseMessage.java   |  44 ++
 .../json/SentryJSONCreateTableMessage.java      |  45 ++
 .../json/SentryJSONDropDatabaseMessage.java     |  44 ++
 .../json/SentryJSONDropPartitionMessage.java    |  49 ++
 .../json/SentryJSONDropTableMessage.java        |  45 ++
 .../json/SentryJSONMessageDeserializer.java     | 110 ++++
 .../json/SentryJSONMessageFactory.java          | 177 +++++++
 .../TestDbPrivilegeCleanupOnDrop.java           |   7 +-
 .../AbstractTestWithStaticConfiguration.java    |   3 +-
 ...actMetastoreTestWithStaticConfiguration.java |   5 +
 ...NotificationListenerInBuiltDeserializer.java | 353 +++++++++++++
 ...bNotificationListenerSentryDeserializer.java |  39 ++
 ...ificationLogUsingDBNotificationListener.java | 351 -------------
 .../TestSentryListenerInBuiltDeserializer.java  |  37 ++
 .../TestSentryListenerSentryDeserializer.java   | 375 ++++++++++++++
 22 files changed, 1886 insertions(+), 620 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/pom.xml b/sentry-binding/sentry-binding-hive/pom.xml
index 07aaae3..ca87836 100644
--- a/sentry-binding/sentry-binding-hive/pom.xml
+++ b/sentry-binding/sentry-binding-hive/pom.xml
@@ -106,6 +106,12 @@ limitations under the License.
       <scope>provided</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.hive.hcatalog</groupId>
+      <artifactId>hive-hcatalog-server-extensions</artifactId>
+      <version>${hive.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
index d12ac15..75190c1 100644
--- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/SentryMetastorePostEventListener.java
@@ -17,15 +17,16 @@
  */
 package org.apache.sentry.binding.metastore;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hive.conf.HiveConf;
 import org.apache.hadoop.hive.metastore.MetaStoreEventListener;
+import org.apache.hadoop.hive.metastore.RawStore;
+import org.apache.hadoop.hive.metastore.RawStoreProxy;
+import org.apache.hadoop.hive.metastore.TableType;
 import org.apache.hadoop.hive.metastore.api.MetaException;
-import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.NotificationEvent;
 import org.apache.hadoop.hive.metastore.events.AddPartitionEvent;
 import org.apache.hadoop.hive.metastore.events.AlterPartitionEvent;
 import org.apache.hadoop.hive.metastore.events.AlterTableEvent;
@@ -34,371 +35,360 @@ import org.apache.hadoop.hive.metastore.events.CreateTableEvent;
 import org.apache.hadoop.hive.metastore.events.DropDatabaseEvent;
 import org.apache.hadoop.hive.metastore.events.DropPartitionEvent;
 import org.apache.hadoop.hive.metastore.events.DropTableEvent;
-import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.sentry.core.common.exception.SentryUserException;
-import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
-import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
-import org.apache.sentry.core.common.Authorizable;
-import org.apache.sentry.core.model.db.Database;
-import org.apache.sentry.core.model.db.Server;
-import org.apache.sentry.core.model.db.Table;
+import org.apache.hive.hcatalog.common.HCatConstants;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory;
 import org.apache.sentry.provider.db.SentryMetastoreListenerPlugin;
-import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
-import org.apache.sentry.service.thrift.SentryServiceClientFactory;
-import org.apache.sentry.service.thrift.ServiceConstants.ConfUtilties;
-import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+/*
+A HMS listener class which should ideally go into the transaction which persists the Hive metadata.
+This class writes all DDL events to the NotificationLog through rawstore.addNotificationEvent(event)
+This class is very similar to DbNotificationListener, except:
+1. It uses a custom SentryJSONMessageFactory which adds additional information to the message part of the event
+ to avoid another round trip from the clients
+2. It handles the cases where actual operation has failed, and hence skips writing to the notification log.
+3. Has additional validations to make sure event has the required information.
+
+This can be replaced with DbNotificationListener in future and sentry's message factory can be plugged in if:
+- HIVE-14011 is fixed: Make MessageFactory truly pluggable
+- 2 and 3 above are handled in DbNotificationListener
+*/
+
 public class SentryMetastorePostEventListener extends MetaStoreEventListener {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(SentryMetastoreListenerPlugin.class);
-  private final HiveAuthzConf authzConf;
-  private final Server server;
+  private RawStore rs;
+  private HiveConf hiveConf;
+  SentryJSONMessageFactory messageFactory;
 
-  protected List<SentryMetastoreListenerPlugin> sentryPlugins = new ArrayList<SentryMetastoreListenerPlugin>();
+  private static SentryMetastorePostEventListener.CleanerThread cleaner = null;
 
-  public SentryMetastorePostEventListener(Configuration config) {
-    super(config);
-
-    if (!(config instanceof HiveConf)) {
-        String error = "Could not initialize Plugin - Configuration is not an instanceof HiveConf";
-        LOGGER.error(error);
-        throw new RuntimeException(error);
+  //Same as DbNotificationListener to make the transition back easy
+  private synchronized void init(HiveConf conf) {
+    try {
+      this.rs = RawStoreProxy.getProxy(conf, conf, conf.getVar(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL), 999999);
+    } catch (MetaException var3) {
+      LOGGER.error("Unable to connect to raw store, notifications will not be tracked", var3);
+      this.rs = null;
     }
 
-    authzConf = HiveAuthzConf.getAuthzConf((HiveConf)config);
-    server = new Server(authzConf.get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
-    Iterable<String> pluginClasses = ConfUtilties.CLASS_SPLITTER
-        .split(config.get(ServerConfig.SENTRY_METASTORE_PLUGINS,
-            ServerConfig.SENTRY_METASTORE_PLUGINS_DEFAULT).trim());
+    if(cleaner == null && this.rs != null) {
+      cleaner = new SentryMetastorePostEventListener.CleanerThread(conf, this.rs);
+      cleaner.start();
+    }
+  }
 
-    try {
-      for (String pluginClassStr : pluginClasses) {
-        Class<?> clazz = config.getClassByName(pluginClassStr);
-        if (!SentryMetastoreListenerPlugin.class.isAssignableFrom(clazz)) {
-          throw new IllegalArgumentException("Class ["
-              + pluginClassStr + "] is not a "
-              + SentryMetastoreListenerPlugin.class.getName());
-        }
-        SentryMetastoreListenerPlugin plugin = (SentryMetastoreListenerPlugin) clazz
-            .getConstructor(Configuration.class, Configuration.class)
-            .newInstance(config, authzConf);
-        sentryPlugins.add(plugin);
-      }
-    } catch (Exception e) {
-      LOGGER.error("Could not initialize Plugin !!", e);
-      throw new RuntimeException(e);
+  public SentryMetastorePostEventListener(Configuration config) {
+    super(config);
+    // The code in MetastoreUtils.getMetaStoreListeners() that calls this looks for a constructor
+    // with a Configuration parameter, so we have to declare config as Configuration.  But it
+    // actually passes a HiveConf, which we need.  So we'll do this ugly down cast.
+    if (!(config instanceof HiveConf)) {
+      String error = "Could not initialize Plugin - Configuration is not an instanceof HiveConf";
+      LOGGER.error(error);
+      throw new RuntimeException(error);
     }
+    hiveConf = (HiveConf)config;
+    messageFactory = new SentryJSONMessageFactory();
+    init(hiveConf);
   }
 
   @Override
-  public void onCreateTable (CreateTableEvent tableEvent) throws MetaException {
+  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
+          throws MetaException {
 
-    // don't sync paths/privileges if the operation has failed
-    if (!tableEvent.getStatus()) {
-      LOGGER.debug("Skip sync paths/privileges with Sentry server for onCreateTable event," +
-        " since the operation failed. \n");
+    // do not write to Notification log if the operation has failed
+    if (!dbEvent.getStatus()) {
+      LOGGER.info("Skipping writing to NotificationLog as the Create database event failed");
       return;
     }
 
-    if (tableEvent.getTable().getSd().getLocation() != null) {
-      String authzObj = tableEvent.getTable().getDbName() + "."
-          + tableEvent.getTable().getTableName();
-      String path = tableEvent.getTable().getSd().getLocation();
-      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-        plugin.addPath(authzObj, path);
-      }
+    String location = dbEvent.getDatabase().getLocationUri();
+    if (location == null || location.isEmpty()) {
+      throw new SentryMalformedEventException("CreateDatabaseEvent has invalid location", dbEvent);
     }
-
-    // drop the privileges on the given table, in case if anything was left
-    // behind during the drop
-    if (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
-      return;
+    String dbName = dbEvent.getDatabase().getName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("CreateDatabaseEvent has invalid dbName", dbEvent);
     }
 
-    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
-        tableEvent.getTable().getTableName());
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_CREATE_DATABASE_EVENT,
+            messageFactory.buildCreateDatabaseMessage(dbEvent.getDatabase()).toString());
+    event.setDbName(dbName);
+    this.enqueue(event);
   }
 
   @Override
-  public void onDropTable(DropTableEvent tableEvent) throws MetaException {
-
-    // don't sync paths/privileges if the operation has failed
-    if (!tableEvent.getStatus()) {
-      LOGGER.debug("Skip syncing paths/privileges with Sentry server for onDropTable event," +
-        " since the operation failed. \n");
-      return;
-    }
+  public void onDropDatabase(DropDatabaseEvent dbEvent) throws MetaException {
 
-    if (tableEvent.getTable().getSd().getLocation() != null) {
-      String authzObj = tableEvent.getTable().getDbName() + "."
-          + tableEvent.getTable().getTableName();
-      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-        plugin.removeAllPaths(authzObj, null);
-      }
-    }
-    // drop the privileges on the given table
-    if (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
+    // do not write to Notification log if the operation has failed
+    if (!dbEvent.getStatus()) {
+      LOGGER.info("Skipping writing to NotificationLog as the Drop database event failed");
       return;
     }
 
-    if (!tableEvent.getStatus()) {
-      return;
+    String dbName = dbEvent.getDatabase().getName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("DropDatabaseEvent has invalid dbName", dbEvent);
     }
 
-    dropSentryTablePrivilege(tableEvent.getTable().getDbName(),
-        tableEvent.getTable().getTableName());
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_DROP_DATABASE_EVENT,
+            messageFactory.buildDropDatabaseMessage(dbEvent.getDatabase()).toString());
+    event.setDbName(dbName);
+    this.enqueue(event);
   }
 
   @Override
-  public void onCreateDatabase(CreateDatabaseEvent dbEvent)
-      throws MetaException {
+  public void onCreateTable (CreateTableEvent tableEvent) throws MetaException {
 
-    // don't sync paths/privileges if the operation has failed
-    if (!dbEvent.getStatus()) {
-      LOGGER.debug("Skip syncing paths/privileges with Sentry server for onCreateDatabase event," +
-        " since the operation failed. \n");
+    // do not write to Notification log if the operation has failed
+    if (!tableEvent.getStatus()) {
+      LOGGER.info("Skipping writing to NotificationLog as the Create table event failed");
       return;
     }
 
-    if (dbEvent.getDatabase().getLocationUri() != null) {
-      String authzObj = dbEvent.getDatabase().getName();
-      String path = dbEvent.getDatabase().getLocationUri();
-      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-        plugin.addPath(authzObj, path);
-      }
+    String dbName = tableEvent.getTable().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("CreateTableEvent has invalid dbName", tableEvent);
     }
-    // drop the privileges on the database, in case anything left behind during
-    // last drop db
-    if (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_CREATE_WITH_POLICY_STORE)) {
-      return;
+    String tableName = tableEvent.getTable().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("CreateTableEvent has invalid tableName", tableEvent);
     }
-
-    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
+    // Create table event should also contain a location.
+    // But, Create view also generates a Create table event, but it does not have a location.
+    // Create view is identified by the tableType. But turns out tableType is not set in some cases.
+    // We assume that tableType is set for all create views.
+    //TODO: Location can be null/empty, handle that in HMSFollower
+    String tableType = tableEvent.getTable().getTableType();
+    if(!(tableType != null && tableType.equals(TableType.VIRTUAL_VIEW.name()))) {
+        if (tableType == null) {
+        LOGGER.warn("TableType is null, assuming it is not TableType.VIRTUAL_VIEW: tableEvent", tableEvent);
+      }
+      String location = tableEvent.getTable().getSd().getLocation();
+      if (location == null || location.isEmpty()) {
+        throw new SentryMalformedEventException("CreateTableEvent has invalid location", tableEvent);
+      }
+    }
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_CREATE_TABLE_EVENT,
+            messageFactory.buildCreateTableMessage(tableEvent.getTable()).toString());
+    event.setDbName(dbName);
+    event.setTableName(tableName);
+    this.enqueue(event);
   }
 
-  /**
-   * Drop the privileges on the database. Note that child tables will be
-   * dropped individually by client, so we just need to handle the removing
-   * the db privileges. The table drop should cleanup the table privileges.
-   */
   @Override
-  public void onDropDatabase(DropDatabaseEvent dbEvent) throws MetaException {
+  public void onDropTable(DropTableEvent tableEvent) throws MetaException {
 
-    // don't sync paths/privileges if the operation has failed
-    if (!dbEvent.getStatus()) {
-      LOGGER.debug("Skip syncing paths/privileges with Sentry server for onDropDatabase event," +
-        " since the operation failed. \n");
+    // do not write to Notification log if the operation has failed
+    if (!tableEvent.getStatus()) {
+      LOGGER.info("Skipping writing to NotificationLog as the Drop table event failed");
       return;
     }
 
-    String authzObj = dbEvent.getDatabase().getName();
-    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-      List<String> tNames = dbEvent.getHandler().get_all_tables(authzObj);
-      plugin.removeAllPaths(authzObj, tNames);
+    String dbName = tableEvent.getTable().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("DropTableEvent has invalid dbName", tableEvent);
     }
-    if (!syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_DROP_WITH_POLICY_STORE)) {
-      return;
+    String tableName = tableEvent.getTable().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("DropTableEvent has invalid tableName", tableEvent);
     }
 
-    dropSentryDbPrivileges(dbEvent.getDatabase().getName());
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_DROP_TABLE_EVENT,
+            messageFactory.buildDropTableMessage(tableEvent.getTable()).toString());
+    event.setDbName(dbName);
+    event.setTableName(tableName);
+    this.enqueue(event);
   }
 
-  /**
-   * Adjust the privileges when table is renamed
-   */
   @Override
   public void onAlterTable (AlterTableEvent tableEvent) throws MetaException {
 
-    // don't sync privileges if the operation has failed
+    // do not write to Notification log if the operation has failed
     if (!tableEvent.getStatus()) {
-      LOGGER.debug("Skip syncing privileges with Sentry server for onAlterTable event," +
-        " since the operation failed. \n");
+      LOGGER.info("Skipping writing to NotificationLog as the Alter table event failed");
       return;
     }
 
-    renameSentryTablePrivilege(tableEvent.getOldTable().getDbName(),
-        tableEvent.getOldTable().getTableName(), 
-        tableEvent.getOldTable().getSd().getLocation(),
-        tableEvent.getNewTable().getDbName(), 
-        tableEvent.getNewTable().getTableName(),
-        tableEvent.getNewTable().getSd().getLocation());
+    String dbName = tableEvent.getNewTable().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterTableEvent's newTable has invalid dbName", tableEvent);
+    }
+    String tableName = tableEvent.getNewTable().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterTableEvent's newTable has invalid tableName", tableEvent);
+    }
+    dbName = tableEvent.getOldTable().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterTableEvent's oldTable has invalid dbName", tableEvent);
+    }
+    tableName = tableEvent.getOldTable().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterTableEvent's oldTable has invalid tableName", tableEvent);
+    }
+    //Alter view also generates an alter table event, but it does not have a location
+    //TODO: Handle this case in Sentry
+    if(!tableEvent.getOldTable().getTableType().equals(TableType.VIRTUAL_VIEW.name())) {
+      String location = tableEvent.getNewTable().getSd().getLocation();
+      if (location == null || location.isEmpty()) {
+        throw new SentryMalformedEventException("AlterTableEvent's newTable has invalid location", tableEvent);
+      }
+      location = tableEvent.getOldTable().getSd().getLocation();
+      if (location == null || location.isEmpty()) {
+        throw new SentryMalformedEventException("AlterTableEvent's oldTable has invalid location", tableEvent);
+      }
+    }
+
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_ALTER_TABLE_EVENT,
+            messageFactory.buildAlterTableMessage(tableEvent.getOldTable(), tableEvent.getNewTable()).toString());
+    event.setDbName(tableEvent.getNewTable().getDbName());
+    event.setTableName(tableEvent.getNewTable().getTableName());
+    this.enqueue(event);
   }
 
   @Override
   public void onAlterPartition(AlterPartitionEvent partitionEvent)
-      throws MetaException {
+          throws MetaException {
 
-    // don't sync privileges if the operation has failed
+    // do not write to Notification log if the operation has failed
     if (!partitionEvent.getStatus()) {
-      LOGGER.debug("Skip syncing privileges with Sentry server for onAlterPartition event," +
-        " since the operation failed. \n");
+      LOGGER.info("Skipping writing to NotificationLog as the Alter partition event failed");
       return;
     }
 
-    String oldLoc = null, newLoc = null;
-    if (partitionEvent.getOldPartition() != null) {
-      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
+    String dbName = partitionEvent.getNewPartition().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterPartitionEvent's newPartition has invalid dbName", partitionEvent);
     }
-    if (partitionEvent.getNewPartition() != null) {
-      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
+    String tableName = partitionEvent.getNewPartition().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("AlterPartitionEvent's newPartition has invalid tableName", partitionEvent);
     }
 
-    if (oldLoc != null && newLoc != null && !oldLoc.equals(newLoc)) {
-      String authzObj =
-          partitionEvent.getOldPartition().getDbName() + "."
-              + partitionEvent.getOldPartition().getTableName();
-      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-        plugin.renameAuthzObject(authzObj, oldLoc,
-            authzObj, newLoc);
-      }
-    }
+    //TODO: Need more validations, but it is tricky as there are many variations and validations change for each one
+    // Alter partition Location
+    // Alter partition property
+    // Any more?
+
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_ALTER_PARTITION_EVENT,
+            messageFactory.buildAlterPartitionMessage(partitionEvent.getOldPartition(), partitionEvent.getNewPartition()).toString());
+
+    event.setDbName(partitionEvent.getNewPartition().getDbName());
+    event.setTableName(partitionEvent.getNewPartition().getTableName());
+    this.enqueue(event);
   }
 
   @Override
   public void onAddPartition(AddPartitionEvent partitionEvent)
-      throws MetaException {
+          throws MetaException {
 
-    // don't sync path if the operation has failed
+    // do not write to Notification log if the operation has failed
     if (!partitionEvent.getStatus()) {
-      LOGGER.debug("Skip syncing path with Sentry server for onAddPartition event," +
-        " since the operation failed. \n");
+      LOGGER.info("Skipping writing to NotificationLog as the Add partition event failed");
       return;
     }
 
-    for (Partition part : partitionEvent.getPartitions()) {
-      if (part.getSd() != null && part.getSd().getLocation() != null) {
-        String authzObj = part.getDbName() + "." + part.getTableName();
-        String path = part.getSd().getLocation();
-        for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-          plugin.addPath(authzObj, path);
-        }
-      }
+    String dbName = partitionEvent.getTable().getDbName();
+    if (dbName == null || dbName.isEmpty()) {
+      throw new SentryMalformedEventException("AddPartitionEvent has invalid dbName", partitionEvent);
+    }
+    String tableName = partitionEvent.getTable().getTableName();
+    if (tableName == null || tableName.isEmpty()) {
+      throw new SentryMalformedEventException("AddPartitionEvent's newPartition has invalid tableName", partitionEvent);
     }
-    super.onAddPartition(partitionEvent);
+
+    //TODO: Need more validations?
+
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_ADD_PARTITION_EVENT,
+            messageFactory.buildAddPartitionMessage(partitionEvent.getTable(), partitionEvent.getPartitions()).toString());
+
+    event.setDbName(partitionEvent.getTable().getDbName());
+    event.setTableName(partitionEvent.getTable().getTableName());
+    this.enqueue(event);
   }
 
   @Override
   public void onDropPartition(DropPartitionEvent partitionEvent)
-      throws MetaException {
+          throws MetaException {
 
-    // don't sync path if the operation has failed
+    // do not write to Notification log if the operation has failed
     if (!partitionEvent.getStatus()) {
-      LOGGER.debug("Skip syncing path with Sentry server for onDropPartition event," +
-        " since the operation failed. \n");
+      LOGGER.info("Skipping writing to NotificationLog as the Drop partition event failed");
       return;
     }
 
-    String authzObj = partitionEvent.getTable().getDbName() + "."
-        + partitionEvent.getTable().getTableName();
-    String path = partitionEvent.getPartition().getSd().getLocation();
-    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-      plugin.removePath(authzObj, path);
-    }
-    super.onDropPartition(partitionEvent);
+    NotificationEvent event = new NotificationEvent(0L, now(), HCatConstants.HCAT_DROP_PARTITION_EVENT,
+            messageFactory.buildDropPartitionMessage(partitionEvent.getTable(), partitionEvent.getPartition()).toString());
+    //TODO: Why is this asymmetric with add partitions(s)?
+    // Seems like adding multiple partitions generate a single event
+    // where as single partition drop generated an event?
+
+    event.setDbName(partitionEvent.getTable().getDbName());
+    event.setTableName(partitionEvent.getTable().getTableName());
+    this.enqueue(event);
   }
 
-  private SentryPolicyServiceClient getSentryServiceClient()
-      throws MetaException {
-    try {
-      return SentryServiceClientFactory.create(authzConf);
-    } catch (Exception e) {
-      throw new MetaException("Failed to connect to Sentry service "
-          + e.getMessage());
+  private int now() {
+    long millis = System.currentTimeMillis();
+    millis /= 1000;
+    if (millis > Integer.MAX_VALUE) {
+      LOGGER.warn("We've passed max int value in seconds since the epoch, " +
+          "all notification times will be the same!");
+      return Integer.MAX_VALUE;
     }
+    return (int)millis;
   }
 
-  private void dropSentryDbPrivileges(String dbName) throws MetaException {
-    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
-    authorizableTable.add(server);
-    authorizableTable.add(new Database(dbName));
-    try {
-      dropSentryPrivileges(authorizableTable);
-    } catch (SentryUserException e) {
-      throw new MetaException("Failed to remove Sentry policies for drop DB "
-          + dbName + " Error: " + e.getMessage());
-    } catch (IOException e) {
-      throw new MetaException("Failed to find local user " + e.getMessage());
+  //Same as DbNotificationListener to make the transition back easy
+  private void enqueue(NotificationEvent event) {
+    if(this.rs != null) {
+      this.rs.addNotificationEvent(event);
+    } else {
+      LOGGER.warn("Dropping event " + event + " since notification is not running.");
     }
-
   }
 
-  private void dropSentryTablePrivilege(String dbName, String tabName)
-      throws MetaException {
-    List<Authorizable> authorizableTable = new ArrayList<Authorizable>();
-    authorizableTable.add(server);
-    authorizableTable.add(new Database(dbName));
-    authorizableTable.add(new Table(tabName));
+  //Same as DbNotificationListener to make the transition back easy
+  private static class CleanerThread extends Thread {
+    private RawStore rs;
+    private int ttl;
 
-    try {
-      dropSentryPrivileges(authorizableTable);
-    } catch (SentryUserException e) {
-      throw new MetaException(
-          "Failed to remove Sentry policies for drop table " + dbName + "."
-              + tabName + " Error: " + e.getMessage());
-    } catch (IOException e) {
-      throw new MetaException("Failed to find local user " + e.getMessage());
+    CleanerThread(HiveConf conf, RawStore rs) {
+      super("CleanerThread");
+      this.rs = rs;
+      this.setTimeToLive(conf.getTimeVar(HiveConf.ConfVars.METASTORE_EVENT_DB_LISTENER_TTL, TimeUnit.SECONDS));
+      this.setDaemon(true);
     }
 
-  }
-  private void dropSentryPrivileges(
-      List<? extends Authorizable> authorizableTable)
-      throws SentryUserException, IOException, MetaException {
-    String requestorUserName = UserGroupInformation.getCurrentUser()
-        .getShortUserName();
-    SentryPolicyServiceClient sentryClient = getSentryServiceClient();
-    sentryClient.dropPrivileges(requestorUserName, authorizableTable);
-
-    // Close the connection after dropping privileges is done.
-    sentryClient.close();
-  }
+    public void run() {
+      while(true) {
+        this.rs.cleanNotificationEvents(this.ttl);
 
-  private void renameSentryTablePrivilege(String oldDbName, String oldTabName,
-      String oldPath, String newDbName, String newTabName, String newPath)
-      throws MetaException {
-    List<Authorizable> oldAuthorizableTable = new ArrayList<Authorizable>();
-    oldAuthorizableTable.add(server);
-    oldAuthorizableTable.add(new Database(oldDbName));
-    oldAuthorizableTable.add(new Table(oldTabName));
-
-    List<Authorizable> newAuthorizableTable = new ArrayList<Authorizable>();
-    newAuthorizableTable.add(server);
-    newAuthorizableTable.add(new Database(newDbName));
-    newAuthorizableTable.add(new Table(newTabName));
-
-    if (!oldTabName.equalsIgnoreCase(newTabName)
-        && syncWithPolicyStore(AuthzConfVars.AUTHZ_SYNC_ALTER_WITH_POLICY_STORE)) {
-
-      SentryPolicyServiceClient sentryClient = getSentryServiceClient();
-
-      try {
-        String requestorUserName = UserGroupInformation.getCurrentUser()
-            .getShortUserName();
-        sentryClient.renamePrivileges(requestorUserName, oldAuthorizableTable, newAuthorizableTable);
-      } catch (SentryUserException e) {
-        throw new MetaException(
-            "Failed to remove Sentry policies for rename table " + oldDbName
-            + "." + oldTabName + "to " + newDbName + "." + newTabName
-            + " Error: " + e.getMessage());
-      } catch (IOException e) {
-        throw new MetaException("Failed to find local user " + e.getMessage());
-      } finally {
-
-        // Close the connection after renaming privileges is done.
-        sentryClient.close();
+        try {
+          Thread.sleep(60000L);
+        } catch (InterruptedException var2) {
+          LOGGER.info("Cleaner thread sleep interupted", var2);
+        }
       }
     }
-    // The HDFS plugin needs to know if it's a path change (set location)
-    for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
-      plugin.renameAuthzObject(oldDbName + "." + oldTabName, oldPath,
-          newDbName + "." + newTabName, newPath);
+
+    public void setTimeToLive(long configTtl) {
+      if(configTtl > 2147483647L) {
+        this.ttl = 2147483647;
+      } else {
+        this.ttl = (int)configTtl;
+      }
+
     }
   }
-
-  private boolean syncWithPolicyStore(AuthzConfVars syncConfVar) {
-    return "true"
-        .equalsIgnoreCase(authzConf.get(syncConfVar.getVar(), "true"));
+  private class SentryMalformedEventException extends MetaException {
+    SentryMalformedEventException(String msg, Object event) {
+      //toString is not implemented in Event classes,
+      // hence using reflection to print the details of the Event object.
+      super(msg + "Event: " + ToStringBuilder.reflectionToString(event));
+    }
   }
-
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
new file mode 100644
index 0000000..890186b
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterPartitionMessage.java
@@ -0,0 +1,78 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.AlterPartitionMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.List;
+
+/*
+* This is only needed as corresponding class in Hive 1.1.0 does not have a default constructor
+ */
+public class JSONAlterPartitionMessage extends AlterPartitionMessage {
+    @JsonProperty
+    String server;
+    @JsonProperty
+    String servicePrincipal;
+    @JsonProperty
+    String db;
+    @JsonProperty
+    String table;
+    @JsonProperty
+    Long timestamp;
+    @JsonProperty
+    List<String> values;
+
+    public JSONAlterPartitionMessage() {}
+    public JSONAlterPartitionMessage(String server, String servicePrincipal, String db, String table, List<String> values, Long timestamp) {
+        this.server = server;
+        this.servicePrincipal = servicePrincipal;
+        this.db = db;
+        this.table = table;
+        this.timestamp = timestamp;
+        this.values = values;
+        this.checkValid();
+    }
+
+    public String getServer() {
+        return this.server;
+    }
+
+    public String getServicePrincipal() {
+        return this.servicePrincipal;
+    }
+
+    public String getDB() {
+        return this.db;
+    }
+
+    public Long getTimestamp() {
+        return this.timestamp;
+    }
+
+    public String getTable() {
+        return this.table;
+    }
+
+    public List<String> getValues() {
+        return this.values;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
new file mode 100644
index 0000000..76211c3
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/JSONAlterTableMessage.java
@@ -0,0 +1,68 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.AlterTableMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * This class is required as this class does not have a default contructor in Hive 1.1.0
+ */
+public class JSONAlterTableMessage extends AlterTableMessage {
+    @JsonProperty
+    String server;
+    @JsonProperty
+    String servicePrincipal;
+    @JsonProperty
+    String db;
+    @JsonProperty
+    String table;
+    @JsonProperty
+    Long timestamp;
+
+    public JSONAlterTableMessage() {}
+    public JSONAlterTableMessage(String server, String servicePrincipal, String db, String table, Long timestamp) {
+        this.server = server;
+        this.servicePrincipal = servicePrincipal;
+        this.db = db;
+        this.table = table;
+        this.timestamp = timestamp;
+        this.checkValid();
+    }
+
+    public String getServer() {
+        return this.server;
+    }
+
+    public String getServicePrincipal() {
+        return this.servicePrincipal;
+    }
+
+    public String getDB() {
+        return this.db;
+    }
+
+    public Long getTimestamp() {
+        return this.timestamp;
+    }
+
+    public String getTable() {
+        return this.table;
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
new file mode 100644
index 0000000..c0c469c
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAddPartitionMessage.java
@@ -0,0 +1,49 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONAddPartitionMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.List;
+import java.util.Map;
+
+public class SentryJSONAddPartitionMessage extends JSONAddPartitionMessage {
+    @JsonProperty
+    List<String> locations;
+
+    public SentryJSONAddPartitionMessage() {
+    }
+
+    public SentryJSONAddPartitionMessage(String server, String servicePrincipal, String db, String table,
+                                         List<Map<String, String>> partitions, Long timestamp, List<String> locations) {
+        super(server, servicePrincipal, db, table, partitions, timestamp);
+        this.locations = locations;
+    }
+
+    public List<String> getLocations() {
+        return locations;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
new file mode 100644
index 0000000..99eb67a
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterPartitionMessage.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.binding.metastore.messaging.json;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.List;
+
+public class SentryJSONAlterPartitionMessage extends JSONAlterPartitionMessage{
+    @JsonProperty
+    String location;
+    @JsonProperty
+    String oldLocation;
+
+    public SentryJSONAlterPartitionMessage() {
+    }
+
+    public SentryJSONAlterPartitionMessage(String server, String servicePrincipal, String db, String table,
+                                           List<String> values, Long timestamp, String oldlocation, String newLocation) {
+        super(server, servicePrincipal, db, table, values, timestamp);
+        this.location = newLocation;
+        this.oldLocation = oldlocation;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public String getOldLocation() {
+        return oldLocation;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
new file mode 100644
index 0000000..6e59e25
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONAlterTableMessage.java
@@ -0,0 +1,50 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class SentryJSONAlterTableMessage extends JSONAlterTableMessage {
+    @JsonProperty
+    String location; //newLocation
+    @JsonProperty
+    String oldLocation;
+
+    public SentryJSONAlterTableMessage() {
+    }
+
+    public SentryJSONAlterTableMessage(String server, String servicePrincipal, String db, String table,
+                                       Long timestamp, String oldLocation, String location) {
+        super(server, servicePrincipal, db, table, timestamp);
+        this.location = location;
+        this.oldLocation = oldLocation;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+    public String getOldLocation() {
+        return oldLocation;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
new file mode 100644
index 0000000..ba19cbe
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateDatabaseMessage.java
@@ -0,0 +1,44 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONCreateDatabaseMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class SentryJSONCreateDatabaseMessage extends JSONCreateDatabaseMessage {
+    @JsonProperty
+    String location;
+
+    public SentryJSONCreateDatabaseMessage() {
+    }
+
+    public SentryJSONCreateDatabaseMessage(String server, String servicePrincipal, String db, Long timestamp, String location) {
+        super(server, servicePrincipal, db, timestamp);
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
new file mode 100644
index 0000000..57d11d2
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONCreateTableMessage.java
@@ -0,0 +1,45 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONCreateTableMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class SentryJSONCreateTableMessage extends JSONCreateTableMessage {
+    @JsonProperty
+    String location;
+
+    public SentryJSONCreateTableMessage() {
+    }
+
+    public SentryJSONCreateTableMessage(String server, String servicePrincipal, String db, String table, Long timestamp, String location) {
+        super(server, servicePrincipal, db, table, timestamp);
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
new file mode 100644
index 0000000..05f83f7
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropDatabaseMessage.java
@@ -0,0 +1,44 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONDropDatabaseMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class SentryJSONDropDatabaseMessage extends JSONDropDatabaseMessage{
+    @JsonProperty
+    String location;
+
+    public SentryJSONDropDatabaseMessage() {
+    }
+
+    public SentryJSONDropDatabaseMessage(String server, String servicePrincipal, String db, Long timestamp, String location) {
+        super(server, servicePrincipal, db, timestamp);
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
new file mode 100644
index 0000000..2ab61f7
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropPartitionMessage.java
@@ -0,0 +1,49 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONDropPartitionMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.List;
+import java.util.Map;
+
+public class SentryJSONDropPartitionMessage extends JSONDropPartitionMessage {
+    @JsonProperty
+    String location;
+
+    public SentryJSONDropPartitionMessage() {
+    }
+
+    public SentryJSONDropPartitionMessage(String server, String servicePrincipal, String db, String table,
+                                          List<Map<String, String>> partitions, Long timestamp, String location) {
+        super(server, servicePrincipal, db, table, partitions, timestamp);
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
new file mode 100644
index 0000000..7005776
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONDropTableMessage.java
@@ -0,0 +1,45 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.json.JSONDropTableMessage;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+
+public class SentryJSONDropTableMessage extends JSONDropTableMessage {
+    @JsonProperty
+    String location;
+
+    public SentryJSONDropTableMessage() {
+    }
+
+    public SentryJSONDropTableMessage(String server, String servicePrincipal, String db, String table, Long timestamp, String location) {
+        super(server, servicePrincipal, db, table, timestamp);
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return SentryJSONMessageDeserializer.serialize(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
new file mode 100644
index 0000000..b645c45
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageDeserializer.java
@@ -0,0 +1,110 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.hive.hcatalog.messaging.*;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.ObjectMapper;
+
+public class SentryJSONMessageDeserializer extends MessageDeserializer {
+    static ObjectMapper mapper = new ObjectMapper();
+
+    public SentryJSONMessageDeserializer() {
+    }
+
+    /**
+     * Method to de-serialize CreateDatabaseMessage instance.
+     */
+    public SentryJSONCreateDatabaseMessage getCreateDatabaseMessage(String messageBody) {
+        try {
+            return (SentryJSONCreateDatabaseMessage)mapper.readValue(messageBody, SentryJSONCreateDatabaseMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONCreateDatabaseMessage.", var3);
+        }
+    }
+
+    public SentryJSONDropDatabaseMessage getDropDatabaseMessage(String messageBody) {
+        try {
+            return (SentryJSONDropDatabaseMessage)mapper.readValue(messageBody, SentryJSONDropDatabaseMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONDropDatabaseMessage.", var3);
+        }
+    }
+
+    public SentryJSONCreateTableMessage getCreateTableMessage(String messageBody) {
+        try {
+            return (SentryJSONCreateTableMessage)mapper.readValue(messageBody, SentryJSONCreateTableMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONCreateTableMessage.", var3);
+        }
+    }
+
+    public SentryJSONAlterTableMessage getAlterTableMessage(String messageBody) {
+        try {
+            return (SentryJSONAlterTableMessage)mapper.readValue(messageBody, SentryJSONAlterTableMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONAlterTableMessage.", var3);
+        }
+    }
+
+    public SentryJSONDropTableMessage getDropTableMessage(String messageBody) {
+        try {
+            return (SentryJSONDropTableMessage)mapper.readValue(messageBody, SentryJSONDropTableMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONDropTableMessage.", var3);
+        }
+    }
+
+    public SentryJSONAddPartitionMessage getAddPartitionMessage(String messageBody) {
+        try {
+            return (SentryJSONAddPartitionMessage)mapper.readValue(messageBody, SentryJSONAddPartitionMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONAddPartitionMessage.", var3);
+        }
+    }
+
+    public SentryJSONAlterPartitionMessage getAlterPartitionMessage(String messageBody) {
+        try {
+            return (SentryJSONAlterPartitionMessage)mapper.readValue(messageBody, SentryJSONAlterPartitionMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONAlterPartitionMessage.", var3);
+        }
+    }
+
+    public SentryJSONDropPartitionMessage getDropPartitionMessage(String messageBody) {
+        try {
+            return (SentryJSONDropPartitionMessage)mapper.readValue(messageBody, SentryJSONDropPartitionMessage.class);
+        } catch (Exception var3) {
+            throw new IllegalArgumentException("Could not construct SentryJSONDropPartitionMessage.", var3);
+        }
+    }
+
+    static {
+        mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
+
+    public static String serialize(Object object) {
+        try {
+            return mapper.writeValueAsString(object);
+        }
+        catch (Exception exception) {
+            throw new IllegalArgumentException("Could not serialize: ", exception);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
new file mode 100644
index 0000000..00e7db8
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/metastore/messaging/json/SentryJSONMessageFactory.java
@@ -0,0 +1,177 @@
+/**
+ * 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.sentry.binding.metastore.messaging.json;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hive.common.classification.InterfaceAudience;
+import org.apache.hadoop.hive.common.classification.InterfaceStability;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.FieldSchema;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.partition.spec.PartitionSpecProxy;
+import org.apache.hive.hcatalog.messaging.*;
+
+import java.util.*;
+
+public class SentryJSONMessageFactory extends MessageFactory {
+    private static final Log LOG = LogFactory.getLog(SentryJSONMessageFactory.class.getName());
+    private static SentryJSONMessageDeserializer deserializer = new SentryJSONMessageDeserializer();
+    public SentryJSONMessageFactory() {
+        LOG.info("Using SentryJSONMessageFactory for building Notification log messages ");
+
+    }
+    public MessageDeserializer getDeserializer() {
+        return deserializer;
+    }
+
+    public String getVersion() {
+        return "0.1";
+    }
+
+    public String getMessageFormat() {
+        return "json";
+    }
+
+    public SentryJSONCreateDatabaseMessage buildCreateDatabaseMessage(Database db) {
+        return new SentryJSONCreateDatabaseMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, db.getName(),
+                Long.valueOf(this.now()), db.getLocationUri());
+    }
+    public SentryJSONDropDatabaseMessage buildDropDatabaseMessage(Database db) {
+        return new SentryJSONDropDatabaseMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, db.getName(),
+                Long.valueOf(this.now()), db.getLocationUri());
+    }
+
+    public SentryJSONCreateTableMessage buildCreateTableMessage(Table table) {
+        return new SentryJSONCreateTableMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, table.getDbName(),
+                table.getTableName(), Long.valueOf(this.now()), table.getSd().getLocation());
+    }
+
+    public SentryJSONAlterTableMessage buildAlterTableMessage(Table before, Table after) {
+        return new SentryJSONAlterTableMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, before.getDbName(),
+                before.getTableName(), Long.valueOf(this.now()), before.getSd().getLocation(), after.getSd().getLocation());
+    }
+
+    public SentryJSONDropTableMessage buildDropTableMessage(Table table) {
+        return new SentryJSONDropTableMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, table.getDbName(),
+                table.getTableName(), Long.valueOf(this.now()), table.getSd().getLocation());
+    }
+
+    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table table, List<Partition> partitions) {
+        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, table.getDbName(),
+                table.getTableName(), getPartitionKeyValues(table, partitions), Long.valueOf(this.now()),
+                getPartitionLocations(partitions));
+    }
+
+    private List<String> getPartitionLocations(List<Partition> partitions) {
+        List<String> paths = new ArrayList<String>();
+        for(Partition partition:partitions) {
+            paths.add(partition.getSd().getLocation());
+        }
+        return paths;
+    }
+
+    //TODO: Not sure what is this used for. Need to investigate
+    private List<String> getPartitionLocations(PartitionSpecProxy partitionSpec) {
+        Iterator<Partition> iterator = partitionSpec.getPartitionIterator();
+        List<String> locations = new ArrayList<String>();
+        while(iterator.hasNext()) {
+            locations.add(iterator.next().getSd().getLocation());
+        }
+        return locations;
+    }
+
+    @InterfaceAudience.LimitedPrivate({"Hive"})
+    @InterfaceStability.Evolving
+    public SentryJSONAddPartitionMessage buildAddPartitionMessage(Table table, PartitionSpecProxy partitionSpec) {
+        return new SentryJSONAddPartitionMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, table.getDbName(),
+                table.getTableName(), getPartitionKeyValues(table, partitionSpec), Long.valueOf(this.now()),
+                getPartitionLocations(partitionSpec));
+    }
+
+    public SentryJSONAlterPartitionMessage buildAlterPartitionMessage(Partition before, Partition after) {
+        /*
+     f (partitionEvent.getOldPartition() != null) {
+      oldLoc = partitionEvent.getOldPartition().getSd().getLocation();
+    }
+    if (partitionEvent.getNewPartition() != null) {
+      newLoc = partitionEvent.getNewPartition().getSd().getLocation();
+    }
+
+    if ((oldLoc != null) && (newLoc != null) && (!oldLoc.equals(newLoc))) {
+      String authzObj =
+              partitionEvent.getOldPartition().getDbName() + "."
+                      + partitionEvent.getOldPartition().getTableName();
+      for (SentryMetastoreListenerPlugin plugin : sentryPlugins) {
+        plugin.renameAuthzObject(authzObj, oldLoc,
+                authzObj, newLoc);
+      }
+    }
+        * */
+        return new SentryJSONAlterPartitionMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, before.getDbName(),
+                before.getTableName(), before.getValues(), Long.valueOf(this.now()), before.getSd().getLocation(),
+                after.getSd().getLocation());
+    }
+
+    public SentryJSONDropPartitionMessage buildDropPartitionMessage(Table table, Partition partition) {
+        return new SentryJSONDropPartitionMessage(HCAT_SERVER_URL, HCAT_SERVICE_PRINCIPAL, partition.getDbName(),
+                partition.getTableName(), Arrays.asList(getPartitionKeyValues(table, partition)),
+                Long.valueOf(this.now()), partition.getSd().getLocation());
+    }
+
+    private static Map<String, String> getPartitionKeyValues(Table table, Partition partition) {
+        LinkedHashMap partitionKeys = new LinkedHashMap();
+
+        for(int i = 0; i < table.getPartitionKeysSize(); ++i) {
+            partitionKeys.put(((FieldSchema)table.getPartitionKeys().get(i)).getName(), partition.getValues().get(i));
+        }
+
+        return partitionKeys;
+    }
+
+    private static List<Map<String, String>> getPartitionKeyValues(Table table, List<Partition> partitions) {
+        ArrayList partitionList = new ArrayList(partitions.size());
+        Iterator i$ = partitions.iterator();
+
+        while(i$.hasNext()) {
+            Partition partition = (Partition)i$.next();
+            partitionList.add(getPartitionKeyValues(table, partition));
+        }
+
+        return partitionList;
+    }
+
+    @InterfaceAudience.LimitedPrivate({"Hive"})
+    @InterfaceStability.Evolving
+    private static List<Map<String, String>> getPartitionKeyValues(Table table, PartitionSpecProxy partitionSpec) {
+        ArrayList partitionList = new ArrayList();
+        PartitionSpecProxy.PartitionIterator iterator = partitionSpec.getPartitionIterator();
+
+        while(iterator.hasNext()) {
+            Partition partition = (Partition)iterator.next();
+            partitionList.add(getPartitionKeyValues(table, partition));
+        }
+
+        return partitionList;
+    }
+    //This is private in parent class
+    private long now() {
+        return System.currentTimeMillis() / 1000L;
+    }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
index 767bcbe..439b9de 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbPrivilegeCleanupOnDrop.java
@@ -32,14 +32,13 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.sentry.tests.e2e.hive.AbstractTestWithStaticConfiguration;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import org.junit.*;
 
 import com.google.common.collect.Lists;
 import com.google.common.io.Resources;
 
+
+@Ignore("Ignoring until SENTRY-1321 is complete")
 public class TestDbPrivilegeCleanupOnDrop extends
     AbstractTestWithStaticConfiguration {
 

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
index 2c4948e..7dc3d0f 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
@@ -515,7 +515,8 @@ public abstract class AbstractTestWithStaticConfiguration {
       } else {
         properties.put(HiveConf.ConfVars.METASTORE_EVENT_LISTENERS.varname,
                 SentryMetastorePostEventListener.class.getName());
-
+        properties.put("hcatalog.message.factory.impl.json",
+            "org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageFactory");
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/sentry/blob/113c5eae/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
index b72e317..567b4c8 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java
@@ -200,6 +200,11 @@ public abstract class AbstractMetastoreTestWithStaticConfiguration extends
     client.createDatabase(db);
   }
 
+  public void dropMetastoreDBIfExists(HiveMetaStoreClient client, String dbName)
+      throws Exception {
+    client.dropDatabase(dbName, true, true, true);
+  }
+
   public void execHiveSQLwithOverlay(final String sqlStmt,
       final String userName, Map<String, String> overLay) throws Exception {
     final HiveConf hiveConf = new HiveConf();