You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by ha...@apache.org on 2017/01/17 19:06:50 UTC

sentry git commit: SENTRY-1594: TransactionBlock should become generic (Alexander Kolbasov, Reviewed by: Hao Hao)

Repository: sentry
Updated Branches:
  refs/heads/master 58d76b93a -> 62bdcbfe9


SENTRY-1594: TransactionBlock should become generic (Alexander Kolbasov, Reviewed by: Hao Hao)

Change-Id: Ib5a00f92c45c8be652c4c1cff268602213f2e53e


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

Branch: refs/heads/master
Commit: 62bdcbfe90e85dba65ee6992c3e7c6ad9ed985e9
Parents: 58d76b9
Author: hahao <ha...@cloudera.com>
Authored: Tue Jan 17 11:05:52 2017 -0800
Committer: hahao <ha...@cloudera.com>
Committed: Tue Jan 17 11:05:52 2017 -0800

----------------------------------------------------------------------
 .../service/persistent/DelegateSentryStore.java | 181 ++++----
 .../db/service/persistent/SentryStore.java      | 423 ++++++++++---------
 .../db/service/persistent/TransactionBlock.java |  15 +-
 .../service/persistent/TransactionManager.java  |  32 +-
 4 files changed, 330 insertions(+), 321 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/62bdcbfe/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java
index 57b6eff..145808c 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java
@@ -63,7 +63,7 @@ public class DelegateSentryStore implements SentryStoreLayer {
   private Set<String> adminGroups;
   private PrivilegeOperatePersistence privilegeOperator;
 
-  public DelegateSentryStore(Configuration conf) throws Exception {
+  DelegateSentryStore(Configuration conf) throws Exception {
     this.privilegeOperator = new PrivilegeOperatePersistence(conf);
     // The generic model doesn't turn on the thread that cleans hive privileges
     conf.set(ServerConfig.SENTRY_STORE_ORPHANED_PRIVILEGE_REMOVAL,"false");
@@ -128,7 +128,7 @@ public class DelegateSentryStore implements SentryStoreLayer {
             if (mRole == null) {
               throw new SentryNoSuchObjectException("Role: " + trimmedRole + " doesn't exist");
             }
-            /**
+            /*
              * check with grant option
              */
             grantOptionCheck(privilege, grantorPrincipal, pm);
@@ -152,7 +152,7 @@ public class DelegateSentryStore implements SentryStoreLayer {
             if (mRole == null) {
               throw new SentryNoSuchObjectException("Role: " + trimmedRole + " doesn't exist");
             }
-            /**
+            /*
              * check with grant option
              */
             grantOptionCheck(privilege, grantorPrincipal, pm);
@@ -209,12 +209,10 @@ public class DelegateSentryStore implements SentryStoreLayer {
 
   /**
    * Grant option check
-   * @param component
-   * @param pm
-   * @param privilegeReader
    * @throws SentryUserException
    */
-  private void grantOptionCheck(PrivilegeObject requestPrivilege, String grantorPrincipal,PersistenceManager pm)
+  private void grantOptionCheck(PrivilegeObject requestPrivilege,
+                                String grantorPrincipal,PersistenceManager pm)
       throws SentryUserException {
 
     if (Strings.isNullOrEmpty(grantorPrincipal)) {
@@ -260,30 +258,30 @@ public class DelegateSentryStore implements SentryStoreLayer {
       return groupNames;
     }
 
-    return (Set<String>) delegate.getTransactionManager().executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            //get groups by roles
-            Query query = pm.newQuery(MSentryGroup.class);
-            StringBuilder filters = new StringBuilder();
-            query.declareVariables("MSentryRole role");
-            List<String> rolesFiler = new LinkedList<String>();
-            for (String role : trimmedRoles) {
-              rolesFiler.add("role.roleName == \"" + role + "\" ");
-            }
-            filters.append("roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")");
-            query.setFilter(filters.toString());
-
-            List<MSentryGroup> groups = (List<MSentryGroup>)query.execute();
-            if (groups == null) {
-              return groupNames;
-            }
-            for (MSentryGroup group : groups) {
-              groupNames.add(group.getGroupName());
-            }
+    return delegate.getTransactionManager().executeTransaction(
+      new TransactionBlock<Set<String>>() {
+        public Set<String> execute(PersistenceManager pm) throws Exception {
+          //get groups by roles
+          Query query = pm.newQuery(MSentryGroup.class);
+          StringBuilder filters = new StringBuilder();
+          query.declareVariables("MSentryRole role");
+          List<String> rolesFiler = new LinkedList<String>();
+          for (String role : trimmedRoles) {
+            rolesFiler.add("role.roleName == \"" + role + "\" ");
+          }
+          filters.append("roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")");
+          query.setFilter(filters.toString());
+          @SuppressWarnings("unchecked")
+          List<MSentryGroup> groups = (List<MSentryGroup>)query.execute();
+          if (groups == null) {
             return groupNames;
           }
-        });
+          for (MSentryGroup group : groups) {
+            groupNames.add(group.getGroupName());
+          }
+          return groupNames;
+        }
+      });
   }
 
   @Override
@@ -295,20 +293,20 @@ public class DelegateSentryStore implements SentryStoreLayer {
       return privileges;
     }
 
-    return (Set<PrivilegeObject>) delegate.getTransactionManager().executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            Set<MSentryRole> mRoles = Sets.newHashSet();
-            for (String role : roles) {
-              MSentryRole mRole = getRole(toTrimmedLower(role), pm);
-              if (mRole != null) {
-                mRoles.add(mRole);
-              }
+    return delegate.getTransactionManager().executeTransaction(
+      new TransactionBlock<Set<PrivilegeObject>>() {
+        public Set<PrivilegeObject> execute(PersistenceManager pm) throws Exception {
+          Set<MSentryRole> mRoles = Sets.newHashSet();
+          for (String role : roles) {
+            MSentryRole mRole = getRole(toTrimmedLower(role), pm);
+            if (mRole != null) {
+              mRoles.add(mRole);
             }
-            privileges.addAll(privilegeOperator.getPrivilegesByRole(mRoles, pm));
-            return privileges;
           }
-        });
+          privileges.addAll(privilegeOperator.getPrivilegesByRole(mRoles, pm));
+          return privileges;
+        }
+      });
   }
 
   @Override
@@ -318,36 +316,38 @@ public class DelegateSentryStore implements SentryStoreLayer {
     Preconditions.checkNotNull(component);
     Preconditions.checkNotNull(service);
 
-    return (Set<PrivilegeObject>) delegate.getTransactionManager().executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            String trimmedComponent = toTrimmedLower(component);
-            String trimmedService = toTrimmedLower(service);
+    return delegate.getTransactionManager().executeTransaction(
+      new TransactionBlock<Set<PrivilegeObject>>() {
+        public Set<PrivilegeObject> execute(PersistenceManager pm) throws Exception {
+          String trimmedComponent = toTrimmedLower(component);
+          String trimmedService = toTrimmedLower(service);
 
-            Set<PrivilegeObject> privileges = Sets.newHashSet();
-            //CaseInsensitive roleNames
-            Set<String> trimmedRoles = toTrimmedLower(roles);
+          Set<PrivilegeObject> privileges = Sets.newHashSet();
+          //CaseInsensitive roleNames
+          Set<String> trimmedRoles = toTrimmedLower(roles);
 
-            if (groups != null) {
-              trimmedRoles.addAll(delegate.getRoleNamesForGroups(groups));
-            }
+          if (groups != null) {
+            trimmedRoles.addAll(delegate.getRoleNamesForGroups(groups));
+          }
 
-            if (trimmedRoles.size() == 0) {
-              return privileges;
-            }
+          if (trimmedRoles.size() == 0) {
+            return privileges;
+          }
 
-            Set<MSentryRole> mRoles = Sets.newHashSet();
-            for (String role : trimmedRoles) {
-              MSentryRole mRole = getRole(role, pm);
-              if (mRole != null) {
-                mRoles.add(mRole);
-              }
+          Set<MSentryRole> mRoles = Sets.newHashSet();
+          for (String role : trimmedRoles) {
+            MSentryRole mRole = getRole(role, pm);
+            if (mRole != null) {
+              mRoles.add(mRole);
             }
-            //get the privileges
-            privileges.addAll(privilegeOperator.getPrivilegesByProvider(trimmedComponent, trimmedService, mRoles, authorizables, pm));
-            return privileges;
           }
-        });
+          //get the privileges
+          privileges.addAll(privilegeOperator.
+                  getPrivilegesByProvider(trimmedComponent,
+                          trimmedService, mRoles, authorizables, pm));
+          return privileges;
+        }
+      });
   }
 
   @Override
@@ -363,34 +363,35 @@ public class DelegateSentryStore implements SentryStoreLayer {
       return privileges;
     }
 
-    return (Set<MSentryGMPrivilege>) delegate.getTransactionManager().executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            String lComponent = toTrimmedLower(component);
-            String lService = toTrimmedLower(service);
-            Set<MSentryRole> mRoles = Sets.newHashSet();
-            for (String role : validActiveRoles) {
-              MSentryRole mRole = getRole(role, pm);
-              if (mRole != null) {
-                mRoles.add(mRole);
-              }
+    return delegate.getTransactionManager().executeTransaction(
+      new TransactionBlock<Set<MSentryGMPrivilege>>() {
+        public Set<MSentryGMPrivilege> execute(PersistenceManager pm) throws Exception {
+          String lComponent = toTrimmedLower(component);
+          String lService = toTrimmedLower(service);
+          Set<MSentryRole> mRoles = Sets.newHashSet();
+          for (String role : validActiveRoles) {
+            MSentryRole mRole = getRole(role, pm);
+            if (mRole != null) {
+              mRoles.add(mRole);
             }
+          }
 
-            //get the privileges
-            Set<MSentryGMPrivilege> mSentryGMPrivileges =
-                privilegeOperator.getPrivilegesByAuthorizable(lComponent, lService, mRoles, authorizables, pm);
-
-            for (MSentryGMPrivilege mSentryGMPrivilege : mSentryGMPrivileges) {
-              /**
-               * force to load all roles related this privilege
-               * avoid the lazy-loading
-               */
-              pm.retrieve(mSentryGMPrivilege);
-              privileges.add(mSentryGMPrivilege);
-            }
-            return privileges;
+          //get the privileges
+          Set<MSentryGMPrivilege> mSentryGMPrivileges =
+              privilegeOperator.getPrivilegesByAuthorizable(lComponent, lService,
+                      mRoles, authorizables, pm);
+
+          for (MSentryGMPrivilege mSentryGMPrivilege : mSentryGMPrivileges) {
+            /*
+             * force to load all roles related this privilege
+             * avoid the lazy-loading
+             */
+            pm.retrieve(mSentryGMPrivilege);
+            privileges.add(mSentryGMPrivilege);
           }
-        });
+          return privileges;
+        }
+      });
   }
 
    @Override

http://git-wip-us.apache.org/repos/asf/sentry/blob/62bdcbfe/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index b7ae634..321c094 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -304,6 +304,7 @@ public class SentryStore {
   private String trimAndLower(String input) {
     return input.trim().toLowerCase();
   }
+
   /**
    * Create a sentry role and persist it. Role name is the primary key for the
    * role, so an attempt to create a role which exists fails with JDO exception.
@@ -334,9 +335,9 @@ public class SentryStore {
      */
   private <T> Long getCount(final Class<T> tClass) {
     try {
-      return (Long) tm.executeTransaction(
-          new TransactionBlock() {
-            public Object execute(PersistenceManager pm) throws Exception {
+      return tm.executeTransaction(
+          new TransactionBlock<Long>() {
+            public Long execute(PersistenceManager pm) throws Exception {
               Query query = pm.newQuery();
               query.setClass(tClass);
               query.setResult("count(this)");
@@ -387,7 +388,7 @@ public class SentryStore {
   /**
    * @return Number of users
    */
-  public Gauge<Long> getUserCountGauge() {
+  Gauge<Long> getUserCountGauge() {
     return new Gauge<Long>() {
       @Override
       public Long getValue() {
@@ -432,7 +433,7 @@ public class SentryStore {
    * @param privilege Privilege to grant
    * @throws Exception
    */
-  public void alterSentryRoleGrantPrivilege(String grantorPrincipal,
+  void alterSentryRoleGrantPrivilege(String grantorPrincipal,
       String roleName, TSentryPrivilege privilege) throws Exception {
     alterSentryRoleGrantPrivileges(grantorPrincipal, roleName,
             Sets.newHashSet(privilege));
@@ -522,7 +523,7 @@ public class SentryStore {
     return mPrivilege;
   }
 
-  public void alterSentryRoleRevokePrivilege(String grantorPrincipal,
+  void alterSentryRoleRevokePrivilege(String grantorPrincipal,
       String roleName, TSentryPrivilege tPrivilege) throws Exception {
     alterSentryRoleRevokePrivileges(grantorPrincipal, roleName,
             Sets.newHashSet(tPrivilege));
@@ -693,7 +694,6 @@ public class SentryStore {
     }
   }
 
-  @SuppressWarnings("unchecked")
   private Set<MSentryPrivilege> getChildPrivileges(PersistenceManager pm, Set<String> roleNames,
       MSentryPrivilege parent) throws SentryInvalidInputException {
     // Column and URI do not have children
@@ -947,9 +947,9 @@ public class SentryStore {
 
   @VisibleForTesting
   MSentryRole getMSentryRoleByName(final String roleName) throws Exception {
-    return (MSentryRole)tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<MSentryRole>() {
+          public MSentryRole execute(PersistenceManager pm) throws Exception {
             String trimmedRoleName = trimAndLower(roleName);
             MSentryRole sentryRole = getRole(pm, trimmedRoleName);
             if (sentryRole == null) {
@@ -964,9 +964,9 @@ public class SentryStore {
     if (roleNames == null || roleNames.isEmpty()) {
       return false;
     }
-    return (Boolean) tm.executeTransaction(
-      new TransactionBlock() {
-        public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+      new TransactionBlock<Boolean>() {
+        public Boolean execute(PersistenceManager pm) throws Exception {
           Query query = pm.newQuery(MSentryPrivilege.class);
           QueryParamBuilder paramBuilder = addRolesFilter(query,null, roleNames);
           paramBuilder.add(SERVER_NAME, serverName);
@@ -978,68 +978,73 @@ public class SentryStore {
       });
   }
 
-  @SuppressWarnings("unchecked")
   private List<MSentryPrivilege> getMSentryPrivileges(final Set<String> roleNames,
-                                                      final TSentryAuthorizable authHierarchy) throws Exception {
-    List<MSentryPrivilege> result = new ArrayList<MSentryPrivilege>();
+                                                      final TSentryAuthorizable
+                                                              authHierarchy)
+          throws Exception {
     if (roleNames == null || roleNames.isEmpty()) {
-      return result;
+      return new ArrayList<>();
     }
 
-      return (List<MSentryPrivilege>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            Query query = pm.newQuery(MSentryPrivilege.class);
-            QueryParamBuilder paramBuilder = addRolesFilter(query, null, roleNames);
-
-            if (authHierarchy != null && authHierarchy.getServer() != null) {
-              paramBuilder.add(SERVER_NAME, authHierarchy.getServer());
-              if (authHierarchy.getDb() != null) {
-                paramBuilder.addNull(URI)
-                        .newChild()
-                          .add(DB_NAME, authHierarchy.getDb())
-                          .addNull(DB_NAME);
-                if (authHierarchy.getTable() != null
-                    && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getTable())) {
-                  if (!AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getTable())) {
-                    paramBuilder.addNull(URI)
-                            .newChild()
-                              .add(TABLE_NAME, authHierarchy.getTable())
-                              .addNull(TABLE_NAME);
-                  }
-                  if (authHierarchy.getColumn() != null
-                      && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getColumn())
-                      && !AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getColumn())) {
-                    paramBuilder.addNull(URI)
-                            .newChild()
-                              .add(COLUMN_NAME, authHierarchy.getColumn())
-                              .addNull(COLUMN_NAME);
-                  }
+    return tm.executeTransaction(
+      new TransactionBlock<List<MSentryPrivilege>>() {
+        public List<MSentryPrivilege> execute(PersistenceManager pm)
+                throws Exception {
+          Query query = pm.newQuery(MSentryPrivilege.class);
+          QueryParamBuilder paramBuilder = addRolesFilter(query, null, roleNames);
+
+          if (authHierarchy != null && authHierarchy.getServer() != null) {
+            paramBuilder.add(SERVER_NAME, authHierarchy.getServer());
+            if (authHierarchy.getDb() != null) {
+              paramBuilder.addNull(URI)
+                      .newChild()
+                        .add(DB_NAME, authHierarchy.getDb())
+                        .addNull(DB_NAME);
+              if (authHierarchy.getTable() != null
+                  && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getTable())) {
+                if (!AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getTable())) {
+                  paramBuilder.addNull(URI)
+                          .newChild()
+                            .add(TABLE_NAME, authHierarchy.getTable())
+                            .addNull(TABLE_NAME);
                 }
-              }
-              if (authHierarchy.getUri() != null) {
-                paramBuilder.addNull(DB_NAME)
-                        .newChild()
-                          .addNull(URI)
+                if (authHierarchy.getColumn() != null
+                    && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getColumn())
+                    && !AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getColumn())) {
+                  paramBuilder.addNull(URI)
                           .newChild()
-                            .addNotNull(URI)
-                            .addCustomParam("\"" + authHierarchy.getUri() +
-                                    "\".startsWith(:URI)", URI, authHierarchy.getUri());
+                            .add(COLUMN_NAME, authHierarchy.getColumn())
+                            .addNull(COLUMN_NAME);
+                }
               }
             }
-            LOGGER.debug("getMSentryPrivileges1() Query: " + paramBuilder.toString());
-            query.setFilter(paramBuilder.toString());
-            return query.executeWithMap(paramBuilder.getArguments());
+            if (authHierarchy.getUri() != null) {
+              paramBuilder.addNull(DB_NAME)
+                      .newChild()
+                        .addNull(URI)
+                        .newChild()
+                          .addNotNull(URI)
+                          .addCustomParam("\"" + authHierarchy.getUri() +
+                                  "\".startsWith(:URI)", URI, authHierarchy.getUri());
+            }
           }
-        });
+          LOGGER.debug("getMSentryPrivileges1() Query: " + paramBuilder.toString());
+          query.setFilter(paramBuilder.toString());
+          @SuppressWarnings("unchecked")
+          List<MSentryPrivilege> result =
+                  (List<MSentryPrivilege>)
+                          query.executeWithMap(paramBuilder.getArguments());
+          return result;
+        }
+      });
   }
 
-  @SuppressWarnings("unchecked")
-  List<MSentryPrivilege> getMSentryPrivilegesByAuth(final Set<String> roleNames,
-      final TSentryAuthorizable authHierarchy) throws Exception {
-      return (List<MSentryPrivilege>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+  private List<MSentryPrivilege> getMSentryPrivilegesByAuth(final Set<String> roleNames,
+                                                            final TSentryAuthorizable
+                                                                    authHierarchy) throws Exception {
+      return tm.executeTransaction(
+        new TransactionBlock<List<MSentryPrivilege>>() {
+          public List<MSentryPrivilege> execute(PersistenceManager pm) throws Exception {
             Query query = pm.newQuery(MSentryPrivilege.class);
             QueryParamBuilder paramBuilder = new QueryParamBuilder();
             if (roleNames == null || roleNames.isEmpty()) {
@@ -1071,9 +1076,11 @@ public class SentryStore {
             FetchGroup grp = pm.getFetchGroup(MSentryPrivilege.class, "fetchRole");
             grp.addMember("roles");
             pm.getFetchPlan().addGroup("fetchRole");
-            // LOGGER.debug("XXX: " + paramBuilder.toString());
             query.setFilter(paramBuilder.toString());
-            return query.executeWithMap(paramBuilder.getArguments());
+            @SuppressWarnings("unchecked")
+            List<MSentryPrivilege> result = (List<MSentryPrivilege>)query.
+                    executeWithMap(paramBuilder.getArguments());
+            return result;
           }
         });
   }
@@ -1158,17 +1165,16 @@ public class SentryStore {
     return convertToTSentryPrivileges(getMSentryPrivileges(roleNames, authHierarchy));
   }
 
-  @SuppressWarnings("unchecked")
   private Set<MSentryRole> getMSentryRolesByGroupName(final String groupName)
       throws Exception {
-    return (Set<MSentryRole>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Set<MSentryRole>>() {
+          public Set<MSentryRole> execute(PersistenceManager pm) throws Exception {
             Set<MSentryRole> roles;
 
             //If no group name was specified, return all roles
             if (groupName == null) {
-              roles = new HashSet<MSentryRole>(getAllRoles(pm));
+              roles = new HashSet<>(getAllRoles(pm));
             } else {
               String trimmedGroupName = groupName.trim();
               MSentryGroup sentryGroup = getGroup(pm, trimmedGroupName);
@@ -1187,7 +1193,8 @@ public class SentryStore {
 
   /**
    * Gets sentry role objects for a given groupName from the persistence layer
-   * @param groupNames : set of groupNames to look up ( if null returns all roles for all groups)
+   * @param groupNames : set of groupNames to look up (if null returns all
+   *                   roles for all groups)
    * @return : Set of thrift sentry role objects
    * @throws SentryNoSuchObjectException
    */
@@ -1207,15 +1214,14 @@ public class SentryStore {
     return convertToTSentryRoles(roleSet);
   }
 
-  @SuppressWarnings("unchecked")
   public Set<String> getRoleNamesForGroups(final Set<String> groups) throws Exception {
     if (groups == null || groups.isEmpty()) {
       return ImmutableSet.of();
     }
 
-    return (Set<String>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Set<String>>() {
+          public Set<String>execute(PersistenceManager pm) throws Exception {
             return getRoleNamesForGroupsCore(pm, groups);
           }
         });
@@ -1225,15 +1231,14 @@ public class SentryStore {
     return convertToRoleNameSet(getRolesForGroups(pm, groups));
   }
 
-  @SuppressWarnings("unchecked")
   public Set<String> getRoleNamesForUsers(final Set<String> users) throws Exception {
     if (users == null || users.isEmpty()) {
       return ImmutableSet.of();
     }
 
-    return (Set<String>) tm.executeTransaction(
-          new TransactionBlock() {
-            public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+          new TransactionBlock<Set<String>>() {
+            public Set<String> execute(PersistenceManager pm) throws Exception {
               return getRoleNamesForUsersCore(pm,users);
             }
           });
@@ -1243,17 +1248,17 @@ public class SentryStore {
     return convertToRoleNameSet(getRolesForUsers(pm, users));
   }
 
-  @SuppressWarnings("unchecked")
-  public Set<TSentryRole> getTSentryRolesByUserNames(final Set<String> users) throws Exception {
-    return (Set<TSentryRole>) tm.executeTransaction(
-        new TransactionBlock() {
-        public Object execute(PersistenceManager pm) throws Exception {
-            Set<MSentryRole> mSentryRoles = getRolesForUsers(pm, users);
-            // Since {@link MSentryRole#getGroups()} is lazy-loading, the converting should be call
-            // before transaction committed.
-            return convertToTSentryRoles(mSentryRoles);
-            }
-          });
+  public Set<TSentryRole> getTSentryRolesByUserNames(final Set<String> users)
+          throws Exception {
+    return tm.executeTransaction(
+      new TransactionBlock<Set<TSentryRole>>() {
+      public Set<TSentryRole> execute(PersistenceManager pm) throws Exception {
+        Set<MSentryRole> mSentryRoles = getRolesForUsers(pm, users);
+        // Since {@link MSentryRole#getGroups()} is lazy-loading,
+        // the conversion should be done before transaction is committed.
+        return convertToTSentryRoles(mSentryRoles);
+        }
+      });
   }
 
   public Set<MSentryRole> getRolesForGroups(PersistenceManager pm, Set<String> groups) {
@@ -1310,21 +1315,20 @@ public class SentryStore {
     return hasAnyServerPrivileges(rolesToQuery, server);
   }
 
-  @SuppressWarnings("unchecked")
   private Set<String> getRolesToQuery(final Set<String> groups, final Set<String> users,
       final TSentryActiveRoleSet roleSet) throws Exception {
-      return (Set<String>) tm.executeTransaction(
-          new TransactionBlock() {
-            public Object execute(PersistenceManager pm) throws Exception {
-              Set<String> activeRoleNames = toTrimedLower(roleSet.getRoles());
-
-              Set<String> roleNames = Sets.newHashSet();
-              roleNames.addAll(toTrimedLower(getRoleNamesForGroupsCore(pm, groups)));
-              roleNames.addAll(toTrimedLower(getRoleNamesForUsersCore(pm, users)));
-              return roleSet.isAll() ? roleNames : Sets.intersection(activeRoleNames,
-                  roleNames);
-            }
-          });
+      return tm.executeTransaction(
+        new TransactionBlock<Set<String>>() {
+          public Set<String> execute(PersistenceManager pm) throws Exception {
+            Set<String> activeRoleNames = toTrimedLower(roleSet.getRoles());
+
+            Set<String> roleNames = Sets.newHashSet();
+            roleNames.addAll(toTrimedLower(getRoleNamesForGroupsCore(pm, groups)));
+            roleNames.addAll(toTrimedLower(getRoleNamesForUsersCore(pm, users)));
+            return roleSet.isAll() ? roleNames : Sets.intersection(activeRoleNames,
+                roleNames);
+          }
+        });
   }
 
   @VisibleForTesting
@@ -1510,34 +1514,34 @@ public class SentryStore {
         });
   }
 
-  @SuppressWarnings("unchecked")
   private MSentryVersion getMSentryVersion() throws Exception {
-    return (MSentryVersion) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            try {
-              Query query = pm.newQuery(MSentryVersion.class);
-              List<MSentryVersion> mSentryVersions = (List<MSentryVersion>) query
-                  .execute();
-              pm.retrieveAll(mSentryVersions);
-              if (mSentryVersions.isEmpty()) {
-                throw new SentryNoSuchObjectException("No matching version found");
-              }
-              if (mSentryVersions.size() > 1) {
-                throw new SentryAccessDeniedException(
-                    "Metastore contains multiple versions");
-              }
-              return mSentryVersions.get(0);
-            } catch (JDODataStoreException e) {
-              if (e.getCause() instanceof MissingTableException) {
-                throw new SentryAccessDeniedException("Version table not found. "
-                    + "The sentry store is not set or corrupt ");
-              } else {
-                throw e;
-              }
+    return tm.executeTransaction(
+      new TransactionBlock<MSentryVersion>() {
+        public MSentryVersion execute(PersistenceManager pm) throws Exception {
+          try {
+            Query query = pm.newQuery(MSentryVersion.class);
+            @SuppressWarnings("unchecked")
+            List<MSentryVersion> mSentryVersions = (List<MSentryVersion>) query
+                .execute();
+            pm.retrieveAll(mSentryVersions);
+            if (mSentryVersions.isEmpty()) {
+              throw new SentryNoSuchObjectException("No matching version found");
+            }
+            if (mSentryVersions.size() > 1) {
+              throw new SentryAccessDeniedException(
+                  "Metastore contains multiple versions");
+            }
+            return mSentryVersions.get(0);
+          } catch (JDODataStoreException e) {
+            if (e.getCause() instanceof MissingTableException) {
+              throw new SentryAccessDeniedException("Version table not found. "
+                  + "The sentry store is not set or corrupt ");
+            } else {
+              throw e;
             }
           }
-        });
+        }
+      });
   }
 
   /**
@@ -1816,12 +1820,12 @@ public class SentryStore {
         ServerConfig.ADMIN_GROUPS, new String[]{}));
   }
 
-  @SuppressWarnings("unchecked")
   public Map<String, HashMap<String, String>> retrieveFullPrivilegeImage() throws Exception {
     Map<String, HashMap<String, String>> result = new HashMap<>();
-    return (Map<String, HashMap<String, String>>) tm.executeTransaction(
-      new TransactionBlock() {
-        public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+      new TransactionBlock<Map<String, HashMap<String, String>>>() {
+        public Map<String, HashMap<String, String>> execute(PersistenceManager pm)
+                throws Exception {
           Map<String, HashMap<String, String>> retVal = new HashMap<>();
           Query query = pm.newQuery(MSentryPrivilege.class);
           QueryParamBuilder paramBuilder = new QueryParamBuilder();
@@ -1832,6 +1836,7 @@ public class SentryStore {
 
           query.setFilter(paramBuilder.toString());
           query.setOrdering("serverName ascending, dbName ascending, tableName ascending");
+          @SuppressWarnings("unchecked")
           List<MSentryPrivilege> privileges =
                   (List<MSentryPrivilege>) query.executeWithMap(paramBuilder.getArguments());
           for (MSentryPrivilege mPriv : privileges) {
@@ -1862,14 +1867,14 @@ public class SentryStore {
   /**
    * @return Mapping of Role -> [Groups]
    */
-  @SuppressWarnings("unchecked")
   public Map<String, LinkedList<String>> retrieveFullRoleImage() throws Exception {
     Map<String, LinkedList<String>> result = new HashMap<>();
-    return (Map<String, LinkedList<String>>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Map<String, LinkedList<String>>>() {
+          public Map<String, LinkedList<String>> execute(PersistenceManager pm) throws Exception {
             Map<String, LinkedList<String>> retVal = new HashMap<>();
             Query query = pm.newQuery(MSentryGroup.class);
+            @SuppressWarnings("unchecked")
             List<MSentryGroup> groups = (List<MSentryGroup>) query.execute();
             for (MSentryGroup mGroup : groups) {
               for (MSentryRole role : mGroup.getRoles()) {
@@ -2078,32 +2083,31 @@ public class SentryStore {
     }
   }
 
-  // get mapping datas for [group,role], [user,role] with the specific roles
+  /** get mapping datas for [group,role], [user,role] with the specific roles */
   @SuppressWarnings("unchecked")
   public List<Map<String, Set<String>>> getGroupUserRoleMapList(final Set<String> roleNames) throws Exception {
-    List<Map<String, Set<String>>> result = new ArrayList<>();
-      return (List<Map<String, Set<String>>>) tm.executeTransaction(
-          new TransactionBlock() {
-            public Object execute(PersistenceManager pm) throws Exception {
-              Query query = pm.newQuery(MSentryRole.class);
-              List<MSentryRole> mSentryRoles;
-              if (roleNames == null || roleNames.isEmpty()) {
-                mSentryRoles = (List<MSentryRole>)query.execute();
-              } else {
-                QueryParamBuilder paramBuilder = new QueryParamBuilder(QueryParamBuilder.Op.OR);
-                paramBuilder.addSet("roleName == ", roleNames);
-                query.setFilter(paramBuilder.toString());
-                mSentryRoles =
-                        (List<MSentryRole>) query.executeWithMap(paramBuilder.getArguments());
-              }
-              Map<String, Set<String>> groupRolesMap = getGroupRolesMap(mSentryRoles);
-              Map<String, Set<String>> userRolesMap = getUserRolesMap(mSentryRoles);
-              List<Map<String, Set<String>>> mapsList = new ArrayList<>();
-              mapsList.add(INDEX_GROUP_ROLES_MAP, groupRolesMap);
-              mapsList.add(INDEX_USER_ROLES_MAP, userRolesMap);
-              return mapsList;
+      return tm.executeTransaction(
+        new TransactionBlock<List<Map<String, Set<String>>>>() {
+          public List<Map<String, Set<String>>> execute(PersistenceManager pm) throws Exception {
+            Query query = pm.newQuery(MSentryRole.class);
+            List<MSentryRole> mSentryRoles;
+            if (roleNames == null || roleNames.isEmpty()) {
+              mSentryRoles = (List<MSentryRole>)query.execute();
+            } else {
+              QueryParamBuilder paramBuilder = new QueryParamBuilder(QueryParamBuilder.Op.OR);
+              paramBuilder.addSet("roleName == ", roleNames);
+              query.setFilter(paramBuilder.toString());
+              mSentryRoles =
+                      (List<MSentryRole>) query.executeWithMap(paramBuilder.getArguments());
             }
-          });
+            Map<String, Set<String>> groupRolesMap = getGroupRolesMap(mSentryRoles);
+            Map<String, Set<String>> userRolesMap = getUserRolesMap(mSentryRoles);
+            List<Map<String, Set<String>>> mapsList = new ArrayList<>();
+            mapsList.add(INDEX_GROUP_ROLES_MAP, groupRolesMap);
+            mapsList.add(INDEX_USER_ROLES_MAP, userRolesMap);
+            return mapsList;
+          }
+        });
   }
 
   private Map<String, Set<String>> getGroupRolesMap(List<MSentryRole> mSentryRoles) {
@@ -2156,27 +2160,29 @@ public class SentryStore {
   /**
    * @return mapping data for [role,privilege] with the specific auth object
    */
-  @SuppressWarnings("unchecked")
   public Map<String, Set<TSentryPrivilege>> getRoleNameTPrivilegesMap(final String dbName,
         final String tableName) throws Exception {
-    return (Map<String, Set<TSentryPrivilege>>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            Query query = pm.newQuery(MSentryPrivilege.class);
-            QueryParamBuilder paramBuilder = new QueryParamBuilder();
+    return tm.executeTransaction(
+      new TransactionBlock<Map<String, Set<TSentryPrivilege>>>() {
+        public Map<String, Set<TSentryPrivilege>> execute(PersistenceManager pm)
+                throws Exception {
+          Query query = pm.newQuery(MSentryPrivilege.class);
+          QueryParamBuilder paramBuilder = new QueryParamBuilder();
 
-            if (!StringUtils.isEmpty(dbName)) {
-                paramBuilder.add(DB_NAME, dbName);
-            }
-            if (!StringUtils.isEmpty(tableName)) {
-                paramBuilder.add(TABLE_NAME, tableName);
-            }
-            query.setFilter(paramBuilder.toString());
-            List<MSentryPrivilege> mSentryPrivileges =
-                    (List<MSentryPrivilege>) query.executeWithMap(paramBuilder.getArguments());
-            return getRolePrivilegesMap(mSentryPrivileges);
+          if (!StringUtils.isEmpty(dbName)) {
+              paramBuilder.add(DB_NAME, dbName);
           }
-        });
+          if (!StringUtils.isEmpty(tableName)) {
+              paramBuilder.add(TABLE_NAME, tableName);
+          }
+          query.setFilter(paramBuilder.toString());
+          @SuppressWarnings("unchecked")
+          List<MSentryPrivilege> mSentryPrivileges =
+                  (List<MSentryPrivilege>) query.
+                          executeWithMap(paramBuilder.getArguments());
+          return getRolePrivilegesMap(mSentryPrivileges);
+        }
+      });
   }
 
   private Map<String, Set<TSentryPrivilege>> getRolePrivilegesMap(
@@ -2204,11 +2210,10 @@ public class SentryStore {
   /**
    * @return Set of all role names, or an empty set if no roles are defined
    */
-  @SuppressWarnings("unchecked")
   public Set<String> getAllRoleNames() throws Exception {
-    return (Set<String>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Set<String>>() {
+          public Set<String> execute(PersistenceManager pm) throws Exception {
             return getAllRoleNamesCore(pm);
           }
         });
@@ -2236,9 +2241,9 @@ public class SentryStore {
    * @param pm PersistenceManager instance
    * @return map of group names to group data for each group
    */
-  @SuppressWarnings("unchecked")
   private Map<String, MSentryGroup> getGroupNameTGroupMap(PersistenceManager pm) {
     Query query = pm.newQuery(MSentryGroup.class);
+    @SuppressWarnings("unchecked")
     List<MSentryGroup> mSentryGroups = (List<MSentryGroup>) query.execute();
     Map<String, MSentryGroup> existGroupsMap = Maps.newHashMap();
     if (mSentryGroups != null) {
@@ -2255,10 +2260,9 @@ public class SentryStore {
    * @param pm PersistenceManager instance
    * @return map of user names to user data for each user
    */
-  // get the all exist users
-  @SuppressWarnings("unchecked")
   private Map<String, MSentryUser> getUserNameToUserMap(PersistenceManager pm) {
     Query query = pm.newQuery(MSentryUser.class);
+    @SuppressWarnings("unchecked")
     List<MSentryUser> users = (List<MSentryUser>) query.execute();
     Map<String, MSentryUser> existUsersMap = Maps.newHashMap();
     if (users != null) {
@@ -2275,9 +2279,9 @@ public class SentryStore {
    * @param pm PersistenceManager instance
    * @return List of all privileges
    */
-  @SuppressWarnings("unchecked")
   private List<MSentryPrivilege> getPrivilegesList(PersistenceManager pm) {
     Query query = pm.newQuery(MSentryPrivilege.class);
+    @SuppressWarnings("unchecked")
     List<MSentryPrivilege> resultList = (List<MSentryPrivilege>) query.execute();
     if (resultList == null) {
       resultList = Lists.newArrayList();
@@ -2286,11 +2290,10 @@ public class SentryStore {
   }
 
   @VisibleForTesting
-  @SuppressWarnings("unchecked")
-  protected Map<String, MSentryRole> getRolesMap() throws Exception {
-    return (Map<String, MSentryRole>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+  Map<String, MSentryRole> getRolesMap() throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Map<String, MSentryRole>>() {
+          public Map<String, MSentryRole> execute(PersistenceManager pm) throws Exception {
             List<MSentryRole> mSentryRoles = getAllRoles(pm);
             Map<String, MSentryRole> existRolesMap = Maps.newHashMap();
             if (mSentryRoles != null) {
@@ -2306,36 +2309,34 @@ public class SentryStore {
   }
 
   @VisibleForTesting
-  @SuppressWarnings("unchecked")
-  protected Map<String, MSentryGroup> getGroupNameToGroupMap() throws Exception {
-    return (Map<String, MSentryGroup>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            return getGroupNameTGroupMap(pm);
-          }
-        });
+  Map<String, MSentryGroup> getGroupNameToGroupMap() throws Exception {
+    return tm.executeTransaction(
+      new TransactionBlock<Map<String, MSentryGroup>>() {
+        public Map<String, MSentryGroup> execute(PersistenceManager pm) throws Exception {
+          return getGroupNameTGroupMap(pm);
+        }
+      });
   }
 
   @VisibleForTesting
-  @SuppressWarnings("unchecked")
-  protected Map<String, MSentryUser> getUserNameToUserMap() throws Exception {
-    return (Map<String, MSentryUser>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
+  Map<String, MSentryUser> getUserNameToUserMap() throws Exception {
+    return tm.executeTransaction(
+        new TransactionBlock<Map<String, MSentryUser>>() {
+          public Map<String, MSentryUser> execute(PersistenceManager pm) throws Exception {
             return getUserNameToUserMap(pm);
           }
         });
   }
 
   @VisibleForTesting
-  @SuppressWarnings("unchecked")
-  protected List<MSentryPrivilege> getPrivilegesList() throws Exception {
-    return (List<MSentryPrivilege>) tm.executeTransaction(
-        new TransactionBlock() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            return getPrivilegesList(pm);
-          }
-        });
+  List<MSentryPrivilege> getPrivilegesList() throws Exception {
+    return tm.executeTransaction(
+      new TransactionBlock<List<MSentryPrivilege>>() {
+        public List<MSentryPrivilege> execute(PersistenceManager pm)
+                throws Exception {
+          return getPrivilegesList(pm);
+        }
+      });
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/sentry/blob/62bdcbfe/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionBlock.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionBlock.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionBlock.java
index 7a57a96..c7b19ce 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionBlock.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionBlock.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -22,16 +22,17 @@ import javax.jdo.PersistenceManager;
 
 /**
  * TransactionBlock wraps the code that is executed inside a single
- * transaction
+ * transaction. The {@link #execute(PersistenceManager)} method returns the
+ * result of the transaction.
  */
-public interface TransactionBlock {
+public interface TransactionBlock<T> {
   /**
-   * Execute some code as a single transaction, the code should not start new transaction
-   * or manipulate transactions with the PersistenceManager. TransactionManager is responsible to
-   * handle the transaction management.
+   * Execute some code as a single transaction, the code should not start new
+   * transaction or manipulate transactions with the PersistenceManager.
+   *
    * @param pm PersistenceManager for the current transaction
    * @return Object with the result of execute()
    * @throws Exception
    */
-  Object execute(PersistenceManager pm) throws Exception;
+  T execute(PersistenceManager pm) throws Exception;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/62bdcbfe/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionManager.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionManager.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionManager.java
index 85a5326..ee13f9f 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionManager.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/TransactionManager.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -38,13 +38,16 @@ import org.apache.sentry.provider.db.service.thrift.SentryMetrics;
 /**
  * TransactionManager is used for executing the database transaction, it supports
  * the transaction with retry mechanism for the unexpected exceptions,
- * except SentryUserExceptions, eg, SentryNoSuchObjectException,
- * SentryAlreadyExistsException etc.
- * <p>
- * The purpose of the class is to separate all transaction houskeeping (opening
+ * except <em>SentryUserExceptions</em>, eg, <em>SentryNoSuchObjectException</em>,
+ * <em>SentryAlreadyExistsException</em> etc. <p>
+ *
+ * The purpose of the class is to separate all transaction housekeeping (opening
  * transaction, rolling back failed transactions) from the actual transaction
- * business logic.
- * <p>
+ * business logic.<p>
+ *
+ * TransactionManager creates an instance of PersistenceManager for each
+ * transaction.<p>
+ *
  * TransactionManager exposes several metrics:
  * <ul>
  *     <li>Timer metric for all transactions</li>
@@ -54,7 +57,8 @@ import org.apache.sentry.provider.db.service.thrift.SentryMetrics;
  */
 public class TransactionManager {
 
-  private static final Logger LOGGER = LoggerFactory.getLogger(TransactionManager.class);
+  private static final Logger LOGGER =
+          LoggerFactory.getLogger(TransactionManager.class);
 
   private final PersistenceManagerFactory pmf;
 
@@ -92,19 +96,20 @@ public class TransactionManager {
 
 
   /**
-   * Execute some code as a single transaction, the code in tb.execute() should not start new
-   * transaction or manipulate transactions with the PersistenceManager.
+   * Execute some code as a single transaction, the code in tb.execute()
+   * should not start new transaction or manipulate transactions with the
+   * PersistenceManager.
    * @param tb transaction block with code to execute
    * @return Object with the result of tb.execute()
    */
-  public Object executeTransaction(TransactionBlock tb) throws Exception {
+  public <T> T executeTransaction(TransactionBlock<T> tb) throws Exception {
     final Timer.Context context = transactionTimer.time();
     try (CloseablePersistenceManager cpm =
              new CloseablePersistenceManager(pmf.getPersistenceManager())) {
       Transaction transaction = cpm.pm.currentTransaction();
       transaction.begin();
       try {
-        Object result = tb.execute(cpm.pm);
+        T result = tb.execute(cpm.pm);
         transaction.commit();
         return result;
       } catch (Exception e) {
@@ -129,7 +134,8 @@ public class TransactionManager {
    * @param tb transaction block with code to execute
    * @return Object with the result of tb.execute()
    */
-  public Object executeTransactionWithRetry(TransactionBlock tb) throws Exception {
+  public <T> T executeTransactionWithRetry(TransactionBlock<T> tb)
+          throws Exception {
     int retryNum = 0;
     while (retryNum < transactionRetryMax) {
       try {