You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sh...@apache.org on 2014/03/13 22:21:18 UTC

[03/13] SENTRY-143: Merge db_policy_store branch into master (Brock Noland via Shreepadma Venugopalan)

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java
new file mode 100644
index 0000000..b5de36e
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java
@@ -0,0 +1,131 @@
+/**
+ * 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.model;
+
+import java.util.Set;
+
+import javax.jdo.annotations.PersistenceCapable;
+
+/**
+ * Database backed Sentry Group. Any changes to this object
+ * require re-running the maven build so DN an re-enhance.
+ */
+@PersistenceCapable
+public class MSentryGroup {
+
+  private String groupName;
+  // set of roles granted to this group
+  private Set<MSentryRole> roles;
+  private long createTime;
+  private String grantorPrincipal;
+
+  public MSentryGroup(String groupName, long createTime, String grantorPrincipal,
+      Set<MSentryRole> roles) {
+    this.setGroupName(groupName);
+    this.createTime = createTime;
+    this.grantorPrincipal = grantorPrincipal;
+    this.setRoles(roles);
+  }
+
+  public long getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(long createTime) {
+    this.createTime = createTime;
+  }
+
+  public String getGrantorPrincipal() {
+    return grantorPrincipal;
+  }
+
+  public void setGrantorPrincipal(String grantorPrincipal) {
+    this.grantorPrincipal = grantorPrincipal;
+  }
+
+  public Set<MSentryRole> getRoles() {
+    return roles;
+  }
+
+  public void setRoles(Set<MSentryRole> roles) {
+    this.roles = roles;
+  }
+
+  public String getGroupName() {
+    return groupName;
+  }
+
+  public void setGroupName(String groupName) {
+    this.groupName = groupName;
+  }
+
+  public void appendRole(MSentryRole role) {
+    if (roles.add(role)) {
+      role.appendGroup(this);
+    }
+  }
+
+  public void removeRole(MSentryRole role) {
+    if (roles.remove(role)) {
+      role.removeGroup(this);
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "MSentryGroup [groupName=" + groupName + ", roles=[...]"
+        + ", createTime=" + createTime + ", grantorPrincipal="
+        + grantorPrincipal + "]";
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + (int) (createTime ^ (createTime >>> 32));
+    result = prime * result
+        + ((grantorPrincipal == null) ? 0 : grantorPrincipal.hashCode());
+    result = prime * result + ((groupName == null) ? 0 : groupName.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    MSentryGroup other = (MSentryGroup) obj;
+    if (createTime != other.createTime)
+      return false;
+    if (grantorPrincipal == null) {
+      if (other.grantorPrincipal != null)
+        return false;
+    } else if (!grantorPrincipal.equals(other.grantorPrincipal))
+      return false;
+    if (groupName == null) {
+      if (other.groupName != null)
+        return false;
+    } else if (!groupName.equals(other.groupName))
+      return false;
+    return true;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPrivilege.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPrivilege.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPrivilege.java
new file mode 100644
index 0000000..7215435
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPrivilege.java
@@ -0,0 +1,247 @@
+/**
+ * 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.model;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jdo.annotations.PersistenceCapable;
+
+/**
+ * Database backed Sentry Privilege. Any changes to this object
+ * require re-running the maven build so DN an re-enhance.
+ */
+@PersistenceCapable
+public class MSentryPrivilege {
+
+  private String privilegeScope;
+  private String privilegeName;
+  private String serverName;
+  private String dbName;
+  private String tableName;
+  private String URI;
+  private String action;
+  // roles this privilege is a part of
+  private Set<MSentryRole> roles;
+  private long createTime;
+  private String grantorPrincipal;
+
+  public MSentryPrivilege() {
+    this.roles = new HashSet<MSentryRole>();
+  }
+
+  public MSentryPrivilege(String privilegeName, String privilegeScope,
+      String serverName, String dbName, String tableName, String URI,
+      String action) {
+    this.privilegeName = privilegeName;
+    this.privilegeScope = privilegeScope;
+    this.serverName = serverName;
+    this.dbName = dbName;
+    this.tableName = tableName;
+    this.URI = URI;
+    this.action = action;
+    this.roles = new HashSet<MSentryRole>();
+  }
+
+  public String getServerName() {
+    return serverName;
+  }
+
+  public void setServerName(String serverName) {
+    this.serverName = serverName;
+  }
+
+  public String getDbName() {
+    return dbName;
+  }
+
+  public void setDbName(String dbName) {
+    this.dbName = dbName;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getURI() {
+    return URI;
+  }
+
+  public void setURI(String uRI) {
+    URI = uRI;
+  }
+
+  public String getAction() {
+    return action;
+  }
+
+  public void setAction(String action) {
+    this.action = action;
+  }
+
+  public long getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(long createTime) {
+    this.createTime = createTime;
+  }
+
+  public String getGrantorPrincipal() {
+    return grantorPrincipal;
+  }
+
+  public void setGrantorPrincipal(String grantorPrincipal) {
+    this.grantorPrincipal = grantorPrincipal;
+  }
+
+  public String getPrivilegeScope() {
+    return privilegeScope;
+  }
+
+  public void setPrivilegeScope(String privilegeScope) {
+    this.privilegeScope = privilegeScope;
+  }
+
+  public String getPrivilegeName() {
+    return privilegeName;
+  }
+
+  public void setPrivilegeName(String privilegeName) {
+    this.privilegeName = privilegeName;
+  }
+
+  public void appendRoles(Set<MSentryRole> roles) {
+    this.roles.addAll(roles);
+  }
+
+  public void appendRole(MSentryRole role) {
+    if (!roles.contains(role)) {
+      roles.add(role);
+      role.appendPrivilege(this);
+    }
+  }
+
+  public void removeRole(MSentryRole role) {
+    for (Iterator<MSentryRole> iter = roles.iterator(); iter.hasNext();) {
+      if (iter.next().getRoleName().equalsIgnoreCase(role.getRoleName())) {
+        iter.remove();
+        role.removePrivilege(this);
+        return;
+      }
+    }
+  }
+
+  public void removeRole(String roleName) {
+    for (MSentryRole role: roles) {
+      if (role.getRoleName().equalsIgnoreCase(roleName)) {
+        roles.remove(role);
+        return;
+      }
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "MSentryPrivilege [privilegeScope=" + privilegeScope
+        + ", privilegeName=" + privilegeName + ", serverName=" + serverName
+        + ", dbName=" + dbName + ", tableName=" + tableName + ", URI=" + URI
+        + ", action=" + action + ", roles=[...]" + ", createTime="
+        + createTime + ", grantorPrincipal=" + grantorPrincipal + "]";
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((URI == null) ? 0 : URI.hashCode());
+    result = prime * result + ((action == null) ? 0 : action.hashCode());
+    result = prime * result + (int) (createTime ^ (createTime >>> 32));
+    result = prime * result + ((dbName == null) ? 0 : dbName.hashCode());
+    result = prime * result
+        + ((grantorPrincipal == null) ? 0 : grantorPrincipal.hashCode());
+    result = prime * result
+        + ((privilegeName == null) ? 0 : privilegeName.hashCode());
+    result = prime * result
+        + ((privilegeScope == null) ? 0 : privilegeScope.hashCode());
+    result = prime * result
+        + ((serverName == null) ? 0 : serverName.hashCode());
+    result = prime * result + ((tableName == null) ? 0 : tableName.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    MSentryPrivilege other = (MSentryPrivilege) obj;
+    if (URI == null) {
+      if (other.URI != null)
+        return false;
+    } else if (!URI.equals(other.URI))
+      return false;
+    if (action == null) {
+      if (other.action != null)
+        return false;
+    } else if (!action.equals(other.action))
+      return false;
+    if (createTime != other.createTime)
+      return false;
+    if (dbName == null) {
+      if (other.dbName != null)
+        return false;
+    } else if (!dbName.equals(other.dbName))
+      return false;
+    if (grantorPrincipal == null) {
+      if (other.grantorPrincipal != null)
+        return false;
+    } else if (!grantorPrincipal.equals(other.grantorPrincipal))
+      return false;
+    if (privilegeName == null) {
+      if (other.privilegeName != null)
+        return false;
+    } else if (!privilegeName.equals(other.privilegeName))
+      return false;
+    if (privilegeScope == null) {
+      if (other.privilegeScope != null)
+        return false;
+    } else if (!privilegeScope.equals(other.privilegeScope))
+      return false;
+    if (serverName == null) {
+      if (other.serverName != null)
+        return false;
+    } else if (!serverName.equals(other.serverName))
+      return false;
+    if (tableName == null) {
+      if (other.tableName != null)
+        return false;
+    } else if (!tableName.equals(other.tableName))
+      return false;
+    return true;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java
new file mode 100644
index 0000000..16be80b
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java
@@ -0,0 +1,179 @@
+/**
+ * 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.model;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jdo.annotations.PersistenceCapable;
+
+import org.apache.sentry.provider.db.service.persistent.SentryNoSuchObjectException;
+
+/**
+ * Database backed Sentry Role. Any changes to this object
+ * require re-running the maven build so DN an re-enhance.
+ */
+@PersistenceCapable
+public class MSentryRole {
+
+  private String roleName;
+  // set of privileges granted to this role
+  private Set<MSentryPrivilege> privileges;
+  // set of groups this role belongs to
+  private Set<MSentryGroup> groups;
+  private long createTime;
+  private String grantorPrincipal;
+
+  public MSentryRole() {
+    privileges = new HashSet<MSentryPrivilege>();
+  }
+
+  MSentryRole(String roleName, long createTime, String grantorPrincipal,
+      Set<MSentryPrivilege> privileges, Set<MSentryGroup> groups) {
+    this.roleName = roleName;
+    this.createTime = createTime;
+    this.grantorPrincipal = grantorPrincipal;
+    this.privileges = privileges;
+    this.groups = groups;
+  }
+
+  public long getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(long createTime) {
+    this.createTime = createTime;
+  }
+
+  public String getGrantorPrincipal() {
+    return grantorPrincipal;
+  }
+
+  public void setGrantorPrincipal(String grantorPrincipal) {
+    this.grantorPrincipal = grantorPrincipal;
+  }
+
+  public String getRoleName() {
+    return roleName;
+  }
+
+  public void setRoleName(String roleName) {
+    this.roleName = roleName;
+  }
+
+  public void setPrivileges(Set<MSentryPrivilege> privileges) {
+    this.privileges = privileges;
+  }
+
+  public Set<MSentryPrivilege> getPrivileges() {
+    return privileges;
+  }
+
+  public void setGroups(Set<MSentryGroup> groups) {
+    this.groups = groups;
+  }
+
+  public Set<MSentryGroup> getGroups() {
+    return groups;
+  }
+
+  public void removePrivilege(MSentryPrivilege privilege) {
+    for (Iterator<MSentryPrivilege> iter = privileges.iterator(); iter.hasNext();) {
+      if (iter.next().getPrivilegeName().equalsIgnoreCase(privilege.getPrivilegeName())) {
+        iter.remove();
+        privilege.removeRole(this);
+        return;
+      }
+    }
+  }
+
+  public void appendPrivileges(Set<MSentryPrivilege> privileges) {
+    this.privileges.addAll(privileges);
+  }
+
+  public void appendPrivilege(MSentryPrivilege privilege) {
+    if (!privileges.contains(privilege)) {
+      privileges.add(privilege);
+      privilege.appendRole(this);
+    }
+  }
+
+  public void appendGroups(Set<MSentryGroup> groups) {
+    this.groups.addAll(groups);
+  }
+
+  public void appendGroup(MSentryGroup group) {
+    if (groups.add(group)) {
+      group.appendRole(this);
+    }
+  }
+
+  public void removeGroup(MSentryGroup group) {
+    if (groups.remove(group)) {
+      group.removeRole(this);
+    }
+  }
+
+  public void removePrivileges() {
+    this.privileges.clear();
+  }
+
+  @Override
+  public String toString() {
+    return "MSentryRole [roleName=" + roleName + ", privileges=[..]"
+        + ", groups=[...]" + ", createTime=" + createTime
+        + ", grantorPrincipal=" + grantorPrincipal + "]";
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + (int) (createTime ^ (createTime >>> 32));
+    result = prime * result
+        + ((grantorPrincipal == null) ? 0 : grantorPrincipal.hashCode());
+    result = prime * result + ((roleName == null) ? 0 : roleName.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    MSentryRole other = (MSentryRole) obj;
+    if (createTime != other.createTime)
+      return false;
+    if (grantorPrincipal == null) {
+      if (other.grantorPrincipal != null)
+        return false;
+    } else if (!grantorPrincipal.equals(other.grantorPrincipal))
+      return false;
+    if (roleName == null) {
+      if (other.roleName != null)
+        return false;
+    } else if (!roleName.equals(other.roleName))
+      return false;
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
new file mode 100644
index 0000000..03f7549
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
@@ -0,0 +1,125 @@
+<?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.
+--> 
+<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN"
+  "http://java.sun.com/dtd/jdo_2_0.dtd">
+<!--
+  Size Limitations:
+
+  Indexed VARCHAR: 767 bytes (MySQL running on InnoDB Engine http://bugs.mysql.com/bug.php?id=13315)
+  Non-indexed VARCHAR: 4000 bytes (max length on Oracle 9i/10g/11g)
+
+-->
+<jdo>  
+  <package name="org.apache.sentry.provider.db.service.model">  
+    <class name="MSentryGroup" identity-type="datastore" table="SENTRY_GROUPS" detachable="true">  
+      <datastore-identity>
+        <column name="GROUP_ID"/>
+      </datastore-identity>
+      <field name="groupName">  
+        <column name="GROUP_NAME" length="128" jdbc-type="VARCHAR"/>
+        <index name="SentryGroupName" unique="true"/>
+      </field>
+      <field name = "createTime">
+      	<column name = "CREATE_TIME" jdbc-type="BIGINT"/>
+      </field>
+      <field name="grantorPrincipal">  
+        <column name="GRANTOR_PRINCIPAL" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      
+      <field name="roles" mapped-by="groups">
+         <collection element-type="org.apache.sentry.provider.db.service.model.MSentryRole"/>
+      </field>
+        
+    </class>
+    
+    <class name="MSentryRole" identity-type="datastore" table="SENTRY_ROLES" detachable="true">  
+      <datastore-identity>
+        <column name="ROLE_ID"/>
+      </datastore-identity>
+      <field name="roleName">  
+        <column name="ROLE_NAME" length="128" jdbc-type="VARCHAR"/>
+        <index name="SentryRoleNaME" unique="true"/>
+      </field>
+      <field name = "createTime">
+      	<column name = "CREATE_TIME" jdbc-type="BIGINT"/>
+      </field>
+      <field name="grantorPrincipal">  
+        <column name="GRANTOR_PRINCIPAL" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name = "privileges" table="ROLES_PRIVILEGES" >
+        <collection element-type="org.apache.sentry.provider.db.service.model.MSentryPrivilege"/>
+            <join>
+                <column name="ROLE_ID"/>
+            </join>
+            <element>
+                <column name="PRIVILEGE_ID"/>
+            </element>
+      </field>  
+      
+      <field name = "groups" table="ROLES_GROUPS" >
+        <collection element-type="org.apache.sentry.provider.db.service.model.MSentryGroup"/>
+            <join>
+                <column name="ROLE_ID"/>
+            </join>
+            <element>
+                <column name="GROUP_ID"/>
+            </element>
+      </field>  
+    </class>
+    
+    <class name="MSentryPrivilege" identity-type="datastore" table="SENTRY_PRIVILEGES" detachable="true">  
+      <datastore-identity>
+        <column name="PRIVILEGE_ID"/>
+      </datastore-identity>
+      <field name="privilegeName">  
+        <column name="PRIVILEGE_NAME" length="128" jdbc-type="VARCHAR"/>
+        <index name="SentryPrivilegeName" unique="true"/>
+      </field>
+      <field name="privilegeScope">  
+        <column name="PRIVILEGE_SCOPE" length="40" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="serverName">  
+        <column name="SERVER_NAME" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="dbName">  
+        <column name="DB_NAME" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="tableName">  
+        <column name="TABLE_NAME" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="URI">  
+        <column name="URI" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="action">  
+        <column name="ACTION" length="40" jdbc-type="VARCHAR"/>
+      </field>
+      <field name = "createTime">
+      	<column name = "CREATE_TIME" jdbc-type="BIGINT"/>
+      </field>
+      <field name="grantorPrincipal">  
+        <column name="GRANTOR_PRINCIPAL" length="4000" jdbc-type="VARCHAR"/>
+      </field>
+      <field name="roles" mapped-by="privileges">
+         <collection element-type="org.apache.sentry.provider.db.service.model.MSentryRole"/>
+      </field>  
+    </class>
+
+  </package>
+</jdo>
+

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/CommitContext.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/CommitContext.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/CommitContext.java
new file mode 100644
index 0000000..c74dbf3
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/CommitContext.java
@@ -0,0 +1,42 @@
+/**
+ * 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.UUID;
+
+/**
+ * Stores the UUID associated with the server who processed
+ * a commit and a commit order sequence id.
+ */
+public class CommitContext {
+
+  private final String serverUUID;
+  private final long sequenceId;
+
+  public CommitContext(UUID serverUUID, long sequenceId) {
+    this.serverUUID = serverUUID.toString();
+    this.sequenceId = sequenceId;
+  }
+  public String getServerUUID() {
+    return serverUUID;
+  }
+  public long getSequenceId() {
+    return sequenceId;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryAlreadyExistsException.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryAlreadyExistsException.java
new file mode 100644
index 0000000..965e64c
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryAlreadyExistsException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.sentry.SentryUserException;
+
+public class SentryAlreadyExistsException extends SentryUserException {
+  private static final long serialVersionUID = 1298632655835L;
+  public SentryAlreadyExistsException(String msg) {
+    super(msg);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryInvalidInputException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryInvalidInputException.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryInvalidInputException.java
new file mode 100644
index 0000000..6ac9942
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryInvalidInputException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.sentry.SentryUserException;
+
+public class SentryInvalidInputException extends SentryUserException {
+  private static final long serialVersionUID = 2962080655835L;
+  public SentryInvalidInputException(String msg) {
+    super(msg);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryNoSuchObjectException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryNoSuchObjectException.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryNoSuchObjectException.java
new file mode 100644
index 0000000..a976880
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryNoSuchObjectException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.sentry.SentryUserException;
+
+public class SentryNoSuchObjectException extends SentryUserException {
+  private static final long serialVersionUID = 2962080655835L;
+  public SentryNoSuchObjectException(String msg) {
+    super(msg);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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
new file mode 100644
index 0000000..f1e502a
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -0,0 +1,461 @@
+/**
+ * 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.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.apache.sentry.provider.db.service.model.MSentryGroup;
+import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryRole;
+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 com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+public class SentryStore {
+  private static final UUID SERVER_UUID = UUID.randomUUID();
+  static final String DEFAULT_DATA_DIR = "sentry_policy_db";
+  /**
+   * 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
+   * and read in commitUpdateTransaction. Synchronization on this
+   * is required to read commitSequenceId.
+   */
+  private long commitSequenceId;
+  private final Properties prop;
+  private final PersistenceManagerFactory pmf;
+  private final String databaseName;
+
+  public SentryStore(String dataDir) {
+    commitSequenceId = 0;
+    databaseName = (dataDir = dataDir.trim()).isEmpty() ? DEFAULT_DATA_DIR : dataDir;
+    prop = getDataSourceProperties();
+    pmf = JDOHelper.getPersistenceManagerFactory(prop);
+  }
+
+  public SentryStore() {
+    this("");
+  }
+
+  public synchronized void stop() {
+    if (pmf != null) {
+      pmf.close();
+    }
+  }
+
+  private Properties getDataSourceProperties() {
+    Properties prop = new Properties();
+    // FIXME: Read from configuration, override the default
+    //prop.setProperty("datanucleus.connectionPoolingType", "BONECP");
+    prop.setProperty("datanucleus.validateTables", "false");
+    prop.setProperty("datanucleus.validateColumns", "false");
+    prop.setProperty("datanucleus.validateConstraints", "false");
+    prop.setProperty("datanucleus.storeManagerType", "rdbms");
+    prop.setProperty("datanucleus.autoCreateSchema", "true");
+    prop.setProperty("datanucleus.fixedDatastore", "false");
+    prop.setProperty("datanucleus.autoStartMechanismMode", "checked");
+    prop.setProperty("datanucleus.transactionIsolation", "read-committed");
+    prop.setProperty("datanucleus.cache.level2", "false");
+    prop.setProperty("datanucleus.cache.level2.type", "none");
+    prop.setProperty("datanucleus.identifierFactory", "datanucleus1");
+    prop.setProperty("datanucleus.rdbms.useLegacyNativeValueStrategy", "true");
+    prop.setProperty("datanucleus.plugin.pluginRegistryBundleCheck", "LOG");
+    prop.setProperty("javax.jdo.option.ConnectionDriverName",
+                     "org.apache.derby.jdbc.EmbeddedDriver");
+    prop.setProperty("javax.jdo.PersistenceManagerFactoryClass",
+                     "org.datanucleus.api.jdo.JDOPersistenceManagerFactory");
+    prop.setProperty("javax.jdo.option.DetachAllOnCommit", "true");
+    prop.setProperty("javax.jdo.option.NonTransactionalRead", "false");
+    prop.setProperty("javax.jdo.option.NonTransactionalWrite", "false");
+    prop.setProperty("javax.jdo.option.ConnectionUserName", "Sentry");
+    prop.setProperty("javax.jdo.option.ConnectionPassword", "Sentry");
+    prop.setProperty("javax.jdo.option.Multithreaded", "true");
+    prop.setProperty("javax.jdo.option.ConnectionURL",
+                     "jdbc:derby:;databaseName=" + databaseName + ";create=true");
+    return prop;
+  }
+
+  /**
+   * PersistenceManager object and Transaction object have a one to one
+   * correspondence. Each PersistenceManager object is associated with a
+   * transaction object and vice versa. Hence we create a persistence manager
+   * instance when we create a new transaction. We create a new transaction
+   * for every store API since we want that unit of work to behave as a
+   * transaction.
+   *
+   * Note that there's only one instance of PersistenceManagerFactory object
+   * for the service.
+   *
+   * Synchronized because we obtain persistence manager
+   */
+  private synchronized PersistenceManager openTransaction() {
+    PersistenceManager pm = pmf.getPersistenceManager();
+    Transaction currentTransaction = pm.currentTransaction();
+    currentTransaction.begin();
+    return pm;
+  }
+
+  /**
+   * Synchronized due to sequence id generation
+   */
+  private synchronized CommitContext commitUpdateTransaction(PersistenceManager pm) {
+    commitTransaction(pm);
+    return new CommitContext(SERVER_UUID, incrementGetSequenceId());
+  }
+
+  /**
+   * Increments commitSequenceId which should not be modified outside
+   * this method.
+   *
+   * @return sequence id
+   */
+  private synchronized long incrementGetSequenceId() {
+    return ++commitSequenceId;
+  }
+
+  private void commitTransaction(PersistenceManager pm) {
+    Transaction currentTransaction = pm.currentTransaction();
+    try {
+      Preconditions.checkState(currentTransaction.isActive(), "Transaction is not active");
+      currentTransaction.commit();
+    } finally {
+      pm.close();
+    }
+  }
+
+  private void rollbackTransaction(PersistenceManager pm) {
+    if (pm == null || pm.isClosed()) {
+      return;
+    }
+    Transaction currentTransaction = pm.currentTransaction();
+    if (currentTransaction.isActive()) {
+      try {
+        currentTransaction.rollback();
+      } finally {
+        pm.close();
+      }
+    }
+  }
+
+  public CommitContext createSentryRole(TSentryRole role)
+  throws SentryAlreadyExistsException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole sentryRole = (MSentryRole) query.execute(role.getRoleName());
+      if (sentryRole == null) {
+        MSentryRole mRole = convertToMSentryRole(role);
+        pm.makePersistent(mRole);
+        CommitContext commit = commitUpdateTransaction(pm);
+        rollbackTransaction = false;
+        return commit;
+      } else {
+        throw new SentryAlreadyExistsException("Role: " + role.getRoleName());
+      }
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  //TODO: handle case where a) privilege already exists, b) role to privilege mapping already exists
+  public CommitContext alterSentryRoleGrantPrivilege(String roleName,
+      TSentryPrivilege privilege) throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole mRole = (MSentryRole) query.execute(roleName);
+      if (mRole == null) {
+        throw new SentryNoSuchObjectException("Role: " + roleName);
+      } else {
+        MSentryPrivilege mPrivilege = convertToMSentryPrivilege(privilege);
+        // add privilege and role objects to each other. needed by datanucleus to model
+        // m:n relationships correctly through a join table.
+        mPrivilege.appendRole(mRole);
+        mRole.appendPrivilege(mPrivilege);
+        pm.makePersistent(mRole);
+        pm.makePersistent(mPrivilege);
+        CommitContext commit = commitUpdateTransaction(pm);
+        rollbackTransaction = false;
+        return commit;
+      }
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  public CommitContext alterSentryRoleRevokePrivilege(String roleName,
+      String privilegeName) throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole mRole = (MSentryRole) query.execute(roleName);
+      if (mRole == null) {
+        throw new SentryNoSuchObjectException("Role: " + roleName);
+      } else {
+        query = pm.newQuery(MSentryPrivilege.class);
+        query.setFilter("this.privilegeName == t");
+        query.declareParameters("java.lang.String t");
+        query.setUnique(true);
+        MSentryPrivilege mPrivilege = (MSentryPrivilege) query.execute(privilegeName);
+        if (mPrivilege == null) {
+          throw new SentryNoSuchObjectException("Privilege: " + privilegeName);
+        } else {
+          // remove privilege and role objects from each other's set. needed by datanucleus to model
+          // m:n relationships correctly through a join table.
+          mRole.removePrivilege(mPrivilege);
+          CommitContext commit = commitUpdateTransaction(pm);
+          rollbackTransaction = false;
+          return commit;
+        }
+      }
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  public CommitContext dropSentryRole(String roleName)
+  throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    roleName = roleName.trim();
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole sentryRole = (MSentryRole) query.execute(roleName);
+      if (sentryRole == null) {
+        throw new SentryNoSuchObjectException("Role " + roleName);
+      } else {
+        pm.retrieve(sentryRole);
+        sentryRole.removePrivileges();
+        pm.deletePersistent(sentryRole);
+      }
+      CommitContext commit = commitUpdateTransaction(pm);
+      rollbackTransaction = false;
+      return commit;
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  public CommitContext alterSentryRoleAddGroups(String grantorPrincipal,
+      String roleName, Set<TSentryGroup> groupNames)
+  throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole role = (MSentryRole) query.execute(roleName);
+      if (role == null) {
+        throw new SentryNoSuchObjectException("Role: " + roleName);
+      } else {
+        query = pm.newQuery(MSentryGroup.class);
+        query.setFilter("this.groupName == t");
+        query.declareParameters("java.lang.String t");
+        query.setUnique(true);
+        List<MSentryGroup> groups = Lists.newArrayList();
+        for (TSentryGroup tGroup : groupNames) {
+          MSentryGroup group = (MSentryGroup) query.execute(tGroup.getGroupName());
+          if (group == null) {
+            group = new MSentryGroup(tGroup.getGroupName(), System.currentTimeMillis(),
+                grantorPrincipal, Sets.newHashSet(role));
+          }
+          group.appendRole(role);
+          groups.add(group);
+        }
+        pm.makePersistentAll(groups);
+        CommitContext commit = commitUpdateTransaction(pm);
+        rollbackTransaction = false;
+        return commit;
+      }
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  public CommitContext alterSentryRoleDeleteGroups(String roleName,
+      Set<TSentryGroup> groupNames)
+  throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole role = (MSentryRole) query.execute(roleName);
+      if (role == null) {
+        throw new SentryNoSuchObjectException("Role: " + roleName);
+      } else {
+        query = pm.newQuery(MSentryGroup.class);
+        query.setFilter("this.groupName == t");
+        query.declareParameters("java.lang.String t");
+        query.setUnique(true);
+        List<MSentryGroup> groups = Lists.newArrayList();
+        for (TSentryGroup tGroup : groupNames) {
+          MSentryGroup group = (MSentryGroup) query.execute(tGroup.getGroupName());
+          if (group != null) {
+            group.removeRole(role);
+            groups.add(group);
+          }
+        }
+        pm.makePersistentAll(groups);
+        CommitContext commit = commitUpdateTransaction(pm);
+        rollbackTransaction = false;
+        return commit;
+      }
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  @VisibleForTesting
+  MSentryRole getMSentryRoleByName(String roleName)
+  throws SentryNoSuchObjectException {
+    boolean rollbackTransaction = true;
+    PersistenceManager pm = null;
+    roleName = roleName.trim();
+    try {
+      pm = openTransaction();
+      Query query = pm.newQuery(MSentryRole.class);
+      query.setFilter("this.roleName == t");
+      query.declareParameters("java.lang.String t");
+      query.setUnique(true);
+      MSentryRole sentryRole = (MSentryRole) query.execute(roleName);
+      if (sentryRole == null) {
+        throw new SentryNoSuchObjectException("Role " + roleName);
+      } else {
+        pm.retrieve(sentryRole);
+      }
+      rollbackTransaction = false;
+      commitTransaction(pm);
+      return sentryRole;
+    } finally {
+      if (rollbackTransaction) {
+        rollbackTransaction(pm);
+      }
+    }
+  }
+
+  public TSentryRole getSentryRoleByName(String roleName)
+  throws SentryNoSuchObjectException {
+    return convertToSentryRole(getMSentryRoleByName(roleName));
+  }
+
+  private MSentryRole convertToMSentryRole(TSentryRole role) {
+    MSentryRole mRole = new MSentryRole();
+    mRole.setCreateTime(role.getCreateTime());
+    mRole.setRoleName(role.getRoleName());
+    mRole.setGrantorPrincipal(role.getGrantorPrincipal());
+    return mRole;
+  }
+
+  private TSentryRole convertToSentryRole(MSentryRole mSentryRole) {
+    TSentryRole role = new TSentryRole();
+    role.setCreateTime(mSentryRole.getCreateTime());
+    role.setRoleName(mSentryRole.getRoleName());
+    role.setGrantorPrincipal(mSentryRole.getGrantorPrincipal());
+
+    Set<TSentryPrivilege> sentryPrivileges = new HashSet<TSentryPrivilege>();
+    for(MSentryPrivilege mSentryPrivilege:mSentryRole.getPrivileges()) {
+      TSentryPrivilege privilege = convertToSentryPrivilege(mSentryPrivilege);
+      sentryPrivileges.add(privilege);
+    }
+
+    role.setPrivileges(sentryPrivileges);
+    return role;
+  }
+
+  private TSentryPrivilege convertToSentryPrivilege(MSentryPrivilege mSentryPrivilege) {
+    TSentryPrivilege privilege = new TSentryPrivilege();
+    privilege.setCreateTime(mSentryPrivilege.getCreateTime());
+    privilege.setPrivilegeName(mSentryPrivilege.getPrivilegeName());
+    privilege.setAction(mSentryPrivilege.getAction());
+    privilege.setPrivilegeScope(mSentryPrivilege.getPrivilegeScope());
+    privilege.setServerName(mSentryPrivilege.getServerName());
+    privilege.setDbName(mSentryPrivilege.getDbName());
+    privilege.setTableName(mSentryPrivilege.getTableName());
+    privilege.setURI(mSentryPrivilege.getURI());
+    privilege.setGrantorPrincipal(mSentryPrivilege.getGrantorPrincipal());
+    return privilege;
+  }
+
+  private MSentryPrivilege convertToMSentryPrivilege(TSentryPrivilege privilege) {
+    MSentryPrivilege mSentryPrivilege = new MSentryPrivilege();
+    mSentryPrivilege.setServerName(privilege.getServerName());
+    mSentryPrivilege.setDbName(privilege.getDbName());
+    mSentryPrivilege.setTableName(privilege.getTableName());
+    mSentryPrivilege.setPrivilegeScope(privilege.getPrivilegeScope());
+    mSentryPrivilege.setAction(privilege.getAction());
+    mSentryPrivilege.setCreateTime(privilege.getCreateTime());
+    mSentryPrivilege.setGrantorPrincipal(privilege.getGrantorPrincipal());
+    mSentryPrivilege.setURI(privilege.getURI());
+    mSentryPrivilege.setPrivilegeName(privilege.getPrivilegeName());
+    return mSentryPrivilege;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandler.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandler.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandler.java
new file mode 100644
index 0000000..506d433
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandler.java
@@ -0,0 +1,71 @@
+/**
+ * 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.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.CommitContext;
+
+/**
+ * Users wishing to be notified when a metadata changing event occurs
+ * should extend this abstract class. All methods which modify the underlying
+ * metadata in SentryPolicyStoreProcessor will have a corresponding method
+ * on this class. Each method will contain a copy of the request and response
+ * object. Therefore any change to the request or response object will be ignored.
+ * Additionally each method will be passed a CommitContext.
+ *
+ * Sub-classes should be thread-safe.
+ */
+public abstract class NotificationHandler {
+
+  private final Configuration config;
+
+  public NotificationHandler(Configuration config) throws Exception {
+    this.config = config;
+  }
+
+  protected Configuration getConf() {
+    return config;
+  }
+
+  public void create_sentry_role(CommitContext context,
+                                 TCreateSentryRoleRequest request, TCreateSentryRoleResponse response) {
+  }
+
+  public void drop_sentry_role(CommitContext context, TDropSentryRoleRequest request,
+                               TDropSentryRoleResponse response) {
+  }
+
+  public void alter_sentry_role_grant_privilege(CommitContext context, TAlterSentryRoleGrantPrivilegeRequest request,
+      TAlterSentryRoleGrantPrivilegeResponse response) {
+  }
+
+  public void alter_sentry_role_revoke_privilege(CommitContext context, TAlterSentryRoleRevokePrivilegeRequest request,
+      TAlterSentryRoleRevokePrivilegeResponse response) {
+  }
+
+  public void alter_sentry_role_add_groups(CommitContext context,
+      TAlterSentryRoleAddGroupsRequest request,
+      TAlterSentryRoleAddGroupsResponse response) {
+  }
+
+  public void alter_sentry_role_delete_groups(
+    CommitContext context, TAlterSentryRoleDeleteGroupsRequest request,
+    TAlterSentryRoleDeleteGroupsResponse response) {
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandlerInvoker.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandlerInvoker.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandlerInvoker.java
new file mode 100644
index 0000000..9d9e867
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/NotificationHandlerInvoker.java
@@ -0,0 +1,146 @@
+/**
+ * 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.thrift;
+
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.CommitContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Invokes configured instances of NotificationHandler. Importantly
+ * NotificationHandler's each receive a copy of the request and
+ * response thrift objects from each successful request.
+ */
+public class NotificationHandlerInvoker extends NotificationHandler {
+  private static final Logger LOGGER = LoggerFactory.getLogger(NotificationHandlerInvoker.class);
+
+  private final ImmutableList<NotificationHandler> handlers;
+
+  public NotificationHandlerInvoker(Configuration conf, NotificationHandler handler)
+  throws Exception {
+    this(conf, ImmutableList.of(handler));
+  }
+
+  public NotificationHandlerInvoker(Configuration conf, List<NotificationHandler> handlers)
+  throws Exception {
+    super(conf);
+    this.handlers = ImmutableList.copyOf(handlers);
+  }
+
+  @Override
+  public void create_sentry_role(CommitContext context,
+                                 TCreateSentryRoleRequest request, TCreateSentryRoleResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.create_sentry_role(context,  new TCreateSentryRoleRequest(request),
+                                   new TCreateSentryRoleResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+
+  @Override
+  public void drop_sentry_role(CommitContext context, TDropSentryRoleRequest request,
+                               TDropSentryRoleResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.drop_sentry_role(context,  new TDropSentryRoleRequest(request),
+                                 new TDropSentryRoleResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+
+  @Override
+  public void alter_sentry_role_grant_privilege(CommitContext context,
+      TAlterSentryRoleGrantPrivilegeRequest request,
+      TAlterSentryRoleGrantPrivilegeResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.alter_sentry_role_grant_privilege(context,
+            new TAlterSentryRoleGrantPrivilegeRequest(request),
+            new TAlterSentryRoleGrantPrivilegeResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+
+  @Override
+  public void alter_sentry_role_revoke_privilege(CommitContext context,
+      TAlterSentryRoleRevokePrivilegeRequest request,
+      TAlterSentryRoleRevokePrivilegeResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.alter_sentry_role_revoke_privilege(context,
+            new TAlterSentryRoleRevokePrivilegeRequest(request),
+            new TAlterSentryRoleRevokePrivilegeResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+
+  @Override
+  public void alter_sentry_role_add_groups(CommitContext context,
+      TAlterSentryRoleAddGroupsRequest request,
+      TAlterSentryRoleAddGroupsResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.alter_sentry_role_add_groups(context, new TAlterSentryRoleAddGroupsRequest(request),
+                                             new TAlterSentryRoleAddGroupsResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+
+  @Override
+  public void alter_sentry_role_delete_groups(
+    CommitContext context, TAlterSentryRoleDeleteGroupsRequest request,
+    TAlterSentryRoleDeleteGroupsResponse response) {
+    for (NotificationHandler handler : handlers) {
+      try {
+        LOGGER.debug("Calling " + handler);
+        handler.alter_sentry_role_delete_groups(context, new TAlterSentryRoleDeleteGroupsRequest(request),
+                                                new TAlterSentryRoleDeleteGroupsResponse(response));
+      } catch (Exception ex) {
+        LOGGER.error("Unexpected error in " + handler + ". Request: "
+                     + request + ", Response: " + response, ex);
+      }
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java
new file mode 100644
index 0000000..34bec93
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java
@@ -0,0 +1,25 @@
+/**
+ * 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.thrift;
+
+public class PolicyStoreConstants {
+
+  public static class PolicyStoreServerConfig {
+    public static final String NOTIFICATION_HANDLERS = "sentry.policy.store.notification.handlers";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryConfigurationException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryConfigurationException.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryConfigurationException.java
new file mode 100644
index 0000000..0e5ad32
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryConfigurationException.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.provider.db.service.thrift;
+
+import org.apache.sentry.SentryUserException;
+
+public class SentryConfigurationException extends SentryUserException {
+  private static final long serialVersionUID = 1298632655835L;
+  public SentryConfigurationException(String msg) {
+    super(msg);
+  }
+  public SentryConfigurationException(String msg, Throwable t) {
+    super(msg, t);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java
new file mode 100644
index 0000000..a4487ee
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.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.provider.db.service.thrift;
+
+import java.net.InetSocketAddress;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
+import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.transport.TSaslClientTransport;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SentryPolicyServiceClient {
+
+  @SuppressWarnings("unused")
+  private final Configuration conf;
+  private final InetSocketAddress serverAddress;
+  private final String[] serverPrincipalParts;
+  private SentryPolicyService.Client client;
+  private TTransport transport;
+  private int connectionTimeout;
+  private static final Logger LOGGER = LoggerFactory
+                                       .getLogger(SentryPolicyServiceClient.class);
+
+  public SentryPolicyServiceClient(Configuration conf) throws Exception {
+    this.conf = conf;
+    this.serverAddress = NetUtils.createSocketAddr(Preconditions.checkNotNull(
+                           conf.get(ClientConfig.SERVER_RPC_ADDRESS), "Config key "
+                           + ClientConfig.SERVER_RPC_ADDRESS + " is required"), conf.getInt(
+                           ClientConfig.SERVER_RPC_PORT, ClientConfig.SERVER_RPC_PORT_DEFAULT));
+    this.connectionTimeout = conf.getInt(ClientConfig.SERVER_RPC_CONN_TIMEOUT,
+                                         ClientConfig.SERVER_RPC_CONN_TIMEOUT_DEFAULT);
+    String serverPrincipal = Preconditions.checkNotNull(
+                               conf.get(ServerConfig.PRINCIPAL), ServerConfig.PRINCIPAL
+                               + " is required");
+    serverPrincipalParts = SaslRpcServer.splitKerberosName(serverPrincipal);
+    Preconditions.checkArgument(serverPrincipalParts.length == 3,
+                                "Kerberos principal should have 3 parts: " + serverPrincipal);
+    transport = new TSocket(serverAddress.getHostString(),
+                            serverAddress.getPort(), connectionTimeout);
+    TTransport saslTransport = new TSaslClientTransport(
+      AuthMethod.KERBEROS.getMechanismName(), null, serverPrincipalParts[0],
+      serverPrincipalParts[1], ClientConfig.SASL_PROPERTIES, null, transport);
+    saslTransport.open();
+    LOGGER.info("Successfully opened transport");
+    TMultiplexedProtocol protocol = new TMultiplexedProtocol(
+      new TBinaryProtocol(saslTransport),
+      SentryPolicyStoreProcessor.SENTRY_POLICY_SERVICE_NAME);
+    client = new SentryPolicyService.Client(protocol);
+    LOGGER.info("Successfully created client");
+  }
+
+  public TCreateSentryRoleResponse createRole(TCreateSentryRoleRequest req)
+  throws TException {
+    return client.create_sentry_role(req);
+  }
+
+  public TListSentryRolesResponse listRoleByName(TListSentryRolesRequest req)
+  throws TException {
+    return client.list_sentry_roles_by_role_name(req);
+  }
+
+  public TDropSentryRoleResponse dropRole(TDropSentryRoleRequest req)
+  throws TException {
+    return client.drop_sentry_role(req);
+  }
+
+  public TAlterSentryRoleGrantPrivilegeResponse grantPrivilege(TAlterSentryRoleGrantPrivilegeRequest req)
+  throws TException {
+    return client.alter_sentry_role_grant_privilege(req);
+  }
+
+  public TAlterSentryRoleRevokePrivilegeResponse revokePrivilege(TAlterSentryRoleRevokePrivilegeRequest req)
+  throws TException {
+    return client.alter_sentry_role_revoke_privilege(req);
+  }
+
+  public void close() {
+    if (transport != null) {
+      transport.close();
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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
new file mode 100644
index 0000000..3fe47dc
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java
@@ -0,0 +1,344 @@
+/**
+ * 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.thrift;
+
+import java.lang.reflect.Constructor;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.CommitContext;
+import org.apache.sentry.provider.db.service.persistent.SentryAlreadyExistsException;
+import org.apache.sentry.provider.db.service.persistent.SentryInvalidInputException;
+import org.apache.sentry.provider.db.service.persistent.SentryNoSuchObjectException;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants.PolicyStoreServerConfig;
+import org.apache.sentry.service.thrift.Status;
+import org.apache.sentry.service.thrift.TSentryResponseStatus;
+import org.apache.thrift.TException;
+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.Splitter;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+@SuppressWarnings("unused")
+public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
+  private static final Logger LOGGER = LoggerFactory.getLogger(SentryPolicyStoreProcessor.class);
+
+  public static final String SENTRY_POLICY_SERVICE_NAME = "SentryPolicyService";
+
+  private final String name;
+  private final Configuration conf;
+  private final SentryStore sentryStore;
+  private final NotificationHandlerInvoker notificationHandlerInvoker;
+  private boolean isReady;
+
+  public SentryPolicyStoreProcessor(String name, Configuration conf) throws Exception {
+    super();
+    this.name = name;
+    this.conf = conf;
+    this.notificationHandlerInvoker = new NotificationHandlerInvoker(conf,
+        createHandlers(conf));
+    isReady = false;
+    sentryStore = new SentryStore();
+    isReady = true;
+  }
+
+  public void stop() {
+    if (isReady) {
+      sentryStore.stop();
+    }
+  }
+
+  @VisibleForTesting
+  static List<NotificationHandler> createHandlers(Configuration conf)
+  throws SentryConfigurationException {
+    List<NotificationHandler> handlers = Lists.newArrayList();
+    Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults()
+                                            .omitEmptyStrings().split(conf.get(PolicyStoreServerConfig.NOTIFICATION_HANDLERS, ""));
+    for (String notificationHandler : notificationHandlers) {
+      Class<?> clazz = null;
+      try {
+        clazz = Class.forName(notificationHandler);
+        if (!NotificationHandler.class.isAssignableFrom(clazz)) {
+          throw new SentryConfigurationException("Class " + notificationHandler + " is not a " +
+                                                 NotificationHandler.class.getName());
+        }
+      } catch (ClassNotFoundException e) {
+        throw new SentryConfigurationException("Value " + notificationHandler +
+                                               " is not a class", e);
+      }
+      Preconditions.checkNotNull(clazz, "Error class cannot be null");
+      try {
+        Constructor<?> constructor = clazz.getConstructor(Configuration.class);
+        handlers.add((NotificationHandler)constructor.newInstance(conf));
+      } catch (Exception e) {
+        throw new SentryConfigurationException("Error attempting to create " + notificationHandler, e);
+      }
+    }
+    return handlers;
+  }
+
+  //TODO:Validate privilege scope?
+  @VisibleForTesting
+  public static String constructPrivilegeName(TSentryPrivilege privilege) throws SentryInvalidInputException {
+    StringBuilder privilegeName = new StringBuilder();
+    String serverName = privilege.getServerName();
+    String dbName = privilege.getDbName();
+    String tableName = privilege.getTableName();
+    String uri = privilege.getURI();
+    String action = privilege.getAction();
+
+    if (serverName == null) {
+      throw new SentryInvalidInputException("Server name is null");
+    }
+
+    if (action.equalsIgnoreCase("SELECT") || action.equalsIgnoreCase("INSERT")) {
+      if (tableName == null || tableName.equals("")) {
+        throw new SentryInvalidInputException("Table name can't be null for SELECT/INSERT privilege");
+      }
+    }
+
+    if (dbName == null || dbName.equals("")) {
+      if (tableName != null && !tableName.equals("")) {
+        throw new SentryInvalidInputException("Db name can't be null");
+      }
+    }
+
+    if (uri == null || uri.equals("")) {
+      privilegeName.append(serverName);
+      privilegeName.append("+");
+      privilegeName.append(dbName);
+
+      if (tableName != null && !tableName.equals("")) {
+        privilegeName.append("+");
+        privilegeName.append(tableName);
+      }
+      privilegeName.append("+");
+      privilegeName.append(action);
+    } else {
+      privilegeName.append(serverName);
+      privilegeName.append("+");
+      privilegeName.append(uri);
+    }
+    return privilegeName.toString();
+  }
+
+  @Override
+  public TCreateSentryRoleResponse create_sentry_role(
+    TCreateSentryRoleRequest request) throws TException {
+    TCreateSentryRoleResponse response = new TCreateSentryRoleResponse();
+    try {
+      CommitContext commitContext = sentryStore.createSentryRole(request.getRole());
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.create_sentry_role(commitContext,
+          request, response);
+    } catch (SentryAlreadyExistsException e) {
+      String msg = "Role: " + request + " already exists.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.AlreadyExists(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+
+  @Override
+  public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege
+  (TAlterSentryRoleGrantPrivilegeRequest request) throws TException {
+
+    TAlterSentryRoleGrantPrivilegeResponse response = new TAlterSentryRoleGrantPrivilegeResponse();
+    try {
+      String privilegeName = constructPrivilegeName(request.getPrivilege());
+      request.getPrivilege().setPrivilegeName(privilegeName);
+      CommitContext commitContext = sentryStore.alterSentryRoleGrantPrivilege(request.getRoleName(),
+                                    request.getPrivilege());
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.alter_sentry_role_grant_privilege(commitContext,
+          request, response);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Role: " + request.getRoleName() + " doesn't exist.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (SentryInvalidInputException e) {
+      String msg = "Invalid input privilege object";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.InvalidInput(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+
+    return response;
+  }
+
+  @Override
+  public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege
+  (TAlterSentryRoleRevokePrivilegeRequest request) throws TException {
+    TAlterSentryRoleRevokePrivilegeResponse response = new TAlterSentryRoleRevokePrivilegeResponse();
+    try {
+      String privilegeName = constructPrivilegeName(request.getPrivilege());
+      request.getPrivilege().setPrivilegeName(privilegeName);
+      CommitContext commitContext = sentryStore.alterSentryRoleRevokePrivilege(request.getRoleName(),
+                                    request.getPrivilege().getPrivilegeName());
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.alter_sentry_role_revoke_privilege(commitContext,
+          request, response);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Privilege: " + request.getPrivilege().getPrivilegeName() + " doesn't exist.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (SentryInvalidInputException e) {
+      String msg = "Invalid input privilege object";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.InvalidInput(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+
+    return response;
+  }
+
+  @Override
+  public TDropSentryRoleResponse drop_sentry_role(
+    TDropSentryRoleRequest request)  throws TException {
+    TDropSentryRoleResponse response = new TDropSentryRoleResponse();
+    TSentryResponseStatus status;
+    try {
+      CommitContext commitContext = sentryStore.dropSentryRole(request.getRoleName());
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.drop_sentry_role(commitContext,
+          request, response);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Role :" + request + " does not exist.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+
+  @Override
+  public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(
+    TAlterSentryRoleAddGroupsRequest request) throws TException {
+    TAlterSentryRoleAddGroupsResponse response = new TAlterSentryRoleAddGroupsResponse();
+    try {
+      CommitContext commitContext = sentryStore.alterSentryRoleAddGroups(request.getRequestorUserName(),
+                                    request.getRoleName(), request.getGroups());
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.alter_sentry_role_add_groups(commitContext,
+          request, response);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Role: " + request + " does not exist.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+
+  @Override
+  public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(
+    TAlterSentryRoleDeleteGroupsRequest request) throws TException {
+    // TODO implement
+    TAlterSentryRoleDeleteGroupsResponse response = new TAlterSentryRoleDeleteGroupsResponse();
+    try {
+      CommitContext commitContext = sentryStore.alterSentryRoleDeleteGroups(null, null);
+      response.setStatus(Status.OK());
+      notificationHandlerInvoker.alter_sentry_role_delete_groups(commitContext,
+          request, response);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Role: " + request + " does not exist.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error adding groups to role: " + request;
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+
+  @Override
+  public TListSentryRolesResponse list_sentry_roles_by_group(
+    TListSentryRolesRequest request) throws TException {
+    TListSentryRolesResponse response = new TListSentryRolesResponse();
+    TSentryResponseStatus status;
+    TSentryRole role = null;
+    Set<TSentryRole> roleSet = new HashSet<TSentryRole>();
+    try {
+      // TODO implement
+      role = sentryStore.getSentryRoleByName(request.getRoleName());
+      roleSet.add(role);
+      response.setRoles(roleSet);
+      response.setStatus(Status.OK());
+    } catch (SentryNoSuchObjectException e) {
+      response.setRoles(roleSet);
+      String msg = "Role: " + request + " couldn't be retrieved.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+
+  @Override
+  public TListSentryRolesResponse list_sentry_roles_by_role_name(
+    TListSentryRolesRequest request) throws TException {
+    TListSentryRolesResponse response = new TListSentryRolesResponse();
+    TSentryResponseStatus status;
+    TSentryRole role = null;
+    Set<TSentryRole> roleSet = new HashSet<TSentryRole>();
+    try {
+      role = sentryStore.getSentryRoleByName(request.getRoleName());
+      roleSet.add(role);
+      response.setRoles(roleSet);
+      response.setStatus(Status.OK());
+    } catch (SentryNoSuchObjectException e) {
+      response.setRoles(roleSet);
+      String msg = "Role: " + request + " couldn't be retrieved.";
+      LOGGER.error(msg, e);
+      response.setStatus(Status.NoSuchObject(msg, e));
+    } catch (Exception e) {
+      String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.setStatus(Status.RuntimeError(msg, e));
+    }
+    return response;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessorFactory.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessorFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessorFactory.java
new file mode 100644
index 0000000..b37db2b
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessorFactory.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.provider.db.service.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.service.thrift.ProcessorFactory;
+import org.apache.thrift.TMultiplexedProcessor;
+import org.apache.thrift.TProcessor;
+
+public class SentryPolicyStoreProcessorFactory extends ProcessorFactory {
+  public SentryPolicyStoreProcessorFactory(Configuration conf) {
+    super(conf);
+  }
+
+  public boolean register(TMultiplexedProcessor multiplexedProcessor) throws Exception {
+    SentryPolicyStoreProcessor sentryServiceHandler =
+        new SentryPolicyStoreProcessor(SentryPolicyStoreProcessor.SENTRY_POLICY_SERVICE_NAME,
+            conf);
+    TProcessor processor =
+      new SentryPolicyService.Processor<SentryPolicyService.Iface>(sentryServiceHandler);
+    multiplexedProcessor.registerProcessor(SentryPolicyStoreProcessor.SENTRY_POLICY_SERVICE_NAME, processor);
+    return true;
+  }
+}