You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by co...@apache.org on 2016/06/24 06:00:50 UTC

[21/44] sentry git commit: SENTRY-1287: Create sentry-service-server module(Colin Ma, reviewed by Dapeng Sun)

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java
new file mode 100644
index 0000000..e59d12a
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java
@@ -0,0 +1,835 @@
+/**
+ * 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.generic.service.thrift;
+
+import static org.apache.sentry.core.common.utils.SentryConstants.AUTHORIZABLE_JOINER;
+import static org.apache.sentry.core.common.utils.SentryConstants.KV_JOINER;
+
+import java.lang.reflect.Constructor;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.utils.SentryConstants;
+import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
+import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.core.common.utils.KeyValue;
+import org.apache.sentry.core.common.utils.AuthorizationComponent;
+import org.apache.sentry.core.common.exception.SentryAccessDeniedException;
+import org.apache.sentry.core.common.exception.SentryAlreadyExistsException;
+import org.apache.sentry.core.common.exception.SentryInvalidInputException;
+import org.apache.sentry.core.common.exception.SentryNoSuchObjectException;
+import org.apache.sentry.core.common.exception.SentryThriftAPIMismatchException;
+import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject;
+import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder;
+import org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer;
+import org.apache.sentry.provider.db.log.entity.JsonLogEntityFactory;
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryRole;
+import org.apache.sentry.provider.db.service.persistent.CommitContext;
+import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.service.thrift.ServiceConstants.ThriftConstants;
+import org.apache.sentry.service.thrift.ServiceConstants;
+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.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public class SentryGenericPolicyProcessor implements SentryGenericPolicyService.Iface {
+  private static final Logger LOGGER = LoggerFactory.getLogger(SentryGenericPolicyProcessor.class);
+  private static final Logger AUDIT_LOGGER = LoggerFactory
+      .getLogger(Constants.AUDIT_LOGGER_NAME_GENERIC);
+  private final Configuration conf;
+  private final ImmutableSet<String> adminGroups;
+  private final SentryStoreLayer store;
+  private final NotificationHandlerInvoker handerInvoker;
+
+  private static final String ACCESS_DENIAL_MESSAGE = "Access denied to ";
+
+  public SentryGenericPolicyProcessor(Configuration conf) throws Exception {
+    this.store = createStore(conf);
+    this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
+    this.conf = conf;
+    adminGroups = ImmutableSet.copyOf((Sets.newHashSet(conf.getStrings(
+        ServerConfig.ADMIN_GROUPS, new String[]{}))));
+  }
+
+  @VisibleForTesting
+  public SentryGenericPolicyProcessor(Configuration conf, SentryStoreLayer store) throws Exception {
+    this.store = store;
+    this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
+    this.conf = conf;
+    adminGroups = ImmutableSet.copyOf(toTrimmed(Sets.newHashSet(conf.getStrings(
+        ServerConfig.ADMIN_GROUPS, new String[]{}))));
+  }
+
+  private void authorize(String requestorUser, Set<String> requestorGroups)
+  throws SentryAccessDeniedException {
+    if (!inAdminGroups(requestorGroups)) {
+      String msg = "User: " + requestorUser + " is part of " + requestorGroups +
+          " which does not, intersect admin groups " + adminGroups;
+      LOGGER.warn(msg);
+      throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + requestorUser);
+    }
+  }
+
+  private Set<String> toTrimmedLower(Set<String> s) {
+    if (null == s) {
+      return new HashSet<String>();
+    }
+    Set<String> result = Sets.newHashSet();
+    for (String v : s) {
+      result.add(v.trim().toLowerCase());
+    }
+    return result;
+  }
+
+  private Set<String> toTrimmed(Set<String> s) {
+    if (null == s) {
+      return new HashSet<String>();
+    }
+    Set<String> result = Sets.newHashSet();
+    for (String v : s) {
+      result.add(v.trim());
+    }
+    return result;
+  }
+
+  private String toTrimmedLower(String s) {
+    if (Strings.isNullOrEmpty(s)){
+      return "";
+    }
+    return s.trim().toLowerCase();
+  }
+
+  public static Set<String> getRequestorGroups(Configuration conf, String userName) throws SentryUserException {
+    return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, userName);
+  }
+
+  private boolean inAdminGroups(Set<String> requestorGroups) {
+    if (Sets.intersection(adminGroups, requestorGroups).isEmpty()) {
+      return false;
+    }
+    return true;
+  }
+
+  public static SentryStoreLayer createStore(Configuration conf) throws SentrySiteConfigurationException {
+    SentryStoreLayer storeLayer = null;
+    String store = conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE, PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE_DEFAULT);
+
+    if (Strings.isNullOrEmpty(store)) {
+      throw new SentrySiteConfigurationException("sentry.generic.policy.store can not be empty");
+    }
+    try {
+      storeLayer = createInstance(store, conf, SentryStoreLayer.class);
+    } catch (Exception e) {
+      throw new SentrySiteConfigurationException("Create sentryStore error: " + e.getMessage(), e);
+    }
+    return storeLayer;
+  }
+
+  public static List<NotificationHandler> createHandlers(Configuration conf) throws SentrySiteConfigurationException {
+
+    List<NotificationHandler> handlers = Lists.newArrayList();
+    Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults()
+        .omitEmptyStrings().split(conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_NOTIFICATION, ""));
+    try {
+      for (String notificationHandler : notificationHandlers) {
+        handlers.add(createInstance(notificationHandler, conf, NotificationHandler.class));
+      }
+    } catch (Exception e) {
+      throw new SentrySiteConfigurationException("Create notificationHandlers error: " + e.getMessage(), e);
+    }
+    return handlers;
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> T createInstance(String className, Configuration conf, Class<T> iface) throws Exception {
+    T result;
+    try {
+      Class<?> clazz = Class.forName(className);
+      if (!iface.isAssignableFrom(clazz)) {
+        throw new IllegalArgumentException("Class " + clazz + " is not a " +
+                                                 iface.getName());
+      }
+      Constructor<T> meth = (Constructor<T>)clazz.getDeclaredConstructor(Configuration.class);
+      meth.setAccessible(true);
+      result = meth.newInstance(new Object[]{conf});
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+    return result;
+  }
+
+  private <T> Response<T> requestHandle(RequestHandler<T> handler) {
+    Response<T> response = new Response<T>();
+    try {
+      response = handler.handle();
+    } catch (SentryAccessDeniedException e) {
+      String msg = "Sentry access denied: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.AccessDenied(e.getMessage(), e);
+    } catch (SentryAlreadyExistsException e) {
+      String msg = "Sentry object already exists: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.AlreadyExists(e.getMessage(), e);
+    } catch (SentryNoSuchObjectException e) {
+      String msg = "Sentry object doesn't exist: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.NoSuchObject(e.getMessage(), e);
+    } catch (SentryInvalidInputException e) {
+      String msg = "Invalid input privilege object: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.InvalidInput(msg, e);
+    } catch (SentryThriftAPIMismatchException e) {
+      String msg = "Sentry thrift API mismatch error: " + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.THRIFT_VERSION_MISMATCH(e.getMessage(), e);
+    } catch (Exception e) {
+      String msg = "Unknown error:" + e.getMessage();
+      LOGGER.error(msg, e);
+      response.status = Status.RuntimeError(msg, e);
+    }
+    return response;
+  }
+
+  private PrivilegeObject toPrivilegeObject(TSentryPrivilege tSentryPrivilege) {
+    Boolean grantOption;
+    if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE)) {
+      grantOption = true;
+    } else if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.FALSE)) {
+      grantOption = false;
+    } else {
+      grantOption = null;
+    }
+    return new Builder().setComponent(tSentryPrivilege.getComponent())
+                                             .setService(tSentryPrivilege.getServiceName())
+                                             .setAuthorizables(toAuthorizables(tSentryPrivilege.getAuthorizables()))
+                                             .setAction(tSentryPrivilege.getAction())
+                                             .withGrantOption(grantOption)
+                                             .build();
+  }
+
+  private TSentryPrivilege fromPrivilegeObject(PrivilegeObject privilege) {
+
+    TSentryPrivilege tPrivilege = new TSentryPrivilege(privilege.getComponent(), privilege.getService(),
+                                                       fromAuthorizable(privilege.getAuthorizables()),
+                                                       privilege.getAction());
+    if (privilege.getGrantOption() == null) {
+      tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+    } else if (privilege.getGrantOption()) {
+      tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+    } else {
+      tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+    }
+    return tPrivilege;
+  }
+
+  private List<TAuthorizable> fromAuthorizable(List<? extends Authorizable> authorizables) {
+    List<TAuthorizable> tAuthorizables = Lists.newArrayList();
+    for (Authorizable authorizable : authorizables) {
+      tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+    }
+    return tAuthorizables;
+  }
+
+  private String fromAuthorizableToStr(List<? extends Authorizable> authorizables) {
+    if (authorizables != null && !authorizables.isEmpty()) {
+      List<String> privileges = Lists.newArrayList();
+
+      for (Authorizable authorizable : authorizables) {
+
+        privileges.add(SentryConstants.KV_JOINER.join(authorizable.getTypeName(),
+            authorizable.getName()));
+      }
+
+      return SentryConstants.AUTHORIZABLE_JOINER.join(privileges);
+    } else {
+      return "";
+    }
+  }
+
+  private List<? extends Authorizable> toAuthorizables(List<TAuthorizable> tAuthorizables) {
+    List<Authorizable> authorizables = Lists.newArrayList();
+    if (tAuthorizables == null) {
+      return authorizables;
+    }
+    for (final TAuthorizable tAuthorizable : tAuthorizables) {
+      authorizables.add(new Authorizable() {
+        @Override
+        public String getTypeName() {
+          return tAuthorizable.getType();
+        }
+        @Override
+        public String getName() {
+          return tAuthorizable.getName();
+        }
+      });
+    }
+    return authorizables;
+  }
+
+  private List<? extends Authorizable> toAuthorizables(String privilegeStr) {
+    List<Authorizable> authorizables = Lists.newArrayList();
+    if (privilegeStr == null) {
+      return authorizables;
+    }
+
+    for (String authorizable : SentryConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) {
+      KeyValue tempKV = new KeyValue(authorizable);
+      final String key = tempKV.getKey();
+      final String value = tempKV.getValue();
+
+      authorizables.add(new Authorizable() {
+        @Override
+        public String getTypeName() {
+          return key;
+        }
+
+        @Override
+        public String getName() {
+          return value;
+        }
+      });
+    }
+
+    return authorizables;
+  }
+
+  // Construct the role to set of privileges mapping based on the
+  // MSentryGMPrivilege information.
+  private TSentryPrivilegeMap toTSentryPrivilegeMap(Set<MSentryGMPrivilege> mPrivileges) {
+
+    // Mapping of <Role, Set<Privilege>>.
+    Map<String, Set<TSentryPrivilege>> tPrivilegeMap = Maps.newTreeMap();
+
+    for (MSentryGMPrivilege mPrivilege : mPrivileges) {
+      for (MSentryRole role : mPrivilege.getRoles()) {
+
+        TSentryPrivilege tPrivilege = toTSentryPrivilege(mPrivilege);
+
+        if (tPrivilegeMap.containsKey(role.getRoleName())) {
+          tPrivilegeMap.get(role.getRoleName()).add(tPrivilege);
+        } else {
+          Set<TSentryPrivilege> tPrivilegeSet = Sets.newTreeSet();
+          tPrivilegeSet.add(tPrivilege);
+          tPrivilegeMap.put(role.getRoleName(), tPrivilegeSet);
+        }
+      }
+    }
+
+    return new TSentryPrivilegeMap(tPrivilegeMap);
+  }
+
+  // Construct TSentryPrivilege based on MSentryGMPrivilege information.
+  private TSentryPrivilege toTSentryPrivilege(MSentryGMPrivilege mPrivilege) {
+
+    TSentryPrivilege tPrivilege = new TSentryPrivilege(mPrivilege.getComponentName(),
+    mPrivilege.getServiceName(), fromAuthorizable(mPrivilege.getAuthorizables()), mPrivilege.getAction());
+
+    if (mPrivilege.getGrantOption() == null) {
+      tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+    } else if (mPrivilege.getGrantOption()) {
+      tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+    } else {
+      tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+    }
+
+    return tPrivilege;
+  }
+
+  private Set<String> buildPermissions(Set<PrivilegeObject> privileges) {
+    Set<String> permissions = Sets.newHashSet();
+    for (PrivilegeObject privilege : privileges) {
+      List<String> hierarchy = Lists.newArrayList();
+      if (hasComponentServerPrivilege(privilege.getComponent())) {
+        hierarchy.add(KV_JOINER.join("server", privilege.getService()));
+      }
+      for (Authorizable authorizable : privilege.getAuthorizables()) {
+        hierarchy.add(KV_JOINER.join(authorizable.getTypeName(),authorizable.getName()));
+      }
+      hierarchy.add(KV_JOINER.join("action", privilege.getAction()));
+      permissions.add(AUTHORIZABLE_JOINER.join(hierarchy));
+    }
+    return permissions;
+  }
+
+  private boolean hasComponentServerPrivilege(String component) {
+    //judge the component whether has the server privilege, for example: sqoop has the privilege on the server
+    return AuthorizationComponent.SQOOP.equalsIgnoreCase(component);
+  }
+
+  @Override
+  public TCreateSentryRoleResponse create_sentry_role(
+      final TCreateSentryRoleRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.createRole(request.getComponent(), request.getRoleName(), request.getRequestorUserName());
+        return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TCreateSentryRoleResponse tResponse = new TCreateSentryRoleResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.create_sentry_role(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for create role: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TDropSentryRoleResponse drop_sentry_role(final TDropSentryRoleRequest request)
+      throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.dropRole(request.getComponent(), request.getRoleName(), request.getRequestorUserName());
+        return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TDropSentryRoleResponse tResponse = new TDropSentryRoleResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.drop_sentry_role(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for drop role: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege(
+      final TAlterSentryRoleGrantPrivilegeRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        CommitContext context = store.alterRoleGrantPrivilege(request.getComponent(), request.getRoleName(), toPrivilegeObject(request.getPrivilege()), request.getRequestorUserName());
+       return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TAlterSentryRoleGrantPrivilegeResponse tResponse = new TAlterSentryRoleGrantPrivilegeResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.alter_sentry_role_grant_privilege(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for grant privilege to role: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege(
+      final TAlterSentryRoleRevokePrivilegeRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        CommitContext context = store.alterRoleRevokePrivilege(request.getComponent(), request.getRoleName(), toPrivilegeObject(request.getPrivilege()), request.getRequestorUserName());
+       return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TAlterSentryRoleRevokePrivilegeResponse tResponse = new TAlterSentryRoleRevokePrivilegeResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.alter_sentry_role_revoke_privilege(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for revoke privilege from role: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(
+      final TAlterSentryRoleAddGroupsRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.alterRoleAddGroups(request.getComponent(), request.getRoleName(), request.getGroups(), request.getRequestorUserName());
+        return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TAlterSentryRoleAddGroupsResponse tResponse = new TAlterSentryRoleAddGroupsResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.alter_sentry_role_add_groups(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for add role to group: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(
+      final TAlterSentryRoleDeleteGroupsRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.alterRoleDeleteGroups(request.getComponent(), request.getRoleName(), request.getGroups(), request.getRequestorUserName());
+        return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TAlterSentryRoleDeleteGroupsResponse tResponse = new TAlterSentryRoleDeleteGroupsResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.alter_sentry_role_delete_groups(respose.context, request, tResponse);
+    }
+
+    try {
+      AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+    } catch (Exception e) {
+      // if any exception, log the exception.
+      String msg = "Error in creating audit log for delete role from group: " + e.getMessage();
+      LOGGER.error(msg, e);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TListSentryRolesResponse list_sentry_roles_by_group(
+      final TListSentryRolesRequest request) throws TException {
+    Response<Set<TSentryRole>> respose = requestHandle(new RequestHandler<Set<TSentryRole>>() {
+      @Override
+      public Response<Set<TSentryRole>> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
+        if (!AccessConstants.ALL.equalsIgnoreCase(request.getGroupName())) {
+          boolean admin = inAdminGroups(groups);
+          //Only admin users can list all roles in the system ( groupname = null)
+          //Non admin users are only allowed to list only groups which they belong to
+          if(!admin && (request.getGroupName() == null || !groups.contains(request.getGroupName()))) {
+            throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + request.getRequestorUserName());
+          }
+          groups.clear();
+          groups.add(request.getGroupName());
+        }
+
+        Set<String> roleNames = store.getRolesByGroups(request.getComponent(), groups);
+        Set<TSentryRole> tSentryRoles = Sets.newHashSet();
+        for (String roleName : roleNames) {
+          Set<String> groupsForRoleName = store.getGroupsByRoles(request.getComponent(), Sets.newHashSet(roleName));
+          tSentryRoles.add(new TSentryRole(roleName, groupsForRoleName));
+        }
+        return new Response<Set<TSentryRole>>(Status.OK(), tSentryRoles);
+      }
+    });
+    TListSentryRolesResponse tResponse = new TListSentryRolesResponse();
+    tResponse.setStatus(respose.status);
+    tResponse.setRoles(respose.content);
+    return tResponse;
+  }
+
+  @Override
+  public TListSentryPrivilegesResponse list_sentry_privileges_by_role(
+      final TListSentryPrivilegesRequest request) throws TException {
+    Response<Set<TSentryPrivilege>> respose = requestHandle(new RequestHandler<Set<TSentryPrivilege>>() {
+      @Override
+      public Response<Set<TSentryPrivilege>> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
+        if (!inAdminGroups(groups)) {
+          Set<String> roleNamesForGroups = toTrimmedLower(store.getRolesByGroups(request.getComponent(), groups));
+          if (!roleNamesForGroups.contains(toTrimmedLower(request.getRoleName()))) {
+            throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + request.getRequestorUserName());
+          }
+        }
+        Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
+                                                                        request.getServiceName(),
+                                                                        Sets.newHashSet(request.getRoleName()),
+                                                                        null, toAuthorizables(request.getAuthorizables()));
+        Set<TSentryPrivilege> tSentryPrivileges = Sets.newHashSet();
+        for (PrivilegeObject privilege : privileges) {
+          tSentryPrivileges.add(fromPrivilegeObject(privilege));
+        }
+        return new Response<Set<TSentryPrivilege>>(Status.OK(), tSentryPrivileges);
+      }
+    });
+    TListSentryPrivilegesResponse tResponse = new TListSentryPrivilegesResponse();
+    tResponse.setStatus(respose.status);
+    tResponse.setPrivileges(respose.content);
+    return tResponse;
+  }
+
+  @Override
+  public TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider(
+      final TListSentryPrivilegesForProviderRequest request) throws TException {
+    Response<Set<String>> respose = requestHandle(new RequestHandler<Set<String>>() {
+      @Override
+      public Response<Set<String>> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        Set<String> activeRoleNames = toTrimmedLower(request.getRoleSet().getRoles());
+        Set<String> roleNamesForGroups = store.getRolesByGroups(request.getComponent(), request.getGroups());
+        Set<String> rolesToQuery = request.getRoleSet().isAll() ? roleNamesForGroups : Sets.intersection(activeRoleNames, roleNamesForGroups);
+        Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
+                                                                        request.getServiceName(),
+                                                                        rolesToQuery, null,
+                                                                        toAuthorizables(request.getAuthorizables()));
+        return new Response<Set<String>>(Status.OK(), buildPermissions(privileges));
+      }
+    });
+    TListSentryPrivilegesForProviderResponse tResponse = new TListSentryPrivilegesForProviderResponse();
+    tResponse.setStatus(respose.status);
+    tResponse.setPrivileges(respose.content);
+    return tResponse;
+  }
+
+  @Override
+  public TListSentryPrivilegesByAuthResponse list_sentry_privileges_by_authorizable(TListSentryPrivilegesByAuthRequest request) throws TException {
+
+    TListSentryPrivilegesByAuthResponse response = new TListSentryPrivilegesByAuthResponse();
+    Map<String, TSentryPrivilegeMap> authRoleMap = Maps.newHashMap();
+
+    // Group names are case sensitive.
+    Set<String> requestedGroups = request.getGroups();
+    String subject = request.getRequestorUserName();
+    TSentryActiveRoleSet activeRoleSet = request.getRoleSet();
+    Set<String> validActiveRoles = Sets.newHashSet();
+
+    try {
+      validateClientVersion(request.getProtocol_version());
+      Set<String> memberGroups = getRequestorGroups(conf, subject);
+
+      // Disallow non-admin users to lookup groups that
+      // they are not part of.
+      if(!inAdminGroups(memberGroups)) {
+
+        if (requestedGroups != null && !requestedGroups.isEmpty()) {
+          for (String requestedGroup : requestedGroups) {
+
+            // If user doesn't belong to one of the requested groups,
+            // then raise security exception.
+            if (!memberGroups.contains(requestedGroup)) {
+              throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + subject);
+            }
+          }
+        } else {
+          // Non-admin's search is limited to its own groups.
+          requestedGroups = memberGroups;
+        }
+
+        Set<String> grantedRoles = toTrimmedLower(store.getRolesByGroups(request.getComponent(), requestedGroups));
+
+        // If activeRoleSet is not null, disallow non-admin to lookup roles that they are not part of.
+        if (activeRoleSet != null && !activeRoleSet.isAll()) {
+
+          Set<String> activeRoleNames = toTrimmedLower(activeRoleSet.getRoles());
+          for (String activeRole : activeRoleNames) {
+            if (!grantedRoles.contains(activeRole)) {
+              throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE
+              + subject);
+            }
+          }
+
+          // For non-admin, valid active roles are intersection of active roles and granted roles.
+          validActiveRoles.addAll(activeRoleSet.isAll() ? grantedRoles : Sets.intersection(activeRoleNames, grantedRoles));
+        } else {
+          // For non-admin, if activeRoleSet is null, valid active roles would be the granted roles.
+          validActiveRoles.addAll(grantedRoles);
+        }
+      } else {
+        // For admin, if requestedGroups are empty, requested roles will be all roles.
+        Set<String> requestedRoles = toTrimmedLower(store.getAllRoleNames());
+        if (requestedGroups != null && !requestedGroups.isEmpty())  {
+          requestedRoles = toTrimmedLower(store.getRolesByGroups(request.getComponent(), requestedGroups));
+        }
+
+        // If activeRoleSet (which is optional) is not null, valid active role will be intersection
+        // of active roles and requested roles. Otherwise, valid active roles are the requested roles.
+        if (activeRoleSet != null && !activeRoleSet.isAll()) {
+          validActiveRoles.addAll(Sets.intersection(toTrimmedLower(activeRoleSet.getRoles()), requestedRoles));
+        } else {
+          validActiveRoles.addAll(requestedRoles);
+        }
+      }
+
+      // If user is not part of any group.. return empty response
+      if (request.getAuthorizablesSet() != null) {
+        for (String authorizablesStr : request.getAuthorizablesSet()) {
+
+          List<? extends Authorizable> authorizables = toAuthorizables(authorizablesStr);
+          Set<MSentryGMPrivilege> sentryPrivileges = store.getPrivilegesByAuthorizable(request.getComponent(), request.getServiceName(), validActiveRoles, authorizables);
+          authRoleMap.put(fromAuthorizableToStr(authorizables), toTSentryPrivilegeMap(sentryPrivileges));
+        }
+      }
+
+      response.setPrivilegesMapByAuth(authRoleMap);
+      response.setStatus(Status.OK());
+    } catch (SentryAccessDeniedException e) {
+      LOGGER.error(e.getMessage(), e);
+      response.setStatus(Status.AccessDenied(e.getMessage(), e));
+    } catch (SentryThriftAPIMismatchException e) {
+      LOGGER.error(e.getMessage(), e);
+      response.setStatus(Status.THRIFT_VERSION_MISMATCH(e.getMessage(), 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 TDropPrivilegesResponse drop_sentry_privilege(
+      final TDropPrivilegesRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.dropPrivilege(request.getComponent(),
+            toPrivilegeObject(request.getPrivilege()),
+            request.getRequestorUserName());
+        return new Response<Void>(Status.OK(), context);
+      }
+    });
+
+    TDropPrivilegesResponse tResponse = new TDropPrivilegesResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.drop_sentry_privilege(respose.context, request, tResponse);
+    }
+    return tResponse;
+  }
+
+  @Override
+  public TRenamePrivilegesResponse rename_sentry_privilege(
+      final TRenamePrivilegesRequest request) throws TException {
+    Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+      @Override
+      public Response<Void> handle() throws Exception {
+        validateClientVersion(request.getProtocol_version());
+        authorize(request.getRequestorUserName(),
+            getRequestorGroups(conf, request.getRequestorUserName()));
+        CommitContext context = store.renamePrivilege(request.getComponent(), request.getServiceName(),
+                                    toAuthorizables(request.getOldAuthorizables()),
+                                    toAuthorizables(request.getNewAuthorizables()),
+                                    request.getRequestorUserName());
+        return new Response<Void>(Status.OK(),context);
+      }
+    });
+
+    TRenamePrivilegesResponse tResponse = new TRenamePrivilegesResponse(respose.status);
+    if (Status.OK.getCode() == respose.status.getValue()) {
+      handerInvoker.rename_sentry_privilege(respose.context, request, tResponse);
+    }
+    return tResponse;
+  }
+
+  private static class Response<T> {
+    private TSentryResponseStatus status;
+    private CommitContext context;
+    private T content;
+
+    Response() {
+    }
+
+    Response(TSentryResponseStatus status, CommitContext context) {
+      this(status,context,null);
+    }
+
+    Response(TSentryResponseStatus status, T content) {
+      this(status,null,content);
+    }
+
+    Response(TSentryResponseStatus status, CommitContext context, T content) {
+      this.status = status;
+      this.context = context;
+      this.content = content;
+    }
+  }
+  private interface RequestHandler <T>{
+    Response<T> handle() throws Exception ;
+  }
+
+  private static void validateClientVersion(int protocolVersion) throws SentryThriftAPIMismatchException {
+    if (ServiceConstants.ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT != protocolVersion) {
+      String msg = "Sentry thrift API protocol version mismatch: Client thrift version " +
+          "is: " + protocolVersion + " , server thrift version " +
+              "is " + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT;
+      throw new SentryThriftAPIMismatchException(msg);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java
new file mode 100644
index 0000000..e9ff627
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java
@@ -0,0 +1,41 @@
+/**
+ * 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.generic.service.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.service.thrift.ProcessorFactory;
+import org.apache.sentry.service.thrift.ServiceConstants;
+import org.apache.thrift.TMultiplexedProcessor;
+import org.apache.thrift.TProcessor;
+
+public class SentryGenericPolicyProcessorFactory extends ProcessorFactory {
+
+  public SentryGenericPolicyProcessorFactory(Configuration conf) {
+    super(conf);
+  }
+
+  @Override
+  public boolean register(TMultiplexedProcessor multiplexedProcessor) throws Exception {
+    SentryGenericPolicyProcessor processHandler = new SentryGenericPolicyProcessor(conf);
+    TProcessor processor = new SentryGenericPolicyProcessorWrapper<SentryGenericPolicyService.Iface>(
+        processHandler);
+    multiplexedProcessor.registerProcessor(ServiceConstants.SENTRY_GENERIC_SERVICE_NAME, processor);
+    return true;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorWrapper.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorWrapper.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorWrapper.java
new file mode 100644
index 0000000..d320d0f
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorWrapper.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.generic.service.thrift;
+
+import org.apache.sentry.provider.db.service.thrift.ThriftUtil;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TProtocol;
+
+public class SentryGenericPolicyProcessorWrapper<I extends SentryGenericPolicyService.Iface>
+    extends SentryGenericPolicyService.Processor<SentryGenericPolicyService.Iface> {
+
+  public SentryGenericPolicyProcessorWrapper(I iface) {
+    super(iface);
+  }
+
+  @Override
+  public boolean process(TProtocol in, TProtocol out) throws TException {
+    // set the ip and impersonator for audit log
+    ThriftUtil.setIpAddress(in);
+    ThriftUtil.setImpersonator(in);
+    return super.process(in, out);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/AuditLoggerTestAppender.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/AuditLoggerTestAppender.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/AuditLoggerTestAppender.java
new file mode 100644
index 0000000..8000ebd
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/AuditLoggerTestAppender.java
@@ -0,0 +1,52 @@
+/*
+ * 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.log.appender;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.spi.LoggingEvent;
+
+import com.google.common.annotations.VisibleForTesting;
+
+@VisibleForTesting
+public class AuditLoggerTestAppender extends AppenderSkeleton {
+  public static final List<LoggingEvent> events = new ArrayList<LoggingEvent>();
+
+  public void close() {
+  }
+
+  public boolean requiresLayout() {
+    return false;
+  }
+
+  @Override
+  protected void append(LoggingEvent event) {
+    events.add(event);
+  }
+
+  public static String getLastLogEvent() {
+    return events.get(events.size() - 1).getMessage().toString();
+  }
+
+  public static Level getLastLogLevel() {
+    return events.get(events.size() - 1).getLevel();
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java
new file mode 100644
index 0000000..fd133f3
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java
@@ -0,0 +1,175 @@
+/**
+ * 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.log.appender;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Writer;
+
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.helpers.CountingQuietWriter;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.LoggingEvent;
+
+public class RollingFileWithoutDeleteAppender extends FileAppender {
+  /**
+   * The default maximum file size is 10MB.
+   */
+  protected long maxFileSize = 10 * 1024 * 1024;
+
+  private long nextRollover = 0;
+
+  /**
+   * The default constructor simply calls its {@link FileAppender#FileAppender
+   * parents constructor}.
+   */
+  public RollingFileWithoutDeleteAppender() {
+    super();
+  }
+
+  /**
+   * Instantiate a RollingFileAppender and open the file designated by
+   * <code>filename</code>. The opened filename will become the ouput
+   * destination for this appender.
+   * <p>
+   * If the <code>append</code> parameter is true, the file will be appended to.
+   * Otherwise, the file desginated by <code>filename</code> will be truncated
+   * before being opened.
+   */
+  public RollingFileWithoutDeleteAppender(Layout layout, String filename,
+      boolean append) throws IOException {
+    super(layout, getLogFileName(filename), append);
+  }
+
+  /**
+   * Instantiate a FileAppender and open the file designated by
+   * <code>filename</code>. The opened filename will become the output
+   * destination for this appender.
+   * <p>
+   * The file will be appended to.
+   */
+  public RollingFileWithoutDeleteAppender(Layout layout, String filename)
+      throws IOException {
+    super(layout, getLogFileName(filename));
+  }
+
+  /**
+   * Get the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   */
+  public long getMaximumFileSize() {
+    return maxFileSize;
+  }
+
+  /**
+   * Implements the usual roll over behaviour.
+   * <p>
+   * <code>File</code> is renamed <code>File.yyyyMMddHHmmss</code> and closed. A
+   * new <code>File</code> is created to receive further log output.
+   */
+  // synchronization not necessary since doAppend is alreasy synched
+  public void rollOver() {
+    if (qw != null) {
+      long size = ((CountingQuietWriter) qw).getCount();
+      LogLog.debug("rolling over count=" + size);
+      // if operation fails, do not roll again until
+      // maxFileSize more bytes are written
+      nextRollover = size + maxFileSize;
+    }
+
+    this.closeFile(); // keep windows happy.
+
+    String newFileName = getLogFileName(fileName);
+    try {
+      // This will also close the file. This is OK since multiple
+      // close operations are safe.
+      this.setFile(newFileName, false, bufferedIO, bufferSize);
+      nextRollover = 0;
+    } catch (IOException e) {
+      if (e instanceof InterruptedIOException) {
+        Thread.currentThread().interrupt();
+      }
+      LogLog.error("setFile(" + newFileName + ", false) call failed: "  + e.getMessage(), e);
+    }
+  }
+
+  public synchronized void setFile(String fileName, boolean append,
+      boolean bufferedIO, int bufferSize) throws IOException {
+    super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
+    if (append) {
+      File f = new File(fileName);
+      ((CountingQuietWriter) qw).setCount(f.length());
+    }
+  }
+
+  /**
+   * Set the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   * <p>
+   * This method is equivalent to {@link #setMaxFileSize} except that it is
+   * required for differentiating the setter taking a <code>long</code> argument
+   * from the setter taking a <code>String</code> argument by the JavaBeans
+   * {@link java.beans.Introspector Introspector}.
+   *
+   * @see #setMaxFileSize(String)
+   */
+  public void setMaximumFileSize(long maxFileSize) {
+    this.maxFileSize = maxFileSize;
+  }
+
+  /**
+   * Set the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   * <p>
+   * In configuration files, the <b>MaxFileSize</b> option takes an long integer
+   * in the range 0 - 2^63. You can specify the value with the suffixes "KB",
+   * "MB" or "GB" so that the integer is interpreted being expressed
+   * respectively in kilobytes, megabytes or gigabytes. For example, the value
+   * "10KB" will be interpreted as 10240.
+   */
+  public void setMaxFileSize(String value) {
+    maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
+  }
+
+  protected void setQWForFiles(Writer writer) {
+    this.qw = new CountingQuietWriter(writer, errorHandler);
+  }
+
+  /**
+   * This method differentiates RollingFileAppender from its super class.
+   */
+  protected void subAppend(LoggingEvent event) {
+    super.subAppend(event);
+
+    if (fileName != null && qw != null) {
+      long size = ((CountingQuietWriter) qw).getCount();
+      if (size >= maxFileSize && size >= nextRollover) {
+        rollOver();
+      }
+    }
+  }
+
+  // Mangled file name. Append the current timestamp
+  private static String getLogFileName(String oldFileName) {
+    return oldFileName + "." + Long.toString(System.currentTimeMillis());
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java
new file mode 100644
index 0000000..a5fe4ec
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java
@@ -0,0 +1,155 @@
+/**
+ * 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.log.entity;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.MappingJsonFactory;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.node.ContainerNode;
+
+abstract public class AuditMetadataLogEntity implements JsonLogEntity {
+
+  static final JsonFactory factory = new MappingJsonFactory();
+  private String serviceName;
+  private String userName;
+  private String impersonator;
+  private String ipAddress;
+  private String operation;
+  private String eventTime;
+  private String operationText;
+  private String allowed;
+  private String objectType;
+  private String component;
+
+  void setCommonAttr(String serviceName, String userName, String impersonator, String ipAddress,
+      String operation, String eventTime, String operationText, String allowed, String objectType,
+      String component) {
+    this.serviceName = serviceName;
+    this.userName = userName;
+    this.impersonator = impersonator;
+    this.ipAddress = ipAddress;
+    this.operation = operation;
+    this.eventTime = eventTime;
+    this.operationText = operationText;
+    this.allowed = allowed;
+    this.objectType = objectType;
+    this.component = component;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  public String getUserName() {
+    return userName;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  public String getImpersonator() {
+    return impersonator;
+  }
+
+  public void setImpersonator(String impersonator) {
+    this.impersonator = impersonator;
+  }
+
+  public String getIpAddress() {
+    return ipAddress;
+  }
+
+  public void setIpAddress(String ipAddress) {
+    this.ipAddress = ipAddress;
+  }
+
+  public String getOperation() {
+    return operation;
+  }
+
+  public void setOperation(String operation) {
+    this.operation = operation;
+  }
+
+  public String getEventTime() {
+    return eventTime;
+  }
+
+  public void setEventTime(String eventTime) {
+    this.eventTime = eventTime;
+  }
+
+  public String getOperationText() {
+    return operationText;
+  }
+
+  public void setOperationText(String operationText) {
+    this.operationText = operationText;
+  }
+
+  public String getAllowed() {
+    return allowed;
+  }
+
+  public void setAllowed(String allowed) {
+    this.allowed = allowed;
+  }
+
+  public String getObjectType() {
+    return objectType;
+  }
+
+  public void setObjectType(String objectType) {
+    this.objectType = objectType;
+  }
+
+  public String getComponent() {
+    return component;
+  }
+
+  public void setComponent(String component) {
+    this.component = component;
+  }
+
+  /**
+   * For use in tests
+   * 
+   * @param json
+   *          incoming JSON to parse
+   * @return a node tree
+   * @throws IOException
+   *           on any parsing problems
+   */
+  public static ContainerNode parse(String json) throws IOException {
+    ObjectMapper mapper = new ObjectMapper(factory);
+    JsonNode jsonNode = mapper.readTree(json);
+    if (!(jsonNode instanceof ContainerNode)) {
+      throw new IOException("Wrong JSON data: " + json);
+    }
+    return (ContainerNode) jsonNode;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java
new file mode 100644
index 0000000..4949ac7
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java
@@ -0,0 +1,124 @@
+/**
+ * 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.log.entity;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.codehaus.jackson.JsonGenerator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DBAuditMetadataLogEntity extends AuditMetadataLogEntity {
+  private static final Logger LOGGER = LoggerFactory.getLogger(DBAuditMetadataLogEntity.class);
+
+  private String databaseName;
+  private String tableName;
+  private String columnName;
+  private String resourcePath;
+
+  public DBAuditMetadataLogEntity() {
+  }
+
+  public DBAuditMetadataLogEntity(String serviceName, String userName, String impersonator,
+      String ipAddress, String operation, String eventTime, String operationText, String allowed,
+      String objectType, String component, String databaseName, String tableName,
+      String columnName, String resourcePath) {
+    setCommonAttr(serviceName, userName, impersonator, ipAddress, operation, eventTime,
+        operationText, allowed, objectType, component);
+    this.databaseName = databaseName;
+    this.tableName = tableName;
+    this.columnName = columnName;
+    this.resourcePath = resourcePath;
+  }
+
+  public String getDatabaseName() {
+    return databaseName;
+  }
+
+  public void setDatabaseName(String databaseName) {
+    this.databaseName = databaseName;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getColumnName() {
+    return columnName;
+  }
+
+  public void setColumnName(String columnName) {
+    this.columnName = columnName;
+  }
+
+  public String getResourcePath() {
+    return resourcePath;
+  }
+
+  public void setResourcePath(String resourcePath) {
+    this.resourcePath = resourcePath;
+  }
+
+  @Override
+  public String toJsonFormatLog() throws Exception {
+    StringWriter stringWriter = new StringWriter();
+    JsonGenerator json = null;
+    try {
+      json = factory.createJsonGenerator(stringWriter);
+      json.writeStartObject();
+      json.writeStringField(Constants.LOG_FIELD_SERVICE_NAME, getServiceName());
+      json.writeStringField(Constants.LOG_FIELD_USER_NAME, getUserName());
+      json.writeStringField(Constants.LOG_FIELD_IMPERSONATOR, getImpersonator());
+      json.writeStringField(Constants.LOG_FIELD_IP_ADDRESS, getIpAddress());
+      json.writeStringField(Constants.LOG_FIELD_OPERATION, getOperation());
+      json.writeStringField(Constants.LOG_FIELD_EVENT_TIME, getEventTime());
+      json.writeStringField(Constants.LOG_FIELD_OPERATION_TEXT, getOperationText());
+      json.writeStringField(Constants.LOG_FIELD_ALLOWED, getAllowed());
+      json.writeStringField(Constants.LOG_FIELD_DATABASE_NAME, databaseName);
+      json.writeStringField(Constants.LOG_FIELD_TABLE_NAME, tableName);
+      json.writeStringField(Constants.LOG_FIELD_COLUMN_NAME, columnName);
+      json.writeStringField(Constants.LOG_FIELD_RESOURCE_PATH, resourcePath);
+      json.writeStringField(Constants.LOG_FIELD_OBJECT_TYPE, getObjectType());
+      json.writeEndObject();
+      json.flush();
+    } catch (IOException e) {
+      String msg = "Error creating audit log in json format: " + e.getMessage();
+      LOGGER.error(msg, e);
+      throw e;
+    } finally {
+      try {
+        if (json != null) {
+          json.close();
+        }
+      } catch (IOException e) {
+        String msg = "Error when close json object: " + e.getMessage();
+        LOGGER.error(msg, e);
+        throw e;
+      }
+    }
+
+    return stringWriter.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java
new file mode 100644
index 0000000..6911772
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.log.entity;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.codehaus.jackson.JsonGenerator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GMAuditMetadataLogEntity extends AuditMetadataLogEntity {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(GMAuditMetadataLogEntity.class);
+  private Map<String, String> privilegesMap;
+
+  public GMAuditMetadataLogEntity() {
+    privilegesMap = new LinkedHashMap<String, String>();
+  }
+
+  public GMAuditMetadataLogEntity(String serviceName, String userName, String impersonator,
+      String ipAddress, String operation, String eventTime, String operationText, String allowed,
+      String objectType, String component, Map<String, String> privilegesMap) {
+    setCommonAttr(serviceName, userName, impersonator, ipAddress, operation, eventTime,
+        operationText, allowed, objectType, component);
+    this.privilegesMap = privilegesMap;
+  }
+
+  @Override
+  public String toJsonFormatLog() throws Exception {
+    StringWriter stringWriter = new StringWriter();
+    JsonGenerator json = null;
+    try {
+      json = factory.createJsonGenerator(stringWriter);
+      json.writeStartObject();
+      json.writeStringField(Constants.LOG_FIELD_SERVICE_NAME, getServiceName());
+      json.writeStringField(Constants.LOG_FIELD_USER_NAME, getUserName());
+      json.writeStringField(Constants.LOG_FIELD_IMPERSONATOR, getImpersonator());
+      json.writeStringField(Constants.LOG_FIELD_IP_ADDRESS, getIpAddress());
+      json.writeStringField(Constants.LOG_FIELD_OPERATION, getOperation());
+      json.writeStringField(Constants.LOG_FIELD_EVENT_TIME, getEventTime());
+      json.writeStringField(Constants.LOG_FIELD_OPERATION_TEXT, getOperationText());
+      json.writeStringField(Constants.LOG_FIELD_ALLOWED, getAllowed());
+      for (Map.Entry<String, String> entry : privilegesMap.entrySet()) {
+        json.writeStringField(entry.getKey(), entry.getValue());
+      }
+      json.writeStringField(Constants.LOG_FIELD_OBJECT_TYPE, getObjectType());
+      json.writeStringField(Constants.LOG_FIELD_COMPONENT, getComponent());
+      json.writeEndObject();
+      json.flush();
+    } catch (IOException e) {
+      String msg = "Error creating audit log in json format: " + e.getMessage();
+      LOGGER.error(msg, e);
+      throw e;
+    } finally {
+      try {
+        if (json != null) {
+          json.close();
+        }
+      } catch (IOException e) {
+        String msg = "Error when close json object: " + e.getMessage();
+        LOGGER.error(msg, e);
+        throw e;
+      }
+    }
+
+    return stringWriter.toString();
+  }
+
+  public Map<String, String> getPrivilegesMap() {
+    return privilegesMap;
+  }
+
+  public void setPrivilegesMap(Map<String, String> privilegesMap) {
+    this.privilegesMap = privilegesMap;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java
new file mode 100644
index 0000000..913f125
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.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.log.entity;
+
+public interface JsonLogEntity {
+
+  String toJsonFormatLog() throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java
new file mode 100644
index 0000000..f6bb8a5
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java
@@ -0,0 +1,351 @@
+/**
+ * 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.log.entity;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.generic.service.thrift.TAuthorizable;
+import org.apache.sentry.provider.db.log.util.CommandUtil;
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddGroupsRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddGroupsResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddUsersRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddUsersResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteGroupsRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteGroupsResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteUsersRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteUsersResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleGrantPrivilegeRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleGrantPrivilegeResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleRevokePrivilegeRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleRevokePrivilegeResponse;
+import org.apache.sentry.provider.db.service.thrift.TCreateSentryRoleRequest;
+import org.apache.sentry.provider.db.service.thrift.TCreateSentryRoleResponse;
+import org.apache.sentry.provider.db.service.thrift.TDropSentryRoleRequest;
+import org.apache.sentry.provider.db.service.thrift.TDropSentryRoleResponse;
+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.ThriftUtil;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.service.thrift.Status;
+import org.apache.sentry.service.thrift.TSentryResponseStatus;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+
+public final class JsonLogEntityFactory {
+
+  private static JsonLogEntityFactory factory = new JsonLogEntityFactory();
+
+  private JsonLogEntityFactory() {
+  }
+
+  public static JsonLogEntityFactory getInstance() {
+    return factory;
+  }
+
+  // log entity for hive/impala create role
+  public JsonLogEntity createJsonLogEntity(TCreateSentryRoleRequest request,
+      TCreateSentryRoleResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    hamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(
+        request.getRoleName(), true));
+
+    return hamle;
+  }
+
+  // log entity for hive/impala drop role
+  public JsonLogEntity createJsonLogEntity(TDropSentryRoleRequest request,
+      TDropSentryRoleResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    hamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(
+        request.getRoleName(), false));
+
+    return hamle;
+  }
+
+  // log entity for hive/impala grant privilege
+  public Set<JsonLogEntity> createJsonLogEntitys(
+      TAlterSentryRoleGrantPrivilegeRequest request,
+      TAlterSentryRoleGrantPrivilegeResponse response, Configuration conf) {
+    ImmutableSet.Builder<JsonLogEntity> setBuilder = ImmutableSet.builder();
+    if (request.isSetPrivileges()) {
+      for (TSentryPrivilege privilege : request.getPrivileges()) {
+        JsonLogEntity logEntity = createJsonLogEntity(request, privilege, response, conf);
+        setBuilder.add(logEntity);
+      }
+    }
+    return setBuilder.build();
+  }
+
+  private JsonLogEntity createJsonLogEntity(
+      TAlterSentryRoleGrantPrivilegeRequest request, TSentryPrivilege privilege,
+      TAlterSentryRoleGrantPrivilegeResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    hamle.setOperationText(CommandUtil.createCmdForGrantPrivilege(request));
+    hamle.setDatabaseName(privilege.getDbName());
+    hamle.setTableName(privilege.getTableName());
+    hamle.setResourcePath(privilege.getURI());
+    return hamle;
+  }
+
+  // log entity for hive/impala revoke privilege
+  public Set<JsonLogEntity> createJsonLogEntitys(
+      TAlterSentryRoleRevokePrivilegeRequest request,
+      TAlterSentryRoleRevokePrivilegeResponse response, Configuration conf) {
+    ImmutableSet.Builder<JsonLogEntity> setBuilder = ImmutableSet.builder();
+    if (request.isSetPrivileges()) {
+      for (TSentryPrivilege privilege : request.getPrivileges()) {
+        JsonLogEntity logEntity = createJsonLogEntity(request, privilege, response, conf);
+        setBuilder.add(logEntity);
+      }
+    }
+    return setBuilder.build();
+  }
+
+  private JsonLogEntity createJsonLogEntity(
+      TAlterSentryRoleRevokePrivilegeRequest request, TSentryPrivilege privilege,
+      TAlterSentryRoleRevokePrivilegeResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    hamle.setOperationText(CommandUtil.createCmdForRevokePrivilege(request));
+    hamle.setDatabaseName(privilege.getDbName());
+    hamle.setTableName(privilege.getTableName());
+    hamle.setResourcePath(privilege.getURI());
+
+    return hamle;
+  }
+
+  // log entity for hive/impala add role to group
+  public JsonLogEntity createJsonLogEntity(
+      TAlterSentryRoleAddGroupsRequest request,
+      TAlterSentryRoleAddGroupsResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    String groups = getGroupsStr(request.getGroupsIterator());
+    hamle.setOperationText(CommandUtil.createCmdForRoleAddGroup(request.getRoleName(), groups));
+
+    return hamle;
+  }
+
+  // log entity for hive/impala delete role from group
+  public JsonLogEntity createJsonLogEntity(
+      TAlterSentryRoleDeleteGroupsRequest request,
+      TAlterSentryRoleDeleteGroupsResponse response, Configuration conf) {
+    DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    String groups = getGroupsStr(request.getGroupsIterator());
+    hamle.setOperationText(CommandUtil.createCmdForRoleDeleteGroup(request.getRoleName(), groups));
+
+    return hamle;
+  }
+
+  private String getGroupsStr(Iterator<TSentryGroup> iter) {
+    StringBuilder groups = new StringBuilder("");
+    if (iter != null) {
+      boolean commaFlg = false;
+      while (iter.hasNext()) {
+        if (commaFlg) {
+          groups.append(", ");
+        } else {
+          commaFlg = true;
+        }
+        groups.append(iter.next().getGroupName());
+      }
+    }
+    return groups.toString();
+  }
+
+  public JsonLogEntity createJsonLogEntity(TAlterSentryRoleAddUsersRequest request,
+      TAlterSentryRoleAddUsersResponse response, Configuration conf) {
+    AuditMetadataLogEntity amle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    String users = getUsersStr(request.getUsersIterator());
+    amle.setOperationText(CommandUtil.createCmdForRoleAddUser(request.getRoleName(), users));
+
+    return amle;
+  }
+
+  public JsonLogEntity createJsonLogEntity(TAlterSentryRoleDeleteUsersRequest request,
+      TAlterSentryRoleDeleteUsersResponse response, Configuration conf) {
+    AuditMetadataLogEntity amle = createCommonHAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName());
+    String users = getUsersStr(request.getUsersIterator());
+    amle.setOperationText(CommandUtil.createCmdForRoleDeleteUser(request.getRoleName(), users));
+
+    return amle;
+  }
+
+  private String getUsersStr(Iterator<String> iter) {
+    StringBuilder users = new StringBuilder("");
+    if (iter != null) {
+      boolean commaFlg = false;
+      while (iter.hasNext()) {
+        if (commaFlg) {
+          users.append(", ");
+        } else {
+          commaFlg = true;
+        }
+        users.append(iter.next());
+      }
+    }
+    return users.toString();
+  }
+
+  public String isAllowed(TSentryResponseStatus status) {
+    if (status.equals(Status.OK())) {
+      return Constants.TRUE;
+    }
+    return Constants.FALSE;
+  }
+
+  // log entity for generic model create role
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    gmamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(request.getRoleName(), true));
+
+    return gmamle;
+  }
+
+  // log entity for generic model drop role
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    gmamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(request.getRoleName(), false));
+
+    return gmamle;
+  }
+
+  // log entity for generic model grant privilege
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    if (request.getPrivilege() != null) {
+      List<TAuthorizable> authorizables = request.getPrivilege().getAuthorizables();
+      Map<String, String> privilegesMap = new LinkedHashMap<String, String>();
+      if (authorizables != null) {
+        for (TAuthorizable authorizable : authorizables) {
+          privilegesMap.put(authorizable.getType(), authorizable.getName());
+        }
+      }
+      gmamle.setPrivilegesMap(privilegesMap);
+    }
+    gmamle.setOperationText(CommandUtil.createCmdForGrantGMPrivilege(request));
+
+    return gmamle;
+  }
+
+  // log entity for generic model revoke privilege
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    if (request.getPrivilege() != null) {
+      List<TAuthorizable> authorizables = request.getPrivilege().getAuthorizables();
+      Map<String, String> privilegesMap = new LinkedHashMap<String, String>();
+      if (authorizables != null) {
+        for (TAuthorizable authorizable : authorizables) {
+          privilegesMap.put(authorizable.getType(), authorizable.getName());
+        }
+      }
+      gmamle.setPrivilegesMap(privilegesMap);
+    }
+    gmamle.setOperationText(CommandUtil.createCmdForRevokeGMPrivilege(request));
+
+    return gmamle;
+  }
+
+  // log entity for generic model add role to group
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    Joiner joiner = Joiner.on(",");
+    String groups = joiner.join(request.getGroupsIterator());
+    gmamle.setOperationText(CommandUtil.createCmdForRoleAddGroup(request.getRoleName(), groups));
+
+    return gmamle;
+  }
+
+  // log entity for hive delete role from group
+  public JsonLogEntity createJsonLogEntity(
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsRequest request,
+      org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsResponse response,
+      Configuration conf) {
+    GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(),
+        request.getRequestorUserName(), request.getClass().getName(), request.getComponent());
+    Joiner joiner = Joiner.on(",");
+    String groups = joiner.join(request.getGroupsIterator());
+    gmamle.setOperationText(CommandUtil.createCmdForRoleDeleteGroup(request.getRoleName(), groups));
+
+    return gmamle;
+  }
+
+  private DBAuditMetadataLogEntity createCommonHAMLE(Configuration conf,
+      TSentryResponseStatus responseStatus, String userName, String requestClassName) {
+    DBAuditMetadataLogEntity hamle = new DBAuditMetadataLogEntity();
+    setCommAttrForAMLE(hamle, conf, responseStatus, userName, requestClassName);
+    return hamle;
+  }
+
+  private GMAuditMetadataLogEntity createCommonGMAMLE(Configuration conf,
+      TSentryResponseStatus responseStatus, String userName, String requestClassName,
+      String component) {
+    GMAuditMetadataLogEntity gmamle = new GMAuditMetadataLogEntity();
+    setCommAttrForAMLE(gmamle, conf, responseStatus, userName, requestClassName);
+    gmamle.setComponent(component);
+    return gmamle;
+  }
+
+  private void setCommAttrForAMLE(AuditMetadataLogEntity amle, Configuration conf,
+      TSentryResponseStatus responseStatus, String userName, String requestClassName) {
+    amle.setUserName(userName);
+    amle.setServiceName(conf.get(ServerConfig.SENTRY_SERVICE_NAME,
+        ServerConfig.SENTRY_SERVICE_NAME_DEFAULT).trim());
+    amle.setImpersonator(ThriftUtil.getImpersonator());
+    amle.setIpAddress(ThriftUtil.getIpAddress());
+    amle.setOperation(Constants.requestTypeToOperationMap.get(requestClassName));
+    amle.setEventTime(Long.toString(System.currentTimeMillis()));
+    amle.setAllowed(isAllowed(responseStatus));
+    amle.setObjectType(Constants.requestTypeToObjectTypeMap
+        .get(requestClassName));
+  }
+}