http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs-int/src/test/java/org/apache/sentry/hdfs/TestSentryAuthorizationProvider.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs-int/src/test/java/org/apache/sentry/hdfs/TestSentryAuthorizationProvider.java
 
b/sentry-hdfs-int/src/test/java/org/apache/sentry/hdfs/TestSentryAuthorizationProvider.java
new file mode 100644
index 0000000..67919fa
--- /dev/null
+++ 
b/sentry-hdfs-int/src/test/java/org/apache/sentry/hdfs/TestSentryAuthorizationProvider.java
@@ -0,0 +1,163 @@
+/**
+ * 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.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclEntryScope;
+import org.apache.hadoop.fs.permission.AclEntryType;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.apache.hadoop.hdfs.server.namenode.EditLogFileOutputStream;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TestSentryAuthorizationProvider {
+  private MiniDFSCluster miniDFS;
+  private UserGroupInformation admin;
+  
+  @Before
+  public void setUp() throws Exception {
+    admin = UserGroupInformation.createUserForTesting(
+        System.getProperty("user.name"), new String[] { "supergroup" });
+    admin.doAs(new PrivilegedExceptionAction<Void>() {
+      @Override
+      public Void run() throws Exception {
+        System.setProperty(MiniDFSCluster.PROP_TEST_BUILD_DATA, 
"target/test/data");
+        Configuration conf = new HdfsConfiguration();
+        conf.set(DFSConfigKeys.DFS_NAMENODE_AUTHORIZATION_PROVIDER_KEY,
+            MockSentryAuthorizationProvider.class.getName());
+        conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
+        EditLogFileOutputStream.setShouldSkipFsyncForTesting(true);
+        miniDFS = new MiniDFSCluster.Builder(conf).build();
+        return null;
+      }
+    });
+  }
+
+  @After
+  public void cleanUp() throws IOException {
+    if (miniDFS != null) {
+      miniDFS.shutdown();
+    }
+  }
+
+  @Test
+  public void testProvider() throws Exception {
+    admin.doAs(new PrivilegedExceptionAction<Void>() {
+      @Override
+      public Void run() throws Exception {
+        String sysUser = 
UserGroupInformation.getCurrentUser().getShortUserName();
+        FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0));
+
+        List<AclEntry> baseAclList = new ArrayList<AclEntry>();
+        AclEntry.Builder builder = new AclEntry.Builder();
+        baseAclList.add(builder.setType(AclEntryType.USER)
+            .setScope(AclEntryScope.ACCESS).build());
+        baseAclList.add(builder.setType(AclEntryType.GROUP)
+            .setScope(AclEntryScope.ACCESS).build());
+        baseAclList.add(builder.setType(AclEntryType.OTHER)
+            .setScope(AclEntryScope.ACCESS).build());
+        Path path1 = new Path("/user/authz/obj/xxx");
+        fs.mkdirs(path1);
+        fs.setAcl(path1, baseAclList);
+
+        fs.mkdirs(new Path("/user/authz/xxx"));
+        fs.mkdirs(new Path("/user/xxx"));
+
+        // root
+        Path path = new Path("/");
+        Assert.assertEquals(sysUser, fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("supergroup", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0755), 
fs.getFileStatus(path).getPermission());
+        Assert.assertTrue(fs.getAclStatus(path).getEntries().isEmpty());
+
+        // dir before prefixes
+        path = new Path("/user");
+        Assert.assertEquals(sysUser, fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("supergroup", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0755), 
fs.getFileStatus(path).getPermission());
+        Assert.assertTrue(fs.getAclStatus(path).getEntries().isEmpty());
+
+        // prefix dir
+        path = new Path("/user/authz");
+        Assert.assertEquals(sysUser, fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("supergroup", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0755), 
fs.getFileStatus(path).getPermission());
+        Assert.assertTrue(fs.getAclStatus(path).getEntries().isEmpty());
+
+        // dir inside of prefix, no obj
+        path = new Path("/user/authz/xxx");
+        FileStatus status = fs.getFileStatus(path);
+        Assert.assertEquals(sysUser, status.getOwner());
+        Assert.assertEquals("supergroup", status.getGroup());
+        Assert.assertEquals(new FsPermission((short) 0755), 
status.getPermission());
+        Assert.assertTrue(fs.getAclStatus(path).getEntries().isEmpty());
+
+        // dir inside of prefix, obj
+        path = new Path("/user/authz/obj");
+        Assert.assertEquals("hive", fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("hive", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0770), 
fs.getFileStatus(path).getPermission());
+        Assert.assertFalse(fs.getAclStatus(path).getEntries().isEmpty());
+
+        List<AclEntry> acls = new ArrayList<AclEntry>();
+        acls.add(new 
AclEntry.Builder().setName(sysUser).setType(AclEntryType.USER).setScope(AclEntryScope.ACCESS).setPermission(FsAction.ALL).build());
+        acls.add(new 
AclEntry.Builder().setName("supergroup").setType(AclEntryType.GROUP).setScope(AclEntryScope.ACCESS).setPermission(FsAction.READ_EXECUTE).build());
+        acls.add(new 
AclEntry.Builder().setName(null).setType(AclEntryType.OTHER).setScope(AclEntryScope.ACCESS).setPermission(FsAction.READ_EXECUTE).build());
+        acls.add(new 
AclEntry.Builder().setName("user-authz").setType(AclEntryType.USER).setScope(AclEntryScope.ACCESS).setPermission(FsAction.ALL).build());
+        Assert.assertEquals(new LinkedHashSet<AclEntry>(acls), new 
LinkedHashSet<AclEntry>(fs.getAclStatus(path).getEntries()));
+
+        // dir inside of prefix, inside of obj
+        path = new Path("/user/authz/obj/xxx");
+        Assert.assertEquals("hive", fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("hive", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0770), 
fs.getFileStatus(path).getPermission());
+        Assert.assertFalse(fs.getAclStatus(path).getEntries().isEmpty());
+        
+        Path path2 = new Path("/user/authz/obj/path2");
+        fs.mkdirs(path2);
+        fs.setAcl(path2, baseAclList);
+
+        // dir outside of prefix
+        path = new Path("/user/xxx");
+        Assert.assertEquals(sysUser, fs.getFileStatus(path).getOwner());
+        Assert.assertEquals("supergroup", fs.getFileStatus(path).getGroup());
+        Assert.assertEquals(new FsPermission((short) 0755), 
fs.getFileStatus(path).getPermission());
+        Assert.assertTrue(fs.getAclStatus(path).getEntries().isEmpty());
+        return null;
+      }
+    });
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs-int/src/test/resources/hdfs-sentry.xml
----------------------------------------------------------------------
diff --git a/sentry-hdfs-int/src/test/resources/hdfs-sentry.xml 
b/sentry-hdfs-int/src/test/resources/hdfs-sentry.xml
new file mode 100644
index 0000000..511bfdd
--- /dev/null
+++ b/sentry-hdfs-int/src/test/resources/hdfs-sentry.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+   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.
+-->
+
+<configuration>
+  <property>
+    <name>sentry.hdfs-plugin.path-prefixes</name>
+    <value>/user/hive/dw</value>
+  </property>
+  <property>
+    <name>sentry.hdfs-plugin.sentry-uri</name>
+    <value>thrift://localhost:1234</value>
+  </property>
+  <property>
+    <name>sentry.hdfs-plugin.stale-threshold.ms</name>
+    <value>-1</value>
+  </property>
+</configuration>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-hdfs/pom.xml b/sentry-hdfs/pom.xml
new file mode 100644
index 0000000..5114c18
--- /dev/null
+++ b/sentry-hdfs/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.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.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.sentry</groupId>
+    <artifactId>sentry</artifactId>
+    <version>1.5.0-incubating-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <artifactId>sentry-hdfs</artifactId>
+  <name>Sentry HDFS Integration</name>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-minicluster</artifactId>
+      <version>2.5.0</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sentry</groupId>
+      <artifactId>sentry-service-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-metastore</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+      <version>2.5.0</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPaths.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPaths.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPaths.java
new file mode 100644
index 0000000..9ea50c7
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPaths.java
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+public interface AuthzPaths {
+
+  public boolean isUnderPrefix(String[] pathElements);
+
+  public String findAuthzObject(String[] pathElements);
+
+  public String findAuthzObjectExactMatch(String[] pathElements);
+
+  public AuthzPathsDumper<? extends AuthzPaths> getPathsDump();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPathsDumper.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPathsDumper.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPathsDumper.java
new file mode 100644
index 0000000..924d3b4
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPathsDumper.java
@@ -0,0 +1,28 @@
+/**
+ * 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 org.apache.sentry.provider.db.service.thrift.TPathsDump;
+
+public interface AuthzPathsDumper<K extends AuthzPaths> {
+
+  public TPathsDump createPathsDump();
+
+  public K initializeFromDump(TPathsDump pathsDump);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPermissions.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPermissions.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPermissions.java
new file mode 100644
index 0000000..1631ae5
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/AuthzPermissions.java
@@ -0,0 +1,28 @@
+/**
+ * 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 org.apache.hadoop.fs.permission.AclEntry;
+
+import java.util.List;
+
+public interface AuthzPermissions {
+
+  public List<AclEntry> getAcls(String authzObj);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/ExtendedMetastoreClient.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/ExtendedMetastoreClient.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/ExtendedMetastoreClient.java
new file mode 100644
index 0000000..c0358f4
--- /dev/null
+++ 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/ExtendedMetastoreClient.java
@@ -0,0 +1,104 @@
+/*
+ * 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.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ExtendedMetastoreClient implements MetastoreClient {
+  
+  private static Logger LOG = 
LoggerFactory.getLogger(ExtendedMetastoreClient.class);
+
+  private HiveMetaStoreClient client;
+  private final HiveConf hiveConf;
+  public ExtendedMetastoreClient(HiveConf hiveConf) {
+    this.hiveConf = hiveConf;
+  }
+
+  @Override
+  public List<Database> getAllDatabases() {
+    List<Database> retList = new ArrayList<Database>();
+    HiveMetaStoreClient client = getClient();
+    if (client != null) {
+      try {
+        for (String dbName : client.getAllDatabases()) {
+          retList.add(client.getDatabase(dbName));
+        }
+      } catch (Exception e) {
+        LOG.error("Could not get All Databases !!", e);
+      }
+    }
+    return retList;
+  }
+
+  @Override
+  public List<Table> getAllTablesOfDatabase(Database db) {
+    List<Table> retList = new ArrayList<Table>();
+    HiveMetaStoreClient client = getClient();
+    if (client != null) {
+      try {
+        for (String tblName : client.getAllTables(db.getName())) {
+          retList.add(client.getTable(db.getName(), tblName));
+        }
+      } catch (Exception e) {
+        LOG.error(String.format(
+            "Could not get Tables for '%s' !!", db.getName()), e);
+      }
+    }
+    return retList;
+  }
+
+  @Override
+  public List<Partition> listAllPartitions(Database db, Table tbl) {
+    HiveMetaStoreClient client = getClient();
+    if (client != null) {
+      try {
+        return client.listPartitions(db.getName(), tbl.getTableName(), 
Short.MAX_VALUE);
+      } catch (Exception e) {
+        LOG.error(String.format(
+            "Could not get partitions for '%s'.'%s' !!", db.getName(),
+            tbl.getTableName()), e);
+      }
+    }
+    return new LinkedList<Partition>();
+  }
+
+  private HiveMetaStoreClient getClient() {
+    if (client == null) {
+      try {
+        client = new HiveMetaStoreClient(hiveConf);
+        return client;
+      } catch (MetaException e) {
+        client = null;
+        LOG.error("Could not create metastore client !!", e);
+        return null;
+      }
+    } else {
+      return client;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPaths.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPaths.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPaths.java
new file mode 100644
index 0000000..e445634
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPaths.java
@@ -0,0 +1,467 @@
+/**
+ * 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.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.fs.Path;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class HMSPaths implements AuthzPaths {
+
+  @VisibleForTesting
+  static List<String> getPathElements(String path) {
+    path = path.trim();
+    if (path.charAt(0) != Path.SEPARATOR_CHAR) {
+      throw new IllegalArgumentException("It must be an absolute path: " + 
+          path);
+    }
+    List<String> list = new ArrayList<String>(32);
+    int idx = 0;
+    int found = path.indexOf(Path.SEPARATOR_CHAR, idx);
+    while (found > -1) {
+      if (found > idx) {
+        list.add(path.substring(idx, found));
+      }
+      idx = found + 1;
+      found = path.indexOf(Path.SEPARATOR_CHAR, idx);
+    }
+    if (idx < path.length()) {
+      list.add(path.substring(idx));
+    }
+    return list;
+  }
+
+  @VisibleForTesting
+  static List<List<String>> gePathsElements(List<String> paths) {
+    List<List<String>> pathsElements = new 
ArrayList<List<String>>(paths.size());
+    for (String path : paths) {
+      pathsElements.add(getPathElements(path));
+    }
+    return pathsElements;
+  }
+
+  @VisibleForTesting
+  enum EntryType {
+    DIR(true),
+    PREFIX(false),
+    AUTHZ_OBJECT(false);
+
+    private boolean removeIfDangling;
+
+    private EntryType(boolean removeIfDangling) {
+      this.removeIfDangling = removeIfDangling;
+    }
+
+    public boolean isRemoveIfDangling() {
+      return removeIfDangling;
+    }
+
+    public byte getByte() {
+      return (byte)toString().charAt(0);
+    }
+    
+    public static EntryType fromByte(byte b) {
+      switch (b) {
+      case ((byte)'D'):
+        return DIR;
+      case ((byte)'P'):
+        return PREFIX;
+      case ((byte)'A'):
+        return AUTHZ_OBJECT;
+      default:
+        return null;
+      }
+    }
+  }
+
+  @VisibleForTesting
+  static class Entry {
+    private Entry parent;
+    private EntryType type;
+    private final String pathElement;
+    private String authzObj;
+    private final Map<String, Entry> children;
+
+    Entry(Entry parent, String pathElement, EntryType type,
+        String authzObj) {
+      this.parent = parent;
+      this.type = type;
+      this.pathElement = pathElement;
+      this.authzObj = authzObj;
+      children = new HashMap<String, Entry>();
+    }
+
+    private void setAuthzObj(String authzObj) {
+      this.authzObj = authzObj;
+    }
+
+    private void setType(EntryType type) {
+      this.type = type;
+    }
+
+    protected void removeParent() {
+      parent = null;
+    }
+
+    public String toString() {
+      return String.format("Entry[fullPath: %s, type: %s, authObject: %s]",
+          getFullPath(), type, authzObj);
+    }
+
+    private Entry createChild(List<String> pathElements, EntryType type,
+        String authzObj) {
+      Entry entryParent = this;
+      for (int i = 0; i < pathElements.size() - 1; i++) {
+        String pathElement = pathElements.get(i);
+        Entry child = entryParent.getChildren().get(pathElement);
+        if (child == null) {
+          child = new Entry(entryParent, pathElement, EntryType.DIR, null);
+          entryParent.getChildren().put(pathElement, child);
+        }
+        entryParent = child;
+      }
+      String lastPathElement = pathElements.get(pathElements.size() - 1);
+      Entry child = entryParent.getChildren().get(lastPathElement);
+      if (child == null) {
+        child = new Entry(entryParent, lastPathElement, type, authzObj);
+        entryParent.getChildren().put(lastPathElement, child);
+      } else if (type == EntryType.AUTHZ_OBJECT &&
+          child.getType() == EntryType.DIR) {
+        // if the entry already existed as dir, we change it  to be a authz obj
+        child.setAuthzObj(authzObj);
+        child.setType(EntryType.AUTHZ_OBJECT);
+      }
+      return child;
+    }
+
+    public static Entry createRoot(boolean asPrefix) {
+      return new Entry(null, "/", (asPrefix) 
+                                   ? EntryType.PREFIX : EntryType.DIR, null);
+    }
+
+    private String toPath(List<String> arr) {
+      StringBuilder sb = new StringBuilder();
+      for (String s : arr) {
+        sb.append(Path.SEPARATOR).append(s);
+      }
+      return sb.toString();
+    }
+    
+    public Entry createPrefix(List<String> pathElements) {
+      Entry prefix = findPrefixEntry(pathElements);
+      if (prefix != null) {
+        throw new IllegalArgumentException(String.format(
+            "Cannot add prefix '%s' under an existing prefix '%s'", 
+            toPath(pathElements), prefix.getFullPath()));
+      }
+      return createChild(pathElements, EntryType.PREFIX, null);
+    }
+
+    public Entry createAuthzObjPath(List<String> pathElements, String 
authzObj) {
+      Entry entry = null;
+      Entry prefix = findPrefixEntry(pathElements);
+      if (prefix != null) {
+        // we only create the entry if is under a prefix, else we ignore it
+        entry = createChild(pathElements, EntryType.AUTHZ_OBJECT, authzObj);
+      }
+      return entry;
+    }
+
+    public void delete() {
+      if (getParent() != null) {
+        if (getChildren().isEmpty()) {
+          getParent().getChildren().remove(getPathElement());
+          getParent().deleteIfDangling();
+          parent = null;
+        } else {
+          // if the entry was for an authz object and has children, we
+          // change it to be a dir entry.
+          if (getType() == EntryType.AUTHZ_OBJECT) {
+            setType(EntryType.DIR);
+            setAuthzObj(null);
+          }
+        }
+      }
+    }
+
+    private void deleteIfDangling() {
+      if (getChildren().isEmpty() && getType().isRemoveIfDangling()) {
+        delete();
+      }
+    }
+
+    public Entry getParent() {
+      return parent;
+    }
+
+    public EntryType getType() {
+      return type;
+    }
+
+    public String getPathElement() {
+      return pathElement;
+    }
+
+    public String getAuthzObj() {
+      return authzObj;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Map<String, Entry> getChildren() {
+      return children;
+    }
+
+    public Entry findPrefixEntry(List<String> pathElements) {
+      Preconditions.checkArgument(pathElements != null,
+          "pathElements cannot be NULL");
+      return (getType() == EntryType.PREFIX) 
+             ? this : findPrefixEntry(pathElements, 0);
+    }
+
+    private Entry findPrefixEntry(List<String> pathElements, int index) {
+      Entry prefixEntry = null;
+      if (index == pathElements.size()) {
+        prefixEntry = null;
+      } else {
+        Entry child = getChildren().get(pathElements.get(index));
+        if (child != null) {
+          if (child.getType() == EntryType.PREFIX) {
+            prefixEntry = child;
+          } else {
+            prefixEntry = child.findPrefixEntry(pathElements, index + 1);
+          }
+        }
+      }
+      return prefixEntry;
+    }
+
+    public Entry find(String[] pathElements, boolean isPartialMatchOk) {
+      Preconditions.checkArgument(
+          pathElements != null && pathElements.length > 0,
+          "pathElements cannot be NULL or empty");
+      return find(pathElements, 0, isPartialMatchOk, null);
+    }
+
+    private Entry find(String[] pathElements, int index,
+        boolean isPartialMatchOk, Entry lastAuthObj) {
+      Entry found = null;
+      if (index == pathElements.length) {
+        if (isPartialMatchOk && (getType() == EntryType.AUTHZ_OBJECT)) {
+          found = this;
+        }
+      } else {
+        Entry child = getChildren().get(pathElements[index]);
+        if (child != null) {
+          if (index == pathElements.length - 1) {
+            found = (child.getType() == EntryType.AUTHZ_OBJECT) ? child : 
lastAuthObj;
+          } else {
+            found = child.find(pathElements, index + 1, isPartialMatchOk,
+                (child.getType() == EntryType.AUTHZ_OBJECT) ? child : 
lastAuthObj);
+          }
+        } else {
+          if (isPartialMatchOk) {
+            found = lastAuthObj;
+          }
+        }
+      }
+      return found;
+    }
+
+    public String getFullPath() {
+      String path = getFullPath(this, new StringBuilder()).toString();
+      if (path.isEmpty()) {
+        path = Path.SEPARATOR;
+      }
+      return path;
+    }
+
+    private StringBuilder getFullPath(Entry entry, StringBuilder sb) {
+      if (entry.getParent() != null) {
+        getFullPath(entry.getParent(), sb).append(Path.SEPARATOR).append(
+            entry.getPathElement());
+      }
+      return sb;
+    }
+
+  }
+
+  private volatile Entry root;
+  private Map<String, Set<Entry>> authzObjToPath;
+
+  public HMSPaths(String[] pathPrefixes) {
+    boolean rootPrefix = false;
+    for (String pathPrefix : pathPrefixes) {
+      rootPrefix = rootPrefix || pathPrefix.equals(Path.SEPARATOR);
+    }
+    if (rootPrefix && pathPrefixes.length > 1) {
+      throw new IllegalArgumentException(
+          "Root is a path prefix, there cannot be other path prefixes");
+    }
+    root = Entry.createRoot(rootPrefix);
+    if (!rootPrefix) {
+      for (String pathPrefix : pathPrefixes) {
+        root.createPrefix(getPathElements(pathPrefix));
+      }
+    }
+    authzObjToPath = new HashMap<String, Set<Entry>>();
+  }
+
+  HMSPaths() {
+    authzObjToPath = new HashMap<String, Set<Entry>>();
+  }
+
+  void _addAuthzObject(String authzObj, List<String> authzObjPaths) {
+    addAuthzObject(authzObj, gePathsElements(authzObjPaths));
+  }
+
+  void addAuthzObject(String authzObj, List<List<String>> 
authzObjPathElements) {
+    Set<Entry> previousEntries = authzObjToPath.get(authzObj);
+    Set<Entry> newEntries = new HashSet<Entry>(authzObjPathElements.size());
+    for (List<String> pathElements : authzObjPathElements) {
+      Entry e = root.createAuthzObjPath(pathElements, authzObj);
+      if (e != null) {
+        newEntries.add(e);
+      } else {
+        // LOG WARN IGNORING PATH, no prefix
+      }
+    }
+    authzObjToPath.put(authzObj, newEntries);
+    if (previousEntries != null) {
+      previousEntries.removeAll(newEntries);
+      if (!previousEntries.isEmpty()) {
+        for (Entry entry : previousEntries) {
+          entry.delete();
+        }
+      }
+    }
+  }
+
+  void addPathsToAuthzObject(String authzObj,
+      List<List<String>> authzObjPathElements, boolean createNew) {
+    Set<Entry> entries = authzObjToPath.get(authzObj);
+    if (entries != null) {
+      Set<Entry> newEntries = new HashSet<Entry>(authzObjPathElements.size());
+      for (List<String> pathElements : authzObjPathElements) {
+        Entry e = root.createAuthzObjPath(pathElements, authzObj);
+        if (e != null) {
+          newEntries.add(e);
+        } else {
+          // LOG WARN IGNORING PATH, no prefix
+        }
+      }
+      entries.addAll(newEntries);
+    } else {
+      if (createNew) {
+        addAuthzObject(authzObj, authzObjPathElements);
+      }
+      // LOG WARN object does not exist
+    }
+  }
+
+  void _addPathsToAuthzObject(String authzObj, List<String> authzObjPaths) {
+    addPathsToAuthzObject(authzObj, gePathsElements(authzObjPaths), false);
+  }
+
+  void addPathsToAuthzObject(String authzObj, List<List<String>> 
authzObjPaths) {
+    addPathsToAuthzObject(authzObj, authzObjPaths, false);
+  }
+
+  void deletePathsFromAuthzObject(String authzObj,
+      List<List<String>> authzObjPathElements) {
+    Set<Entry> entries = authzObjToPath.get(authzObj);
+    if (entries != null) {
+      Set<Entry> toDelEntries = new 
HashSet<Entry>(authzObjPathElements.size());
+      for (List<String> pathElements : authzObjPathElements) {
+        Entry entry = root.find(
+            pathElements.toArray(new String[pathElements.size()]), false);
+        if (entry != null) {
+          entry.delete();
+          toDelEntries.add(entry);
+        } else {
+          // LOG WARN IGNORING PATH, it was not in registered
+        }
+      }
+      entries.removeAll(toDelEntries);
+    } else {
+      // LOG WARN object does not exist
+    }
+  }
+
+  void deleteAuthzObject(String authzObj) {
+    Set<Entry> entries = authzObjToPath.remove(authzObj);
+    if (entries != null) {
+      for (Entry entry : entries) {
+        entry.delete();
+      }
+    }
+  }
+
+  @Override
+  public String findAuthzObject(String[] pathElements) {
+    return findAuthzObject(pathElements, true);
+  }
+
+  @Override
+  public String findAuthzObjectExactMatch(String[] pathElements) {
+    return findAuthzObject(pathElements, false);
+  }
+
+  public String findAuthzObject(String[] pathElements, boolean isPartialOk) {
+    // Handle '/'
+    if ((pathElements == null)||(pathElements.length == 0)) return null;
+    String authzObj = null;
+    Entry entry = root.find(pathElements, isPartialOk);
+    if (entry != null) {
+      authzObj = entry.getAuthzObj();
+    }
+    return authzObj;
+  }
+
+  @Override
+  public boolean isUnderPrefix(String[] pathElements) {
+    return root.findPrefixEntry(Lists.newArrayList(pathElements)) != null;
+  }
+
+  // Used by the serializer
+  Entry getRootEntry() {
+    return root;
+  }
+
+  void setRootEntry(Entry root) {
+    this.root = root;
+  }
+
+  void setAuthzObjToPathMapping(Map<String, Set<Entry>> mapping) {
+    authzObjToPath = mapping;
+  }
+
+  @Override
+  public HMSPathsSerDe getPathsDump() {
+    return new HMSPathsSerDe(this);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPathsSerDe.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPathsSerDe.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPathsSerDe.java
new file mode 100644
index 0000000..7a25d29
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/HMSPathsSerDe.java
@@ -0,0 +1,113 @@
+/**
+ * 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.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sentry.hdfs.HMSPaths.Entry;
+import org.apache.sentry.hdfs.HMSPaths.EntryType;
+import org.apache.sentry.provider.db.service.thrift.TPathsDump;
+import org.apache.sentry.provider.db.service.thrift.TPathEntry;
+
+public class HMSPathsSerDe implements AuthzPathsDumper<HMSPaths> {
+
+  private final HMSPaths hmsPaths;
+
+  static class Tuple {
+    final TPathEntry entry;
+    final int id;
+    Tuple(TPathEntry entry, int id) {
+      this.entry = entry;
+      this.id = id;
+    }
+  }
+
+  public HMSPathsSerDe(HMSPaths hmsPaths) {
+    this.hmsPaths = hmsPaths;
+  }
+
+  @Override
+  public TPathsDump createPathsDump() {
+    AtomicInteger counter = new AtomicInteger(0);
+    Map<Integer, TPathEntry> idMap = new HashMap<Integer, TPathEntry>();
+    Tuple tRootTuple =
+        createTPathEntry(hmsPaths.getRootEntry(), counter, idMap);
+    idMap.put(tRootTuple.id, tRootTuple.entry);
+    cloneToTPathEntry(hmsPaths.getRootEntry(), tRootTuple.entry, counter, 
idMap);
+    return new TPathsDump(tRootTuple.id, idMap);
+  }
+
+  private void cloneToTPathEntry(Entry parent, TPathEntry tParent,
+      AtomicInteger counter, Map<Integer, TPathEntry> idMap) {
+    for (Entry child : parent.getChildren().values()) {
+      Tuple childTuple = createTPathEntry(child, counter, idMap);
+      tParent.getChildren().add(childTuple.id);
+      cloneToTPathEntry(child, childTuple.entry, counter, idMap);
+    }
+  }
+
+  private Tuple createTPathEntry(Entry entry, AtomicInteger idCounter,
+      Map<Integer, TPathEntry> idMap) {
+    int myId = idCounter.incrementAndGet();
+    TPathEntry tEntry = new TPathEntry(entry.getType().getByte(),
+        entry.getPathElement(), new HashSet<Integer>());
+    if (entry.getAuthzObj() != null) {
+      tEntry.setAuthzObj(entry.getAuthzObj());
+    }
+    idMap.put(myId, tEntry);
+    return new Tuple(tEntry, myId);
+  }
+
+  @Override
+  public HMSPaths initializeFromDump(TPathsDump pathDump) {
+    HMSPaths hmsPaths = new HMSPaths();
+    TPathEntry tRootEntry = pathDump.getNodeMap().get(pathDump.getRootId());
+    Entry rootEntry = new Entry(null, tRootEntry.getPathElement(),
+        EntryType.fromByte(tRootEntry.getType()), tRootEntry.getAuthzObj());
+    Map<String, Set<Entry>> authzObjToPath = new HashMap<String, Set<Entry>>();
+    cloneToEntry(tRootEntry, rootEntry, pathDump.getNodeMap(), authzObjToPath);
+    hmsPaths.setRootEntry(rootEntry);
+    hmsPaths.setAuthzObjToPathMapping(authzObjToPath);
+    return hmsPaths;
+  }
+
+  private void cloneToEntry(TPathEntry tParent, Entry parent,
+      Map<Integer, TPathEntry> idMap, Map<String, Set<Entry>> authzObjToPath) {
+    for (Integer id : tParent.getChildren()) {
+      TPathEntry tChild = idMap.get(id);
+      Entry child = new Entry(parent, tChild.getPathElement(),
+          EntryType.fromByte(tChild.getType()), tChild.getAuthzObj());
+      if (child.getAuthzObj() != null) {
+        Set<Entry> paths = authzObjToPath.get(child.getAuthzObj());
+        if (paths == null) {
+          paths = new HashSet<Entry>();
+          authzObjToPath.put(child.getAuthzObj(), paths);
+        }
+        paths.add(child);
+      }
+      parent.getChildren().put(child.getPathElement(), child);
+      cloneToEntry(tChild, child, idMap, authzObjToPath);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/MetastoreClient.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/MetastoreClient.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/MetastoreClient.java
new file mode 100644
index 0000000..3b64756
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/MetastoreClient.java
@@ -0,0 +1,34 @@
+/**
+ * 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.util.List;
+
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.Table;
+
+public interface MetastoreClient {
+
+  public List<Database> getAllDatabases();
+
+  public List<Table> getAllTablesOfDatabase(Database db);
+
+  public List<Partition> listAllPartitions(Database db, Table tbl);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PathsUpdate.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PathsUpdate.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PathsUpdate.java
new file mode 100644
index 0000000..faa28f1
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PathsUpdate.java
@@ -0,0 +1,84 @@
+/**
+ * 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.net.URI;
+import java.net.URISyntaxException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sentry.provider.db.service.thrift.TPathChanges;
+import org.apache.sentry.provider.db.service.thrift.TPathsUpdate;
+
+import com.google.common.collect.Lists;
+
+public class PathsUpdate implements Updateable.Update {
+  
+  public static String ALL_PATHS = "__ALL_PATHS__";
+
+  private final TPathsUpdate tPathsUpdate;
+
+  public PathsUpdate(TPathsUpdate tPathsUpdate) {
+    this.tPathsUpdate = tPathsUpdate;
+  }
+
+  public PathsUpdate(long seqNum, boolean hasFullImage) {
+    tPathsUpdate = new TPathsUpdate(hasFullImage, seqNum,
+        new LinkedList<TPathChanges>());
+  }
+
+  @Override
+  public boolean hasFullImage() {
+    return tPathsUpdate.isHasFullImage();
+  }
+  public TPathChanges newPathChange(String authzObject) {
+    TPathChanges pathChanges = new TPathChanges(authzObject,
+        new LinkedList<List<String>>(), new LinkedList<List<String>>());
+    tPathsUpdate.addToPathChanges(pathChanges);
+    return pathChanges;
+  }
+  public List<TPathChanges> getPathChanges() {
+    return tPathsUpdate.getPathChanges();
+  }
+
+  @Override
+  public long getSeqNum() {
+    return tPathsUpdate.getSeqNum();
+  }
+
+  @Override
+  public void setSeqNum(long seqNum) {
+    tPathsUpdate.setSeqNum(seqNum);
+  }
+
+  public TPathsUpdate getThriftObject() {
+    return tPathsUpdate;
+  }
+
+  
+
+  public static List<String> cleanPath(String path) {
+    try {
+      return Lists.newArrayList(new URI(path).getPath().split("^/")[1]
+          .split("/"));
+    } catch (URISyntaxException e) {
+      throw new RuntimeException("Incomprehensible path [" + path + "]");
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PermissionsUpdate.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PermissionsUpdate.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PermissionsUpdate.java
new file mode 100644
index 0000000..d9a6592
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/PermissionsUpdate.java
@@ -0,0 +1,93 @@
+/**
+ * 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.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import org.apache.sentry.provider.db.service.thrift.TPermissionsUpdate;
+import org.apache.sentry.provider.db.service.thrift.TPrivilegeChanges;
+import org.apache.sentry.provider.db.service.thrift.TRoleChanges;
+
+public class PermissionsUpdate implements Updateable.Update {
+
+  public static String ALL_AUTHZ_OBJ = "__ALL_AUTHZ_OBJ__";
+  public static String ALL_PRIVS = "__ALL_PRIVS__";
+  public static String ALL_ROLES = "__ALL_ROLES__";
+  public static String ALL_GROUPS = "__ALL_GROUPS__";
+
+  private final TPermissionsUpdate tPermUpdate;
+
+  public PermissionsUpdate(TPermissionsUpdate tPermUpdate) {
+    this.tPermUpdate = tPermUpdate;
+  }
+
+  public PermissionsUpdate(long seqNum, boolean hasFullImage) {
+    this.tPermUpdate = new TPermissionsUpdate(hasFullImage, seqNum,
+        new HashMap<String, TPrivilegeChanges>(),
+        new HashMap<String, TRoleChanges>());
+  }
+
+  @Override
+  public long getSeqNum() {
+    return tPermUpdate.getSeqNum();
+  }
+
+  @Override
+  public void setSeqNum(long seqNum) {
+    tPermUpdate.setSeqNum(seqNum);
+  }
+
+  @Override
+  public boolean hasFullImage() {
+    return tPermUpdate.isHasfullImage();
+  }
+
+  public TPrivilegeChanges addPrivilegeUpdate(String authzObj) {
+    if (tPermUpdate.getPrivilegeChanges().containsKey(authzObj)) {
+      return tPermUpdate.getPrivilegeChanges().get(authzObj);
+    }
+    TPrivilegeChanges privUpdate = new TPrivilegeChanges(authzObj,
+        new HashMap<String, String>(), new HashMap<String, String>());
+    tPermUpdate.getPrivilegeChanges().put(authzObj, privUpdate);
+    return privUpdate;
+  }
+
+  public TRoleChanges addRoleUpdate(String role) {
+    if (tPermUpdate.getRoleChanges().containsKey(role)) {
+      return tPermUpdate.getRoleChanges().get(role);
+    }
+    TRoleChanges roleUpdate = new TRoleChanges(role, new LinkedList<String>(),
+        new LinkedList<String>());
+    tPermUpdate.getRoleChanges().put(role, roleUpdate);
+    return roleUpdate;
+  }
+
+  public Collection<TRoleChanges> getRoleUpdates() {
+    return tPermUpdate.getRoleChanges().values();
+  }
+
+  public Collection<TPrivilegeChanges> getPrivilegeUpdates() {
+    return tPermUpdate.getPrivilegeChanges().values();
+  }
+
+  public TPermissionsUpdate getThriftObject() {
+    return tPermUpdate;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/Updateable.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/Updateable.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/Updateable.java
new file mode 100644
index 0000000..1649ffc
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/Updateable.java
@@ -0,0 +1,61 @@
+/**
+ * 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.util.concurrent.locks.ReadWriteLock;
+
+public interface Updateable<K extends Updateable.Update> {
+  
+  public interface Update {
+
+    boolean hasFullImage();
+    
+    long getSeqNum();
+
+    void setSeqNum(long seqNum);
+
+  }
+
+  /**
+   * Apply multiple partial updates in order
+   * @param update
+   * @param lock External Lock. 
+   * @return
+   */
+  public void updatePartial(Iterable<K> update, ReadWriteLock lock);
+
+  /**
+   * This returns a new object with the full update applied
+   * @param update
+   * @return
+   */
+  public Updateable<K> updateFull(K update);
+
+  /**
+   * Return sequence number of Last Update
+   */
+  public long getLastUpdatedSeqNum();
+
+  /**
+   * Create and Full image update of the local data structure
+   * @param currSeqNum
+   * @return
+   */
+  public K createFullImageUpdate(long currSeqNum);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/UpdateableAuthzPaths.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/UpdateableAuthzPaths.java 
b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/UpdateableAuthzPaths.java
new file mode 100644
index 0000000..8680d5d
--- /dev/null
+++ b/sentry-hdfs/src/main/java/org/apache/sentry/hdfs/UpdateableAuthzPaths.java
@@ -0,0 +1,130 @@
+/**
+ * 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.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReadWriteLock;
+
+import org.apache.sentry.provider.db.service.thrift.TPathChanges;
+import org.apache.sentry.provider.db.service.thrift.TPathsDump;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UpdateableAuthzPaths implements AuthzPaths, 
Updateable<PathsUpdate> {
+  private volatile HMSPaths paths;
+  private final AtomicLong seqNum = new AtomicLong(0);
+
+  private static Logger LOG = 
LoggerFactory.getLogger(UpdateableAuthzPaths.class);
+  
+  public UpdateableAuthzPaths(String[] pathPrefixes) {
+    this.paths = new HMSPaths(pathPrefixes);
+  }
+
+  UpdateableAuthzPaths(HMSPaths paths) {
+    this.paths = paths;
+  }
+
+  @Override
+  public boolean isUnderPrefix(String[] pathElements) {
+    return paths.isUnderPrefix(pathElements);
+  }
+
+  @Override
+  public String findAuthzObject(String[] pathElements) {
+    return  paths.findAuthzObject(pathElements);
+  }
+
+  @Override
+  public String findAuthzObjectExactMatch(String[] pathElements) {
+    return  paths.findAuthzObjectExactMatch(pathElements);
+  }
+
+  @Override
+  public UpdateableAuthzPaths updateFull(PathsUpdate update) {
+    UpdateableAuthzPaths other = getPathsDump().initializeFromDump(
+        update.getThriftObject().getPathsDump());
+    other.seqNum.set(update.getSeqNum());
+    return other;
+  }
+
+  @Override
+  public void updatePartial(Iterable<PathsUpdate> updates, ReadWriteLock lock) 
{
+    lock.writeLock().lock();
+    try {
+      int counter = 0;
+      for (PathsUpdate update : updates) {
+        applyPartialUpdate(update);
+        if (++counter > 99) {
+          counter = 0;
+          lock.writeLock().unlock();
+          lock.writeLock().lock();
+        }
+        seqNum.set(update.getSeqNum());
+        LOG.warn("##### Updated paths seq Num [" + seqNum.get() + "]");
+      }
+    } finally {
+      lock.writeLock().unlock();
+    }
+  }
+
+  private void applyPartialUpdate(PathsUpdate update) {
+    for (TPathChanges pathChanges : update.getPathChanges()) {
+      paths.addPathsToAuthzObject(pathChanges.getAuthzObj(), pathChanges
+          .getAddPaths(), true);
+      List<List<String>> delPaths = pathChanges.getDelPaths();
+      if ((delPaths.size() == 1) && (delPaths.get(0).size() == 1)
+          && (delPaths.get(0).get(0).equals(PathsUpdate.ALL_PATHS))) {
+        // Remove all paths.. eg. drop table
+        paths.deleteAuthzObject(pathChanges.getAuthzObj());
+      } else {
+        paths.deletePathsFromAuthzObject(pathChanges.getAuthzObj(), pathChanges
+            .getDelPaths());
+      }
+    }
+  }
+
+  @Override
+  public long getLastUpdatedSeqNum() {
+    return seqNum.get();
+  }
+
+  @Override
+  public PathsUpdate createFullImageUpdate(long currSeqNum) {
+    PathsUpdate pathsUpdate = new PathsUpdate(currSeqNum, true);
+    
pathsUpdate.getThriftObject().setPathsDump(getPathsDump().createPathsDump());
+    return pathsUpdate;
+  }
+
+  @Override
+  public AuthzPathsDumper<UpdateableAuthzPaths> getPathsDump() {
+    return new AuthzPathsDumper<UpdateableAuthzPaths>() {
+
+      @Override
+      public TPathsDump createPathsDump() {
+        return 
UpdateableAuthzPaths.this.paths.getPathsDump().createPathsDump();
+      }
+
+      @Override
+      public UpdateableAuthzPaths initializeFromDump(TPathsDump pathsDump) {
+        return new UpdateableAuthzPaths(new 
HMSPaths().getPathsDump().initializeFromDump(
+            pathsDump));
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAdapter.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAdapter.java 
b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAdapter.java
new file mode 100644
index 0000000..24c63a5
--- /dev/null
+++ b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAdapter.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
+ *
+ *     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 org.apache.sentry.provider.db.service.thrift.UpdateForwarder;
+
+public class DummyAdapter {
+//public class DummyAdapter<K extends UpdateForwarder.Update> {
+//
+//  private final UpdateForwarder<K> destCache;
+//  private final UpdateForwarder<K> srcCache;
+//
+//  public DummyAdapter(UpdateForwarder<K> destCache, UpdateForwarder<K> 
srcCache) {
+//    super();
+//    this.destCache = destCache;
+//    this.srcCache = srcCache;
+//  }
+//
+//  public void getDestToPullUpdatesFromSrc() {
+//    for (K update : srcCache.getAllUpdatesFrom(destCache.getLastCommitted() 
+ 1)) {
+//      destCache.handleUpdateNotification(update);
+//    }
+//  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAuthzSource.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAuthzSource.java 
b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAuthzSource.java
new file mode 100644
index 0000000..57299c8
--- /dev/null
+++ b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyAuthzSource.java
@@ -0,0 +1,60 @@
+/**
+ * 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 org.apache.sentry.hdfs.old.AuthzPermCache.AuthzSource;
+//import org.apache.sentry.hdfs.old.AuthzPermCache.PrivilegeInfo;
+//import org.apache.sentry.hdfs.old.AuthzPermCache.RoleInfo;
+
+public class DummyAuthzSource {
+//public class DummyAuthzSource implements AuthzSource{
+//
+//  public Map<String, PrivilegeInfo> privs = new HashMap<String, 
PrivilegeInfo>();
+//  public Map<String, RoleInfo> roles = new HashMap<String, RoleInfo>();
+//
+//  @Override
+//  public PrivilegeInfo loadPrivilege(String authzObj) throws Exception {
+//    return privs.get(authzObj);
+//  }
+//
+//  @Override
+//  public RoleInfo loadGroupsForRole(String group) throws Exception {
+//    return roles.get(group);
+//  }
+//
+//  @Override
+//  public PermissionsUpdate createFullImage(long seqNum) {
+//    PermissionsUpdate retVal = new PermissionsUpdate(seqNum, true);
+//    for (Map.Entry<String, PrivilegeInfo> pE : privs.entrySet()) {
+//      PrivilegeChanges pUpdate = retVal.addPrivilegeUpdate(pE.getKey());
+//      PrivilegeInfo pInfo = pE.getValue();
+//      for (Map.Entry<String, FsAction> ent : 
pInfo.roleToPermission.entrySet()) {
+//        pUpdate.addPrivilege(ent.getKey(), ent.getValue().SYMBOL);
+//      }
+//    }
+//    for (Map.Entry<String, RoleInfo> rE : roles.entrySet()) {
+//      RoleChanges rUpdate = retVal.addRoleUpdate(rE.getKey());
+//      RoleInfo rInfo = rE.getValue();
+//      for (String role : rInfo.groups) {
+//        rUpdate.addGroup(role);
+//      }
+//    }
+//    return retVal;
+//  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0eb6645e/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyHMSClient.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyHMSClient.java 
b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyHMSClient.java
new file mode 100644
index 0000000..3f66c87
--- /dev/null
+++ b/sentry-hdfs/src/test/java/org/apache/sentry/hdfs/DummyHMSClient.java
@@ -0,0 +1,79 @@
+/**
+ * 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.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.sentry.hdfs.MetastoreClient;
+
+public class DummyHMSClient implements MetastoreClient {
+
+  private HashMap<Database, HashMap<Table, HashSet<Partition>>> hmsData =
+      new HashMap<Database, HashMap<Table, HashSet<Partition>>>();
+
+  @Override
+  public List<Database> getAllDatabases() {
+    return new ArrayList<Database>(hmsData.keySet());
+  }
+
+  @Override
+  public List<Table> getAllTablesOfDatabase(Database db) {
+    if (hmsData.containsKey(db)) {
+      return new ArrayList<Table>(hmsData.get(db).keySet());
+    }
+    return new ArrayList<Table>();
+  }
+
+  @Override
+  public List<Partition> listAllPartitions(Database db, Table tbl) {
+    if (hmsData.containsKey(db)) {
+      if (hmsData.get(db).containsKey(tbl)) {
+        return new ArrayList<Partition>(hmsData.get(db).get(tbl));
+      }
+    }
+    return new ArrayList<Partition>();
+  }
+
+  public Database addDb(String dbName, String location) {
+    Database db = new Database(dbName, null, location, null);
+    hmsData.put(db, new HashMap<Table, HashSet<Partition>>());
+    return db;
+  }
+
+  public Table addTable(Database db, String tblName, String location) {
+    Table tbl = 
+        new Table(tblName, db.getName(), null, 0, 0, 0, 
+            new StorageDescriptor(null, location, null, null, false, 0, null, 
null, null, null),
+            null, null, null, null, null);
+    hmsData.get(db).put(tbl, new HashSet<Partition>());
+    return tbl;
+  }
+  
+  public void addPartition(Database db, Table tbl, String partitionPath) {
+    Partition part = new Partition(null, db.getName(), tbl.getTableName(), 0, 
0,
+        new StorageDescriptor(null, partitionPath, null, null, false, 0, null, 
null, null, null), null);
+    hmsData.get(db).get(tbl).add(part);
+  }
+}

Reply via email to