You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by sp...@apache.org on 2020/10/09 00:26:17 UTC

[ranger] branch master updated: RANGER-2986: Performance improvements for Ranger usersync

This is an automated email from the ASF dual-hosted git repository.

spolavarapu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 4610df1  RANGER-2986: Performance improvements for Ranger usersync
4610df1 is described below

commit 4610df1fd126a07f1e19c5bed53e50742bb9f428
Author: Sailaja Polavarapu <sp...@cloudera.com>
AuthorDate: Thu Oct 8 17:25:31 2020 -0700

    RANGER-2986: Performance improvements for Ranger usersync
---
 distro/src/main/assembly/admin-web.xml             |    1 +
 distro/src/main/assembly/usersync.xml              |    1 +
 pom.xml                                            |    4 +
 security-admin/pom.xml                             |    5 +
 .../main/java/org/apache/ranger/biz/XUserMgr.java  |  463 ++++-
 .../java/org/apache/ranger/db/XXGroupUserDao.java  |   53 +-
 .../main/java/org/apache/ranger/db/XXUserDao.java  |   17 +
 .../java/org/apache/ranger/rest/XUserREST.java     |   58 +-
 .../apache/ranger/service/XGroupUserService.java   |   33 +
 .../ranger/view/VXUsersGroupRoleAssignments.java   |   66 -
 .../main/resources/META-INF/jpa_named_queries.xml  |   17 +
 ugsync-util/.gitignore                             |    3 +
 ugsync-util/pom.xml                                |   53 +
 .../ugsyncutil}/model/FileSyncSourceInfo.java      |    2 +-
 .../ranger/ugsyncutil/model/GroupUserInfo.java     |   67 +
 .../ugsyncutil}/model/LdapSyncSourceInfo.java      |    2 +-
 .../ranger/ugsyncutil}/model/UgsyncAuditInfo.java  |    2 +-
 .../ugsyncutil}/model/UnixSyncSourceInfo.java      |    2 +-
 .../model/UsersGroupRoleAssignments.java           |    2 +-
 .../ranger/ugsyncutil}/model/XGroupInfo.java       |    2 +-
 .../apache/ranger/ugsyncutil}/model/XUserInfo.java |   22 +-
 ugsync/pom.xml                                     |    5 +
 .../process/LdapDeltaUserGroupBuilder.java         | 1235 -------------
 .../process/LdapPolicyMgrUserGroupBuilder.java     | 1297 -------------
 .../ldapusersync/process/LdapUserGroupBuilder.java | 1263 ++++++-------
 .../process/PolicyMgrUserGroupBuilder.java         |   29 -
 .../unixusersync/config/UserGroupSyncConfig.java   |   31 +-
 .../unixusersync/model/GetXGroupListResponse.java  |    3 +-
 .../model/GetXUserGroupListResponse.java           |   50 -
 .../unixusersync/model/GetXUserListResponse.java   |    1 +
 .../ranger/unixusersync/model/GroupUserInfo.java   |   40 -
 .../ranger/unixusersync/model/MUserInfo.java       |   70 -
 .../ranger/unixusersync/model/UserGroupInfo.java   |   41 -
 .../ranger/unixusersync/model/XUserGroupInfo.java  |   59 -
 .../process/FileSourceUserGroupBuilder.java        |   78 +-
 .../process/PolicyMgrUserGroupBuilder.java         | 1930 +++++++++-----------
 .../unixusersync/process/UnixUserGroupBuilder.java |  133 +-
 .../usergroupsync/AbstractUserGroupSource.java     |    2 +-
 .../apache/ranger/usergroupsync/UserGroupSink.java |   17 +-
 .../process/TestFileSourceUserGroupBuilder.java    |    3 +-
 .../process/TestUnixUserGroupBuilder.java          |   44 +-
 .../LdapPolicyMgrUserGroupBuilderTest.java         |   89 -
 .../PolicyMgrUserGroupBuilderTest.java             |   59 +-
 .../ranger/usergroupsync/TestLdapUserGroup.java    |  369 +---
 44 files changed, 2386 insertions(+), 5337 deletions(-)

diff --git a/distro/src/main/assembly/admin-web.xml b/distro/src/main/assembly/admin-web.xml
index fcab9ab..19ab3bc 100644
--- a/distro/src/main/assembly/admin-web.xml
+++ b/distro/src/main/assembly/admin-web.xml
@@ -268,6 +268,7 @@
           <include>com.carrotsearch:hppc</include>
           <include>joda-time:joda-time</include>
           <include>org.apache.ranger:ranger-plugins-cred</include>
+          <include>org.apache.ranger:ugsyn-util</include>
         </includes>
       </binaries>
     </moduleSet>
diff --git a/distro/src/main/assembly/usersync.xml b/distro/src/main/assembly/usersync.xml
index 8d66c38..3fb1a53 100644
--- a/distro/src/main/assembly/usersync.xml
+++ b/distro/src/main/assembly/usersync.xml
@@ -59,6 +59,7 @@
 							<include>org.apache.httpcomponents:httpclient:jar:${httpcomponents.httpclient.version}</include>
 							<include>commons-codec:commons-codec</include>
 							<include>org.apache.ranger:ranger-plugins-common</include>
+							<include>org.apache.ranger:ugsync-util</include>
 							<include>org.codehaus.woodstox:stax2-api</include>
 							<include>com.fasterxml.woodstox:woodstox-core</include>
 							<include>org.apache.htrace:htrace-core4</include>
diff --git a/pom.xml b/pom.xml
index 59b8667..0531809 100644
--- a/pom.xml
+++ b/pom.xml
@@ -252,6 +252,7 @@
                 <module>plugin-nifi-registry</module>
                 <module>plugin-presto</module>
                 <module>plugin-kudu</module>
+                <module>ugsync-util</module>
                 <module>ugsync</module>
                 <module>ugsync/ldapconfigchecktool/ldapconfigcheck</module>
                 <module>unixauthclient</module>
@@ -303,6 +304,7 @@
             <modules>
                 <module>agents-common</module>
                 <module>security-admin</module>
+                <module>ugsync-util</module>
             </modules>
         </profile>
         <profile>
@@ -545,6 +547,7 @@
                 <module>plugin-nifi</module>
                 <module>plugin-nifi-registry</module>
                 <module>plugin-kudu</module>
+                <module>ugsync-util</module>
                 <module>ugsync</module>
                 <module>ugsync/ldapconfigchecktool/ldapconfigcheck</module>
                 <module>unixauthclient</module>
@@ -629,6 +632,7 @@
                 <module>plugin-nifi</module>
                 <module>plugin-nifi-registry</module>
                 <module>plugin-presto</module>
+                <module>ugsync-util</module>
                 <module>ugsync</module>
                 <module>ugsync/ldapconfigchecktool/ldapconfigcheck</module>
                 <module>unixauthclient</module>
diff --git a/security-admin/pom.xml b/security-admin/pom.xml
index 0a0692d..72e8018 100644
--- a/security-admin/pom.xml
+++ b/security-admin/pom.xml
@@ -506,6 +506,11 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>ugsync-util</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
             <version>${springframework.test.version}</version>
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
index ca492fe..4a371f8 100755
--- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
@@ -21,6 +21,7 @@ package org.apache.ranger.biz;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -28,9 +29,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.Collections;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ranger.common.*;
 import org.apache.ranger.entity.XXGroupPermission;
@@ -45,6 +46,8 @@ import org.apache.ranger.plugin.model.UserInfo;
 import org.apache.ranger.plugin.util.RangerUserStore;
 import org.apache.ranger.security.context.RangerAPIMapping;
 import org.apache.ranger.service.*;
+import org.apache.ranger.ugsyncutil.model.GroupUserInfo;
+import org.apache.ranger.ugsyncutil.model.UsersGroupRoleAssignments;
 import org.apache.ranger.view.*;
 import org.apache.log4j.Logger;
 import org.apache.ranger.db.RangerDaoManager;
@@ -1541,70 +1544,6 @@ public class XUserMgr extends XUserMgrBase {
 
 	}
 
-	public List<String> updateUserRoleAssignments(VXUsersGroupRoleAssignments ugRoleAssignments) {
-		List<String> updatedUsers = new ArrayList<>();
-		// For each user get groups and compute roles based on group role assignments
-		for (String userName : ugRoleAssignments.getUsers()) {
-			if (userMgr.getUserProfileByLoginId(userName) == null) {
-				logger.info(userName + " doesn't exist and hence ignoring role assignments");
-				continue;
-			}
-			String userRole = RangerConstants.ROLE_USER;
-			Map<String, String> userMap = ugRoleAssignments.getUserRoleAssignments();
-			if (!userMap.isEmpty() && userMap.containsKey(userName)) {
-				// Add the user role that is defined in user role assignments
-				userRole = userMap.get(userName);
-			} else {
-				Map<String, String> groupMap = ugRoleAssignments.getGroupRoleAssignments();
-
-				if (!groupMap.isEmpty()) {
-					for (String group : getGroupsForUser(userName)) {
-						String value = groupMap.get(group);
-						if (value != null) {
-							userRole = value;
-						}
-					}
-				}
-			}
-
-			String updatedUser = setRolesByUserName(userName, Collections.singletonList(userRole));
-			if (updatedUser != null) {
-				updatedUsers.add(updatedUser);
-			}
-		}
-		return updatedUsers;
-	}
-
-	private String setRolesByUserName(String userName, List<String> roleListNewProfile) {
-		if (logger.isDebugEnabled()) {
-			logger.debug("==> XUserMgr.setRolesByUserName(" + userName + ", " + roleListNewProfile + ")");
-		}
-		String ret = null;
-		xaBizUtil.blockAuditorRoleUser();
-		if (roleListNewProfile == null) {
-			roleListNewProfile = new ArrayList<String>();
-		}
-
-		if(userName!=null && roleListNewProfile.size()>0){
-			checkAccessRoles(roleListNewProfile);
-			VXPortalUser oldUserProfile = userMgr.getUserProfileByLoginId(userName);
-			if(oldUserProfile!=null){
-				denySelfRoleChange(oldUserProfile.getLoginId());
-				updateUserRolesPermissions(oldUserProfile,roleListNewProfile);
-				logger.info("<== XUserMgr.setRolesByUserName returned roles for " + userName + " are: " + roleListNewProfile );
-				ret = userName;
-			}else{
-				logger.error(userName + "doesn't exist.");
-			}
-		}else{
-			logger.error(userName + "doesn't exist or new role assignments are empty");
-		}
-		if (logger.isDebugEnabled()) {
-			logger.debug("<== XUserMgr.setRolesByUserName(" + userName + ", " + roleListNewProfile + ") ret = " + ret);
-		}
-		return ret;
-	}
-
 	public VXStringList getUserRolesByExternalID(Long userId) {
 		VXUser vXUser=getXUser(userId);
 		if(vXUser==null){
@@ -2654,4 +2593,398 @@ public class XUserMgr extends XUserMgrBase {
 
 		return ret;
 	}
+
+	public int createOrUpdateXUsers(VXUserList users) {
+		xaBizUtil.blockAuditorRoleUser();
+		int ret = 0;
+
+		for (VXUser vXUser : users.getList()) {
+			if (vXUser == null || vXUser.getName() == null
+					|| "null".equalsIgnoreCase(vXUser.getName())
+					|| vXUser.getName().trim().isEmpty()) {
+				throw restErrorUtil.createRESTException("Please provide a valid "
+						+ "username.", MessageEnums.INVALID_INPUT_DATA);
+			}
+			checkAccess(vXUser.getName());
+
+			String username = vXUser.getName();
+			VXPortalUser vXPortalUser = userMgr.getUserProfileByLoginId(username);
+			if (vXPortalUser == null) {
+				vXPortalUser = new VXPortalUser();
+				vXPortalUser.setLoginId(username);
+				vXPortalUser.setFirstName(vXUser.getFirstName());
+				if ("null".equalsIgnoreCase(vXPortalUser.getFirstName())) {
+					vXPortalUser.setFirstName("");
+				}
+				vXPortalUser.setLastName(vXUser.getLastName());
+				if ("null".equalsIgnoreCase(vXPortalUser.getLastName())) {
+					vXPortalUser.setLastName("");
+				}
+
+				String emailAddress = vXUser.getEmailAddress();
+				if (StringUtils.isNotEmpty(emailAddress) && !stringUtil.validateEmail(emailAddress)) {
+					logger.warn("Invalid email address:" + emailAddress);
+					throw restErrorUtil.createRESTException("Please provide valid email address.",
+							MessageEnums.INVALID_INPUT_DATA);
+				}
+				vXPortalUser.setEmailAddress(emailAddress);
+
+				if (vXPortalUser.getFirstName() != null
+						&& vXPortalUser.getLastName() != null
+						&& !vXPortalUser.getFirstName().trim().isEmpty()
+						&& !vXPortalUser.getLastName().trim().isEmpty()) {
+					vXPortalUser.setPublicScreenName(vXPortalUser.getFirstName() + " "
+							+ vXPortalUser.getLastName());
+				} else {
+					vXPortalUser.setPublicScreenName(vXUser.getName());
+				}
+
+				vXPortalUser.setStatus(RangerCommonEnums.STATUS_ENABLED);
+				vXPortalUser.setUserSource(RangerCommonEnums.USER_EXTERNAL);
+				String saltEncodedpasswd = userMgr.encrypt(username,
+						vXUser.getPassword());
+				vXPortalUser.setPassword(saltEncodedpasswd);
+				vXPortalUser.setUserRoleList(vXUser.getUserRoleList());
+				XXPortalUser user = userMgr.mapVXPortalUserToXXPortalUser(vXPortalUser);
+
+				user = daoManager.getXXPortalUser().create(user);
+
+				// Create the UserRole for this user
+				Collection<String> userRoleList = vXUser.getUserRoleList();
+				if (userRoleList != null) {
+					for (String userRole : userRoleList) {
+						userMgr.addUserRole(user.getId(),
+								userRole);
+					}
+				}
+
+				vXUser = xUserService.createResource(vXUser);
+				List<XXTrxLog> trxLogList = xUserService.getTransactionLog(
+						vXUser, "create");
+
+				if (vXPortalUser != null) {
+					assignPermissionToUser(vXPortalUser.getUserRoleList(), vXPortalUser.getId(), vXUser.getId(), true);
+				}
+				xaBizUtil.createTrxLog(trxLogList);
+			} else {
+				if (logger.isDebugEnabled()) {
+					logger.debug("Update user " + username);
+				}
+				updateXUser(vXUser, vXPortalUser);
+			}
+			ret++;
+		}
+
+		try {
+			daoManager.getXXGlobalState().onGlobalAppDataChange(RANGER_USER_GROUP_GLOBAL_STATE_NAME);
+		} catch (Exception excp) {
+			logger.error("createOrUpdateXGroups() failed", excp);
+		}
+
+		return ret;
+	}
+
+	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
+	public int createOrUpdateXGroups(VXGroupList groups) {
+		for (VXGroup vXGroup : groups.getList()) {
+			createXGroupWithoutLogin(vXGroup);
+		}
+		try {
+			daoManager.getXXGlobalState().onGlobalAppDataChange(RANGER_USER_GROUP_GLOBAL_STATE_NAME);
+		} catch (Exception excp) {
+			logger.error("createOrUpdateXGroups() failed", excp);
+		}
+		return groups.getListSize();
+	}
+
+	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
+	private void createOrDeleteXGroupUsers(GroupUserInfo groupUserInfo, Map<String, Long> usersFromDB) {
+		checkAdminAccess();
+		xaBizUtil.blockAuditorRoleUser();
+		String groupName = groupUserInfo.getGroupName();
+		if (CollectionUtils.isEmpty(groupUserInfo.getAddUsers()) && CollectionUtils.isEmpty(groupUserInfo.getDelUsers())) {
+			logger.info("Group memberships for source are empty for " + groupName);
+			return;
+		}
+		Set<String> groupUsers = groupUserInfo.getAddUsers();
+		if (CollectionUtils.isNotEmpty(groupUsers)) {
+			xGroupUserService.createOrUpdateXGroupUsers(groupName, groupUsers, usersFromDB);
+		}
+
+		if (CollectionUtils.isNotEmpty(groupUserInfo.getDelUsers())) {
+			for (String username : groupUserInfo.getDelUsers()) {
+				deleteXGroupAndXUser(groupName, username);
+			}
+		}
+	}
+
+	public int createOrDeleteXGroupUserList(List<GroupUserInfo> groupUserInfoList) {
+		int updatedGroups = 0;
+		if (CollectionUtils.isNotEmpty(groupUserInfoList)) {
+			Map<String, Long> usersFromDB = daoManager.getXXUser().getAllUserIds();
+			if (MapUtils.isNotEmpty(usersFromDB)) {
+				for (GroupUserInfo groupUserInfo : groupUserInfoList) {
+					createOrDeleteXGroupUsers(groupUserInfo, usersFromDB);
+				}
+				updatedGroups = groupUserInfoList.size();
+			}
+		}
+		return updatedGroups;
+	}
+
+	public List<String> updateUserRoleAssignments(UsersGroupRoleAssignments ugRoleAssignments) {
+		List<String> updatedUsers = new ArrayList<>();
+		// For each user get groups and compute roles based on group role assignments
+		for (String userName : ugRoleAssignments.getUsers()) {
+			VXPortalUser vXPortalUser = userMgr.getUserProfileByLoginId(userName);
+			if (vXPortalUser == null) {
+				logger.info(userName + " doesn't exist and hence ignoring role assignments");
+				continue;
+			}
+			if (vXPortalUser.getUserSource() != RangerCommonEnums.USER_EXTERNAL){
+				logger.info(userName + " is internal to ranger admin and hence ignoring role assignments");
+				continue;
+			}
+			String userRole = RangerConstants.ROLE_USER;
+			Map<String, String> userMap = ugRoleAssignments.getUserRoleAssignments();
+			if (!userMap.isEmpty() && userMap.containsKey(userName)) {
+				// Add the user role that is defined in user role assignments
+				userRole = userMap.get(userName);
+			} else {
+				Map<String, String> groupMap = ugRoleAssignments.getGroupRoleAssignments();
+
+				if (!groupMap.isEmpty()) {
+					for (String group : getGroupsForUser(userName)) {
+						String value = groupMap.get(group);
+						if (value != null) {
+							userRole = value;
+						}
+					}
+				}
+			}
+
+			if (!vXPortalUser.getUserRoleList().contains(userRole)) {
+				//Update the role of the user only if newly computed role is different from the existing role.
+				String updatedUser = setRolesByUserName(userName, Collections.singletonList(userRole));
+				if (updatedUser != null) {
+					updatedUsers.add(updatedUser);
+				}
+			}
+		}
+		return updatedUsers;
+	}
+
+	private String setRolesByUserName(String userName, List<String> roleListNewProfile) {
+		if (logger.isDebugEnabled()) {
+			logger.debug("==> XUserMgr.setRolesByUserName(" + userName + ", " + roleListNewProfile + ")");
+		}
+		String ret = null;
+		xaBizUtil.blockAuditorRoleUser();
+		if (roleListNewProfile == null) {
+			roleListNewProfile = new ArrayList<String>();
+		}
+
+		if(userName!=null && roleListNewProfile.size()>0){
+			checkAccessRoles(roleListNewProfile);
+			VXPortalUser oldUserProfile = userMgr.getUserProfileByLoginId(userName);
+			if(oldUserProfile!=null){
+				denySelfRoleChange(oldUserProfile.getLoginId());
+				updateUserRolesPermissions(oldUserProfile,roleListNewProfile);
+				logger.info("<== XUserMgr.setRolesByUserName returned roles for " + userName + " are: " + roleListNewProfile );
+				ret = userName;
+			}else{
+				logger.error(userName + "doesn't exist.");
+			}
+		}else{
+			logger.error(userName + "doesn't exist or new role assignments are empty");
+		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("<== XUserMgr.setRolesByUserName(" + userName + ", " + roleListNewProfile + ") ret = " + ret);
+		}
+		return ret;
+	}
+
+	private void assignPermissionToUser(Collection<String> vXPortalUserList, Long vXPortalUserId, Long xUserId, boolean isCreate) {
+		HashMap<String, Long> moduleNameId = getAllModuleNameAndIdMap();
+		if(moduleNameId!=null){
+			if(CollectionUtils.isNotEmpty(vXPortalUserList)){
+				for (String role : vXPortalUserList) {
+
+					if (role.equals(RangerConstants.ROLE_USER)) {
+
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_RESOURCE_BASED_POLICIES), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_REPORTS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_SECURITY_ZONE), isCreate);
+					} else if (role.equals(RangerConstants.ROLE_SYS_ADMIN)) {
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_REPORTS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_RESOURCE_BASED_POLICIES), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_AUDIT), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_USER_GROUPS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_TAG_BASED_POLICIES), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_SECURITY_ZONE), isCreate);
+					} else if (role.equals(RangerConstants.ROLE_KEY_ADMIN)) {
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_AUDIT), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_USER_GROUPS),isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_KEY_MANAGER), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_REPORTS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_RESOURCE_BASED_POLICIES), isCreate);
+					} else if (role.equals(RangerConstants.ROLE_KEY_ADMIN_AUDITOR)) {
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_AUDIT), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_USER_GROUPS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_KEY_MANAGER), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_REPORTS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_RESOURCE_BASED_POLICIES), isCreate);
+					} else if (role.equals(RangerConstants.ROLE_ADMIN_AUDITOR)) {
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_REPORTS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_RESOURCE_BASED_POLICIES), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_AUDIT), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_USER_GROUPS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_TAG_BASED_POLICIES), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerAPIMapping.TAB_PERMISSIONS), isCreate);
+						createOrUpdateUserPermisson(vXPortalUserId, xUserId, moduleNameId.get(RangerConstants.MODULE_SECURITY_ZONE), isCreate);
+					}
+
+				}
+			}
+		}
+	}
+
+	private void createOrUpdateUserPermisson(Long portalUserId, Long xUserId, Long moduleId, boolean isCreate) {
+		VXUserPermission vXUserPermission;
+		XXUserPermission xUserPermission = daoManager.getXXUserPermission().findByModuleIdAndPortalUserId(portalUserId, moduleId);
+		if (xUserPermission == null) {
+			vXUserPermission = new VXUserPermission();
+
+			// When Creating XXUserPermission UI sends xUserId, to keep it consistent here xUserId should be used
+			vXUserPermission.setUserId(xUserId);
+
+			vXUserPermission.setIsAllowed(RangerCommonEnums.IS_ALLOWED);
+			vXUserPermission.setModuleId(moduleId);
+			try {
+				vXUserPermission = this.createXUserPermission(vXUserPermission);
+				logger.info("Permission assigned to user: [" + vXUserPermission.getUserName() + "] For Module: [" + vXUserPermission.getModuleName() + "]");
+			} catch (Exception e) {
+				logger.error("Error while assigning permission to user: [" + portalUserId + "] for module: [" + moduleId + "]", e);
+			}
+		} else if (isCreate) {
+			vXUserPermission = xUserPermissionService.populateViewBean(xUserPermission);
+			vXUserPermission.setIsAllowed(RangerCommonEnums.IS_ALLOWED);
+			vXUserPermission = this.updateXUserPermission(vXUserPermission);
+			logger.info("Permission Updated for user: [" + vXUserPermission.getUserName() + "] For Module: [" + vXUserPermission.getModuleName() + "]");
+		}
+	}
+
+	public VXUser updateXUser(VXUser vXUser, VXPortalUser oldUserProfile) {
+		VXPortalUser vXPortalUser = new VXPortalUser();
+		if (oldUserProfile != null && oldUserProfile.getId() != null) {
+			vXPortalUser.setId(oldUserProfile.getId());
+		}
+
+		vXPortalUser.setFirstName(vXUser.getFirstName());
+		if("null".equalsIgnoreCase(vXPortalUser.getFirstName())){
+			vXPortalUser.setFirstName("");
+		}
+		vXPortalUser.setLastName(vXUser.getLastName());
+		if("null".equalsIgnoreCase(vXPortalUser.getLastName())){
+			vXPortalUser.setLastName("");
+		}
+		vXPortalUser.setEmailAddress(vXUser.getEmailAddress());
+		vXPortalUser.setLoginId(vXUser.getName());
+		vXPortalUser.setStatus(vXUser.getStatus());
+		vXPortalUser.setUserRoleList(vXUser.getUserRoleList());
+		if (vXPortalUser.getFirstName() != null
+				&& vXPortalUser.getLastName() != null
+				&& !vXPortalUser.getFirstName().trim().isEmpty()
+				&& !vXPortalUser.getLastName().trim().isEmpty()) {
+			vXPortalUser.setPublicScreenName(vXPortalUser.getFirstName() + " "
+					+ vXPortalUser.getLastName());
+		} else {
+			vXPortalUser.setPublicScreenName(vXUser.getName());
+		}
+		vXPortalUser.setUserSource(oldUserProfile.getUserSource());
+
+		String hiddenPasswordString = PropertiesUtil.getProperty("ranger.password.hidden", "*****");
+		String password = vXUser.getPassword();
+		if (oldUserProfile != null && password != null
+				&& password.equals(hiddenPasswordString)) {
+			vXPortalUser.setPassword(oldUserProfile.getPassword());
+		}
+		else if(oldUserProfile != null && oldUserProfile.getUserSource() == RangerCommonEnums.USER_EXTERNAL && password != null){
+			vXPortalUser.setPassword(oldUserProfile.getPassword());
+			logger.debug("User is trrying to change external user password which we are not allowing it to change");
+		}
+		else if(password != null){
+			validatePassword(vXUser);
+			vXPortalUser.setPassword(password);
+		}
+		XXPortalUser xXPortalUser = new XXPortalUser();
+		xXPortalUser = userMgr.updateUserWithPass(vXPortalUser);
+
+		//update permissions start
+		Collection<String> roleListUpdatedProfile =new ArrayList<String>();
+		if (oldUserProfile != null && oldUserProfile.getId() != null) {
+			if(vXUser!=null && vXUser.getUserRoleList()!=null){
+				Collection<String> roleListOldProfile = oldUserProfile.getUserRoleList();
+				Collection<String> roleListNewProfile = vXUser.getUserRoleList();
+				if(roleListNewProfile!=null && roleListOldProfile!=null){
+					for (String role : roleListNewProfile) {
+						if(role!=null && !roleListOldProfile.contains(role)){
+							roleListUpdatedProfile.add(role);
+						}
+					}
+
+				}
+			}
+		}
+		if(roleListUpdatedProfile!=null && roleListUpdatedProfile.size()>0){
+			vXPortalUser.setUserRoleList(roleListUpdatedProfile);
+			List<XXUserPermission> xuserPermissionList = daoManager
+					.getXXUserPermission()
+					.findByUserPermissionId(vXPortalUser.getId());
+			if (xuserPermissionList!=null && xuserPermissionList.size()>0){
+				for (XXUserPermission xXUserPermission : xuserPermissionList) {
+					if (xXUserPermission != null) {
+						try {
+							xUserPermissionService.deleteResource(xXUserPermission.getId());
+						} catch (Exception e) {
+							logger.error(e.getMessage());
+						}
+					}
+				}
+			}
+		}
+		//update permissions end
+		Collection<String> roleList = new ArrayList<String>();
+		if (xXPortalUser != null) {
+			roleList = userMgr.getRolesForUser(xXPortalUser);
+		}
+		if (roleList == null || roleList.size() == 0) {
+			roleList = new ArrayList<String>();
+			roleList.add(RangerConstants.ROLE_USER);
+		}
+
+		// TODO I've to get the transaction log from here.
+		// There is nothing to log anything in XXUser so far.
+		vXUser = xUserService.updateResource(vXUser);
+		vXUser.setUserRoleList(roleList);
+		if (oldUserProfile != null) {
+			if (oldUserProfile.getUserSource() == RangerCommonEnums.USER_APP) {
+				vXUser.setPassword(password);
+			}
+			else if (oldUserProfile.getUserSource() == RangerCommonEnums.USER_EXTERNAL) {
+				vXUser.setPassword(oldUserProfile.getPassword());
+			}
+		}
+
+		List<XXTrxLog> trxLogList = xUserService.getTransactionLog(vXUser,
+				oldUserProfile, "update");
+		vXUser.setPassword(hiddenPasswordString);
+
+		Long userId = vXUser.getId();
+		assignPermissionToUser(vXPortalUser.getUserRoleList(), vXPortalUser.getId(), userId, true);
+
+		xaBizUtil.createTrxLog(trxLogList);
+
+		return vXUser;
+	}
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXGroupUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXGroupUserDao.java
index 1e41e70..1fb6921 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXGroupUserDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXGroupUserDao.java
@@ -20,10 +20,7 @@
  package org.apache.ranger.db;
 
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 import javax.persistence.NoResultException;
 
@@ -134,4 +131,52 @@ public class XXGroupUserDao extends BaseDao<XXGroupUser> {
 		}
 		return null;
 	}
+
+	public Map<String, Set<String>> findUsersByGroupIds() {
+		Map<String, Set<String>> groupUsers = new HashMap<>();
+
+		try {
+			List<Object[]> rows = (List<Object[]>) getEntityManager()
+					.createNamedQuery("XXGroupUser.findUsersByGroupIds")
+					.getResultList();
+			if (rows != null) {
+				for (Object[] row : rows) {
+					if (groupUsers.containsKey((String)row[0])) {
+						groupUsers.get((String)row[0]).add((String)row[1]);
+					} else {
+						Set<String> users = new HashSet<>();
+						users.add((String)row[1]);
+						groupUsers.put((String)row[0], users);
+					}
+				}
+			}
+		} catch (NoResultException e) {
+			//Ignore
+		}
+		return groupUsers;
+	}
+
+	public Map<String, XXGroupUser> findUsersByGroupName(String groupName) {
+		Map<String, XXGroupUser> users = new HashMap<>();
+
+		if (StringUtils.isNotBlank(groupName)) {
+			try {
+				List<Object[]> rows = (List<Object[]>) getEntityManager()
+						.createNamedQuery("XXGroupUser.findUsersByGroupName")
+						.setParameter("groupName", groupName)
+						.getResultList();
+				if (rows != null) {
+					for (Object[] row : rows) {
+							users.put((String)row[0], (XXGroupUser)row[1]);
+					}
+				}
+			} catch (NoResultException e) {
+				if (logger.isDebugEnabled()) {
+					logger.debug(e.getMessage());
+				}
+			}
+		}
+
+		return users;
+	}
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java
index 1198c6d..4c0f33e 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java
@@ -92,4 +92,21 @@ public class XXUserDao extends BaseDao<XXUser> {
 		return userGroups;
 	}
 
+	public Map<String, Long> getAllUserIds() {
+		Map<String, Long> users = new HashMap<>();
+		try {
+			List<Object[]> rows = (List<Object[]>) getEntityManager().createNamedQuery("XXUser.getAllUserIds").getResultList();
+			if (rows != null) {
+				for (Object[] row : rows) {
+					users.put((String)row[0], (Long)row[1]);
+				}
+			}
+		} catch (NoResultException e) {
+			if (logger.isDebugEnabled()) {
+				logger.debug(e.getMessage());
+			}
+		}
+		return users;
+	}
+
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
index e299f1f..03ccfbe 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
@@ -17,11 +17,13 @@
  * under the License.
  */
 
- package org.apache.ranger.rest;
+package org.apache.ranger.rest;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -75,6 +77,8 @@ import org.apache.ranger.service.XPermMapService;
 import org.apache.ranger.service.XResourceService;
 import org.apache.ranger.service.XUserPermissionService;
 import org.apache.ranger.service.XUserService;
+import org.apache.ranger.ugsyncutil.model.GroupUserInfo;
+import org.apache.ranger.ugsyncutil.model.UsersGroupRoleAssignments;
 import org.apache.ranger.view.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
@@ -308,14 +312,6 @@ public class XUserREST {
 	}
 
 	@POST
-	@Path("/users/roleassignments")
-	@Produces({ "application/xml", "application/json" })
-	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
-	public List<String> setXUserRolesByName(VXUsersGroupRoleAssignments ugRoleAssignments) {
-		return xUserMgr.updateUserRoleAssignments(ugRoleAssignments);
-	}
-
-	@POST
 	@Path("/secure/users")
 	@Produces({ "application/xml", "application/json" })
 	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
@@ -1370,4 +1366,46 @@ public class XUserREST {
 
 		return xUserMgr.postUserGroupAuditInfo(vxUgsyncAuditInfo);
 	}
+
+	@GET
+	@Path("/ugsync/groupusers")
+	@Produces({ "application/xml", "application/json" })
+	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+	public Map<String, Set<String>> getAllGroupUsers() {
+		return rangerDaoManager.getXXGroupUser().findUsersByGroupIds();
+	}
+
+	@POST
+	@Path("/ugsync/users")
+	@Produces({ "application/xml", "application/json" })
+	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+	public String addOrUpdateUsers(VXUserList users) {
+		int ret = xUserMgr.createOrUpdateXUsers(users);
+		return String.valueOf(ret);
+	}
+
+	@POST
+	@Path("/ugsync/groups")
+	@Produces({ "application/xml", "application/json" })
+	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+	public int addOrUpdateGroups(VXGroupList groups) {
+		int ret = xUserMgr.createOrUpdateXGroups(groups);
+		return ret;
+	}
+
+	@POST
+	@Path("/ugsync/groupusers")
+	@Produces({ "application/xml", "application/json" })
+	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+	public int addOrUpdateGroupUsersList(List<GroupUserInfo> groupUserInfoList) {
+		return xUserMgr.createOrDeleteXGroupUserList(groupUserInfoList);
+	}
+
+	@POST
+	@Path("/users/roleassignments")
+	@Produces({ "application/xml", "application/json" })
+	@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+	public List<String> setXUserRolesByName(UsersGroupRoleAssignments ugRoleAssignments) {
+		return xUserMgr.updateUserRoleAssignments(ugRoleAssignments);
+	}
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/service/XGroupUserService.java b/security-admin/src/main/java/org/apache/ranger/service/XGroupUserService.java
index bf39f5a..74431b0 100644
--- a/security-admin/src/main/java/org/apache/ranger/service/XGroupUserService.java
+++ b/security-admin/src/main/java/org/apache/ranger/service/XGroupUserService.java
@@ -23,6 +23,8 @@ import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.ranger.common.AppConstants;
 import org.apache.ranger.common.MessageEnums;
@@ -103,6 +105,37 @@ public class XGroupUserService extends
 		return vxGroupUser;
 	}
 
+	public void createOrUpdateXGroupUsers(String groupName, Set<String> users, Map<String, Long> usersFromDB) {
+		XXGroup xxGroup = daoManager.getXXGroup().findByGroupName(groupName);
+		Map<String, XXGroupUser> groupUsers = daoManager.getXXGroupUser().findUsersByGroupName(groupName);
+		XXPortalUser xXPortalUser = daoManager.getXXPortalUser().getById(createdByUserId);
+		for (String username : users) {
+			if (usersFromDB.containsKey(username)) {
+				// Add or update group user mapping only if the user exists in x_user table.
+				XXGroupUser xxGroupUser = groupUsers.get(username);
+				if (xxGroupUser != null) {
+					if (xXPortalUser != null) {
+						xxGroupUser.setAddedByUserId(createdByUserId);
+						xxGroupUser.setUpdatedByUserId(createdByUserId);
+					}
+					xxGroupUser = getDao().update(xxGroupUser);
+				} else {
+					xxGroupUser = new XXGroupUser();
+					VXGroupUser vXGroupUser = new VXGroupUser();
+					vXGroupUser.setUserId(usersFromDB.get(username));
+					vXGroupUser.setName(groupName);
+					vXGroupUser.setParentGroupId(xxGroup.getId());
+					xxGroupUser = mapViewToEntityBean(vXGroupUser, xxGroupUser, 0);
+				}
+				VXGroupUser vXGroupUser = postCreate(xxGroupUser);
+				if (logger.isDebugEnabled()) {
+					logger.debug(String.format("createXGroupUserFromMap(): Create or update group user mapping with groupname =  " + vXGroupUser.getName()
+							+ " username = %s userId = %d", username, vXGroupUser.getUserId()));
+				}
+			}
+		}
+	}
+
 	public VXGroupUser readResourceWithOutLogin(Long id) {
 		XXGroupUser resource = getDao().getById(id);
 		if (resource == null) {
diff --git a/security-admin/src/main/java/org/apache/ranger/view/VXUsersGroupRoleAssignments.java b/security-admin/src/main/java/org/apache/ranger/view/VXUsersGroupRoleAssignments.java
deleted file mode 100644
index 848a2c1..0000000
--- a/security-admin/src/main/java/org/apache/ranger/view/VXUsersGroupRoleAssignments.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.view;
-
-import org.codehaus.jackson.annotate.JsonAutoDetect;
-import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
-import org.codehaus.jackson.annotate.JsonIgnoreProperties;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import java.util.List;
-import java.util.Map;
-
-@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-@JsonIgnoreProperties(ignoreUnknown = true)
-@XmlRootElement
-public class VXUsersGroupRoleAssignments {
-
-	List<String> users;
-
-	Map<String, String> groupRoleAssignments;
-
-	Map<String, String> userRoleAssignments;
-
-	public List<String> getUsers() {
-		return users;
-	}
-
-	public void setUsers(List<String> users) {
-		this.users = users;
-	}
-
-	public Map<String, String> getGroupRoleAssignments() {
-		return groupRoleAssignments;
-	}
-
-	public void setGroupRoleAssignments(Map<String, String> groupRoleAssignments) {
-		this.groupRoleAssignments = groupRoleAssignments;
-	}
-
-	public Map<String, String> getUserRoleAssignments() {
-		return userRoleAssignments;
-	}
-
-	public void setUserRoleAssignments(Map<String, String> userRoleAssignments) {
-		this.userRoleAssignments = userRoleAssignments;
-	}
-}
\ No newline at end of file
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index 7d9e145..a8f5818 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -134,6 +134,23 @@
 		</query>
 	</named-query>
 
+	<named-query name="XXUser.getAllUserIds">
+		<query>SELECT user.name, user.id FROM XXUser user
+		</query>
+	</named-query>
+
+	<named-query name="XXGroupUser.findUsersByGroupIds">
+               <query>SELECT group.name, user.name FROM XXUser user, XXGroup group, XXGroupUser groupUser
+                       WHERE user.id=groupUser.userId and group.id=groupUser.parentGroupId
+               </query>
+       </named-query>
+
+	<named-query name="XXGroupUser.findUsersByGroupName">
+		<query>SELECT user.name FROM XXUser user, XXGroupUser groupUser
+			WHERE user.id=groupUser.userId and groupUser.name = :groupName
+		</query>
+	</named-query>
+
 	<!-- XXPermMap -->
 	<named-query name="XXPermMap.findByResourceId">
 		<query>SELECT obj FROM XXPermMap obj WHERE obj.resourceId = :resourceId
diff --git a/ugsync-util/.gitignore b/ugsync-util/.gitignore
new file mode 100644
index 0000000..02f68bb
--- /dev/null
+++ b/ugsync-util/.gitignore
@@ -0,0 +1,3 @@
+/target/
+/bin/
+.settings/
diff --git a/ugsync-util/pom.xml b/ugsync-util/pom.xml
new file mode 100644
index 0000000..aa992ca
--- /dev/null
+++ b/ugsync-util/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ranger</artifactId>
+        <groupId>org.apache.ranger</groupId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>ugsync-util</artifactId>
+    <packaging>jar</packaging>
+    <name>User Group Synchronizer Util</name>
+    <description>User Group Synchronizer Util</description>
+    <dependencies>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <version>${codehaus.jackson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-jaxrs</artifactId>
+            <version>${codehaus.jackson.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/FileSyncSourceInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/FileSyncSourceInfo.java
similarity index 97%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/FileSyncSourceInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/FileSyncSourceInfo.java
index a6348d5..d6f12f1 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/FileSyncSourceInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/FileSyncSourceInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 public class FileSyncSourceInfo {
 	private String fileName;
diff --git a/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/GroupUserInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/GroupUserInfo.java
new file mode 100644
index 0000000..ffb6625
--- /dev/null
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/GroupUserInfo.java
@@ -0,0 +1,67 @@
+/*
+ * 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.ranger.ugsyncutil.model;;
+
+import java.util.Set;
+
+public class GroupUserInfo {
+    String groupName;
+    Set<String> addUsers;
+    Set<String> delUsers;
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    public Set<String> getAddUsers() {
+        return addUsers;
+    }
+
+    public void setAddUsers(Set<String> addUsers) {
+        this.addUsers = addUsers;
+    }
+
+    public Set<String> getDelUsers() {
+        return delUsers;
+    }
+
+    public void setDelUsers(Set<String> delUsers) {
+        this.delUsers = delUsers;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        toString(sb);
+        return sb.toString();
+    }
+
+    public StringBuilder toString(StringBuilder sb) {
+        sb.append("GroupUserInfo [groupName= ").append(groupName);
+        sb.append(", addUsers = ").append(addUsers);
+        sb.append(", delUsers = ").append(delUsers);
+        sb.append("]");
+        return sb;
+    }
+}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/LdapSyncSourceInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/LdapSyncSourceInfo.java
similarity index 98%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/LdapSyncSourceInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/LdapSyncSourceInfo.java
index 54802a0..2de4faf 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/LdapSyncSourceInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/LdapSyncSourceInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 public class LdapSyncSourceInfo {
 	private String ldapUrl;
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UgsyncAuditInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UgsyncAuditInfo.java
similarity index 98%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/UgsyncAuditInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UgsyncAuditInfo.java
index 65ac89b..3407c69 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UgsyncAuditInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UgsyncAuditInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 public class UgsyncAuditInfo {
 
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UnixSyncSourceInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UnixSyncSourceInfo.java
similarity index 98%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/UnixSyncSourceInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UnixSyncSourceInfo.java
index 6e5df9d..1445655 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UnixSyncSourceInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UnixSyncSourceInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 public class UnixSyncSourceInfo {
 	private String unixBackend;
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UsersGroupRoleAssignments.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UsersGroupRoleAssignments.java
similarity index 97%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/UsersGroupRoleAssignments.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UsersGroupRoleAssignments.java
index e6cabdb..ce0b9dd 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UsersGroupRoleAssignments.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/UsersGroupRoleAssignments.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.ranger.unixusersync.model;
+package org.apache.ranger.ugsyncutil.model;
 
 import java.util.List;
 import java.util.Map;
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XGroupInfo.java
similarity index 97%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XGroupInfo.java
index b61f39c..df04266 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XGroupInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 public class XGroupInfo {
 	
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java
similarity index 89%
rename from ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java
rename to ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java
index bee6323..9405a76 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java
+++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.model;
+ package org.apache.ranger.ugsyncutil.model;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,6 +27,8 @@ public class XUserInfo {
 	private String name;
 	private String 	description;
 	private String otherAttributes;
+	private String userSource;
+	private String status;
     private List<String> groupNameList = new ArrayList<String>();
     private List<String> userRoleList = new ArrayList<String>();
 	
@@ -48,7 +50,23 @@ public class XUserInfo {
 	public void setDescription(String description) {
 		this.description = description;
 	}
-	
+
+	public String getUserSource() {
+		return userSource;
+	}
+
+	public void setUserSource(String userSource) {
+		this.userSource = userSource;
+	}
+
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
 	public void setGroupNameList(List<String> groupNameList) {
 		this.groupNameList = groupNameList;
 	}
diff --git a/ugsync/pom.xml b/ugsync/pom.xml
index 8a1431c..07e0c58 100644
--- a/ugsync/pom.xml
+++ b/ugsync/pom.xml
@@ -142,6 +142,11 @@
 			<artifactId>jackson-jaxrs</artifactId>
 			<version>${codehaus.jackson.version}</version>
 		</dependency>
+        <dependency>
+            <groupId>org.apache.ranger</groupId>
+            <artifactId>ugsync-util</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
deleted file mode 100644
index 011c9c6..0000000
--- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
- package org.apache.ranger.ldapusersync.process;
-
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.HashMap;
-import java.util.UUID;
-import java.util.NoSuchElementException;
-
-import javax.naming.Context;
-import javax.naming.InvalidNameException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.Control;
-import javax.naming.ldap.InitialLdapContext;
-import javax.naming.ldap.LdapContext;
-import javax.naming.ldap.PagedResultsControl;
-import javax.naming.ldap.PagedResultsResponseControl;
-import javax.naming.ldap.StartTlsRequest;
-import javax.naming.ldap.StartTlsResponse;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.apache.commons.collections.BidiMap;
-import org.apache.commons.collections.bidimap.DualHashBidiMap;
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
-import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.apache.ranger.unixusersync.model.LdapSyncSourceInfo;
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
-import org.apache.ranger.usergroupsync.AbstractUserGroupSource;
-import org.apache.ranger.usergroupsync.UserGroupSink;
-
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.Table;
-
-public class LdapDeltaUserGroupBuilder extends AbstractUserGroupSource {
-	
-	private static final Logger LOG = Logger.getLogger(LdapDeltaUserGroupBuilder.class);
-	
-	private static final String DATA_TYPE_BYTEARRAY = "byte[]";
-	private static final String DATE_FORMAT = "yyyyMMddHHmmss";
-	private static final int PAGE_SIZE = 500;
-	private static long deltaSyncUserTime = 0; // Used for AD uSNChanged 
-	private static long deltaSyncGroupTime = 0; // Used for AD uSNChanged
-	private String deltaSyncUserTimeStamp; // Used for OpenLdap modifyTimestamp
-	private String deltaSyncGroupTimeStamp; // Used for OpenLdap modifyTimestamp
-
-  private String ldapUrl;
-  private String ldapBindDn;
-  private String ldapBindPassword;
-  private String ldapAuthenticationMechanism;
-  private String ldapReferral;
-  private String searchBase;
-
-  private String[] userSearchBase;
-	private String userNameAttribute;
-	private String userCloudIdAttribute;
-  private int    userSearchScope;
-  private String userObjectClass;
-  private String userSearchFilter;
-  private String extendedUserSearchFilter;
-  private SearchControls userSearchControls;
-  private Set<String> userGroupNameAttributeSet;
-  private Set<String> otherUserAttributes;
-
-  private boolean pagedResultsEnabled = true;
-  private int pagedResultsSize = PAGE_SIZE;
-
-  private boolean groupSearchFirstEnabled = false;
-  private boolean userSearchEnabled = false;
-  private boolean groupSearchEnabled = true;
-  private String[] groupSearchBase;
-  private int    groupSearchScope;
-  private String groupObjectClass;
-  private String groupSearchFilter;
-  private String extendedGroupSearchFilter;
-  private String extendedAllGroupsSearchFilter;
-  private SearchControls groupSearchControls;
-  private String groupMemberAttributeName;
-  private String groupNameAttribute;
-	private String groupCloudIdAttribute;
-	private Set<String> otherGroupAttributes;
-	private int groupHierarchyLevels;
-
-	private LdapContext ldapContext;
-	StartTlsResponse tls;
-
-	private boolean userNameCaseConversionFlag = false;
-	private boolean groupNameCaseConversionFlag = false;
-	private boolean userNameLowerCaseFlag = false;
-	private boolean groupNameLowerCaseFlag = false;
-
-  private Table<String, String, String> groupUserTable;
-  private Map<String, String> userNameMap;
-	private HashSet<String> groupNames;
-	private BidiMap groupNameMap;
-	UgsyncAuditInfo ugsyncAuditInfo;
-	LdapSyncSourceInfo ldapSyncSourceInfo;
-	int noOfNewUsers;
-	int noOfNewGroups;
-	int noOfModifiedUsers;
-	int noOfModifiedGroups;
-	private Map<String, Map<String, String>> groupInfoMap;
-
-	public static void main(String[] args) throws Throwable {
-		LdapDeltaUserGroupBuilder  ugBuilder = new LdapDeltaUserGroupBuilder();
-		ugBuilder.init();
-	}
-
-	public LdapDeltaUserGroupBuilder() {
-		super();
-		LOG.info("LdapDeltaUserGroupBuilder created");
-
-		String userNameCaseConversion = config.getUserNameCaseConversion();
-
-		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion)) {
-		    userNameCaseConversionFlag = false;
-		}
-		else {
-		    userNameCaseConversionFlag = true;
-		    userNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion);
-		}
-
-		String groupNameCaseConversion = config.getGroupNameCaseConversion();
-
-		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion)) {
-		    groupNameCaseConversionFlag = false;
-		}
-		else {
-		    groupNameCaseConversionFlag = true;
-		    groupNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion);
-		}
-	}
-
-	@Override
-	public void init() throws Throwable{
-		deltaSyncUserTime = 0;
-		deltaSyncGroupTime = 0;
-		DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
-		deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
-		deltaSyncGroupTimeStamp = dateFormat.format(new Date(0));
-		userNameMap = new HashMap<String, String>();
-		groupNames = new HashSet<String>();
-		setConfig();
-		ugsyncAuditInfo = new UgsyncAuditInfo();
-		ldapSyncSourceInfo = new LdapSyncSourceInfo();
-		ldapSyncSourceInfo.setLdapUrl(ldapUrl);
-		ldapSyncSourceInfo.setIncrementalSycn("True");
-		ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled));
-		ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled));
-		ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled));
-		ldapSyncSourceInfo.setGroupHierarchyLevel(Integer.toString(groupHierarchyLevels));
-		ugsyncAuditInfo.setSyncSource("LDAP/AD");
-		ugsyncAuditInfo.setLdapSyncSourceInfo(ldapSyncSourceInfo);
-	}
-
-	private void createLdapContext() throws Throwable {
-		Properties env = new Properties();
-		env.put(Context.INITIAL_CONTEXT_FACTORY,
-				"com.sun.jndi.ldap.LdapCtxFactory");
-		env.put(Context.PROVIDER_URL, ldapUrl);
-		if (ldapUrl.startsWith("ldaps") && (config.getSSLTrustStorePath() != null && !config.getSSLTrustStorePath().trim().isEmpty())) {
-			env.put("java.naming.ldap.factory.socket", "org.apache.ranger.ldapusersync.process.CustomSSLSocketFactory");
-		}
-
-		if (StringUtils.isNotEmpty(userCloudIdAttribute)) {
-			if (config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
-				env.put("java.naming.ldap.attributes.binary", userCloudIdAttribute);
-			}
-		}
-
-		if (StringUtils.isNotEmpty(groupCloudIdAttribute)) {
-			if (config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
-				env.put("java.naming.ldap.attributes.binary", groupCloudIdAttribute);
-			}
-		}
-
-		for (String otherUserAttribute : otherUserAttributes) {
-			String attrType = config.getOtherUserAttributeDataType(otherUserAttribute);
-			if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
-				env.put("java.naming.ldap.attributes.binary", otherUserAttribute);
-			}
-		}
-
-		for (String otherGroupAttribute : otherGroupAttributes) {
-			String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute);
-			if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
-				env.put("java.naming.ldap.attributes.binary", otherGroupAttribute);
-			}
-		}
-
-		ldapContext = new InitialLdapContext(env, null);
-		if (!ldapUrl.startsWith("ldaps")) {
-			if (config.isStartTlsEnabled()) {
-				tls = (StartTlsResponse) ldapContext.extendedOperation(new StartTlsRequest());
-				if (config.getSSLTrustStorePath() != null && !config.getSSLTrustStorePath().trim().isEmpty()) {
-					tls.negotiate(CustomSSLSocketFactory.getDefault());
-				} else {
-					tls.negotiate();
-				}
-				LOG.info("Starting TLS session...");
-			}
-		}
-
-		ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, ldapBindDn);
-		ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, ldapBindPassword);
-		ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, ldapAuthenticationMechanism);
-		ldapContext.addToEnvironment(Context.REFERRAL, ldapReferral);
-	}
-
-	private void setConfig() throws Throwable {
-		LOG.info("LdapDeltaUserGroupBuilder initialization started");
-
-		groupSearchFirstEnabled =   config.isGroupSearchFirstEnabled();
-		userSearchEnabled =   config.isUserSearchEnabled();
-		groupSearchEnabled =   config.isGroupSearchEnabled();
-    ldapUrl = config.getLdapUrl();
-    ldapBindDn = config.getLdapBindDn();
-    ldapBindPassword = config.getLdapBindPassword();
-    //ldapBindPassword = "admin-password";
-    ldapAuthenticationMechanism = config.getLdapAuthenticationMechanism();
-    ldapReferral = config.getContextReferral();
-		searchBase = config.getSearchBase();
-
-		userSearchBase = config.getUserSearchBase().split(";");
-		userSearchScope = config.getUserSearchScope();
-		userObjectClass = config.getUserObjectClass();
-		userSearchFilter = config.getUserSearchFilter();
-
-		userNameAttribute = config.getUserNameAttribute();
-		userCloudIdAttribute = config.getUserCloudIdAttribute();
-
-		Set<String> userSearchAttributes = new HashSet<String>();
-		userSearchAttributes.add(userNameAttribute);
-		userSearchAttributes.add(userCloudIdAttribute);
-		// For Group based search, user's group name attribute should not be added to the user search attributes
-		if (!groupSearchFirstEnabled && !groupSearchEnabled) {
-			userGroupNameAttributeSet = config.getUserGroupNameAttributeSet();
-			for (String useGroupNameAttribute : userGroupNameAttributeSet) {
-				userSearchAttributes.add(useGroupNameAttribute);
-			}
-		}
-		otherUserAttributes = config.getOtherUserAttributes();
-		for (String otherUserAttribute : otherUserAttributes) {
-			userSearchAttributes.add(otherUserAttribute);
-		}
-		userSearchAttributes.add("uSNChanged");
-		userSearchAttributes.add("modifytimestamp");
-		userSearchControls = new SearchControls();
-		userSearchControls.setSearchScope(userSearchScope);
-		userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
-				new String[userSearchAttributes.size()]));
-
-    pagedResultsEnabled =   config.isPagedResultsEnabled();
-    pagedResultsSize =   config.getPagedResultsSize();
-
-    groupSearchBase = config.getGroupSearchBase().split(";");
-    groupSearchScope = config.getGroupSearchScope();
-    groupObjectClass = config.getGroupObjectClass();
-    groupSearchFilter = config.getGroupSearchFilter();
-    groupMemberAttributeName =  config.getUserGroupMemberAttributeName();
-    groupNameAttribute = config.getGroupNameAttribute();
-    groupCloudIdAttribute = config.getGroupCloudIdAttribute();
-		groupHierarchyLevels = config.getGroupHierarchyLevels();
-
-    extendedGroupSearchFilter =  "(&"  + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
-
-    groupSearchControls = new SearchControls();
-    groupSearchControls.setSearchScope(groupSearchScope);
-
-    Set<String> groupSearchAttributes = new HashSet<String>();
-    groupSearchAttributes.add(groupNameAttribute);
-    groupSearchAttributes.add(groupCloudIdAttribute);
-    groupSearchAttributes.add(groupMemberAttributeName);
-    groupSearchAttributes.add("uSNChanged");
-    groupSearchAttributes.add("modifytimestamp");
-    otherGroupAttributes = config.getOtherGroupAttributes();
-    for (String otherGroupAttribute : otherGroupAttributes) {
-		groupSearchAttributes.add(otherGroupAttribute);
-    }
-    groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
-			new String[groupSearchAttributes.size()]));
-
-		if (LOG.isInfoEnabled()) {
-			LOG.info("LdapDeltaUserGroupBuilder initialization completed with --  "
-					+ "ldapUrl: " + ldapUrl
-					+ ",  ldapBindDn: " + ldapBindDn
-					+ ",  ldapBindPassword: ***** "
-					+ ",  ldapAuthenticationMechanism: " + ldapAuthenticationMechanism
-          + ",  searchBase: " + searchBase
-          + ",  userSearchBase: " + Arrays.toString(userSearchBase)
-          + ",  userSearchScope: " + userSearchScope
-					+ ",  userObjectClass: " + userObjectClass
-					+ ",  userSearchFilter: " + userSearchFilter
-					+ ",  extendedUserSearchFilter: " + extendedUserSearchFilter
-					+ ",  userNameAttribute: " + userNameAttribute
-					+ ",  userSearchAttributes: " + userSearchAttributes
-          + ",  userGroupNameAttributeSet: " + userGroupNameAttributeSet
-			+ ",  otherUserAttributes: " + otherUserAttributes
-          + ",  pagedResultsEnabled: " + pagedResultsEnabled
-          + ",  pagedResultsSize: " + pagedResultsSize
-          + ",  groupSearchEnabled: " + groupSearchEnabled
-          + ",  groupSearchBase: " + Arrays.toString(groupSearchBase)
-          + ",  groupSearchScope: " + groupSearchScope
-          + ",  groupObjectClass: " + groupObjectClass
-          + ",  groupSearchFilter: " + groupSearchFilter
-          + ",  extendedGroupSearchFilter: " + extendedGroupSearchFilter
-          + ",  extendedAllGroupsSearchFilter: " + extendedAllGroupsSearchFilter
-          + ",  groupMemberAttributeName: " + groupMemberAttributeName
-          + ",  groupNameAttribute: " + groupNameAttribute
-          + ", groupSearchAttributes: " + groupSearchAttributes
-          + ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
-          + ", userSearchEnabled: " + userSearchEnabled
-          + ",  ldapReferral: " + ldapReferral
-      );
-		}
-
-	}
-
-	private void closeLdapContext() throws Throwable {
-		if (tls != null) {
-			tls.close();
-		}
-		if (ldapContext != null) {
-			ldapContext.close();
-		}
-	}
-
-	@Override
-	public boolean isChanged() {
-		// we do not want to get the full ldap dit and check whether anything has changed
-		return true;
-	}
-
-	@Override
-	public void updateSink(UserGroupSink sink) throws Throwable {
-		LOG.info("LdapDeltaUserGroupBuilder updateSink started");
-		groupUserTable = HashBasedTable.create();
-        groupNameMap = new DualHashBidiMap();
-		groupInfoMap = new HashMap<>();
-		noOfNewUsers = 0;
-		noOfNewGroups = 0;
-		noOfModifiedUsers = 0;
-		noOfModifiedGroups = 0;
-
-        if (!groupSearchFirstEnabled) {
-			LOG.info("Performing user search first");
-			getUsers(sink);
-			if (groupSearchEnabled) {
-				getGroups(sink);
-			}
-			//LOG.debug("Total No. of users saved = " + groupUserTable.columnKeySet().size());
-
-		} else {
-			LOG.info("Performing Group search first");
-			getGroups(sink);
-			if (userSearchEnabled) {
-				LOG.info("User search is enabled and hence computing user membership.");
-				getUsers(sink);
-			}
-		}
-		if (groupUserTable.isEmpty()) {
-			//System.out.println("groupUserTable is empty!!");
-			ugsyncAuditInfo.setNoOfNewUsers(Integer.toUnsignedLong(noOfNewUsers));
-			ugsyncAuditInfo.setNoOfNewGroups(Integer.toUnsignedLong(noOfNewGroups));
-			ugsyncAuditInfo.setNoOfModifiedUsers(Integer.toUnsignedLong(noOfModifiedUsers));
-			ugsyncAuditInfo.setNoOfModifiedGroups(Integer.toUnsignedLong(noOfModifiedGroups));
-			ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter);
-			ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter);
-			try {
-				sink.postUserGroupAuditInfo(ugsyncAuditInfo);
-			} catch (Throwable t) {
-				LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
-			}
-			return;
-		}
-        
-		if (groupHierarchyLevels > 0) {
-			LOG.info("Going through group hierarchy for nested group evaluation");
-            Set<String> groupFullNames = groupNameMap.keySet();
-			for(String group : groupFullNames) {
-				Set<String> nextLevelGroups = groupUserTable.column(group).keySet();
-				goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels-1, groupNameMap.get(group).toString());
-			}
-			LOG.info("Completed group hierarchy computation");
-		}
-
-		Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator();
-		while (groupUserTableIterator.hasNext()) {
-			String groupName = groupUserTableIterator.next();
-			//System.out.println("Group name from the groupUserTable: " + groupName);
-			Map<String,String> groupUsersMap =  groupUserTable.row(groupName);
-			Set<String> userSet = new HashSet<String>();
-			for(Map.Entry<String, String> entry : groupUsersMap.entrySet()){
-				//String transformUserName = userNameTransform(entry.getKey());
-		         userSet.add(entry.getValue());
-		    }
-			List<String> userList = new ArrayList<>(userSet);
-			String transformGroupName = groupNameTransform(groupName);
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("addOrUpdateGroup(): group = " + groupName + " users = " + userList);
-			}
-			try {
-				sink.addOrUpdateGroup(transformGroupName, groupInfoMap.get(groupName), userList);
-			} catch (Throwable t) {
-				LOG.error("sink.addOrUpdateGroup failed with exception: " + t.getMessage()
-				+ ", for group: " + transformGroupName
-				+ ", users: " + userList);
-			}
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("postUserGroupAuditInfo(): noOfUsers = " + noOfNewUsers + " noOfGroups = " + noOfNewGroups);
-		}
-
-		ugsyncAuditInfo.setNoOfNewUsers(Integer.toUnsignedLong(noOfNewUsers));
-		ugsyncAuditInfo.setNoOfNewGroups(Integer.toUnsignedLong(noOfNewGroups));
-		ugsyncAuditInfo.setNoOfModifiedUsers(Integer.toUnsignedLong(noOfModifiedUsers));
-		ugsyncAuditInfo.setNoOfModifiedGroups(Integer.toUnsignedLong(noOfModifiedGroups));
-		ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter);
-		ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter);
-		ldapSyncSourceInfo.setTotalUsersSynced(userNameMap.size());
-		ldapSyncSourceInfo.setTotalGroupsSynced(groupNames.size());
-
-		try {
-			sink.postUserGroupAuditInfo(ugsyncAuditInfo);
-		} catch (Throwable t) {
-			LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
-		}
-	}
-
-	private void getUsers(UserGroupSink sink) throws Throwable {
-		NamingEnumeration<SearchResult> userSearchResultEnum = null;
-		NamingEnumeration<SearchResult> groupSearchResultEnum = null;
-		try {
-			createLdapContext();
-			int total;
-			// Activate paged results
-			if (pagedResultsEnabled)   {
-				ldapContext.setRequestControls(new Control[]{
-						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
-			}
-			DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
-			if (groupSearchFirstEnabled && groupUserTable.rowKeySet().size() != 0) {
-				// Fix RANGER-1957: Perform full sync when group search is enabled and when there are updates to the groups
-				deltaSyncUserTime = 0;
-				deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
-			}
-
-			extendedUserSearchFilter = "(objectclass=" + userObjectClass + ")(|(uSNChanged>=" + deltaSyncUserTime + ")(modifyTimestamp>=" + deltaSyncUserTimeStamp + "Z))";
-
-			if (userSearchFilter != null && !userSearchFilter.trim().isEmpty()) {
-				String customFilter = userSearchFilter.trim();
-				if (!customFilter.startsWith("(")) {
-					customFilter = "(" + customFilter + ")";
-				}
-
-				extendedUserSearchFilter = "(&" + extendedUserSearchFilter + customFilter + ")";
-			} else {
-				extendedUserSearchFilter = "(&" + extendedUserSearchFilter + ")";
-			}
-			LOG.info("extendedUserSearchFilter = " + extendedUserSearchFilter);
-
-			long highestdeltaSyncUserTime = deltaSyncUserTime;
-
-			// When multiple OUs are configured, go through each OU as the user search base to search for users.
-			for (int ou=0; ou<userSearchBase.length; ou++) {
-				byte[] cookie = null;
-				int counter = 0;
-				try {
-				int paged = 0;
-				do {
-					userSearchResultEnum = ldapContext
-							.search(userSearchBase[ou], extendedUserSearchFilter,
-									userSearchControls);
-
-					while (userSearchResultEnum.hasMore()) {
-						// searchResults contains all the user entries
-						final SearchResult userEntry = userSearchResultEnum.next();
-
-						if (userEntry == null)  {
-							if (LOG.isInfoEnabled())  {
-								LOG.info("userEntry null, skipping sync for the entry");
-							}
-							continue;
-						}
-						//System.out.println("userEntry = " + userEntry);
-
-						Attributes attributes =   userEntry.getAttributes();
-						if (attributes == null)  {
-							if (LOG.isInfoEnabled())  {
-								LOG.info("attributes  missing for entry " + userEntry.getNameInNamespace() +
-										", skipping sync");
-							}
-							continue;
-						}
-
-						Attribute userNameAttr  = attributes.get(userNameAttribute);
-						if (userNameAttr == null)  {
-							if (LOG.isInfoEnabled())  {
-								LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() +
-										", skipping sync");
-							}
-							continue;
-						}
-
-						String userFullName = (userEntry.getNameInNamespace()).toLowerCase();
-						String userName = (String) userNameAttr.get();
-
-						if (userName == null || userName.trim().isEmpty())  {
-							if (LOG.isInfoEnabled())  {
-								LOG.info(userNameAttribute + " empty for entry " + userEntry.getNameInNamespace() +
-										", skipping sync");
-							}
-							continue;
-						}
-
-						Attribute timeStampAttr  = attributes.get("uSNChanged");
-						if (timeStampAttr != null) {
-							String uSNChangedVal = (String) timeStampAttr.get();
-							long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
-							LOG.info("uSNChangedVal = " + uSNChangedVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
-							if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
-								highestdeltaSyncUserTime = currentDeltaSyncTime;
-							}
-						} else {
-							timeStampAttr = attributes.get("modifytimestamp");
-							if (timeStampAttr != null) {
-								String timeStampVal = (String) timeStampAttr.get();
-								Date parseDate = dateFormat.parse(timeStampVal);
-								long currentDeltaSyncTime = parseDate.getTime();
-								LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
-								if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
-									highestdeltaSyncUserTime = currentDeltaSyncTime;
-									deltaSyncUserTimeStamp = timeStampVal;
-								}
-							}
-						}
-
-						Map<String, String> userAttrMap = new HashMap<>();
-						Attribute userCloudIdAttr = attributes.get(userCloudIdAttribute);
-						if (userCloudIdAttr != null) {
-							addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, config.getUserCloudIdAttributeDataType());
-						}
-						for (String otherUserAttribute : otherUserAttributes) {
-							if (attributes.get(otherUserAttribute) != null) {
-								String attrType = config.getOtherUserAttributeDataType(otherUserAttribute);
-								addToAttrMap(userAttrMap, otherUserAttribute, attributes.get(otherUserAttribute), attrType);
-							}
-						}
-
-						if (!groupSearchFirstEnabled) {
-							String transformUserName = userNameTransform(userName);
-							try {
-								sink.addOrUpdateUser(transformUserName, userAttrMap, null);
-							} catch (Throwable t) {
-								LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-								+ ", for user: " + transformUserName);
-							}
-							//System.out.println("Adding user fullname = " + userFullName + " username = " + transformUserName);
-							if (userNameMap.containsKey(userFullName)) {
-								noOfModifiedUsers++;
-							} else {
-								noOfNewUsers++;
-							}
-							userNameMap.put(userFullName, transformUserName);
-							Set<String> groups = new HashSet<String>();
-
-							// Get all the groups from the group name attribute of the user only when group search is not enabled.
-							if (!groupSearchEnabled) {
-								for (String useGroupNameAttribute : userGroupNameAttributeSet) {
-									Attribute userGroupfAttribute = userEntry.getAttributes().get(useGroupNameAttribute);
-									if (userGroupfAttribute != null) {
-										NamingEnumeration<?> groupEnum = userGroupfAttribute.getAll();
-										while (groupEnum.hasMore()) {
-											String gName = getShortName((String) groupEnum
-													.next());
-											String transformGroupName = groupNameTransform(gName);
-											groups.add(transformGroupName);
-										}
-									}
-								}
-							}
-
-							List<String> groupList = new ArrayList<String>(groups);
-							try {
-								sink.addOrUpdateUser(transformUserName, userAttrMap, groupList);
-
-							} catch (Throwable t) {
-								LOG.error("sink.addOrUpdateUserGroups failed with exception: " + t.getMessage()
-								+ ", for user: " + transformUserName + " and groups: " + groupList);
-							}
-                            counter++;
-						} else {
-							// If the user from the search result is present in the group user table,
-							// then addorupdate user to ranger admin.
-							if (LOG.isDebugEnabled()) {
-								LOG.debug("Chekcing if the user " + userFullName + " is part of the retrieved groups");
-							}
-							if ((groupUserTable.containsColumn(userFullName) || groupUserTable.containsColumn(userName))) {
-								if (!userNameMap.containsKey(userFullName)) {
-									String transformUserName = userNameTransform(userName);
-									try {
-										sink.addOrUpdateUser(transformUserName, userAttrMap, null);
-									} catch (Throwable t) {
-										LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-												+ ", for user: " + transformUserName);
-									}
-									userNameMap.put(userFullName, transformUserName);
-									//Also update the username in the groupUserTable with the one from username attribute.
-									Map<String, String> userMap = groupUserTable.column(userFullName);
-									for (Map.Entry<String, String> entry : userMap.entrySet()) {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("Updating groupUserTable " + entry.getValue() + " with: " + transformUserName + " for " + entry.getKey());
-										}
-										groupUserTable.put(entry.getKey(), userFullName, transformUserName);
-									}
-									counter++;
-									noOfNewUsers++;
-								} else {
-									noOfModifiedUsers++;
-								}
-							}
-
-						}
-
-                        if (counter <= 2000) {
-                            if (LOG.isInfoEnabled()) {
-                                LOG.info("Updating user count: " + counter
-                                        + ", userName: " + userName);
-                            }
-                            if ( counter == 2000 ) {
-                                LOG.info("===> 2000 user records have been synchronized so far. From now on, only a summary progress log will be written for every 100 users. To continue to see detailed log for every user, please enable Trace level logging. <===");
-                            }
-                        } else {
-                            if (LOG.isTraceEnabled()) {
-                                LOG.trace("Updating user count: " + counter
-                                        + ", userName: " + userName);
-                            } else  {
-                                if ( counter % 100 == 0) {
-                                    LOG.info("Synced " + counter + " users till now");
-                                }
-                            }
-                        }
-
-					}
-
-					// Examine the paged results control response
-					Control[] controls = ldapContext.getResponseControls();
-					if (controls != null) {
-						for (int i = 0; i < controls.length; i++) {
-							if (controls[i] instanceof PagedResultsResponseControl) {
-								PagedResultsResponseControl prrc =
-										(PagedResultsResponseControl)controls[i];
-								total = prrc.getResultSize();
-								if (total != 0) {
-									if (LOG.isDebugEnabled()) {
-										LOG.debug("END-OF-PAGE total : " + total);
-									}
-								} else {
-									if (LOG.isDebugEnabled()) {
-										LOG.debug("END-OF-PAGE total : unknown");
-									}
-								}
-								cookie = prrc.getCookie();
-							}
-						}
-					} else {
-						if (LOG.isDebugEnabled()) {
-							LOG.debug("No controls were sent from the server");
-						}
-					}
-					// Re-activate paged results
-					if (pagedResultsEnabled)   {
-						if (LOG.isDebugEnabled()) {
-							LOG.debug(String.format("Fetched paged results round: %s", ++paged));
-						}
-						ldapContext.setRequestControls(new Control[]{
-								new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
-					}
-				} while (cookie != null);
-				LOG.info("LdapDeltaUserGroupBuilder.getUsers() completed with user count: "
-						+ counter);
-				} catch (Exception t) {
-					LOG.error("LdapDeltaUserGroupBuilder.getUsers() failed with exception: ", t);
-					LOG.info("LdapDeltaUserGroupBuilder.getUsers() user count: "
-							+ counter);
-				}
-			}
-			if (deltaSyncUserTime < highestdeltaSyncUserTime) {
-				// Incrementing highestdeltaSyncUserTime (for AD) in order to avoid search record repetition for next sync cycle.
-				deltaSyncUserTime = highestdeltaSyncUserTime + 1;
-				// Incrementing the highest timestamp value (for Openldap) with 1sec in order to avoid search record repetition for next sync cycle.
-				deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60l));
-			}
-		} finally {
-			if (userSearchResultEnum != null) {
-				userSearchResultEnum.close();
-			}
-			if (groupSearchResultEnum != null) {
-				groupSearchResultEnum.close();
-			}
-			closeLdapContext();
-		}
-	}
-
-	private void getGroups(UserGroupSink sink) throws Throwable {
-		NamingEnumeration<SearchResult> groupSearchResultEnum = null;
-        DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
-        long highestdeltaSyncGroupTime = deltaSyncGroupTime;
-		try {
-			createLdapContext();
-			int total;
-			// Activate paged results
-			if (pagedResultsEnabled)   {
-				ldapContext.setRequestControls(new Control[]{
-						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
-			}
-			extendedGroupSearchFilter = "(objectclass=" + groupObjectClass + ")";
-			if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
-				String customFilter = groupSearchFilter.trim();
-				if (!customFilter.startsWith("(")) {
-					customFilter = "(" + customFilter + ")";
-				}
-				extendedGroupSearchFilter = extendedGroupSearchFilter + customFilter;
-			}
-
-			extendedAllGroupsSearchFilter = "(&"  + extendedGroupSearchFilter + "(|(uSNChanged>=" + deltaSyncGroupTime + ")(modifyTimestamp>=" + deltaSyncGroupTimeStamp + "Z)))";
-
-			LOG.info("extendedAllGroupsSearchFilter = " + extendedAllGroupsSearchFilter);
-			for (int ou=0; ou<groupSearchBase.length; ou++) {
-				byte[] cookie = null;
-				int counter = 0;
-				try {
-					int paged = 0;
-					do {
-						groupSearchResultEnum = ldapContext
-								.search(groupSearchBase[ou], extendedAllGroupsSearchFilter,
-										groupSearchControls);
-						while (groupSearchResultEnum.hasMore()) {
-							final SearchResult groupEntry = groupSearchResultEnum.next();
-							if (groupEntry == null) {
-								if (LOG.isInfoEnabled())  {
-									LOG.info("groupEntry null, skipping sync for the entry");
-								}
-								continue;
-							}
-							counter++;
-							Attributes attributes =   groupEntry.getAttributes();
-							Attribute groupNameAttr = attributes.get(groupNameAttribute);
-							if (groupNameAttr == null) {
-								if (LOG.isInfoEnabled())  {
-									LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() +
-											", skipping sync");
-								}
-								continue;
-							}
-							String gName = (String) groupNameAttr.get();
-							String transformGroupName = groupNameTransform(gName);
-							Map<String, String> groupAttrMap = new HashMap<>();
-							Attribute groupCloudIdAttr = attributes.get(groupCloudIdAttribute);
-							if (groupCloudIdAttr != null) {
-								addToAttrMap(groupAttrMap, "cloud_id", groupCloudIdAttr, config.getGroupCloudIdAttributeDataType());
-							}
-							for (String otherGroupAttribute : otherGroupAttributes) {
-								if (attributes.get(otherGroupAttribute) != null) {
-									String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute);
-									addToAttrMap(groupAttrMap, otherGroupAttribute, attributes.get(otherGroupAttribute), attrType);
-								}
-							}
-							groupInfoMap.put(gName, groupAttrMap);
-							// If group based search is enabled, then
-							// update the group name to ranger admin
-							// check for group members and populate userInfo object with user's full name and group mapping
-							if (groupSearchFirstEnabled) {
-								if (LOG.isDebugEnabled()) {
-									LOG.debug("Update Ranger admin with " + transformGroupName);
-								}
-								sink.addOrUpdateGroup(transformGroupName, groupAttrMap);
-							}
-
-							Attribute timeStampAttr  = attributes.get("uSNChanged");
-							if (timeStampAttr != null) {
-								String uSNChangedVal = (String) timeStampAttr.get();
-								long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
-								if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
-									highestdeltaSyncGroupTime = currentDeltaSyncTime;
-								}
-							} else {
-								timeStampAttr = attributes.get("modifytimestamp");
-								if (timeStampAttr != null) {
-									String timeStampVal = (String) timeStampAttr.get();
-									Date parseDate = dateFormat.parse(timeStampVal);
-									long currentDeltaSyncTime = parseDate.getTime();
-									LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
-									if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
-										highestdeltaSyncGroupTime = currentDeltaSyncTime;
-										deltaSyncGroupTimeStamp = timeStampVal;
-									}
-								}
-							}
-							Attribute groupMemberAttr = attributes.get(groupMemberAttributeName);
-							int userCount = 0;
-							if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
-								LOG.info("No members available for " + gName);
-								if (groupSearchFirstEnabled) {
-									if (groupNames.contains(gName)) {
-										noOfModifiedGroups++;
-									} else {
-										noOfNewGroups++;
-									}
-									groupNames.add(gName);
-								}
-								continue;
-							}
-
-							NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
-							while (userEnum.hasMore()) {
-								String originalUserFullName = (String) userEnum.next();
-								if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
-									continue;
-								}
-								userCount++;
-								String userName = getShortName(originalUserFullName);
-								originalUserFullName = originalUserFullName.toLowerCase();
-								if (groupSearchFirstEnabled && !userSearchEnabled) {
-									String transformUserName = userNameTransform(userName);
-									try {
-										Map<String, String> userAttrMap = new HashMap<>();
-										sink.addOrUpdateUser(transformUserName, userAttrMap, null);
-									} catch (Throwable t) {
-										LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-										+ ", for user: " + transformUserName);
-									}
-									if (userNameMap.containsKey(originalUserFullName)) {
-										noOfModifiedUsers++;
-									} else {
-										noOfNewUsers++;
-									}
-									userNameMap.put(originalUserFullName, transformUserName);
-								}
-								//System.out.println("Adding " + userNameMap.get(originalUserFullName) + " and fullname = " + originalUserFullName + " to " + gName);
-								if (userNameMap.get(originalUserFullName) != null) {
-									groupUserTable.put(gName, originalUserFullName, userNameMap.get(originalUserFullName));
-								} else {
-									groupUserTable.put(gName, originalUserFullName, originalUserFullName);
-								}
-                                groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
-							}
-
-
-							if (groupNames.contains(gName)) {
-								noOfModifiedGroups++;
-							} else {
-								noOfNewGroups++;
-							}
-							groupNames.add(gName);
-							LOG.info("No. of members in the group " + gName + " = " + userCount);
-						}
-						// Examine the paged results control response
-						Control[] controls = ldapContext.getResponseControls();
-						if (controls != null) {
-							for (int i = 0; i < controls.length; i++) {
-								if (controls[i] instanceof PagedResultsResponseControl) {
-									PagedResultsResponseControl prrc =
-											(PagedResultsResponseControl)controls[i];
-									total = prrc.getResultSize();
-									if (total != 0) {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : " + total);
-										}
-									} else {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : unknown");
-										}
-									}
-									cookie = prrc.getCookie();
-								}
-							}
-						} else {
-							if (LOG.isDebugEnabled()) {
-								LOG.debug("No controls were sent from the server");
-							}
-						}
-						// Re-activate paged results
-						if (pagedResultsEnabled)   {
-							if (LOG.isDebugEnabled()) {
-								LOG.debug(String.format("Fetched paged results round: %s", ++paged));
-							}
-							ldapContext.setRequestControls(new Control[]{
-									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
-						}
-					} while (cookie != null);
-					LOG.info("LdapDeltaUserGroupBuilder.getGroups() completed with group count: "
-							+ counter);
-				} catch (Exception t) {
-					LOG.error("LdapDeltaUserGroupBuilder.getGroups() failed with exception: " + t);
-					LOG.info("LdapDeltaUserGroupBuilder.getGroups() group count: "
-							+ counter);
-				}
-			}
-
-		} finally {
-			if (groupSearchResultEnum != null) {
-				groupSearchResultEnum.close();
-			}
-			closeLdapContext();
-		}
-
-        if (groupHierarchyLevels > 0) {
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("deltaSyncGroupTime = " + deltaSyncGroupTime);
-			}
-            if (deltaSyncGroupTime > 0) {
-				LOG.info("LdapDeltaUserGroupBuilder.getGroups(): Going through group hierarchy for nested group evaluation for deltasync");
-				goUpGroupHierarchyLdap(groupNameMap.keySet(), groupHierarchyLevels-1);
-            }
-        }
-
-        if (deltaSyncGroupTime < highestdeltaSyncGroupTime) {
-            // Incrementing highestdeltaSyncGroupTime (for AD) in order to avoid search record repetition for next sync cycle.
-            deltaSyncGroupTime = highestdeltaSyncGroupTime+1;
-            // Incrementing the highest timestamp value (for OpenLdap) with 1min in order to avoid search record repetition for next sync cycle.
-            deltaSyncGroupTimeStamp = dateFormat.format(new Date(highestdeltaSyncGroupTime + 60l));
-        }
-	}
-
-	private static String getShortName(String longName) {
-		if (StringUtils.isEmpty(longName)) {
-			return null;
-		}
-		String shortName = "";
-		try {
-			LdapName subjectDN = new LdapName(longName);
-			List<Rdn> rdns = subjectDN.getRdns();
-			for (int i = rdns.size() - 1; i >= 0; i--) {
-				if (StringUtils.isNotEmpty(shortName)) {
-					break;
-				}
-				Rdn rdn = rdns.get(i);
-				Attributes attributes = rdn.toAttributes();
-				try {
-					Attribute uid = attributes.get("uid");
-					if (uid != null) {
-						Object value = uid.get();
-						if (value != null) {
-							shortName = value.toString();
-						}
-					} else {
-						Attribute cn = attributes.get("cn");
-						if (cn != null) {
-							Object value = cn.get();
-							if (value != null) {
-								shortName = value.toString();
-							}
-						}
-					}
-				} catch (NoSuchElementException ignore) {
-					shortName = longName;
-				} catch (NamingException ignore) {
-					shortName = longName;
-				}
-			}
-		} catch (InvalidNameException ex) {
-			shortName = longName;
-		}
-		LOG.info("longName: " + longName + ", userName: " + shortName);
-		return shortName;
-	}
-
-	private String userNameTransform(String userName) {
-		//String userNameTransform = userName;
-		if (userNameCaseConversionFlag) {
-			if (userNameLowerCaseFlag) {
-				userName = userName.toLowerCase();
-			}
-			else {
-				userName = userName.toUpperCase();
-			}
-		}
-
-		if (userNameRegExInst != null) {
-			userName = userNameRegExInst.transform(userName);
-		}
-
-		return userName;
-	}
-
-	private String groupNameTransform(String groupName) {
-		//String userNameTransform = userName;
-		if (groupNameCaseConversionFlag) {
-			if (groupNameLowerCaseFlag) {
-				groupName = groupName.toLowerCase();
-			}
-			else {
-				groupName = groupName.toUpperCase();
-			}
-		}
-
-		if (groupNameRegExInst != null) {
-			groupName = groupNameRegExInst.transform(groupName);
-		}
-
-		return groupName;
-	}
-
-	private void goUpGroupHierarchy(Set<String> groups, int groupHierarchyLevels, String groupSName) throws InvalidNameException {
-		if (groupHierarchyLevels <= 0 || groups.isEmpty()) {
-			return;
-		}
-        LOG.info("nextLevelGroups = " + groups + " for group = " + groupSName);
-		Set<String> nextLevelGroups;
-
-		for (String group : groups) {
-            String groupFullName = groupNameMap.getKey(group).toString();
-
-			// Add all members of sub group to the parent groups if the member is not a group in turn
-			Set<String> allMembers = groupUserTable.row(groupSName).keySet();
-			LOG.info("members of " + groupSName + " = " + allMembers);
-			for(String member : allMembers) {
-				String memberName = getShortName(member);
-				if (!groupUserTable.containsRow(memberName)) { //Check if the member of a group is in turn a group
-					LOG.info("Adding " + member + " to " + group);
-					String userSName = groupUserTable.get(groupSName, member);
-					LOG.info("Short name of " + member + " = " + userSName);
-					if (userSName != null) {
-						groupUserTable.put(group, member, userSName); //Add users from the nested group to parent group
-					}
-				}
-			}
-			nextLevelGroups = groupUserTable.column(groupFullName).keySet();
-			goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels - 1, group);
-		}
-	}
-
-	private void goUpGroupHierarchyLdap(Set<String> groupDNs, int groupHierarchyLevels) throws Throwable {
-		if (groupHierarchyLevels <= 0 || groupDNs.isEmpty()) {
-			return;
-		}
-		Set<String> nextLevelGroups = new HashSet<String>();
-
-		NamingEnumeration<SearchResult> groupSearchResultEnum = null;
-		try {
-			createLdapContext();
-			int total;
-			// Activate paged results
-			if (pagedResultsEnabled)   {
-				ldapContext.setRequestControls(new Control[]{
-						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
-			}
-			String groupFilter = "(&(objectclass=" + groupObjectClass + ")";
-			if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
-				String customFilter = groupSearchFilter.trim();
-				if (!customFilter.startsWith("(")) {
-					customFilter = "(" + customFilter + ")";
-				}
-				groupFilter += customFilter + "(|";
-			}
-			StringBuilder filter = new StringBuilder();
-
-			for (String groupDN : groupDNs) {
-				filter.append("(").append(groupMemberAttributeName).append("=")
-						.append(groupDN).append(")");
-			}
-			filter.append("))");
-			groupFilter += filter;
-
-			LOG.info("extendedAllGroupsSearchFilter = " + groupFilter);
-			for (int ou=0; ou<groupSearchBase.length; ou++) {
-				byte[] cookie = null;
-				int counter = 0;
-				try {
-					do {
-						groupSearchResultEnum = ldapContext
-								.search(groupSearchBase[ou], groupFilter,
-										groupSearchControls);
-						while (groupSearchResultEnum.hasMore()) {
-							final SearchResult groupEntry = groupSearchResultEnum.next();
-							if (groupEntry == null) {
-								if (LOG.isInfoEnabled())  {
-									LOG.info("groupEntry null, skipping sync for the entry");
-								}
-								continue;
-							}
-							counter++;
-							Attribute groupNameAttr = groupEntry.getAttributes().get(groupNameAttribute);
-							if (groupNameAttr == null) {
-								if (LOG.isInfoEnabled())  {
-									LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() +
-											", skipping sync");
-								}
-								continue;
-							}
-							nextLevelGroups.add(groupEntry.getNameInNamespace());
-							String gName = (String) groupNameAttr.get();
-
-							Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
-							int userCount = 0;
-							if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
-								LOG.info("No members available for " + gName);
-								continue;
-							}
-
-							Map<String, String> groupAttrMap = new HashMap<>();
-							for (String otherGroupAttribute : otherGroupAttributes) {
-								Attribute otherGroupAttr = groupEntry.getAttributes().get(otherGroupAttribute);
-								if (otherGroupAttr != null) {
-									groupAttrMap.put(otherGroupAttribute, (String) otherGroupAttr.get());
-								}
-							}
-							groupInfoMap.put(gName, groupAttrMap);
-
-							NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
-							while (userEnum.hasMore()) {
-								String originalUserFullName = (String) userEnum.next();
-								if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
-									continue;
-								}
-								userCount++;
-								originalUserFullName = originalUserFullName.toLowerCase();
-                                if (userNameMap.get(originalUserFullName) != null) {
-                                    groupUserTable.put(gName, originalUserFullName, userNameMap.get(originalUserFullName));
-                                } else {
-                                    groupUserTable.put(gName, originalUserFullName, originalUserFullName);
-                                }
-								groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
-
-							}
-							LOG.info("No. of members in the group " + gName + " = " + userCount);
-						}
-						// Examine the paged results control response
-						Control[] controls = ldapContext.getResponseControls();
-						if (controls != null) {
-							for (int i = 0; i < controls.length; i++) {
-								if (controls[i] instanceof PagedResultsResponseControl) {
-									PagedResultsResponseControl prrc =
-											(PagedResultsResponseControl)controls[i];
-									total = prrc.getResultSize();
-									if (total != 0) {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : " + total);
-										}
-									} else {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : unknown");
-										}
-									}
-									cookie = prrc.getCookie();
-								}
-							}
-						} else {
-							if (LOG.isDebugEnabled()) {
-								LOG.debug("No controls were sent from the server");
-							}
-						}
-						// Re-activate paged results
-						if (pagedResultsEnabled)   {
-							ldapContext.setRequestControls(new Control[]{
-									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
-						}
-					} while (cookie != null);
-					LOG.info("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() completed with group count: "
-							+ counter);
-				} catch (RuntimeException re) {
-					LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with runtime exception: ", re);
-					throw re;
-				} catch (Exception t) {
-					LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with exception: ", t);
-					LOG.info("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() group count: "
-							+ counter);
-				}
-			}
-
-		} catch (RuntimeException re) {
-			LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with exception: ", re);
-			throw re;
-		} finally {
-			if (groupSearchResultEnum != null) {
-				groupSearchResultEnum.close();
-			}
-			closeLdapContext();
-		}
-		goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels-1);
-	}
-
-	private void addToAttrMap(Map<String, String> userAttrMap, String attrName, Attribute attr, String attrType) throws Throwable{
-		if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
-			try {
-				byte[] otherUserAttrBytes = (byte[]) attr.get();
-				//Convert objectGUID into string and add to userAttrMap
-				String attrVal = UUID.nameUUIDFromBytes(otherUserAttrBytes).toString();
-				userAttrMap.put(attrName, attrVal);
-			} catch (ClassCastException e) {
-				LOG.error(attrName + " type is not set properly " + e.getMessage());
-			}
-		} else if (attrType.equals("String")) {
-			userAttrMap.put(attrName, (String) attr.get());
-		} else {
-			// This should not be reached.
-			LOG.warn("Attribute Type " + attrType + " not supported for " + attrName);
-		}
-	}
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
deleted file mode 100644
index 2df7dfb..0000000
--- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
+++ /dev/null
@@ -1,1297 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.ldapusersync.process;
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.security.KeyStore;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-import java.lang.reflect.Type;
-
-import javax.security.auth.Subject;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.Cookie;
-import javax.ws.rs.core.NewCookie;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.MapUtils;
-import org.apache.hadoop.security.SecureClientLogin;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.ranger.plugin.util.URLEncoderUtil;
-import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.apache.ranger.unixusersync.model.*;
-import org.apache.ranger.unixusersync.process.RangerUgSyncRESTClient;
-import org.apache.ranger.usergroupsync.UserGroupSink;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.reflect.TypeToken;
-import com.sun.jersey.api.client.ClientResponse;
-
-public class LdapPolicyMgrUserGroupBuilder implements UserGroupSink {
-
-private static final Logger LOG = Logger.getLogger(LdapPolicyMgrUserGroupBuilder.class);
-
-	private static final String AUTHENTICATION_TYPE = "hadoop.security.authentication";
-	private String AUTH_KERBEROS = "kerberos";
-	private static final String PRINCIPAL = "ranger.usersync.kerberos.principal";
-	private static final String KEYTAB = "ranger.usersync.kerberos.keytab";
-	private static final String NAME_RULE = "hadoop.security.auth_to_local";
-
-	private static final String PM_ADD_USER_GROUP_INFO_URI = "/service/xusers/users/userinfo";	// POST
-	public static final String PM_UPDATE_USERS_ROLES_URI  = "/service/xusers/users/roleassignments";	// PUT
-
-	private static final String PM_ADD_GROUP_USER_INFO_URI = "/service/xusers/groups/groupinfo";	// POST
-
-	private static final String PM_ADD_GROUP_URI = "/service/xusers/groups/";				// POST
-
-	private static final String PM_DEL_USER_GROUP_LINK_URI = "/service/xusers/group/${groupName}/user/${userName}"; // DELETE
-
-	public static final String PM_GET_GROUP_USER_MAP_LIST_URI = "/service/xusers/groupusers/groupName/${groupName}";		// GET
-
-	private static final String PM_ADD_LOGIN_USER_URI = "/service/users/default";			// POST
-
-	private static final String PM_AUDIT_INFO_URI = "/service/xusers/ugsync/auditinfo/";				// POST
-
-	private static final String GROUP_SOURCE_EXTERNAL ="1";
-
-	private static String LOCAL_HOSTNAME = "unknown";
-	private String recordsToPullPerCall = "1000";
-	private boolean isMockRun = false;
-	private String policyMgrBaseUrl;
-	private Cookie sessionId=null;
-	private boolean isValidRangerCookie=false;
-	List<NewCookie> cookieList=new ArrayList<>();
-
-	private UserGroupSyncConfig  config = UserGroupSyncConfig.getInstance();
-
-	private UserGroupInfo				usergroupInfo = new UserGroupInfo();
-	private GroupUserInfo				groupuserInfo = new GroupUserInfo();
-	private volatile RangerUgSyncRESTClient ldapUgSyncClient;
-
-	private String authenticationType = null;
-	String principal;
-	String keytab;
-	String nameRules;
-    Map<String, String> userMap = new LinkedHashMap<String, String>();
-    Map<String, String> groupMap = new LinkedHashMap<String, String>();
-    private boolean isRangerCookieEnabled;
-    private String rangerCookieName;
-	static {
-		try {
-			LOCAL_HOSTNAME = java.net.InetAddress.getLocalHost().getCanonicalHostName();
-		} catch (UnknownHostException e) {
-			LOCAL_HOSTNAME = "unknown";
-		}
-	}
-
-	synchronized public void init() throws Throwable {
-		recordsToPullPerCall = config.getMaxRecordsPerAPICall();
-		policyMgrBaseUrl = config.getPolicyManagerBaseURL();
-		isMockRun = config.isMockRunEnabled();
-		isRangerCookieEnabled = config.isUserSyncRangerCookieEnabled();
-		rangerCookieName = config.getRangerAdminCookieName();
-
-		if (isMockRun) {
-			LOG.setLevel(Level.DEBUG);
-		}
-		sessionId=null;
-		String keyStoreFile =  config.getSSLKeyStorePath();
-		String trustStoreFile = config.getSSLTrustStorePath();
-		String keyStoreFilepwd = config.getSSLKeyStorePathPassword();
-		String trustStoreFilepwd = config.getSSLTrustStorePathPassword();
-		String keyStoreType = KeyStore.getDefaultType();
-		String trustStoreType = KeyStore.getDefaultType();
-		authenticationType = config.getProperty(AUTHENTICATION_TYPE,"simple");
-		try {
-			principal = SecureClientLogin.getPrincipal(config.getProperty(PRINCIPAL,""), LOCAL_HOSTNAME);
-		} catch (IOException ignored) {
-			 // do nothing
-		}
-		keytab = config.getProperty(KEYTAB,"");
-		nameRules = config.getProperty(NAME_RULE,"DEFAULT");
-		ldapUgSyncClient = new RangerUgSyncRESTClient(policyMgrBaseUrl, keyStoreFile, keyStoreFilepwd, keyStoreType,
-				trustStoreFile, trustStoreFilepwd, trustStoreType, authenticationType, principal, keytab,
-				config.getPolicyMgrUserName(), config.getPolicyMgrPassword());
-
-        String userGroupRoles = config.getGroupRoleRules();
-        if (userGroupRoles != null && !userGroupRoles.isEmpty()) {
-            getRoleForUserGroups(userGroupRoles);
-        }
-        if (LOG.isDebugEnabled()) {
-			LOG.debug("PolicyMgrUserGroupBuilder.init()==> PolMgrBaseUrl : "+policyMgrBaseUrl+" KeyStore File : "+keyStoreFile+" TrustStore File : "+trustStoreFile+ "Authentication Type : "+authenticationType);
-		}
-    }
-
-	@Override
-	public void addOrUpdateUser(String userName, List<String> groups) throws Throwable {
-
-	}
-
-	@Override
-	public void addOrUpdateGroup(String groupName, Map<String, String> groupAttrs) throws Throwable {
-		//* Build the group info object and do the rest call
-			if ( ! isMockRun ) {
-				if ( addGroupInfo(groupName, groupAttrs) == null) {
-					String msg = "Failed to add addorUpdate group info";
-					LOG.error(msg);
-					throw new Exception(msg);
-				}
-			}
-
-	}
-
-	private XGroupInfo addGroupInfo(final String groupName, Map<String, String> groupAttrs){
-		XGroupInfo ret = null;
-		XGroupInfo group = null;
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMXAGroup(" + groupName + ")");
-		}
-		if (! isMockRun) {
-			group = addXGroupInfo(groupName, groupAttrs);
-		}
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
-			try {
-				LOG.info("Using principal = " + principal + " and keytab = " + keytab);
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final XGroupInfo groupInfo = group;
-				ret = Subject.doAs(sub, new PrivilegedAction<XGroupInfo>() {
-					@Override
-					public XGroupInfo run() {
-						try {
-							return getAddedGroupInfo(groupInfo);
-						} catch (Exception e) {
-							LOG.error("Failed to build Group List : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : ", e);
-			}
-			return null;
-		} else {
-			return getAddedGroupInfo(group);
-		}
-	}
-
-	private XGroupInfo addXGroupInfo(String aGroupName, Map<String, String> groupAttrs) {
-
-		XGroupInfo addGroup = new XGroupInfo();
-
-		addGroup.setName(aGroupName);
-
-		addGroup.setDescription(aGroupName + " - add from Unix box");
-
-		addGroup.setGroupType("1");
-
-		addGroup.setGroupSource(GROUP_SOURCE_EXTERNAL);
-		Gson gson = new Gson();
-		addGroup.setOtherAttributes(gson.toJson(groupAttrs));
-		groupuserInfo.setXgroupInfo(addGroup);
-
-		return addGroup;
-	}
-
-	private XGroupInfo getAddedGroupInfo(XGroupInfo group){
-		XGroupInfo ret = null;
-		String response = null;
-		ClientResponse clientRes = null;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(group);
-		String relativeUrl = PM_ADD_GROUP_URI;
-
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(group, relativeUrl);
-		}
-		else {
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("Group" + jsonString);
-			}
-			try {
-				clientRes = ldapUgSyncClient.post(relativeUrl, null, group);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}
-			catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
-			}
-		}
-
-		if ( LOG.isDebugEnabled() ) {
-			LOG.debug("RESPONSE: [" + response + "]");
-		}
-
-		ret = gson.fromJson(response, XGroupInfo.class);
-
-		return ret;
-	}
-
-	public static void main(String[] args) throws Throwable {
-		LdapPolicyMgrUserGroupBuilder  ugbuilder = new LdapPolicyMgrUserGroupBuilder();
-		ugbuilder.init();
-
-	}
-
-	@Override
-	public void addOrUpdateUser(String userName) throws Throwable {
-
-	}
-
-	@Override
-	public void addOrUpdateUser(String userName, Map<String, String> userAttrs, List<String> groups) throws Throwable {
-		// First add to x_portal_user
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMAccount(" + userName + ")");
-		}
-		if (! isMockRun) {
-			if (addMUser(userName, userAttrs) == null) {
-				String msg = "Failed to add portal user";
-				LOG.error(msg);
-				throw new Exception(msg);
-			}
-		}
-		//* Build the user group info object with empty groups and do the rest call
-		if ( ! isMockRun ) {
-			// If the rest call to ranger admin fails,
-			// propagate the failure to the caller for retry in next sync cycle.
-			if (addUserGroupInfo(userName, userAttrs, groups) == null ) {
-				String msg = "Failed to add addorUpdate user group info";
-				LOG.error(msg);
-				throw new Exception(msg);
-			}
-		}
-	}
-
-	private UserGroupInfo addUserGroupInfo(String userName, Map<String, String> userAttrs, List<String> groups){
-		if(LOG.isDebugEnabled()) {
-	 		LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addUserGroupInfo " + userName + " and groups");
-	 	}
-		UserGroupInfo ret = null;
-		XUserInfo user = null;
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMXAUser(" + userName + ")");
-		}
-
-		if (! isMockRun) {
-			user = addXUserInfo(userName, userAttrs);
-		}
-		if (CollectionUtils.isNotEmpty(groups)) {
-			for (String g : groups) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")");
-				}
-			}
-		}
-		if (! isMockRun ) {
-			addXUserGroupInfo(user, groups);
-		}
-
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UserGroupInfo result = ret;
-				ret = Subject.doAs(sub, new PrivilegedAction<UserGroupInfo>() {
-					@Override
-					public UserGroupInfo run() {
-						try {
-							return getUsergroupInfo(result);
-						} catch (Exception e) {
-							LOG.error("Failed to add User Group Info : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return null;
-		}else{
-			return getUsergroupInfo(ret);
-		}
-	}
-
-	private XUserInfo addXUserInfo(String aUserName, Map<String, String> userAttrs) {
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addXUserInfo " + aUserName + " and " + userAttrs);
-		}
-
-		XUserInfo xuserInfo = new XUserInfo();
-
-		xuserInfo.setName(aUserName);
-
-		xuserInfo.setDescription(aUserName + " - add from Unix box");
-		if (MapUtils.isNotEmpty(userAttrs)) {
-			Gson gson = new Gson();
-			xuserInfo.setOtherAttributes(gson.toJson(userAttrs));
-		}
-		List<String> roleList = new ArrayList<String>();
-		if (userMap.containsKey(aUserName)) {
-			roleList.add(userMap.get(aUserName));
-		}else{
-			roleList.add("ROLE_USER");
-		}
-		xuserInfo.setUserRoleList(roleList);
-		usergroupInfo.setXuserInfo(xuserInfo);
-
-		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.addXUserInfo " + aUserName + " and " + userAttrs);
-		}
-
-		return xuserInfo;
-	}
-
-	private void addXUserGroupInfo(XUserInfo aUserInfo, List<String> aGroupList) {
-
-		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addXUserGroupInfo ");
-		}
-		List<XGroupInfo> xGroupInfoList = new ArrayList<XGroupInfo>();
-
-		if (CollectionUtils.isNotEmpty(aGroupList)) {
-			for (String groupName : aGroupList) {
-				XGroupInfo group = addXGroupInfo(groupName, null);
-				xGroupInfoList.add(group);
-				addXUserGroupInfo(aUserInfo, group);
-			}
-		}
-
-		usergroupInfo.setXgroupInfo(xGroupInfoList);
-		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.addXUserGroupInfo ");
-		}
-	}
-
-	private XUserGroupInfo addXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
-
-
-	    XUserGroupInfo ugInfo = new XUserGroupInfo();
-
-		ugInfo.setUserId(aUserInfo.getId());
-
-		ugInfo.setGroupName(aGroupInfo.getName());
-
-		// ugInfo.setParentGroupId("1");
-
-        return ugInfo;
-	}
-
-	private UserGroupInfo getUsergroupInfo(UserGroupInfo ret) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.getUsergroupInfo(UserGroupInfo ret)");
-		}
-		String response = null;
-		ClientResponse clientRes = null;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(usergroupInfo);
-		String relativeUrl = PM_ADD_USER_GROUP_INFO_URI;
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("USER GROUP MAPPING" + jsonString);
-		}
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(usergroupInfo,relativeUrl);
-		}
-		else {
-			try {
-				clientRes = ldapUgSyncClient.post(relativeUrl, null, usergroupInfo);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}
-			catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
-			}
-		}
-		if ( LOG.isDebugEnabled() ) {
-			LOG.debug("RESPONSE: [" + response + "]");
-		}
-		ret = gson.fromJson(response, UserGroupInfo.class);
-
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.getUsergroupInfo (UserGroupInfo ret)");
-		}
-		return ret;
-	}
-
-	@Override
-	public void addOrUpdateGroup(String groupName, List<String> users) throws Throwable {
-	}
-
-	@Override
-	public void addOrUpdateGroup(String groupName, Map<String, String> groupAttrs, List<String> users) throws Throwable {
-		// First get the existing group user mappings from Ranger admin.
-		// Then compute the delta and send the updated group user mappings to ranger admin.
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("addOrUpdateGroup for " + groupName + " with users: " + users);
-		}
-		GroupUserInfo groupUserInfo = null;
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
-			try {
-				LOG.info("Using principal = " + principal + " and keytab = " + keytab);
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final String gName = groupName;
-				groupUserInfo = Subject.doAs(sub, new PrivilegedAction<GroupUserInfo>() {
-					@Override
-					public GroupUserInfo run() {
-						try {
-							return getGroupUserInfo(gName);
-						} catch (Exception e) {
-							LOG.error("Failed to build Group List : ", e);
-						}
-						return null;
-					}
-				});
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : ", e);
-			}
-		} else {
-			groupUserInfo = getGroupUserInfo(groupName);
-		}
-
-        List<String> oldUsers = new ArrayList<String>();
-        Map<String, List<String>> oldUserMap = new HashMap<String, List<String>>();
-        if (groupUserInfo != null && groupUserInfo.getXuserInfo() != null) {
-            for (XUserInfo xUserInfo : groupUserInfo.getXuserInfo()) {
-                oldUsers.add(xUserInfo.getName());
-                oldUserMap.put(xUserInfo.getName(), xUserInfo.getUserRoleList());
-            }
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("Returned users for group " + groupUserInfo.getXgroupInfo().getName() + " are: " + oldUsers);
-			}
-		}
-
-		List<String> addUsers = new ArrayList<String>();
-		List<String> delUsers = new ArrayList<String>();
-
-		for (String user : oldUsers) {
-			if (!users.contains(user)) {
-				delUsers.add(user);
-			}
-		}
-		if (oldUsers.isEmpty()) {
-			addUsers = users;
-		} else {
-            for (String user : users) {
-                if (!oldUsers.contains(user)|| !(oldUserMap.get(user).contains(groupMap.get(groupName)))) {
-                    addUsers.add(user);
-                }
-			}
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("addUsers = " + addUsers);
-		}
-		delXGroupUserInfo(groupName, delUsers);
-
-		//* Add user to group mapping in the x_group_user table.
-		//* Here the assumption is that the user already exists in x_portal_user table.
-		if ( ! isMockRun ) {
-			// If the rest call to ranger admin fails,
-			// propagate the failure to the caller for retry in next sync cycle.
-			GroupUserInfo ret = addGroupUserInfo(groupName, groupAttrs, addUsers);
-			if (ret == null ) {
-				String msg = "Failed to add addorUpdate group user info";
-				LOG.error(msg);
-				throw new Exception(msg);
-			}
-		}
-
-		// Update roles for both deleted & new users in this group when role assignments are configured.
-		if (!groupMap.isEmpty() || !userMap.isEmpty()) {
-			UsersGroupRoleAssignments ugRoleAssignments = new UsersGroupRoleAssignments();
-			List<String> allUsers = new ArrayList<>();
-			if (!delUsers.isEmpty()) {
-				allUsers.addAll(delUsers);
-			}
-			if (!addUsers.isEmpty()) {
-				allUsers.addAll(addUsers);
-			}
-			if (!allUsers.isEmpty()) {
-				ugRoleAssignments.setUsers(allUsers);
-				ugRoleAssignments.setGroupRoleAssignments(groupMap);
-				ugRoleAssignments.setUserRoleAssignments(userMap);
-				if (updateRoles(ugRoleAssignments) == null) {
-					LOG.error("Unable to update roles for " + allUsers);
-				}
-			}
-		}
-	}
-
-	private List<String> updateRoles(UsersGroupRoleAssignments ugRoleAssignments) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("LdapPolicyMgrUserGroupBuilder.updateUserRole(" + ugRoleAssignments.getUsers() + ")");
-		}
-
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UsersGroupRoleAssignments result = ugRoleAssignments;
-				List<String> ret = Subject.doAs(sub, new PrivilegedAction<List<String>>() {
-					@Override
-					public List<String> run() {
-						try {
-							return updateUsersRoles(result);
-						} catch (Exception e) {
-							LOG.error("Failed to add User Group Info : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return null;
-		}else{
-			return updateUsersRoles(ugRoleAssignments);
-		}
-	}
-
-	private List<String> updateUsersRoles(UsersGroupRoleAssignments ugRoleAssignments) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.updateUserRoles(" + ugRoleAssignments.getUsers() + ")");
-		}
-		List<String> ret = null;
-		try {
-			String response = null;
-			ClientResponse clientRes = null;
-			Gson gson = new GsonBuilder().create();
-			String jsonString = gson.toJson(ugRoleAssignments);
-			String url = PM_UPDATE_USERS_ROLES_URI;
-
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("USER role MAPPING" + jsonString);
-			}
-			if (isRangerCookieEnabled) {
-				response = cookieBasedUploadEntity(ugRoleAssignments, url);
-			} else {
-				try {
-					clientRes = ldapUgSyncClient.post(url, null, ugRoleAssignments);
-					if (clientRes != null) {
-						response = clientRes.getEntity(String.class);
-					}
-				} catch (Throwable t) {
-					LOG.error("Failed to get response, Error is : ", t);
-				}
-			}
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("RESPONSE: [" + response + "]");
-			}
-			Type listType = new TypeToken<ArrayList<String>>() {
-			}.getType();
-			ret = new Gson().fromJson(response, listType);
-
-		} catch (Exception e) {
-
-			LOG.warn( "ERROR: Unable to update roles for: " + ugRoleAssignments.getUsers(), e);
-		}
-
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.updateUserRoles(" + ret + ")");
-		}
-		return ret;
-	}
-
-	@Override
-	public void postUserGroupAuditInfo(UgsyncAuditInfo ugsyncAuditInfo) throws Throwable {
-		if (! isMockRun) {
-			addUserGroupAuditInfo(ugsyncAuditInfo);
-		}
-
-	}
-
-	private void addUserGroupAuditInfo(UgsyncAuditInfo auditInfo) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addAuditInfo(" + auditInfo.getNoOfNewUsers() + ", " + auditInfo.getNoOfNewGroups() +
-					", " + auditInfo.getNoOfModifiedUsers() + ", " + auditInfo.getNoOfModifiedGroups() +
-					", " + auditInfo.getSyncSource() + ")");
-		}
-
-		if (authenticationType != null
-				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
-				&& SecureClientLogin.isKerberosCredentialExists(principal,
-				keytab)) {
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UgsyncAuditInfo auditInfoFinal = auditInfo;
-				Subject.doAs(sub, new PrivilegedAction<Void>() {
-					@Override
-					public Void run() {
-						try {
-							getUserGroupAuditInfo(auditInfoFinal);
-						} catch (Exception e) {
-							LOG.error("Failed to add User : ", e);
-						}
-						return null;
-					}
-				});
-				return;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return;
-		} else {
-			getUserGroupAuditInfo(auditInfo);
-		}
-	}
-
-
-	private void getUserGroupAuditInfo(UgsyncAuditInfo userInfo) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
-		}
-		String response = null;
-		ClientResponse clientRes = null;
-		Gson gson = new GsonBuilder().create();
-		String relativeUrl = PM_AUDIT_INFO_URI;
-
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(userInfo, relativeUrl);
-		}
-		else {
-			try {
-				clientRes = ldapUgSyncClient.post(relativeUrl, null, userInfo);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}
-			catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
-			}
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("RESPONSE[" + response + "]");
-		}
-		gson.fromJson(response, UgsyncAuditInfo.class);
-
-		if(LOG.isDebugEnabled()){
-			LOG.debug("AuditInfo Creation successful ");
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
-		}
-	}
-
-	private void delXGroupUserInfo(final String groupName, List<String> userList) {
-		if(LOG.isDebugEnabled()) {
-	 		LOG.debug("==> LdapPolicyMgrUserGroupBuilder.delXGroupUserInfo " + groupName + " and " + userList);
-	 	}
-		for(final String userName : userList) {
-			if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
-				try {
-					LOG.info("Using principal = " + principal + " and keytab = " + keytab);
-					Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-					Subject.doAs(sub, new PrivilegedAction<Void>() {
-						@Override
-						public Void run() {
-							try {
-								delXGroupUserInfo(groupName, userName);
-							} catch (Exception e) {
-								LOG.error("Failed to build Group List : ", e);
-							}
-							return null;
-						}
-					});
-				} catch (Exception e) {
-					LOG.error("Failed to Authenticate Using given Principal and Keytab : ",e);
-				}
-			} else {
-				delXGroupUserInfo(groupName, userName);
-			}
-		}
-	}
-
-	private void delXGroupUserInfo(String groupName, String userName) {
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.delXUserGroupInfo()");
-		}
-
-		try {
-			ClientResponse response = null;
-
-			String relativeUrl = PM_DEL_USER_GROUP_LINK_URI.replaceAll(Pattern.quote("${groupName}"),
-					   URLEncoderUtil.encodeURIParam(groupName)).replaceAll(Pattern.quote("${userName}"), URLEncoderUtil.encodeURIParam(userName));
-			if (isRangerCookieEnabled) {
-				if (sessionId != null && isValidRangerCookie) {
-					response = ldapUgSyncClient.delete(relativeUrl, null, sessionId);
-					if (response != null) {
-						if (!(response.toString().contains(relativeUrl))) {
-							response.setStatus(HttpServletResponse.SC_NOT_FOUND);
-							sessionId = null;
-							isValidRangerCookie = false;
-						} else if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-							LOG.warn("response from ranger is 401 unauthorized");
-							sessionId = null;
-							isValidRangerCookie = false;
-						} else if (response.getStatus() == HttpServletResponse.SC_NO_CONTENT
-								|| response.getStatus() == HttpServletResponse.SC_OK) {
-							cookieList = response.getCookies();
-							for (NewCookie cookie : cookieList) {
-								if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
-									sessionId = cookie.toCookie();
-									isValidRangerCookie = true;
-									break;
-								}
-							}
-						}
-
-						if (response.getStatus() != HttpServletResponse.SC_OK && response.getStatus() != HttpServletResponse.SC_NO_CONTENT
-								&& response.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-							sessionId = null;
-							isValidRangerCookie = false;
-						}
-					}
-				}
-			}
-			else {
-				response = ldapUgSyncClient.delete(relativeUrl, null);
-			}
-		    if ( LOG.isDebugEnabled() ) {
-		    	LOG.debug("RESPONSE: [" + response.toString() + "]");
-		    }
-		} catch (Exception e) {
-			LOG.warn( "ERROR: Unable to delete GROUP: " + groupName  + " from USER:" + userName , e);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.delXUserGroupInfo()");
-		}
-	}
-
-	private GroupUserInfo addGroupUserInfo(String groupName, Map<String, String> groupAttrs, List<String> users){
-		if(LOG.isDebugEnabled()) {
-	 		LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addGroupUserInfo " + groupName + " and " + users);
-	 	}
-		GroupUserInfo ret = null;
-		XGroupInfo group = null;
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMXAGroup(" + groupName + ")");
-		}
-		if (! isMockRun) {
-			group = addXGroupInfo(groupName, groupAttrs);
-		}
-		for(String u : users) {
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("INFO: addPMXAGroupToUser(" + groupName + "," + u + ")");
-			}
-		}
-		if (! isMockRun ) {
-			addXGroupUserInfo(group, users);
-		}
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final GroupUserInfo result = ret;
-				ret = Subject.doAs(sub, new PrivilegedAction<GroupUserInfo>() {
-					@Override
-					public GroupUserInfo run() {
-						try {
-							return getGroupUserInfo(result);
-						} catch (Exception e) {
-							LOG.error("Failed to add User Group Info : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return null;
-		}else{
-			return getGroupUserInfo(ret);
-		}
-	}
-
-	private void addXGroupUserInfo(XGroupInfo aGroupInfo, List<String> aUserList) {
-
-		List<XUserInfo> xUserInfoList = new ArrayList<XUserInfo>();
-
-		for(String userName : aUserList) {
-			XUserInfo user = addXUserInfo(userName, null);
-			xUserInfoList.add(user);
-			addXUserGroupInfo(user, aGroupInfo);
-		}
-
-		groupuserInfo.setXuserInfo(xUserInfoList);
-	}
-
-	private GroupUserInfo getGroupUserInfo(GroupUserInfo ret) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.getGroupUserInfo(GroupUserInfo ret)");
-		}
-		String response = null;
-		ClientResponse clientRes = null;
-		String relativeUrl = PM_ADD_GROUP_USER_INFO_URI;
-		Gson gson = new GsonBuilder().create();
-
-        String jsonString = gson.toJson(groupuserInfo);
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("GROUP USER MAPPING" + jsonString);
-        }
-
-        if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(groupuserInfo,relativeUrl);
-		}
-        else {
-			try {
-				clientRes = ldapUgSyncClient.post(relativeUrl, null, groupuserInfo);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
-			}
-        }
-        if (LOG.isDebugEnabled()) {
-			LOG.debug("RESPONSE: [" + response + "]");
-		}
-		ret = gson.fromJson(response, GroupUserInfo.class);
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.getGroupUserInfo(GroupUserInfo ret)");
-		}
-		return ret;
-	}
-
-	
-	private MUserInfo addMUser(String aUserName, Map<String, String> userAttrs) {
-		MUserInfo ret = null;
-		MUserInfo userInfo = new MUserInfo();
-
-		userInfo.setLoginId(aUserName);
-		userInfo.setFirstName(aUserName);
-        userInfo.setLastName(aUserName);
-		Gson gson = new Gson();
-        userInfo.setOtherAttributes(gson.toJson(userAttrs));
-        String str[] = new String[1];
-        if (userMap.containsKey(aUserName)) {
-            str[0] = userMap.get(aUserName);
-        }
-        userInfo.setUserRoleList(str);
-        if (authenticationType != null
-                && AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
-                && SecureClientLogin.isKerberosCredentialExists(principal,
-                        keytab)) {
-            try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final MUserInfo result = ret;
-				final MUserInfo userInfoFinal = userInfo;
-				ret = Subject.doAs(sub, new PrivilegedAction<MUserInfo>() {
-					@Override
-					public MUserInfo run() {
-						try {
-							return getMUser(userInfoFinal, result);
-						} catch (Exception e) {
-							LOG.error("Failed to add User : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return null;
-		} else {
-			return getMUser(userInfo, ret);
-		}
-	}
-
-
-	private MUserInfo getMUser(MUserInfo userInfo, MUserInfo ret) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.getMUser()");
-		}
-		String response = null;
-		ClientResponse clientRes = null;
-		Gson gson = new GsonBuilder().create();
-		String relativeUrl = PM_ADD_LOGIN_USER_URI;
-		if (isRangerCookieEnabled) {
-			response = cookieBasedUploadEntity(userInfo, relativeUrl);
-		} else {
-			try {
-				clientRes = ldapUgSyncClient.post(relativeUrl, null, userInfo);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			} catch (Exception e) {
-				LOG.error("Failed to get response, Error is : " + e.getMessage());
-			}
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("RESPONSE[" + response + "]");
-		}
-	    ret = gson.fromJson(response, MUserInfo.class);
-
-	    if (LOG.isDebugEnabled()) {
-			LOG.debug("MUser Creation successful " + ret);
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.getMUser()");
-		}
-		return ret;
-	}
-	
-	public GroupUserInfo getGroupUserInfo(String groupName) {
-		GroupUserInfo ret = null;
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.getGroupUserInfo(String groupName)");
-		}
-		try {
-			String response = null;
-			ClientResponse clientRes = null;
-			Gson gson = new GsonBuilder().create();
-			String relativeUrl = PM_GET_GROUP_USER_MAP_LIST_URI.replaceAll(Pattern.quote("${groupName}"),
-					   URLEncoderUtil.encodeURIParam(groupName));
-
-			if (isRangerCookieEnabled) {
-				response = cookieBasedGetEntity(relativeUrl, 0);
-			}
-			else {
-				clientRes = ldapUgSyncClient.get(relativeUrl, null);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}
-			if(LOG.isDebugEnabled()){
-				LOG.debug("RESPONSE for " + relativeUrl + ": [" + response + "]");
-			}
-
-		    ret = gson.fromJson(response, GroupUserInfo.class);
-
-		} catch (Exception e) {
-
-			LOG.warn( "ERROR: Unable to get group user mappings for: " + groupName, e);
-		}
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.getGroupUserInfo(String groupName)");
-		}
-		return ret;
-	}
-
-	private String cookieBasedUploadEntity(Object obj, String apiURL ) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.cookieBasedUploadEntity()");
-		}
-		String response = null;
-		if (sessionId != null && isValidRangerCookie) {
-			response = tryUploadEntityWithCookie(obj, apiURL);
-		}
-		else{
-			response = tryUploadEntityWithCred(obj, apiURL);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.cookieBasedUploadEntity()");
-		}
-		return response;
-	}
-
-	private String cookieBasedGetEntity(String apiURL ,int retrievedCount) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.cookieBasedGetEntity()");
-		}
-		String response = null;
-		if (sessionId != null && isValidRangerCookie) {
-			response = tryGetEntityWithCookie(apiURL,retrievedCount);
-		}
-		else{
-			response = tryGetEntityWithCred(apiURL,retrievedCount);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.cookieBasedGetEntity()");
-		}
-		return response;
-	}
-
-	private String tryUploadEntityWithCookie(Object obj, String apiURL) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-		try {
-			clientResp = ldapUgSyncClient.post(apiURL, null, obj, sessionId);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
-		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT || clientResp.getStatus() == HttpServletResponse.SC_OK) {
-				List<NewCookie> respCookieList = clientResp.getCookies();
-				for (NewCookie cookie : respCookieList) {
-					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
-						if (!(sessionId.getValue().equalsIgnoreCase(cookie.toCookie().getValue()))) {
-							sessionId = cookie.toCookie();
-						}
-						isValidRangerCookie = true;
-						break;
-					}
-				}
-			}
-
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK	&& clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
-		}
-		return response;
-	}
-
-
-	private String tryUploadEntityWithCred(Object obj, String apiURL){
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(obj);
-
-		if ( LOG.isDebugEnabled() ) {
-		   LOG.debug("USER GROUP MAPPING" + jsonString);
-		}
-		try{
-			clientResp = ldapUgSyncClient.post(apiURL, null, obj);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
-		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				LOG.warn("Credentials response from ranger is 401.");
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_OK || clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
-				cookieList = clientResp.getCookies();
-				for (NewCookie cookie : cookieList) {
-					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
-						sessionId = cookie.toCookie();
-						isValidRangerCookie = true;
-						LOG.info("valid cookie saved ");
-						break;
-					}
-				}
-			}
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK && clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
-		}
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
-		}
-		return response;
-	}
-
-	private String tryGetEntityWithCred(String apiURL, int retrievedCount) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.tryGetEntityWithCred()");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-
-		Map<String, String> queryParams = new HashMap<String, String>();
-		queryParams.put("pageSize", recordsToPullPerCall);
-		queryParams.put("startIndex", String.valueOf(retrievedCount));
-		try{
-			clientResp = ldapUgSyncClient.get(apiURL, queryParams);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
-		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				LOG.warn("Credentials response from ranger is 401.");
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_OK || clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
-				cookieList = clientResp.getCookies();
-				for (NewCookie cookie : cookieList) {
-					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
-						sessionId = cookie.toCookie();
-						isValidRangerCookie = true;
-						LOG.info("valid cookie saved ");
-						break;
-					}
-				}
-			}
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK && clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
-		}
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.tryGetEntityWithCred()");
-		}
-		return response;
-	}
-
-
-	private String tryGetEntityWithCookie(String apiURL, int retrievedCount) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> LdapPolicyMgrUserGroupBuilder.tryGetEntityWithCookie()");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-
-		Map<String, String> queryParams = new HashMap<String, String>();
-		queryParams.put("pageSize", recordsToPullPerCall);
-		queryParams.put("startIndex", String.valueOf(retrievedCount));
-		try {
-			clientResp = ldapUgSyncClient.get(apiURL, queryParams, sessionId);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
-		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT || clientResp.getStatus() == HttpServletResponse.SC_OK) {
-				List<NewCookie> respCookieList = clientResp.getCookies();
-				for (NewCookie cookie : respCookieList) {
-					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
-						if (!(sessionId.getValue().equalsIgnoreCase(cookie.toCookie().getValue()))) {
-							sessionId = cookie.toCookie();
-						}
-						isValidRangerCookie = true;
-						break;
-					}
-				}
-			}
-
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK	&& clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== LdapPolicyMgrUserGroupBuilder.tryGetEntityWithCookie()");
-		}
-		return response;
-	}
-
-    private void getRoleForUserGroups(String userGroupRolesData) {
-        String roleDelimiter = config.getRoleDelimiter();
-        String userGroupDelimiter = config.getUserGroupDelimiter();
-        String userNameDelimiter = config.getUserGroupNameDelimiter();
-        if (roleDelimiter == null || roleDelimiter.isEmpty()) {
-            roleDelimiter = "&";
-        }
-        if (userGroupDelimiter == null || userGroupDelimiter.isEmpty()) {
-            userGroupDelimiter = ":";
-        }
-        if (userNameDelimiter == null || userNameDelimiter.isEmpty()) {
-            userNameDelimiter = ",";
-        }
-        StringTokenizer str = new StringTokenizer(userGroupRolesData,
-                roleDelimiter);
-        int flag = 0;
-        String userGroupCheck = null;
-        String roleName = null;
-        while (str.hasMoreTokens()) {
-            flag = 0;
-            String tokens = str.nextToken();
-            if (tokens != null && !tokens.isEmpty()) {
-                StringTokenizer userGroupRoles = new StringTokenizer(tokens,
-                        userGroupDelimiter);
-                if (userGroupRoles != null) {
-                    while (userGroupRoles.hasMoreElements()) {
-                        String userGroupRolesTokens = userGroupRoles
-                                .nextToken();
-                        if (userGroupRolesTokens != null
-                                && !userGroupRolesTokens.isEmpty()) {
-                            flag++;
-                            switch (flag) {
-                            case 1:
-                                roleName = userGroupRolesTokens;
-                                break;
-                            case 2:
-                                userGroupCheck = userGroupRolesTokens;
-                                break;
-                            case 3:
-                                StringTokenizer userGroupNames = new StringTokenizer(
-                                        userGroupRolesTokens, userNameDelimiter);
-                                if (userGroupNames != null) {
-                                    while (userGroupNames.hasMoreElements()) {
-                                        String userGroup = userGroupNames
-                                                .nextToken();
-                                        if (userGroup != null
-                                                && !userGroup.isEmpty()) {
-                                            if (userGroupCheck.trim().equalsIgnoreCase("u")) {
-                                                userMap.put(userGroup.trim(), roleName.trim());
-                                            } else if (userGroupCheck.trim().equalsIgnoreCase("g")) {
-                                                groupMap.put(userGroup.trim(),
-                                                        roleName.trim());
-                                            }
-                                        }
-                                    }
-                                }
-                                break;
-                            default:
-                                userMap.clear();
-                                groupMap.clear();
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
index ca3aad8..7e5e70a 100644
--- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
+++ b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
@@ -20,20 +20,21 @@
 package org.apache.ranger.ldapusersync.process;
 
 
-import java.util.ArrayList;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Date;
 import java.util.HashSet;
-import java.util.List;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.NoSuchElementException;
+import java.util.HashMap;
+import java.util.UUID;
 
 import javax.naming.Context;
 import javax.naming.InvalidNameException;
 import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.SearchControls;
@@ -45,108 +46,95 @@ import javax.naming.ldap.PagedResultsControl;
 import javax.naming.ldap.PagedResultsResponseControl;
 import javax.naming.ldap.StartTlsRequest;
 import javax.naming.ldap.StartTlsResponse;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.apache.ranger.unixusersync.model.LdapSyncSourceInfo;
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
-import org.apache.ranger.usergroupsync.AbstractUserGroupSource;
+import org.apache.ranger.ugsyncutil.model.LdapSyncSourceInfo;
+import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo;
 import org.apache.ranger.usergroupsync.UserGroupSink;
 
-public class LdapUserGroupBuilder extends AbstractUserGroupSource {
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import org.apache.ranger.usergroupsync.UserGroupSource;
 
+public class LdapUserGroupBuilder implements UserGroupSource {
+	
 	private static final Logger LOG = Logger.getLogger(LdapUserGroupBuilder.class);
 
+	private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance();
+	
+	private static final String DATA_TYPE_BYTEARRAY = "byte[]";
+	private static final String DATE_FORMAT = "yyyyMMddHHmmss";
 	private static final int PAGE_SIZE = 500;
-
-	private String ldapUrl;
-	private String ldapBindDn;
-	private String ldapBindPassword;
-	private String ldapAuthenticationMechanism;
-	private String ldapReferral;
-	private String searchBase;
-
-	private String[] userSearchBase;
+	private static long deltaSyncUserTime = 0; // Used for AD uSNChanged 
+	private static long deltaSyncGroupTime = 0; // Used for AD uSNChanged
+	private String deltaSyncUserTimeStamp; // Used for OpenLdap modifyTimestamp
+	private String deltaSyncGroupTimeStamp; // Used for OpenLdap modifyTimestamp
+
+  private String ldapUrl;
+  private String ldapBindDn;
+  private String ldapBindPassword;
+  private String ldapAuthenticationMechanism;
+  private String ldapReferral;
+  private String searchBase;
+
+  private String[] userSearchBase;
 	private String userNameAttribute;
-	private int userSearchScope;
-	private String userObjectClass;
-	private String userSearchFilter;
-	private String extendedUserSearchFilter;
-	private SearchControls userSearchControls;
-	private Set<String> userGroupNameAttributeSet;
-
-	private boolean pagedResultsEnabled = true;
-	private int pagedResultsSize = PAGE_SIZE;
-
-	private boolean groupSearchFirstEnabled;
-	private boolean userSearchEnabled;
-	private boolean groupSearchEnabled = true;
-	private String[] groupSearchBase;
-	private int groupSearchScope;
-	private String groupObjectClass;
-	private String groupSearchFilter;
-	private String extendedGroupSearchFilter;
-	private String extendedAllGroupsSearchFilter;
-	private SearchControls groupSearchControls;
-	private String groupMemberAttributeName;
-	private String groupNameAttribute;
-    private int groupHierarchyLevels;
+	private String userCloudIdAttribute;
+  private int    userSearchScope;
+  private String userObjectClass;
+  private String userSearchFilter;
+  private String extendedUserSearchFilter;
+  private SearchControls userSearchControls;
+  private Set<String> otherUserAttributes;
+
+  private boolean pagedResultsEnabled = true;
+  private int pagedResultsSize = PAGE_SIZE;
+
+  private boolean groupSearchFirstEnabled = true;
+  private boolean userSearchEnabled = true;
+  private boolean groupSearchEnabled = true;
+  private String[] groupSearchBase;
+  private int    groupSearchScope;
+  private String groupObjectClass;
+  private String groupSearchFilter;
+  private String extendedGroupSearchFilter;
+  private String extendedAllGroupsSearchFilter;
+  private SearchControls groupSearchControls;
+  private String groupMemberAttributeName;
+  private String groupNameAttribute;
+	private String groupCloudIdAttribute;
+	private Set<String> otherGroupAttributes;
+	private int groupHierarchyLevels;
 
 	private LdapContext ldapContext;
-	private StartTlsResponse tls;
-
-	private boolean userNameCaseConversionFlag;
-	private boolean groupNameCaseConversionFlag;
-	private boolean userNameLowerCaseFlag;
-	private boolean groupNameLowerCaseFlag;
-
-	private Map<String, UserInfo> userGroupMap;
-    //private Set<String> firstGroupDNs;
-	private Set<String> allUsers;
+	StartTlsResponse tls;
 
+  private Table<String, String, String> groupUserTable;
 	UgsyncAuditInfo ugsyncAuditInfo;
 	LdapSyncSourceInfo ldapSyncSourceInfo;
 
+	private Map<String, Map<String, String>> sourceUsers; // key is user DN and value is map of user attributes containing original name, DN, etc...
+	private Map<String, Map<String, String>> sourceGroups; // key is group DN and value is map of group attributes containing original name, DN, etc...
+	private Map<String, Set<String>> sourceGroupUsers; // key is group DN and value is set of user DNs (members)
+
 	public static void main(String[] args) throws Throwable {
-		LdapUserGroupBuilder  ugBuilder = new LdapUserGroupBuilder();
+		LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder();
 		ugBuilder.init();
 	}
 
-	public LdapUserGroupBuilder() {
-		super();
-		LOG.info("LdapUserGroupBuilder created");
-
-		String userNameCaseConversion = config.getUserNameCaseConversion();
-
-		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion)) {
-			userNameCaseConversionFlag = false;
-		}
-		else {
-			userNameCaseConversionFlag = true;
-			userNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion);
-		}
-
-		String groupNameCaseConversion = config.getGroupNameCaseConversion();
-
-		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion)) {
-			groupNameCaseConversionFlag = false;
-		}
-		else {
-			groupNameCaseConversionFlag = true;
-			groupNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion);
-		}
-	}
-
 	@Override
 	public void init() throws Throwable{
+		deltaSyncUserTime = 0;
+		deltaSyncGroupTime = 0;
+		DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+		deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
+		deltaSyncGroupTimeStamp = dateFormat.format(new Date(0));
 		setConfig();
 		ugsyncAuditInfo = new UgsyncAuditInfo();
 		ldapSyncSourceInfo = new LdapSyncSourceInfo();
 		ldapSyncSourceInfo.setLdapUrl(ldapUrl);
-		ldapSyncSourceInfo.setIncrementalSycn("False");
+		ldapSyncSourceInfo.setIncrementalSycn("True");
 		ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled));
 		ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled));
 		ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled));
@@ -164,6 +152,32 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 			env.put("java.naming.ldap.factory.socket", "org.apache.ranger.ldapusersync.process.CustomSSLSocketFactory");
 		}
 
+		if (StringUtils.isNotEmpty(userCloudIdAttribute)) {
+			if (config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
+				env.put("java.naming.ldap.attributes.binary", userCloudIdAttribute);
+			}
+		}
+
+		if (StringUtils.isNotEmpty(groupCloudIdAttribute)) {
+			if (config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
+				env.put("java.naming.ldap.attributes.binary", groupCloudIdAttribute);
+			}
+		}
+
+		for (String otherUserAttribute : otherUserAttributes) {
+			String attrType = config.getOtherUserAttributeDataType(otherUserAttribute);
+			if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+				env.put("java.naming.ldap.attributes.binary", otherUserAttribute);
+			}
+		}
+
+		for (String otherGroupAttribute : otherGroupAttributes) {
+			String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute);
+			if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+				env.put("java.naming.ldap.attributes.binary", otherGroupAttribute);
+			}
+		}
+
 		ldapContext = new InitialLdapContext(env, null);
 		if (!ldapUrl.startsWith("ldaps")) {
 			if (config.isStartTlsEnabled()) {
@@ -186,80 +200,68 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 	private void setConfig() throws Throwable {
 		LOG.info("LdapUserGroupBuilder initialization started");
 
-		groupSearchFirstEnabled =   config.isGroupSearchFirstEnabled();
-		userSearchEnabled =   config.isUserSearchEnabled();
-		groupSearchEnabled =   config.isGroupSearchEnabled();
-		ldapUrl = config.getLdapUrl();
-		ldapBindDn = config.getLdapBindDn();
-		ldapBindPassword = config.getLdapBindPassword();
-		ldapAuthenticationMechanism = config.getLdapAuthenticationMechanism();
-		ldapReferral = config.getContextReferral();
+		groupSearchFirstEnabled =   true;
+		userSearchEnabled =   true;
+		groupSearchEnabled =   true;
+    ldapUrl = config.getLdapUrl();
+    ldapBindDn = config.getLdapBindDn();
+    ldapBindPassword = config.getLdapBindPassword();
+    //ldapBindPassword = "admin-password";
+    ldapAuthenticationMechanism = config.getLdapAuthenticationMechanism();
+    ldapReferral = config.getContextReferral();
 		searchBase = config.getSearchBase();
 
 		userSearchBase = config.getUserSearchBase().split(";");
 		userSearchScope = config.getUserSearchScope();
 		userObjectClass = config.getUserObjectClass();
 		userSearchFilter = config.getUserSearchFilter();
-		extendedUserSearchFilter = "(objectclass=" + userObjectClass + ")";
-		if (userSearchFilter != null && !userSearchFilter.trim().isEmpty()) {
-			String customFilter = userSearchFilter.trim();
-			if (!customFilter.startsWith("(")) {
-				customFilter = "(" + customFilter + ")";
-			}
-
-			extendedUserSearchFilter = "(&" + extendedUserSearchFilter + customFilter + ")";
-		}
 
 		userNameAttribute = config.getUserNameAttribute();
+		userCloudIdAttribute = config.getUserCloudIdAttribute();
 
 		Set<String> userSearchAttributes = new HashSet<String>();
 		userSearchAttributes.add(userNameAttribute);
-		// For Group based search, user's group name attribute should not be added to the user search attributes
-		if (!groupSearchFirstEnabled && !groupSearchEnabled) {
-			userGroupNameAttributeSet = config.getUserGroupNameAttributeSet();
-			for (String useGroupNameAttribute : userGroupNameAttributeSet) {
-				userSearchAttributes.add(useGroupNameAttribute);
-			}
+		userSearchAttributes.add(userCloudIdAttribute);
+		otherUserAttributes = config.getOtherUserAttributes();
+		for (String otherUserAttribute : otherUserAttributes) {
+			userSearchAttributes.add(otherUserAttribute);
 		}
-
+		userSearchAttributes.add("uSNChanged");
+		userSearchAttributes.add("modifytimestamp");
 		userSearchControls = new SearchControls();
 		userSearchControls.setSearchScope(userSearchScope);
 		userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
-                new String[userSearchAttributes.size()]));
-
-		pagedResultsEnabled =   config.isPagedResultsEnabled();
-		pagedResultsSize =   config.getPagedResultsSize();
-
-		groupSearchBase = config.getGroupSearchBase().split(";");
-		groupSearchScope = config.getGroupSearchScope();
-		groupObjectClass = config.getGroupObjectClass();
-		groupSearchFilter = config.getGroupSearchFilter();
-		groupMemberAttributeName =  config.getUserGroupMemberAttributeName();
-		groupNameAttribute = config.getGroupNameAttribute();
-        groupHierarchyLevels = config.getGroupHierarchyLevels();
-
-		extendedGroupSearchFilter = "(objectclass=" + groupObjectClass + ")";
-		if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
-			String customFilter = groupSearchFilter.trim();
-			if (!customFilter.startsWith("(")) {
-				customFilter = "(" + customFilter + ")";
-			}
-			extendedGroupSearchFilter = extendedGroupSearchFilter + customFilter;
-		}
-		extendedAllGroupsSearchFilter = "(&"  + extendedGroupSearchFilter + ")";
-		if (!groupSearchFirstEnabled) {
-			extendedGroupSearchFilter =  "(&"  + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
-		}
-
-		groupSearchControls = new SearchControls();
-		groupSearchControls.setSearchScope(groupSearchScope);
-
-		Set<String> groupSearchAttributes = new HashSet<String>();
-		groupSearchAttributes.add(groupNameAttribute);
-		groupSearchAttributes.add(groupMemberAttributeName);
-
-		groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
-				new String[groupSearchAttributes.size()]));
+				new String[userSearchAttributes.size()]));
+
+    pagedResultsEnabled =   config.isPagedResultsEnabled();
+    pagedResultsSize =   config.getPagedResultsSize();
+
+    groupSearchBase = config.getGroupSearchBase().split(";");
+    groupSearchScope = config.getGroupSearchScope();
+    groupObjectClass = config.getGroupObjectClass();
+    groupSearchFilter = config.getGroupSearchFilter();
+    groupMemberAttributeName =  config.getUserGroupMemberAttributeName();
+    groupNameAttribute = config.getGroupNameAttribute();
+    groupCloudIdAttribute = config.getGroupCloudIdAttribute();
+		groupHierarchyLevels = config.getGroupHierarchyLevels();
+
+    extendedGroupSearchFilter =  "(&"  + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
+
+    groupSearchControls = new SearchControls();
+    groupSearchControls.setSearchScope(groupSearchScope);
+
+    Set<String> groupSearchAttributes = new HashSet<String>();
+    groupSearchAttributes.add(groupNameAttribute);
+    groupSearchAttributes.add(groupCloudIdAttribute);
+    groupSearchAttributes.add(groupMemberAttributeName);
+    groupSearchAttributes.add("uSNChanged");
+    groupSearchAttributes.add("modifytimestamp");
+    otherGroupAttributes = config.getOtherGroupAttributes();
+    for (String otherGroupAttribute : otherGroupAttributes) {
+		groupSearchAttributes.add(otherGroupAttribute);
+    }
+    groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
+			new String[groupSearchAttributes.size()]));
 
 		if (LOG.isInfoEnabled()) {
 			LOG.info("LdapUserGroupBuilder initialization completed with --  "
@@ -267,31 +269,31 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 					+ ",  ldapBindDn: " + ldapBindDn
 					+ ",  ldapBindPassword: ***** "
 					+ ",  ldapAuthenticationMechanism: " + ldapAuthenticationMechanism
-					+ ",  searchBase: " + searchBase
-					+ ",  userSearchBase: " + Arrays.toString(userSearchBase)
-					+ ",  userSearchScope: " + userSearchScope
+          + ",  searchBase: " + searchBase
+          + ",  userSearchBase: " + Arrays.toString(userSearchBase)
+          + ",  userSearchScope: " + userSearchScope
 					+ ",  userObjectClass: " + userObjectClass
 					+ ",  userSearchFilter: " + userSearchFilter
 					+ ",  extendedUserSearchFilter: " + extendedUserSearchFilter
 					+ ",  userNameAttribute: " + userNameAttribute
 					+ ",  userSearchAttributes: " + userSearchAttributes
-					+ ",  userGroupNameAttributeSet: " + userGroupNameAttributeSet
-					+ ",  pagedResultsEnabled: " + pagedResultsEnabled
-					+ ",  pagedResultsSize: " + pagedResultsSize
-					+ ",  groupSearchEnabled: " + groupSearchEnabled
-					+ ",  groupSearchBase: " + Arrays.toString(groupSearchBase)
-					+ ",  groupSearchScope: " + groupSearchScope
-					+ ",  groupObjectClass: " + groupObjectClass
-					+ ",  groupSearchFilter: " + groupSearchFilter
-					+ ",  extendedGroupSearchFilter: " + extendedGroupSearchFilter
-					+ ",  extendedAllGroupsSearchFilter: " + extendedAllGroupsSearchFilter
-					+ ",  groupMemberAttributeName: " + groupMemberAttributeName
-					+ ",  groupNameAttribute: " + groupNameAttribute
-					+ ", groupSearchAttributes: " + groupSearchAttributes
-					+ ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
-					+ ", userSearchEnabled: " + userSearchEnabled
-					+ ",  ldapReferral: " + ldapReferral
-					);
+			+ ",  otherUserAttributes: " + otherUserAttributes
+          + ",  pagedResultsEnabled: " + pagedResultsEnabled
+          + ",  pagedResultsSize: " + pagedResultsSize
+          + ",  groupSearchEnabled: " + groupSearchEnabled
+          + ",  groupSearchBase: " + Arrays.toString(groupSearchBase)
+          + ",  groupSearchScope: " + groupSearchScope
+          + ",  groupObjectClass: " + groupObjectClass
+          + ",  groupSearchFilter: " + groupSearchFilter
+          + ",  extendedGroupSearchFilter: " + extendedGroupSearchFilter
+          + ",  extendedAllGroupsSearchFilter: " + extendedAllGroupsSearchFilter
+          + ",  groupMemberAttributeName: " + groupMemberAttributeName
+          + ",  groupNameAttribute: " + groupNameAttribute
+          + ", groupSearchAttributes: " + groupSearchAttributes
+          + ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
+          + ", userSearchEnabled: " + userSearchEnabled
+          + ",  ldapReferral: " + ldapReferral
+      );
 		}
 
 	}
@@ -313,133 +315,81 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 
 	@Override
 	public void updateSink(UserGroupSink sink) throws Throwable {
-		LOG.info("LDAPUserGroupBuilder updateSink started");
-		userGroupMap = new HashMap<String, UserInfo>();
-		Set<String> allGroups = new HashSet<String>();
-		allUsers = new HashSet<String>();
-
-		if (!groupSearchFirstEnabled) {
-			LOG.info("Performing user search first");
-			getUsers(sink);
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("Total No. of users saved = " + userGroupMap.size());
-			}
-			if (!groupSearchEnabled && groupHierarchyLevels > 0) {
-				getRootDN();
+		LOG.info("LdapUserGroupBuilder updateSink started");
+		groupUserTable = HashBasedTable.create();
+		sourceGroups = new HashMap<>();
+		sourceUsers = new HashMap<>();
+		sourceGroupUsers = new HashMap<>();
+
+        long highestdeltaSyncGroupTime = getGroups();
+        long highestdeltaSyncUserTime = getUsers();
+
+		if (groupHierarchyLevels > 0) {
+			LOG.info("Going through group hierarchy for nested group evaluation");
+            Set<String> groupFullNames = sourceGroups.keySet();
+			for(String group : groupFullNames) {
+				Set<String> nextLevelGroups = groupUserTable.column(group).keySet();
+				goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels-1, group);
 			}
-            //Iterator<UserInfo> userInfoIterator = userGroupMap.
-			for (UserInfo userInfo : userGroupMap.values()) {
-				String userName = userInfo.getUserName();
-				if (groupSearchEnabled) {
-					// Perform group search
-					LOG.info("groupSearch is enabled, would search for groups and compute memberships");
-                    //firstGroupDNs = new HashSet<String>();
-					getGroups(sink, userInfo);
-				}
-                if (groupHierarchyLevels > 0) {
-					if (LOG.isDebugEnabled()) {
-						LOG.debug("Going through group hierarchy for nested group evaluation");
-					}
-                    goUpGroupHierarchyLdap(userInfo.getGroupDNs(), groupHierarchyLevels - 1, userInfo);
-					if (LOG.isDebugEnabled()) {
-						LOG.debug("Completed group hierarchy computation");
-					}
-                }
-				List<String> groupList = userInfo.getGroups();
-				allGroups.addAll(groupList);
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("updateSink(): group list for " + userName + " = " + groupList);
-				}
-				if (userNameCaseConversionFlag) {
-					if (userNameLowerCaseFlag) {
-						userName = userName.toLowerCase();
-					}
-					else {
-						userName = userName.toUpperCase();
-					}
-				}
+			LOG.info("Completed group hierarchy computation");
+		}
 
-				if (userNameRegExInst != null) {
-					userName = userNameRegExInst.transform(userName);
+		Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator();
+		while (groupUserTableIterator.hasNext()) {
+			String groupName = groupUserTableIterator.next();
+			Map<String,String> groupUsersMap =  groupUserTable.row(groupName);
+			Set<String> userSet = new HashSet<String>();
+			for(Map.Entry<String, String> entry : groupUsersMap.entrySet()){
+				if (sourceUsers.containsKey(entry.getValue())) {
+					userSet.add(entry.getValue());
 				}
-				try {
-					sink.addOrUpdateUser(userName, groupList);
-				} catch (Throwable t) {
-					LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-					+ ", for user: " + userName
-					+ ", groups: " + groupList);
-				}
-			}
-			ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter);
-			ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter);
-			ldapSyncSourceInfo.setTotalUsersSynced(allUsers.size());
-			ldapSyncSourceInfo.setTotalGroupsSynced(allGroups.size());
-			try {
-				sink.postUserGroupAuditInfo(ugsyncAuditInfo);
-			} catch (Throwable t) {
-				LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
+		    }
+			sourceGroupUsers.put(groupName, userSet);
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Users = " + sourceUsers.keySet());
+			LOG.debug("Groups = " + sourceGroups.keySet());
+			LOG.debug("GroupUsers = " + sourceGroupUsers.keySet());
+		}
+
+		try {
+			sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers);
+			DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+			LOG.info("deltaSyncUserTime = " + deltaSyncUserTime + " and highestdeltaSyncUserTime = " + highestdeltaSyncUserTime);
+			if (deltaSyncUserTime < highestdeltaSyncUserTime) {
+				// Incrementing highestdeltaSyncUserTime (for AD) in order to avoid search record repetition for next sync cycle.
+				deltaSyncUserTime = highestdeltaSyncUserTime + 1;
+				// Incrementing the highest timestamp value (for Openldap) with 1sec in order to avoid search record repetition for next sync cycle.
+				deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60l));
 			}
 
-		} else {
-			LOG.info("Performing Group search first");
-			getGroups(sink, null);
-			 // Go through the userInfo map and update ranger admin.
-            for (UserInfo userInfo : userGroupMap.values()) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("userName from map = " + userInfo.getUserFullName());
-				}
-                String userName = getShortName(userInfo.getUserFullName());
-                if (groupHierarchyLevels > 0) {
-                    //System.out.println("Going through group hierarchy for nested group evaluation");
-                    goUpGroupHierarchyLdap(userInfo.getGroupDNs(), groupHierarchyLevels - 1, userInfo);
-                    //System.out.println("Completed group hierarchy computation");
-                }
-				List<String> groupList = userInfo.getGroups();
-				allGroups.addAll(groupList);
-                if (userSearchEnabled) {
-                    LOG.info("User search is enabled and hence computing user membership.");
-                    getUsers(sink);
-                } else {
-                    LOG.info("User search is disabled and hence using the group member attribute for username" + userName);
-					allGroups.addAll(groupList);
-					allUsers.add(userName); // Note:- in this case the usernames may contain groups as part of nested groups
-                    if (userNameCaseConversionFlag) {
-                        if (userNameLowerCaseFlag) {
-                            userName = userName.toLowerCase();
-                        } else {
-                            userName = userName.toUpperCase();
-                        }
-                    }
-
-                    if (userNameRegExInst != null) {
-                        userName = userNameRegExInst.transform(userName);
-                    }
-
-                    try {
-                        sink.addOrUpdateUser(userName, groupList);
-                    } catch (Throwable t) {
-                        LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-                                + ", for user: " + userName
-                                + ", groups: " + groupList);
-                    }
-                }
-            }
-			ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter);
-			ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter);
-			ldapSyncSourceInfo.setTotalUsersSynced(allUsers.size());
-			ldapSyncSourceInfo.setTotalGroupsSynced(allGroups.size());
-			try {
-				sink.postUserGroupAuditInfo(ugsyncAuditInfo);
-			} catch (Throwable t) {
-				LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
+			LOG.info("deltaSyncGroupTime = " + deltaSyncGroupTime + " and highestdeltaSyncGroupTime = " + highestdeltaSyncGroupTime);
+			// Update deltaSyncUserTime/deltaSyncUserTimeStamp here so that in case of failures, we get updates in next cycle
+			if (deltaSyncGroupTime < highestdeltaSyncGroupTime) {
+				// Incrementing highestdeltaSyncGroupTime (for AD) in order to avoid search record repetition for next sync cycle.
+				deltaSyncGroupTime = highestdeltaSyncGroupTime+1;
+				// Incrementing the highest timestamp value (for OpenLdap) with 1min in order to avoid search record repetition for next sync cycle.
+				deltaSyncGroupTimeStamp = dateFormat.format(new Date(highestdeltaSyncGroupTime + 60l));
 			}
+		} catch (Throwable t) {
+			LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t);
+		}
+
+		ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter);
+		ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter);
+
+		try {
+			sink.postUserGroupAuditInfo(ugsyncAuditInfo);
+		} catch (Throwable t) {
+			LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
 		}
 	}
 
-	private void getUsers(UserGroupSink sink) throws Throwable {
-		UserInfo userInfo;
+	private long getUsers() throws Throwable {
 		NamingEnumeration<SearchResult> userSearchResultEnum = null;
 		NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+		long highestdeltaSyncUserTime;
 		try {
 			createLdapContext();
 			int total;
@@ -448,210 +398,182 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 				ldapContext.setRequestControls(new Control[]{
 						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
 			}
+			DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+			if (groupUserTable.rowKeySet().size() != 0 || !config.isDeltaSyncEnabled()) {
+				// Fix RANGER-1957: Perform full sync when there are updates to the groups or when incremental sync is not enabled
+				deltaSyncUserTime = 0;
+				deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
+			}
+
+			extendedUserSearchFilter = "(objectclass=" + userObjectClass + ")(|(uSNChanged>=" + deltaSyncUserTime + ")(modifyTimestamp>=" + deltaSyncUserTimeStamp + "Z))";
+
+			if (userSearchFilter != null && !userSearchFilter.trim().isEmpty()) {
+				String customFilter = userSearchFilter.trim();
+				if (!customFilter.startsWith("(")) {
+					customFilter = "(" + customFilter + ")";
+				}
+
+				extendedUserSearchFilter = "(&" + extendedUserSearchFilter + customFilter + ")";
+			} else {
+				extendedUserSearchFilter = "(&" + extendedUserSearchFilter + ")";
+			}
+			LOG.info("extendedUserSearchFilter = " + extendedUserSearchFilter);
+
+			highestdeltaSyncUserTime = deltaSyncUserTime;
 
 			// When multiple OUs are configured, go through each OU as the user search base to search for users.
-			for (String ou : userSearchBase) {
+			for (int ou=0; ou<userSearchBase.length; ou++) {
 				byte[] cookie = null;
 				int counter = 0;
 				try {
-					int paged = 0;
-					do {
-						userSearchResultEnum = ldapContext
-								.search(ou, extendedUserSearchFilter, userSearchControls);
+				int paged = 0;
+				do {
+					userSearchResultEnum = ldapContext
+							.search(userSearchBase[ou], extendedUserSearchFilter,
+									userSearchControls);
+
+					while (userSearchResultEnum.hasMore()) {
+						// searchResults contains all the user entries
+						final SearchResult userEntry = userSearchResultEnum.next();
+
+						if (userEntry == null)  {
+							if (LOG.isInfoEnabled())  {
+								LOG.info("userEntry null, skipping sync for the entry");
+							}
+							continue;
+						}
 
-						while (userSearchResultEnum.hasMore()) {
-							// searchResults contains all the user entries
-							final SearchResult userEntry = userSearchResultEnum.next();
+						Attributes attributes =   userEntry.getAttributes();
+						if (attributes == null)  {
+							if (LOG.isInfoEnabled())  {
+								LOG.info("attributes  missing for entry " + userEntry.getNameInNamespace() +
+										", skipping sync");
+							}
+							continue;
+						}
 
-							if (userEntry == null)  {
-								if (LOG.isInfoEnabled())  {
-									LOG.info("userEntry null, skipping sync for the entry");
-								}
-								continue;
+						Attribute userNameAttr  = attributes.get(userNameAttribute);
+						if (userNameAttr == null)  {
+							if (LOG.isInfoEnabled())  {
+								LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() +
+										", skipping sync");
 							}
+							continue;
+						}
 
-							Attributes attributes = userEntry.getAttributes();
-							if (attributes == null)  {
-								if (LOG.isInfoEnabled())  {
-									LOG.info("attributes  missing for entry " + userEntry.getNameInNamespace() +
-											", skipping sync");
-								}
-								continue;
+						String userFullName = (userEntry.getNameInNamespace());
+						String userName = (String) userNameAttr.get();
+
+						if (userName == null || userName.trim().isEmpty())  {
+							if (LOG.isInfoEnabled())  {
+								LOG.info(userNameAttribute + " empty for entry " + userEntry.getNameInNamespace() +
+										", skipping sync");
 							}
+							continue;
+						}
 
-							Attribute userNameAttr  = attributes.get(userNameAttribute);
-							if (userNameAttr == null)  {
-								if (LOG.isInfoEnabled())  {
-									LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() +
-											", skipping sync");
+						Attribute timeStampAttr  = attributes.get("uSNChanged");
+						if (timeStampAttr != null) {
+							String uSNChangedVal = (String) timeStampAttr.get();
+							long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
+							LOG.info("uSNChangedVal = " + uSNChangedVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+							if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
+								highestdeltaSyncUserTime = currentDeltaSyncTime;
+							}
+						} else {
+							timeStampAttr = attributes.get("modifytimestamp");
+							if (timeStampAttr != null) {
+								String timeStampVal = (String) timeStampAttr.get();
+								Date parseDate = dateFormat.parse(timeStampVal);
+								long currentDeltaSyncTime = parseDate.getTime();
+								LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+								if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
+									highestdeltaSyncUserTime = currentDeltaSyncTime;
+									deltaSyncUserTimeStamp = timeStampVal;
 								}
-								continue;
 							}
+						}
 
-							String userName = (String) userNameAttr.get();
-
-							if (userName == null || userName.trim().isEmpty())  {
-								if (LOG.isInfoEnabled())  {
-									LOG.info(userNameAttribute + " empty for entry " + userEntry.getNameInNamespace() +
-											", skipping sync");
-								}
-								continue;
+						Map<String, String> userAttrMap = new HashMap<>();
+						userAttrMap.put("original_name", userName);
+						userAttrMap.put("full_name", userFullName);
+						Attribute userCloudIdAttr = attributes.get(userCloudIdAttribute);
+						if (userCloudIdAttr != null) {
+							addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, config.getUserCloudIdAttributeDataType());
+						}
+						for (String otherUserAttribute : otherUserAttributes) {
+							if (attributes.get(otherUserAttribute) != null) {
+								String attrType = config.getOtherUserAttributeDataType(otherUserAttribute);
+								addToAttrMap(userAttrMap, otherUserAttribute, attributes.get(otherUserAttribute), attrType);
 							}
+						}
 
-							if (!groupSearchFirstEnabled) {
-								userInfo = new UserInfo(userName, userEntry.getNameInNamespace());
-								Set<String> groups = new HashSet<String>();
-
-								// Get all the groups from the group name attribute of the user only when group search is not enabled.
-								if (!groupSearchEnabled) {
-									for (String useGroupNameAttribute : userGroupNameAttributeSet) {
-										Attribute userGroupfAttribute = userEntry.getAttributes().get(useGroupNameAttribute);
-										if (userGroupfAttribute != null) {
-											NamingEnumeration<?> groupEnum = userGroupfAttribute.getAll();
-											while (groupEnum.hasMore()) {
-                                                String groupDN = (String) groupEnum.next();
-												if (LOG.isDebugEnabled()) {
-													LOG.debug("Adding " + groupDN + " to " + userName);
-												}
-                                                userInfo.addGroupDN(groupDN);
-												String gName = getShortName(groupDN);
-												if (groupNameCaseConversionFlag) {
-													if (groupNameLowerCaseFlag) {
-														gName = gName.toLowerCase();
-													} else {
-														gName = gName.toUpperCase();
-													}
-												}
-												if (groupNameRegExInst != null) {
-													gName = groupNameRegExInst.transform(gName);
-												}
-												groups.add(gName);
-											}
-										}
-									}
-								}
+						sourceUsers.put(userFullName, userAttrMap);
+						counter++;
+
+                        if (counter <= 2000) {
+                            if (LOG.isInfoEnabled()) {
+                                LOG.info("Updating user count: " + counter
+                                        + ", userName: " + userName);
+                            }
+                            if ( counter == 2000 ) {
+                                LOG.info("===> 2000 user records have been synchronized so far. From now on, only a summary progress log will be written for every 100 users. To continue to see detailed log for every user, please enable Trace level logging. <===");
+                            }
+                        } else {
+                            if (LOG.isTraceEnabled()) {
+                                LOG.trace("Updating user count: " + counter
+                                        + ", userName: " + userName);
+                            } else  {
+                                if ( counter % 100 == 0) {
+                                    LOG.info("Synced " + counter + " users till now");
+                                }
+                            }
+                        }
 
-								userInfo.addGroups(groups);
+					}
 
-								//populate the userGroupMap with username, userInfo.
-								//userInfo contains details of user that will be later used for
-								//group search to compute group membership as well as to call sink.addOrUpdateUser()
-								if (userGroupMap.containsKey(userName)) {
-									LOG.warn("user object with username " + userName + " already exists and is replaced with the latest user object." );
-								}
-								userGroupMap.put(userName, userInfo);
-								allUsers.add(userName);
-
-								//List<String> groupList = new ArrayList<String>(groups);
-								List<String> groupList = userInfo.getGroups();
-								counter++;
-								if (counter <= 2000) {
-									if (LOG.isInfoEnabled()) {
-										LOG.info("Updating user count: " + counter
-												+ ", userName: " + userName + ", groupList: "
-												+ groupList);
-									}
-									if ( counter == 2000 ) {
-										LOG.info("===> 2000 user records have been synchronized so far. From now on, only a summary progress log will be written for every 100 users. To continue to see detailed log for every user, please enable Trace level logging. <===");
+					// Examine the paged results control response
+					Control[] controls = ldapContext.getResponseControls();
+					if (controls != null) {
+						for (int i = 0; i < controls.length; i++) {
+							if (controls[i] instanceof PagedResultsResponseControl) {
+								PagedResultsResponseControl prrc =
+										(PagedResultsResponseControl)controls[i];
+								total = prrc.getResultSize();
+								if (total != 0) {
+									if (LOG.isDebugEnabled()) {
+										LOG.debug("END-OF-PAGE total : " + total);
 									}
 								} else {
-									if (LOG.isTraceEnabled()) {
-										LOG.trace("Updating user count: " + counter
-												+ ", userName: " + userName + ", groupList: "
-												+ groupList);
-									} else  {
-										if ( counter % 100 == 0) {
-											LOG.info("Synced " + counter + " users till now");
-										}
+									if (LOG.isDebugEnabled()) {
+										LOG.debug("END-OF-PAGE total : unknown");
 									}
 								}
-							} else {
-								// If the user from the search result is present in the usersList,
-								// then update user name in the userInfo map with the value from the search result
-								// and update ranger admin.
-								String userFullName = (userEntry.getNameInNamespace()).toLowerCase();
-								if (LOG.isDebugEnabled()) {
-									LOG.debug("Checking if the user " + userFullName + " is part of the retrieved groups");
-								}
-
-								userInfo = userGroupMap.get(userFullName);
-								if (userInfo == null) {
-									userInfo = userGroupMap.get(userName.toLowerCase());
-								}
-								if (userInfo != null) {
-									counter++;
-									LOG.info("Updating username for " + userFullName + " with " + userName);
-									userInfo.updateUserName(userName);
-									allUsers.add(userName);
-                                    List<String> groupList = userInfo.getGroups();
-                                    if (userNameCaseConversionFlag) {
-                                        if (userNameLowerCaseFlag) {
-                                            userName = userName.toLowerCase();
-                                        }
-                                        else {
-                                            userName = userName.toUpperCase();
-                                        }
-                                    }
-
-                                    if (userNameRegExInst != null) {
-                                        userName = userNameRegExInst.transform(userName);
-                                    }
-
-                                    try {
-                                        sink.addOrUpdateUser(userName, groupList);
-                                    } catch (Throwable t) {
-                                        LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-                                                + ", for user: " + userName
-                                                + ", groups: " + groupList);
-                                    }
-								}
+								cookie = prrc.getCookie();
 							}
-
 						}
-
-						// Examine the paged results control response
-						Control[] controls = ldapContext.getResponseControls();
-						if (controls != null) {
-							for (Control control : controls) {
-								if (control instanceof PagedResultsResponseControl) {
-									PagedResultsResponseControl prrc =
-											(PagedResultsResponseControl)control;
-									total = prrc.getResultSize();
-									if (total != 0) {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : " + total);
-										}
-									} else {
-										if (LOG.isDebugEnabled()) {
-											LOG.debug("END-OF-PAGE total : unknown");
-										}
-									}
-									cookie = prrc.getCookie();
-								}
-							}
-						} else {
-							if (LOG.isDebugEnabled()) {
-								LOG.debug("No controls were sent from the server");
-							}
+					} else {
+						if (LOG.isDebugEnabled()) {
+							LOG.debug("No controls were sent from the server");
 						}
-						// Re-activate paged results
-						if (pagedResultsEnabled)   {
-							if (LOG.isDebugEnabled()) {
-								LOG.debug(String.format("Fetched paged results round: %s", ++paged));
-							}
-							ldapContext.setRequestControls(new Control[]{
-									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
+					}
+					// Re-activate paged results
+					if (pagedResultsEnabled)   {
+						if (LOG.isDebugEnabled()) {
+							LOG.debug(String.format("Fetched paged results round: %s", ++paged));
 						}
-					} while (cookie != null);
-					LOG.info("LDAPUserGroupBuilder.getUsers() completed with user count: "
-							+ counter);
-				} catch (Throwable t) {
-					LOG.error("LDAPUserGroupBuilder.getUsers() failed with exception: " + t);
-					LOG.info("LDAPUserGroupBuilder.getUsers() user count: "
+						ldapContext.setRequestControls(new Control[]{
+								new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
+					}
+				} while (cookie != null);
+				LOG.info("LdapUserGroupBuilder.getUsers() completed with user count: "
+						+ counter);
+				} catch (Exception t) {
+					LOG.error("LdapUserGroupBuilder.getUsers() failed with exception: ", t);
+					LOG.info("LdapUserGroupBuilder.getUsers() user count: "
 							+ counter);
 				}
 			}
-
 		} finally {
 			if (userSearchResultEnum != null) {
 				userSearchResultEnum.close();
@@ -661,123 +583,135 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 			}
 			closeLdapContext();
 		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("highestdeltaSyncUserTime = " + highestdeltaSyncUserTime);
+		}
+		return highestdeltaSyncUserTime;
 	}
 
-	private void getGroups(UserGroupSink sink, UserInfo userInfo) throws Throwable {
-        //LOG.debug("getGroups(): for user " + userInfo.getUserName());
+	private long getGroups() throws Throwable {
 		NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+        DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+        long highestdeltaSyncGroupTime = deltaSyncGroupTime;
 		try {
 			createLdapContext();
 			int total;
-            // Activate paged results
+			// Activate paged results
 			if (pagedResultsEnabled)   {
 				ldapContext.setRequestControls(new Control[]{
 						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
 			}
-            for (String ou : groupSearchBase) {
+			extendedGroupSearchFilter = "(objectclass=" + groupObjectClass + ")";
+			if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
+				String customFilter = groupSearchFilter.trim();
+				if (!customFilter.startsWith("(")) {
+					customFilter = "(" + customFilter + ")";
+				}
+				extendedGroupSearchFilter = extendedGroupSearchFilter + customFilter;
+			}
+
+			if (!config.isDeltaSyncEnabled()) {
+				// Perform full sync when incremental sync is not enabled
+				deltaSyncGroupTime = 0;
+				deltaSyncGroupTimeStamp = dateFormat.format(new Date(0));
+			}
+
+			extendedAllGroupsSearchFilter = "(&"  + extendedGroupSearchFilter + "(|(uSNChanged>=" + deltaSyncGroupTime + ")(modifyTimestamp>=" + deltaSyncGroupTimeStamp + "Z)))";
+
+			LOG.info("extendedAllGroupsSearchFilter = " + extendedAllGroupsSearchFilter);
+			for (int ou=0; ou<groupSearchBase.length; ou++) {
 				byte[] cookie = null;
 				int counter = 0;
 				try {
 					int paged = 0;
 					do {
-						if (!groupSearchFirstEnabled) {
-							if (userInfo == null) {
-								// Should never reach this.
-								LOG.error("No user information provided for group search!");
-								return;
-							}
-							if (LOG.isDebugEnabled()) {
-								LOG.debug("Searching for groups for user " + userInfo.getUserName() +
-										" using filter " + String.format(extendedGroupSearchFilter, userInfo.getUserFullName(),
-												userInfo.getUserName()));
-							}
-							groupSearchResultEnum = ldapContext
-									.search(ou, extendedGroupSearchFilter,
-											new Object[]{userInfo.getUserFullName(), userInfo.getUserName()},
-											groupSearchControls);
-						} else {
-							// If group based search is enabled, then first retrieve all the groups based on the group configuration.
-							groupSearchResultEnum = ldapContext
-									.search(ou, extendedAllGroupsSearchFilter,
-											groupSearchControls);
-						}
+						groupSearchResultEnum = ldapContext
+								.search(groupSearchBase[ou], extendedAllGroupsSearchFilter,
+										groupSearchControls);
 						while (groupSearchResultEnum.hasMore()) {
 							final SearchResult groupEntry = groupSearchResultEnum.next();
-							if (groupEntry != null) {
-								counter++;
-								Attribute groupNameAttr = groupEntry.getAttributes().get(groupNameAttribute);
-                                //System.out.println("getGroups(): Going through all groups");
-								if (groupNameAttr == null) {
-									if (LOG.isInfoEnabled())  {
-										LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() +
-												", skipping sync");
-									}
-									continue;
+							if (groupEntry == null) {
+								if (LOG.isInfoEnabled())  {
+									LOG.info("groupEntry null, skipping sync for the entry");
 								}
-                                String groupDN = groupEntry.getNameInNamespace();
-                                //System.out.println("getGroups(): groupDN = " + groupDN);
-                                String gName = (String) groupNameAttr.get();
-								if (groupNameCaseConversionFlag) {
-									if (groupNameLowerCaseFlag) {
-										gName = gName.toLowerCase();
-									} else {
-										gName = gName.toUpperCase();
-									}
+								continue;
+							}
+							counter++;
+							Attributes attributes =   groupEntry.getAttributes();
+							Attribute groupNameAttr = attributes.get(groupNameAttribute);
+							if (groupNameAttr == null) {
+								if (LOG.isInfoEnabled())  {
+									LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() +
+											", skipping sync");
 								}
-								if (groupNameRegExInst != null) {
-									gName = groupNameRegExInst.transform(gName);
+								continue;
+							}
+							String groupFullName = (groupEntry.getNameInNamespace());
+							String gName = (String) groupNameAttr.get();
+							Map<String, String> groupAttrMap = new HashMap<>();
+							groupAttrMap.put("original_name", gName);
+							groupAttrMap.put("full_name", groupFullName);
+							Attribute groupCloudIdAttr = attributes.get(groupCloudIdAttribute);
+							if (groupCloudIdAttr != null) {
+								addToAttrMap(groupAttrMap, "cloud_id", groupCloudIdAttr, config.getGroupCloudIdAttributeDataType());
+							}
+							for (String otherGroupAttribute : otherGroupAttributes) {
+								if (attributes.get(otherGroupAttribute) != null) {
+									String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute);
+									addToAttrMap(groupAttrMap, otherGroupAttribute, attributes.get(otherGroupAttribute), attrType);
 								}
-								if (!groupSearchFirstEnabled) {
-									//computedGroups.add(gName);
-									if (LOG.isInfoEnabled())  {
-										LOG.info("computed groups for user: " + userInfo.getUserName() + ", groups: " + gName);
-									}
-                                    userInfo.addGroupDN(groupDN);
-                                    userInfo.addGroup(gName);
-								} else {
-									// If group based search is enabled, then
-									// update the group name to ranger admin
-									// check for group members and populate userInfo object with user's full name and group mapping
-									Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
-									if (LOG.isDebugEnabled()) {
-										LOG.debug("Update Ranger admin with " + gName);
-									}
-									int userCount = 0;
-									if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
-										LOG.info("No members available for " + gName);
-										sink.addOrUpdateGroup(gName, new HashMap<String, String>(), null);
-										continue;
-									}
-									sink.addOrUpdateGroup(gName, new HashMap<String, String>());
-									NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
-									while (userEnum.hasMore()) {
-										String originalUserFullName = (String) userEnum.next();
-										if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
-											continue;
-										}
-										String userFullName = originalUserFullName.toLowerCase();
-										userCount++;
-										if (!userGroupMap.containsKey(userFullName)) {
-											userInfo = new UserInfo(userFullName, originalUserFullName); // Preserving the original full name for later
-											userGroupMap.put(userFullName, userInfo);
-										} else {
-											userInfo = userGroupMap.get(userFullName);
-                                        }
-                                        LOG.info("Adding " + gName + " to user " + userInfo.getUserFullName());
-                                        userInfo.addGroup(gName);
-                                        userInfo.addGroupDN(groupDN);
+							}
+							sourceGroups.put(groupFullName, groupAttrMap);
+
+							Attribute timeStampAttr  = attributes.get("uSNChanged");
+							if (timeStampAttr != null) {
+								String uSNChangedVal = (String) timeStampAttr.get();
+								long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
+								if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
+									highestdeltaSyncGroupTime = currentDeltaSyncTime;
+								}
+							} else {
+								timeStampAttr = attributes.get("modifytimestamp");
+								if (timeStampAttr != null) {
+									String timeStampVal = (String) timeStampAttr.get();
+									Date parseDate = dateFormat.parse(timeStampVal);
+									long currentDeltaSyncTime = parseDate.getTime();
+									LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+									if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
+										highestdeltaSyncGroupTime = currentDeltaSyncTime;
+										deltaSyncGroupTimeStamp = timeStampVal;
 									}
-									LOG.info("No. of members in the group " + gName + " = " + userCount);
 								}
 							}
+							Attribute groupMemberAttr = attributes.get(groupMemberAttributeName);
+							int userCount = 0;
+							if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
+								LOG.info("No members available for " + gName);
+								sourceGroupUsers.put(groupFullName, new HashSet<>());
+								continue;
+							}
+
+							NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
+							while (userEnum.hasMore()) {
+								String originalUserFullName = (String) userEnum.next();
+								if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
+									sourceGroupUsers.put(groupFullName, new HashSet<>());
+									continue;
+								}
+								userCount++;
+
+								groupUserTable.put(groupFullName, originalUserFullName, originalUserFullName);
+							}
+
+							LOG.info("No. of members in the group " + gName + " = " + userCount);
 						}
 						// Examine the paged results control response
 						Control[] controls = ldapContext.getResponseControls();
 						if (controls != null) {
-							for (Control control : controls) {
-								if (control instanceof PagedResultsResponseControl) {
+							for (int i = 0; i < controls.length; i++) {
+								if (controls[i] instanceof PagedResultsResponseControl) {
 									PagedResultsResponseControl prrc =
-											(PagedResultsResponseControl)control;
+											(PagedResultsResponseControl)controls[i];
 									total = prrc.getResultSize();
 									if (total != 0) {
 										if (LOG.isDebugEnabled()) {
@@ -805,11 +739,11 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
 						}
 					} while (cookie != null);
-					LOG.info("LDAPUserGroupBuilder.getGroups() completed with group count: "
+					LOG.info("LdapUserGroupBuilder.getGroups() completed with group count: "
 							+ counter);
-				} catch (Throwable t) {
-					LOG.error("LDAPUserGroupBuilder.getGroups() failed with exception: " + t);
-					LOG.info("LDAPUserGroupBuilder.getGroups() group count: "
+				} catch (Exception t) {
+					LOG.error("LdapUserGroupBuilder.getGroups() failed with exception: " + t);
+					LOG.info("LdapUserGroupBuilder.getGroups() group count: "
 							+ counter);
 				}
 			}
@@ -820,56 +754,52 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 			}
 			closeLdapContext();
 		}
-	}
 
+        if (groupHierarchyLevels > 0) {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("deltaSyncGroupTime = " + deltaSyncGroupTime);
+			}
+            if (deltaSyncGroupTime > 0) {
+				LOG.info("LdapUserGroupBuilder.getGroups(): Going through group hierarchy for nested group evaluation for deltasync");
+				goUpGroupHierarchyLdap(sourceGroups.keySet(), groupHierarchyLevels-1);
+            }
+        }
 
-	private static String getShortName(String longName) {
-		if (StringUtils.isEmpty(longName)) {
-			return null;
+        if (LOG.isDebugEnabled()) {
+        	LOG.debug("highestdeltaSyncGroupTime = " + highestdeltaSyncGroupTime);
 		}
-		String shortName = "";
-		try {
-			LdapName subjectDN = new LdapName(longName);
-			List<Rdn> rdns = subjectDN.getRdns();
-			for (int i = rdns.size() - 1; i >= 0; i--) {
-				if (StringUtils.isNotEmpty(shortName)) {
-					break;
-				}
-				Rdn rdn = rdns.get(i);
-				Attributes attributes = rdn.toAttributes();
-				try {
-					Attribute uid = attributes.get("uid");
-					if (uid != null) {
-						Object value = uid.get();
-						if (value != null) {
-							shortName = value.toString();
-						}
-					} else {
-						Attribute cn = attributes.get("cn");
-						if (cn != null) {
-							Object value = cn.get();
-							if (value != null) {
-								shortName = value.toString();
-							}
-						}
+
+        return highestdeltaSyncGroupTime;
+	}
+
+	private void goUpGroupHierarchy(Set<String> groups, int groupHierarchyLevels, String groupSName) throws InvalidNameException {
+		if (groupHierarchyLevels <= 0 || groups.isEmpty()) {
+			return;
+		}
+        LOG.info("nextLevelGroups = " + groups + " for group = " + groupSName);
+		Set<String> nextLevelGroups;
+
+		for (String group : groups) {
+
+			// Add all members of sub group to the parent groups if the member is not a group in turn
+			Set<String> allMembers = groupUserTable.row(groupSName).keySet();
+			LOG.info("members of " + groupSName + " = " + allMembers);
+			for(String member : allMembers) {
+				if (!groupUserTable.containsRow(member)) { //Check if the member of a group is in turn a group
+					LOG.info("Adding " + member + " to " + group);
+					String userSName = groupUserTable.get(groupSName, member);
+					LOG.info("Short name of " + member + " = " + userSName);
+					if (userSName != null) {
+						groupUserTable.put(group, member, userSName); //Add users from the nested group to parent group
 					}
-				} catch (NoSuchElementException ignore) {
-					shortName = longName;
-				} catch (NamingException ignore) {
-					shortName = longName;
 				}
 			}
-		} catch (InvalidNameException ex) {
-			shortName = longName;
+			nextLevelGroups = groupUserTable.column(group).keySet();
+			goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels - 1, group);
 		}
-		LOG.info("longName: " + longName + ", userName: " + shortName);
-		return shortName;
 	}
 
-	private void goUpGroupHierarchyLdap(Set<String> groupDNs, int groupHierarchyLevels, UserInfo userInfo) throws Throwable {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("goUpGroupHierarchyLdap(): Incoming groups " + groupDNs);
-		}
+	private void goUpGroupHierarchyLdap(Set<String> groupDNs, int groupHierarchyLevels) throws Throwable {
 		if (groupHierarchyLevels <= 0 || groupDNs.isEmpty()) {
 			return;
 		}
@@ -885,13 +815,13 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
 			}
 			String groupFilter = "(&(objectclass=" + groupObjectClass + ")";
-            if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
-                String customFilter = groupSearchFilter.trim();
-                if (!customFilter.startsWith("(")) {
-                    customFilter = "(" + customFilter + ")";
-                }
-                groupFilter += customFilter + "(|";
-            }
+			if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
+				String customFilter = groupSearchFilter.trim();
+				if (!customFilter.startsWith("(")) {
+					customFilter = "(" + customFilter + ")";
+				}
+				groupFilter += customFilter + "(|";
+			}
 			StringBuilder filter = new StringBuilder();
 
 			for (String groupDN : groupDNs) {
@@ -899,20 +829,17 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 						.append(groupDN).append(")");
 			}
 			filter.append("))");
-            groupFilter += filter;
+			groupFilter += filter;
 
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("extendedAllGroupsSearchFilter = " + groupFilter);
-			}
-			for (String ou : groupSearchBase) {
+			LOG.info("extendedAllGroupsSearchFilter = " + groupFilter);
+			for (int ou=0; ou<groupSearchBase.length; ou++) {
 				byte[] cookie = null;
 				int counter = 0;
 				try {
 					do {
 						groupSearchResultEnum = ldapContext
-									.search(ou, groupFilter,
-											groupSearchControls);
-                        //System.out.println("goUpGroupHierarchyLdap(): Going through the sub groups");
+								.search(groupSearchBase[ou], groupFilter,
+										groupSearchControls);
 						while (groupSearchResultEnum.hasMore()) {
 							final SearchResult groupEntry = groupSearchResultEnum.next();
 							if (groupEntry == null) {
@@ -930,29 +857,48 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 								}
 								continue;
 							}
-                            String groupDN = groupEntry.getNameInNamespace();
-                            //System.out.println("goUpGroupHierarchyLdap(): next Level Group DN = " + groupDN);
-							nextLevelGroups.add(groupDN);
+							String groupFullName = (groupEntry.getNameInNamespace());
+							nextLevelGroups.add(groupFullName);
 							String gName = (String) groupNameAttr.get();
-							if (groupNameCaseConversionFlag) {
-								if (groupNameLowerCaseFlag) {
-									gName = gName.toLowerCase();
-								} else {
-									gName = gName.toUpperCase();
+
+							Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
+							int userCount = 0;
+							if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
+								LOG.info("No members available for " + gName);
+								continue;
+							}
+
+
+							Map<String, String> groupAttrMap = new HashMap<>();
+							groupAttrMap.put("original_name", gName);
+							groupAttrMap.put("full_name", groupFullName);
+							for (String otherGroupAttribute : otherGroupAttributes) {
+								Attribute otherGroupAttr = groupEntry.getAttributes().get(otherGroupAttribute);
+								if (otherGroupAttr != null) {
+									groupAttrMap.put(otherGroupAttribute, (String) otherGroupAttr.get());
 								}
 							}
-							if (groupNameRegExInst != null) {
-								gName = groupNameRegExInst.transform(gName);
+							sourceGroups.put(gName, groupAttrMap);
+
+							NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
+							while (userEnum.hasMore()) {
+								String originalUserFullName = (String) userEnum.next();
+								if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
+									continue;
+								}
+								userCount++;
+								groupUserTable.put(groupFullName, originalUserFullName, originalUserFullName);
+
 							}
-							userInfo.addGroup(gName);
+							LOG.info("No. of members in the group " + gName + " = " + userCount);
 						}
 						// Examine the paged results control response
 						Control[] controls = ldapContext.getResponseControls();
 						if (controls != null) {
-							for (Control control : controls) {
-								if (control instanceof PagedResultsResponseControl) {
+							for (int i = 0; i < controls.length; i++) {
+								if (controls[i] instanceof PagedResultsResponseControl) {
 									PagedResultsResponseControl prrc =
-											(PagedResultsResponseControl)control;
+											(PagedResultsResponseControl)controls[i];
 									total = prrc.getResultSize();
 									if (total != 0) {
 										if (LOG.isDebugEnabled()) {
@@ -974,7 +920,7 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 						// Re-activate paged results
 						if (pagedResultsEnabled)   {
 							ldapContext.setRequestControls(new Control[]{
-									new PagedResultsControl(PAGE_SIZE, cookie, Control.CRITICAL) });
+									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
 						}
 					} while (cookie != null);
 					LOG.info("LdapUserGroupBuilder.goUpGroupHierarchyLdap() completed with group count: "
@@ -998,81 +944,24 @@ public class LdapUserGroupBuilder extends AbstractUserGroupSource {
 			}
 			closeLdapContext();
 		}
-		goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels - 1, userInfo);
+		goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels-1);
 	}
 
-	private void getRootDN() throws Throwable {
-		NamingEnumeration groupSearchResultEnum = null;
-		SearchControls sc1 = new SearchControls();
-		sc1.setSearchScope(SearchControls.OBJECT_SCOPE);
-		sc1.setReturningAttributes(new String[]{"namingContexts"});
-		try {
-			createLdapContext();
-			groupSearchResultEnum = ldapContext
-					.search("", "objectclass=*", sc1);
-			//System.out.println("goUpGroupHierarchyLdap(): Going through the sub groups");
-			while (groupSearchResultEnum.hasMore()) {
-				SearchResult result1 = (SearchResult) groupSearchResultEnum.next();
-
-				Attributes attrs = result1.getAttributes();
-				Attribute attr = attrs.get("namingContexts");
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("namingContexts = " + attr);
-				}
-				groupSearchBase = new String[] {attr.get(0).toString()};
-				LOG.info("RootDN = " + Arrays.toString(groupSearchBase));
-			}
-		} catch (RuntimeException re) {
-			throw re;
-		} finally {
-			if (groupSearchResultEnum != null) {
-				groupSearchResultEnum.close();
+	private void addToAttrMap(Map<String, String> userAttrMap, String attrName, Attribute attr, String attrType) throws Throwable{
+		if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+			try {
+				byte[] otherUserAttrBytes = (byte[]) attr.get();
+				//Convert objectGUID into string and add to userAttrMap
+				String attrVal = UUID.nameUUIDFromBytes(otherUserAttrBytes).toString();
+				userAttrMap.put(attrName, attrVal);
+			} catch (ClassCastException e) {
+				LOG.error(attrName + " type is not set properly " + e.getMessage());
 			}
-			closeLdapContext();
+		} else if (attrType.equals("String")) {
+			userAttrMap.put(attrName, (String) attr.get());
+		} else {
+			// This should not be reached.
+			LOG.warn("Attribute Type " + attrType + " not supported for " + attrName);
 		}
 	}
 }
-
-class UserInfo {
-	private String userName;
-	private String userFullName;
-	private Set<String> groupList;
-    private Set<String> groupDNList;
-
-	public UserInfo(String userName, String userFullName) {
-		this.userName = userName;
-		this.userFullName = userFullName;
-		this.groupList = new HashSet<String>();
-        this.groupDNList = new HashSet<String>();
-	}
-
-	public void updateUserName(String userName) {
-		this.userName = userName;
-	}
-
-	public String getUserName() {
-		return userName;
-	}
-	public String getUserFullName() {
-		return userFullName;
-	}
-	public void addGroups(Set<String> groups) {
-		groupList.addAll(groups);
-	}
-	public void addGroup(String group) {
-		groupList.add(group);
-	}
-	public List<String> getGroups() {
-		return (new ArrayList<String>(groupList));
-	}
-
-    public void addGroupDNs(Set<String> groupDNs) {
-        groupDNList.addAll(groupDNs);
-    }
-    public void addGroupDN(String groupDN) {
-        groupDNList.add(groupDN);
-    }
-    public Set<String> getGroupDNs() {
-        return (groupDNList);
-    }
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/PolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/PolicyMgrUserGroupBuilder.java
deleted file mode 100644
index d275181..0000000
--- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/PolicyMgrUserGroupBuilder.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.ldapusersync.process;
-
-public class PolicyMgrUserGroupBuilder extends org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder {
-	
-	public static void main(String[] args) throws Throwable {
-		PolicyMgrUserGroupBuilder  ugbuilder = new PolicyMgrUserGroupBuilder();
-		ugbuilder.init();
-		
-	}
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
index 2c98bd8..5ef78cf 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
@@ -104,12 +104,8 @@ public class UserGroupSyncConfig  {
 
 	private static final String UGSYNC_SINK_CLASS = "org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder";
 
-	private static final String LGSYNC_DELTASYNC_SINK_CLASS = "org.apache.ranger.ldapusersync.process.LdapPolicyMgrUserGroupBuilder";
-	
 	private static final String LGSYNC_SOURCE_CLASS = "org.apache.ranger.ldapusersync.process.LdapUserGroupBuilder";
 
-	private static final String LGSYNC_DELTASYNC_SOURCE_CLASS = "org.apache.ranger.ldapusersync.process.LdapDeltaUserGroupBuilder";
-
 	private static final String LGSYNC_LDAP_URL = "ranger.usersync.ldap.url";
 	
 	private static final String LGSYNC_LDAP_DELTASYNC_ENABLED = "ranger.usersync.ldap.deltasync";
@@ -174,10 +170,10 @@ public class UserGroupSyncConfig  {
 	private static final int DEFAULT_LGSYNC_PAGED_RESULTS_SIZE = 500;
 
 	private static final String LGSYNC_GROUP_SEARCH_ENABLED = "ranger.usersync.group.searchenabled";
-	private static final boolean DEFAULT_LGSYNC_GROUP_SEARCH_ENABLED = false;
+	private static final boolean DEFAULT_LGSYNC_GROUP_SEARCH_ENABLED = true;
 
 	private static final String LGSYNC_GROUP_SEARCH_FIRST_ENABLED = "ranger.usersync.group.search.first.enabled";
-	private static final boolean DEFAULT_LGSYNC_GROUP_SEARCH_FIRST_ENABLED = false;
+	private static final boolean DEFAULT_LGSYNC_GROUP_SEARCH_FIRST_ENABLED = true;
 
 	/*This flag (ranger.usersync.user.searchenabled) is used only when group search first is enabled to get username either -
 	 * from the group member attribute of the group or
@@ -460,7 +456,7 @@ public class UserGroupSyncConfig  {
 		String val =  prop.getProperty(UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_PARAM);
 		String className = getUserGroupSource().getClass().getName();
 		if (val == null) {
-			if (LGSYNC_SOURCE_CLASS.equals(className) || LGSYNC_DELTASYNC_SOURCE_CLASS.equals(className)) {
+			if (LGSYNC_SOURCE_CLASS.equals(className)) {
 				return UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_LDAP_DEFAULT_VALUE;
 			} else {
 				return UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_UNIX_DEFAULT_VALUE;
@@ -469,7 +465,7 @@ public class UserGroupSyncConfig  {
 		else {
 			long ret = Long.parseLong(val);
 			long min_interval;
-			if (LGSYNC_SOURCE_CLASS.equals(className) || LGSYNC_DELTASYNC_SOURCE_CLASS.equals(className)) {
+			if (LGSYNC_SOURCE_CLASS.equals(className)) {
 				min_interval = UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_LDAP_DEFAULT_VALUE;
 			}else if(UGSYNC_SOURCE_CLASS.equals(className)){
 				min_interval = UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_UNIX_DEFAULT_VALUE;
@@ -495,8 +491,8 @@ public class UserGroupSyncConfig  {
 			syncSource=getSyncSource();
 		}
 		else {
-			if (val.equalsIgnoreCase(LGSYNC_SOURCE_CLASS) && isDeltaSyncEnabled()) {
-				val = LGSYNC_DELTASYNC_SOURCE_CLASS;
+			if (val.equalsIgnoreCase(LGSYNC_SOURCE_CLASS)) {
+				val = LGSYNC_SOURCE_CLASS;
 			}
 			syncSource = val;
 		}
@@ -506,11 +502,7 @@ public class UserGroupSyncConfig  {
 		if(syncSource!=null && syncSource.equalsIgnoreCase("UNIX")){
 			className = UGSYNC_SOURCE_CLASS;
 		}else if(syncSource!=null && syncSource.equalsIgnoreCase("LDAP")){
-			if (!isDeltaSyncEnabled()) {
-				className = LGSYNC_SOURCE_CLASS;
-			} else {
-				className = LGSYNC_DELTASYNC_SOURCE_CLASS;
-			}
+			className = LGSYNC_SOURCE_CLASS;
 		} 
 
 		return className;
@@ -529,14 +521,9 @@ public class UserGroupSyncConfig  {
 
 	public UserGroupSink getUserGroupSink() throws Throwable {
 		String val =  prop.getProperty(UGSYNC_SINK_CLASS_PARAM);
-		String className = getUserGroupSourceClassName();
 
-		if (className.equals(LGSYNC_DELTASYNC_SOURCE_CLASS)) {
-			val = LGSYNC_DELTASYNC_SINK_CLASS;
-		} else {
-			if(val == null || val.trim().isEmpty()) {
-				val = UGSYNC_SINK_CLASS;
-			}
+		if(val == null || val.trim().isEmpty()) {
+			val = UGSYNC_SINK_CLASS;
 		}
 
 		Class<UserGroupSink> ugSinkClass = (Class<UserGroupSink>)Class.forName(val);
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXGroupListResponse.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXGroupListResponse.java
index 5f1e9af..c0e8a09 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXGroupListResponse.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXGroupListResponse.java
@@ -22,6 +22,7 @@
 import java.util.List;
 
 import com.google.gson.annotations.SerializedName;
+import org.apache.ranger.ugsyncutil.model.XGroupInfo;
 
 public class GetXGroupListResponse {
 	private int totalCount;
@@ -44,7 +45,5 @@ public class GetXGroupListResponse {
 	public void setXgroupInfoList(List<XGroupInfo> xgroupInfoList) {
 		this.xgroupInfoList = xgroupInfoList;
 	}
-	
-	
 
 }
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserGroupListResponse.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserGroupListResponse.java
deleted file mode 100644
index cf6957d..0000000
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserGroupListResponse.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
- package org.apache.ranger.unixusersync.model;
-
-import java.util.List;
-
-import com.google.gson.annotations.SerializedName;
-
-public class GetXUserGroupListResponse {
-	private int totalCount;
-
-	@SerializedName("vXGroupUsers")
-	List<XUserGroupInfo> xusergroupInfoList;
-
-	public int getTotalCount() {
-		return totalCount;
-	}
-
-	public void setTotalCount(int totalCount) {
-		this.totalCount = totalCount;
-	}
-
-	public List<XUserGroupInfo> getXusergroupInfoList() {
-		return xusergroupInfoList;
-	}
-
-	public void setXusergroupInfoList(List<XUserGroupInfo> xusergroupInfoList) {
-		this.xusergroupInfoList = xusergroupInfoList;
-	}
-
-	
-	
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserListResponse.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserListResponse.java
index 809a847..16ad7d6 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserListResponse.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GetXUserListResponse.java
@@ -22,6 +22,7 @@
 import java.util.List;
 
 import com.google.gson.annotations.SerializedName;
+import org.apache.ranger.ugsyncutil.model.XUserInfo;
 
 public class GetXUserListResponse {
 
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java
deleted file mode 100644
index a2cfa7b..0000000
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.unixusersync.model;
-
-import java.util.List;
-
-public class GroupUserInfo {
-	XGroupInfo xgroupInfo;
-	List<XUserInfo> xuserInfo;
-
-	public XGroupInfo getXgroupInfo() {
-		return xgroupInfo;
-	}
-	public void setXgroupInfo(XGroupInfo xgroupInfo) {
-		this.xgroupInfo = xgroupInfo;
-	}
-	public List<XUserInfo> getXuserInfo() {
-		return xuserInfo;
-	}
-	public void setXuserInfo(List<XUserInfo> xuserInfo) {
-		this.xuserInfo = xuserInfo;
-	}
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java
deleted file mode 100644
index 4f865af..0000000
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
- package org.apache.ranger.unixusersync.model;
-
-public class MUserInfo {
-	
-	private String loginId;
-	private String firstName;
-	private String lastName;
-	private String emailAddress;
-	private String[] userRoleList = { "ROLE_USER" };
-	private String otherAttributes;
-	
-	
-	public String getLoginId() {
-		return loginId;
-	}
-	public void setLoginId(String loginId) {
-		this.loginId = loginId;
-	}
-	public String getFirstName() {
-		return firstName;
-	}
-	public void setFirstName(String firstName) {
-		this.firstName = firstName;
-	}
-	public String getLastName() {
-		return lastName;
-	}
-	public void setLastName(String lastName) {
-		this.lastName = lastName;
-	}
-	public String getEmailAddress() {
-		return emailAddress;
-	}
-	public void setEmailAddress(String emailAddress) {
-		this.emailAddress = emailAddress;
-	}
-	public String[] getUserRoleList() {
-		return userRoleList;
-	}
-	public void setUserRoleList(String[] userRoleList) {
-		this.userRoleList = userRoleList;
-	}
-
-	public String getOtherAttributes() {
-		return otherAttributes;
-	}
-
-	public void setOtherAttributes(String otherAttributes) {
-		this.otherAttributes = otherAttributes;
-	}
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UserGroupInfo.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UserGroupInfo.java
deleted file mode 100644
index 936acca..0000000
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/UserGroupInfo.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.unixusersync.model;
-
-import java.util.List;
-
-public class UserGroupInfo {
-
-	XUserInfo xuserInfo;
-	List<XGroupInfo> xgroupInfo;
-
-	public XUserInfo getXuserInfo() {
-		return xuserInfo;
-	}
-	public void setXuserInfo(XUserInfo xuserInfo) {
-		this.xuserInfo = xuserInfo;
-	}
-	public List<XGroupInfo> getXgroupInfo() {
-		return xgroupInfo;
-	}
-	public void setXgroupInfo(List<XGroupInfo> xgroupInfo) {
-		this.xgroupInfo = xgroupInfo;
-	}
-}
\ No newline at end of file
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserGroupInfo.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserGroupInfo.java
deleted file mode 100644
index 06b21e0..0000000
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserGroupInfo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
- package org.apache.ranger.unixusersync.model;
-
-import com.google.gson.annotations.SerializedName;
-
-public class XUserGroupInfo {
-
-	private String userId;
-	@SerializedName("name")
-	private String groupName;
-	private String parentGroupId;
-
-	
-	
-	public String getUserId() {
-		return userId;
-	}
-
-	public void setUserId(String userId) {
-		this.userId = userId;
-	}
-
-	public String getGroupName() {
-		return groupName;
-	}
-
-	public void setGroupName(String groupName) {
-		this.groupName = groupName;
-	}
-	
-	public String getParentGroupId() {
-		return parentGroupId;
-	}
-
-	public void setParentGroupId(String parentGroupId) {
-		this.parentGroupId = parentGroupId;
-	}
-
-	
-	
-}
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/FileSourceUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/FileSourceUserGroupBuilder.java
index 5850585..5f3523e 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/FileSourceUserGroupBuilder.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/FileSourceUserGroupBuilder.java
@@ -24,31 +24,41 @@ import java.io.File;
 import java.io.FileReader;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.ArrayList;
 
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.csv.CSVFormat;
 import org.apache.commons.csv.CSVParser;
 import org.apache.commons.csv.CSVRecord;
 import org.apache.log4j.Logger;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.apache.ranger.unixusersync.model.FileSyncSourceInfo;
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
+import org.apache.ranger.ugsyncutil.model.FileSyncSourceInfo;
+import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo;
 import org.apache.ranger.usergroupsync.AbstractUserGroupSource;
 import org.apache.ranger.usergroupsync.UserGroupSink;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.stream.JsonReader;
+import org.apache.ranger.usergroupsync.UserGroupSource;
 
-public class FileSourceUserGroupBuilder extends AbstractUserGroupSource {
+public class FileSourceUserGroupBuilder extends AbstractUserGroupSource  implements UserGroupSource {
 	private static final Logger LOG = Logger.getLogger(FileSourceUserGroupBuilder.class);
 
 	private Map<String,List<String>> user2GroupListMap     = new HashMap<String,List<String>>();
 	private String                   userGroupFilename     = null;
+	private Map<String, Map<String, String>> sourceUsers; // Stores username and attr name & value pairs
+	private Map<String, Map<String, String>> sourceGroups; // Stores groupname and attr name & value pairs
+	private Map<String, Set<String>> sourceGroupUsers;
 	private long                     usergroupFileModified = 0;
 	private UgsyncAuditInfo ugsyncAuditInfo;
 	private FileSyncSourceInfo				 fileSyncSourceInfo;
-	private Set<String>				groupNames;
 	private boolean isStartupFlag = false;
 
 	private boolean isUpdateSinkSucc = true;
@@ -110,8 +120,6 @@ public class FileSourceUserGroupBuilder extends AbstractUserGroupSource {
 	@Override
 	public void updateSink(UserGroupSink sink) throws Throwable {
 		isUpdateSinkSucc = true;
-		String user=null;
-		List<String> groups=null;
 		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 		Date lastModifiedTime = new Date(usergroupFileModified);
 		Date syncTime = new Date(System.currentTimeMillis());
@@ -122,32 +130,44 @@ public class FileSourceUserGroupBuilder extends AbstractUserGroupSource {
 			buildUserGroupInfo();
 
 			for (Map.Entry<String, List<String>> entry : user2GroupListMap.entrySet()) {
-				user = entry.getKey();
-				try {
-					if (userNameRegExInst != null) {
-						user = userNameRegExInst.transform(user);
-					}
-					groups = entry.getValue();
-					if (groupNameRegExInst != null) {
-						List<String> mappedGroups = new ArrayList<>();
-						for (String group : groups) {
-							mappedGroups.add(groupNameRegExInst.transform(group));
+				String userName = entry.getKey();
+				Map<String, String> userAttrMap = new HashMap<>();
+				userAttrMap.put("original_name", userName);
+				userAttrMap.put("full_name", userName);
+				sourceUsers.put(userName, userAttrMap);
+				List<String> groups = entry.getValue();
+				if (groups != null) {
+					for(String groupName : groups) {
+						Map<String, String> groupAttrMap = new HashMap<>();
+						groupAttrMap.put("original_name", groupName);
+						groupAttrMap.put("full_name", groupName);
+						sourceGroups.put(groupName, groupAttrMap);
+						Set<String> groupUsers = sourceGroupUsers.get(groupName);
+						if (CollectionUtils.isNotEmpty(groupUsers)) {
+							groupUsers.add(userName);
+						} else {
+							groupUsers = new HashSet<>();
+							groupUsers.add(userName);
 						}
-						groups = mappedGroups;
+						sourceGroupUsers.put(groupName, groupUsers);
 					}
-					groupNames.addAll(groups);
-					sink.addOrUpdateUser(user, groups);
-				} catch (Throwable t) {
-					LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-							+ ", for user: " + user
-							+ ", groups: " + groups);
-					isUpdateSinkSucc = false;
 				}
+
+			}
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Users = " + sourceUsers.keySet());
+				LOG.debug("Groups = " + sourceGroups.keySet());
+				LOG.debug("GroupUsers = " + sourceGroupUsers.keySet());
+			}
+
+			try {
+				sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers);
+			} catch (Throwable t) {
+				LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t);
+				isUpdateSinkSucc = false;
 			}
 		}
 		try {
-			fileSyncSourceInfo.setTotalUsersSynced(user2GroupListMap.size());
-			fileSyncSourceInfo.setTotalGroupsSynced(groupNames.size());
 			sink.postUserGroupAuditInfo(ugsyncAuditInfo);
 		} catch (Throwable t) {
 			LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage());
@@ -172,7 +192,9 @@ public class FileSourceUserGroupBuilder extends AbstractUserGroupSource {
 	}
 
 	public void buildUserGroupInfo() throws Throwable {
-		groupNames = new HashSet<>();
+		sourceUsers = new HashMap<>();
+		sourceGroups = new HashMap<>();
+		sourceGroupUsers = new HashMap<>();
 		buildUserGroupList();
 		if ( LOG.isDebugEnabled()) {
 			print();
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
index ec986b9..6a4661e 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
@@ -17,50 +17,48 @@
  * under the License.
  */
 
- package org.apache.ranger.unixusersync.process;
+package org.apache.ranger.unixusersync.process;
 
 import java.io.IOException;
+import java.lang.reflect.Type;
 import java.net.UnknownHostException;
 import java.security.KeyStore;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.ArrayList;
 import java.util.StringTokenizer;
-import java.util.regex.Pattern;
+import java.util.LinkedHashMap;
 
 import javax.security.auth.Subject;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.NewCookie;
 
+import com.google.gson.reflect.TypeToken;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.security.SecureClientLogin;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
-import org.apache.ranger.plugin.util.URLEncoderUtil;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
 import org.apache.ranger.unixusersync.model.GetXGroupListResponse;
-import org.apache.ranger.unixusersync.model.GetXUserGroupListResponse;
 import org.apache.ranger.unixusersync.model.GetXUserListResponse;
-import org.apache.ranger.unixusersync.model.MUserInfo;
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
-import org.apache.ranger.unixusersync.model.UserGroupInfo;
-import org.apache.ranger.unixusersync.model.XGroupInfo;
-import org.apache.ranger.unixusersync.model.XUserGroupInfo;
-import org.apache.ranger.unixusersync.model.XUserInfo;
-import org.apache.ranger.usergroupsync.UserGroupSink;
+import org.apache.ranger.ugsyncutil.model.*;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.sun.jersey.api.client.ClientResponse;
+import org.apache.ranger.usergroupsync.AbstractUserGroupSource;
+import org.apache.ranger.usergroupsync.UserGroupSink;
 
-public class PolicyMgrUserGroupBuilder implements UserGroupSink {
+public class PolicyMgrUserGroupBuilder extends AbstractUserGroupSource implements UserGroupSink {
 
-	private static final Logger LOG = Logger.getLogger(PolicyMgrUserGroupBuilder.class);
+private static final Logger LOG = Logger.getLogger(PolicyMgrUserGroupBuilder.class);
 
 	private static final String AUTHENTICATION_TYPE = "hadoop.security.authentication";
 	private String AUTH_KERBEROS = "kerberos";
@@ -69,58 +67,66 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 	private static final String NAME_RULE = "hadoop.security.auth_to_local";
 
 	public static final String PM_USER_LIST_URI  = "/service/xusers/users/";				// GET
-	private static final String PM_ADD_USER_GROUP_INFO_URI = "/service/xusers/users/userinfo";	// POST
+	private static final String PM_ADD_USERS_URI = "/service/xusers/ugsync/users";	// POST
 
-	public static final String PM_GROUP_LIST_URI = "/service/xusers/groups/";				// GET
-	private static final String PM_ADD_GROUP_URI = "/service/xusers/groups/";				// POST
+	private static final String PM_ADD_GROUP_USER_LIST_URI = "/service/xusers/ugsync/groupusers";	// POST
 
+	public static final String PM_GROUP_LIST_URI = "/service/xusers/groups/";				// GET
+	private static final String PM_ADD_GROUPS_URI = "/service/xusers/ugsync/groups/";				// POST
 
-	public static final String PM_USER_GROUP_MAP_LIST_URI = "/service/xusers/groupusers/";		// GET
 
-	private static final String PM_DEL_USER_GROUP_LINK_URI = "/service/xusers/group/${groupName}/user/${userName}"; // DELETE
+	public static final String PM_GET_ALL_GROUP_USER_MAP_LIST_URI = "/service/xusers/ugsync/groupusers";		// GET
 
-	private static final String PM_ADD_LOGIN_USER_URI = "/service/users/default";			// POST
 	private static final String PM_AUDIT_INFO_URI = "/service/xusers/ugsync/auditinfo/";				// POST
 
-	private static final String GROUP_SOURCE_EXTERNAL ="1";
+	public static final String PM_UPDATE_USERS_ROLES_URI  = "/service/xusers/users/roleassignments";	// PUT
+
+	private static final String SOURCE_EXTERNAL ="1";
+	private static final String STATUS_ENABLED = "1";
 
-	private static final String RANGER_ADMIN_COOKIE_NAME = "RANGERADMINSESSIONID";
 	private static String LOCAL_HOSTNAME = "unknown";
-	private String recordsToPullPerCall = "1000";
+	private String recordsToPullPerCall = "10";
 	private boolean isMockRun = false;
 	private String policyMgrBaseUrl;
-
 	private Cookie sessionId=null;
 	private boolean isValidRangerCookie=false;
 	List<NewCookie> cookieList=new ArrayList<>();
+	private boolean isStartupFlag;
 
 	private UserGroupSyncConfig  config = UserGroupSyncConfig.getInstance();
 
-	private UserGroupInfo				usergroupInfo = new UserGroupInfo();
-	private List<XGroupInfo> 			xgroupList;
-	private List<XUserInfo> 			xuserList;
-	private List<XUserGroupInfo> 		xusergroupList;
-	private HashMap<String,XUserInfo>  	userId2XUserInfoMap;
-	private HashMap<String,XUserInfo>  	userName2XUserInfoMap;
-	private HashMap<String,XGroupInfo>  groupName2XGroupInfoMap;
+	private volatile RangerUgSyncRESTClient ldapUgSyncClient;
+
+	private Map<String, XUserInfo> userCache; // Key is user name as in ranger db
+	private Map<String, XGroupInfo> groupCache; // Key is group name as in ranger db
+	private Map<String, Set<String>> groupUsersCache; // Key is group name and value is set of user names (as stored in ranger DB)
+	private Map<String, String> groupNameMap; // Key is group DN and value is group name as stored in ranger DB
+	private Map<String, String> userNameMap; // Key is user DN and value is user name as stored in ranger DB
+
+	private Map<String, XGroupInfo> deltaGroups;
+	private Map<String, XUserInfo> deltaUsers;
+	private Map<String, Set<String>> deltaGroupUsers;
+	private Set<String> computeRolesForUsers;
 
-	private String authenticationType = null;
-	String principal;
-	String keytab;
-	String nameRules;
-    Map<String, String> userMap;
-    Map<String, String> groupMap;
 	private int noOfNewUsers;
 	private int noOfNewGroups;
 	private int noOfModifiedUsers;
 	private int noOfModifiedGroups;
-	private HashSet<String> newUserList = new HashSet<String>();
-	private HashSet<String> modifiedUserList = new HashSet<String>();
-	private HashSet<String> newGroupList = new HashSet<String>();
-	private HashSet<String> modifiedGroupList = new HashSet<String>();
-	private boolean isRangerCookieEnabled;
-	boolean isStartupFlag = false;
-    private volatile RangerUgSyncRESTClient uGSyncClient;
+
+	private boolean userNameCaseConversionFlag;
+	private boolean groupNameCaseConversionFlag;
+	private boolean userNameLowerCaseFlag = false;
+	private boolean groupNameLowerCaseFlag = false;
+
+	private String authenticationType = null;
+	String principal;
+	String keytab;
+	String nameRules;
+    Map<String, String> userMap = new LinkedHashMap<String, String>();
+    Map<String, String> groupMap = new LinkedHashMap<>();
+
+    private boolean isRangerCookieEnabled;
+    private String rangerCookieName;
 	static {
 		try {
 			LOCAL_HOSTNAME = java.net.InetAddress.getLocalHost().getCanonicalHostName();
@@ -129,31 +135,48 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		}
 	}
 
-
 	public static void main(String[] args) throws Throwable {
-		PolicyMgrUserGroupBuilder  ugbuilder = new PolicyMgrUserGroupBuilder();
+		PolicyMgrUserGroupBuilder ugbuilder = new PolicyMgrUserGroupBuilder();
 		ugbuilder.init();
+
 	}
 
+	public PolicyMgrUserGroupBuilder() {
+		super();
+
+		String userNameCaseConversion = config.getUserNameCaseConversion();
+
+		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion)) {
+			userNameCaseConversionFlag = false;
+		}
+		else {
+			userNameCaseConversionFlag = true;
+			userNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion);
+		}
+
+		String groupNameCaseConversion = config.getGroupNameCaseConversion();
+
+		if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion)) {
+			groupNameCaseConversionFlag = false;
+		}
+		else {
+			groupNameCaseConversionFlag = true;
+			groupNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion);
+		}
+	}
 
 	synchronized public void init() throws Throwable {
-		xgroupList = new ArrayList<XGroupInfo>();
-		xuserList = new ArrayList<XUserInfo>();
-		xusergroupList = new ArrayList<XUserGroupInfo>();
-		userId2XUserInfoMap = new HashMap<String,XUserInfo>();
-		userName2XUserInfoMap = new HashMap<String,XUserInfo>();
-		groupName2XGroupInfoMap = new HashMap<String,XGroupInfo>();
-		userMap = new LinkedHashMap<String, String>();
-		groupMap = new LinkedHashMap<String, String>();
 		recordsToPullPerCall = config.getMaxRecordsPerAPICall();
 		policyMgrBaseUrl = config.getPolicyManagerBaseURL();
 		isMockRun = config.isMockRunEnabled();
-		noOfNewUsers = 0;
-		noOfModifiedUsers = 0;
-		noOfNewGroups = 0;
-		noOfModifiedGroups = 0;
-		isStartupFlag = true;
 		isRangerCookieEnabled = config.isUserSyncRangerCookieEnabled();
+		rangerCookieName = config.getRangerAdminCookieName();
+		groupNameMap = new HashMap<>();
+		userNameMap = new HashMap<>();
+		userCache = new HashMap<>();
+		groupCache = new HashMap<>();
+		isStartupFlag = true;
+
 		if (isMockRun) {
 			LOG.setLevel(Level.DEBUG);
 		}
@@ -172,7 +195,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		}
 		keytab = config.getProperty(KEYTAB,"");
 		nameRules = config.getProperty(NAME_RULE,"DEFAULT");
-		uGSyncClient = new RangerUgSyncRESTClient(policyMgrBaseUrl, keyStoreFile, keyStoreFilepwd, keyStoreType,
+		ldapUgSyncClient = new RangerUgSyncRESTClient(policyMgrBaseUrl, keyStoreFile, keyStoreFilepwd, keyStoreType,
 				trustStoreFile, trustStoreFilepwd, trustStoreType, authenticationType, principal, keytab,
 				config.getPolicyMgrUserName(), config.getPolicyMgrPassword());
 
@@ -181,8 +204,100 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
             getRoleForUserGroups(userGroupRoles);
         }
 		buildUserGroupInfo();
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("PolicyMgrUserGroupBuilder.init()==> PolMgrBaseUrl : "+policyMgrBaseUrl+" KeyStore File : "+keyStoreFile+" TrustStore File : "+trustStoreFile+ "Authentication Type : "+authenticationType);
+
+        if (LOG.isDebugEnabled()) {
+			LOG.debug("PolicyMgrUserGroupBuilderOld.init()==> PolMgrBaseUrl : "+policyMgrBaseUrl+" KeyStore File : "+keyStoreFile+" TrustStore File : "+trustStoreFile+ "Authentication Type : "+authenticationType);
+		}
+
+    }
+
+	@Override
+	public void postUserGroupAuditInfo(UgsyncAuditInfo ugsyncAuditInfo) throws Throwable {
+		ugsyncAuditInfo.setNoOfNewUsers(Integer.toUnsignedLong(noOfNewUsers));
+		ugsyncAuditInfo.setNoOfNewGroups(Integer.toUnsignedLong(noOfNewGroups));
+		ugsyncAuditInfo.setNoOfModifiedUsers(Integer.toUnsignedLong(noOfModifiedUsers));
+		ugsyncAuditInfo.setNoOfModifiedGroups(Integer.toUnsignedLong(noOfModifiedGroups));
+		int noOfCachedUsers = userCache.size();
+		int noOfCachedGroups = groupCache.size();
+		switch (ugsyncAuditInfo.getSyncSource()) {
+			case "LDAP/AD":
+				ugsyncAuditInfo.getLdapSyncSourceInfo().setTotalUsersSynced(noOfCachedUsers);
+				ugsyncAuditInfo.getLdapSyncSourceInfo().setTotalGroupsSynced(noOfCachedGroups);
+				break;
+			case "Unix":
+				ugsyncAuditInfo.getUnixSyncSourceInfo().setTotalUsersSynced(noOfCachedUsers);
+				ugsyncAuditInfo.getUnixSyncSourceInfo().setTotalGroupsSynced(noOfCachedGroups);
+				break;
+			case "File" :
+				ugsyncAuditInfo.getFileSyncSourceInfo().setTotalUsersSynced(noOfCachedUsers);
+				ugsyncAuditInfo.getFileSyncSourceInfo().setTotalGroupsSynced(noOfCachedGroups);
+				break;
+			default:
+				break;
+		}
+
+		if (!isMockRun) {
+			addUserGroupAuditInfo(ugsyncAuditInfo);
+		}
+
+	}
+
+	@Override
+	public void addOrUpdateUsersGroups(Map<String, Map<String, String>> sourceGroups,
+									   Map<String, Map<String, String>> sourceUsers,
+									   Map<String, Set<String>> sourceGroupUsers) throws Throwable {
+
+		noOfNewUsers = 0;
+		noOfNewGroups = 0;
+		noOfModifiedUsers = 0;
+		noOfModifiedGroups = 0;
+		computeRolesForUsers = new HashSet<>();
+
+		if (MapUtils.isNotEmpty(sourceGroups)) {
+			addOrUpdateGroups(sourceGroups);
+		}
+		if (MapUtils.isNotEmpty(sourceUsers)) {
+			addOrUpdateUsers(sourceUsers);
+		}
+
+		if (MapUtils.isNotEmpty(sourceGroupUsers)) {
+			addOrUpdateGroupUsers(sourceGroupUsers);
+		}
+
+		if (isStartupFlag) {
+			// This is to handle any config changes for role assignments that might impact existing users in ranger db
+			if (MapUtils.isNotEmpty(userMap)) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("adding " + userMap.keySet() + " for computing roles during startup");
+				}
+				computeRolesForUsers.addAll(userMap.keySet()); // Add all the user defined in the role assignment rules
+			}
+			if (MapUtils.isNotEmpty(groupMap)) {
+				for (String groupName : groupMap.keySet()) {
+					if (LOG.isDebugEnabled()) {
+						LOG.debug("adding " + groupUsersCache.get(groupName) + " from " + groupName + " for computing roles during startup");
+					}
+					computeRolesForUsers.addAll(groupUsersCache.get(groupName));
+				}
+			}
+		}
+
+		if (CollectionUtils.isNotEmpty(computeRolesForUsers)) {
+			updateUserRoles();
+		}
+		isStartupFlag = false;
+
+		if (LOG.isDebugEnabled()){
+			LOG.debug("Update cache");
+		}
+		if (MapUtils.isNotEmpty(deltaGroups)) {
+			groupCache.putAll(deltaGroups);
+		}
+		if (MapUtils.isNotEmpty(deltaUsers)) {
+			userCache.putAll(deltaUsers);
+		}
+		if (MapUtils.isNotEmpty(deltaGroupUsers)) {
+			groupUsersCache.putAll(deltaGroupUsers);
 		}
 	}
 
@@ -202,8 +317,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 						try {
 							buildGroupList();
 							buildUserList();
-							buildUserGroupLinkList();
-							rebuildUserGroupMap();
+							buildGroupUserLinkList();
 						} catch (Exception e) {
 							LOG.error("Failed to build Group List : ", e);
 						}
@@ -216,320 +330,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		} else {
 			buildGroupList();
 			buildUserList();
-			buildUserGroupLinkList();
-			rebuildUserGroupMap();
-			if (LOG.isDebugEnabled()) {
-				this.print();
-			}
-		}
-	}
-
-	private void rebuildUserGroupMap() {
-
-		for(XUserInfo user : xuserList) {
-			addUserToList(user);
-		}
-
-		for(XGroupInfo group : xgroupList) {
-			addGroupToList(group);
-		}
-
-
-		for(XUserGroupInfo ug : xusergroupList) {
-			addUserGroupToList(ug);
-		}
-
-
-	}
-
-
-	private void addUserToList(XUserInfo aUserInfo) {
-		if (! xuserList.contains(aUserInfo)) {
-			xuserList.add(aUserInfo);
-		}
-
-		String userId = aUserInfo.getId();
-
-		if (userId != null) {
-			userId2XUserInfoMap.put(userId, aUserInfo);
-		}
-
-		String userName = aUserInfo.getName();
-
-		if (userName != null) {
-			userName2XUserInfoMap.put(userName, aUserInfo);
-		}
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("PolicyMgrUserGroupBuilder:addUserToList() xuserList.size() = " + xuserList.size());
-		}
-	}
-
-
-	private void addGroupToList(XGroupInfo aGroupInfo) {
-
-		if (! xgroupList.contains(aGroupInfo) ) {
-			xgroupList.add(aGroupInfo);
-		}
-
-		if (aGroupInfo.getName() != null) {
-			groupName2XGroupInfoMap.put(aGroupInfo.getName(), aGroupInfo);
-		}
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("PolicyMgrUserGroupBuilder:addGroupToList() xgroupList.size() = " + xgroupList.size());
-		}
-	}
-
-	private void addUserGroupToList(XUserGroupInfo ugInfo) {
-		String userId = ugInfo.getUserId();
-
-		if (userId != null) {
-			XUserInfo user = userId2XUserInfoMap.get(userId);
-
-			if (user != null) {
-				List<String> groups = user.getGroups();
-				if (! groups.contains(ugInfo.getGroupName())) {
-					groups.add(ugInfo.getGroupName());
-				}
-			}
-		}
-	}
-
-	private void addUserGroupInfoToList(XUserInfo userInfo, XGroupInfo groupInfo) {
-		String userId = userInfo.getId();
-
-		if (userId != null) {
-			XUserInfo user = userId2XUserInfoMap.get(userId);
-
-			if (user != null) {
-				List<String> groups = user.getGroups();
-				if (! groups.contains(groupInfo.getName())) {
-					groups.add(groupInfo.getName());
-				}
-			}
-		}
-	}
-
-	private void delUserGroupFromList(XUserInfo userInfo, XGroupInfo groupInfo) {
-		List<String> groups = userInfo.getGroups();
-		if (groups.contains(groupInfo.getName())) {
-			groups.remove(groupInfo.getName());
-		}
-	}
-
-	private void print() {
-		LOG.debug("Number of users read [" + xuserList.size() + "]");
-		for(XUserInfo user : xuserList) {
-			LOG.debug("USER: " + user.getName());
-			for(String group : user.getGroups()) {
-				LOG.debug("\tGROUP: " + group);
-			}
-		}
-	}
-
-	@Override
-	public void addOrUpdateUser(String userName, List<String> groups) throws Throwable {
-
-		XUserInfo user = userName2XUserInfoMap.get(userName);
-
-		if (groups == null) {
-			groups = new ArrayList<String>();
-		}
-		if (user == null) {    // Does not exists
-			//noOfNewUsers++;
-			newUserList.add(userName);
-			for (String group : groups) {
-				if (groupName2XGroupInfoMap.containsKey(group) && !newGroupList.contains(group)) {
-					modifiedGroupList.add(group);
-				} else {
-					//LOG.info("Adding new group " + group + " for user = " + userName);
-					newGroupList.add(group);
-				}
-			}
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("INFO: addPMAccount(" + userName + ")");
-			}
-			if (! isMockRun) {
-				if (addMUser(userName) == null) {
-					String msg = "Failed to add portal user";
-					LOG.error(msg);
-					throw new Exception(msg);
-				}
-			}
-
-			//* Build the user group info object and do the rest call
- 			if ( ! isMockRun ) {
- 				// If the rest call to ranger admin fails,
- 				// propagate the failure to the caller for retry in next sync cycle.
- 				if (addUserGroupInfo(userName,groups) == null ) {
- 					String msg = "Failed to add addorUpdate user group info";
- 					LOG.error(msg);
- 					throw new Exception(msg);
- 				}
- 			}
-
-		}
-		else {					// Validate group memberships
-			List<String> oldGroups = user.getGroups();
-			List<String> addGroups = new ArrayList<String>();
-			List<String> delGroups = new ArrayList<String>();
-			List<String> updateGroups = new ArrayList<String>();
-			Set<String> cumulativeGroups = new HashSet<>();
-			XGroupInfo tempXGroupInfo=null;
-			for(String group : groups) {
-				if (! oldGroups.contains(group)) {
-					addGroups.add(group);
-					if (!groupName2XGroupInfoMap.containsKey(group)) {
-						newGroupList.add(group);
-					} else {
-						modifiedGroupList.add(group);
-					}
-				}else{
-					tempXGroupInfo=groupName2XGroupInfoMap.get(group);
-					if(tempXGroupInfo!=null && ! GROUP_SOURCE_EXTERNAL.equals(tempXGroupInfo.getGroupSource())){
-						updateGroups.add(group);
-					}
-				}
-			}
-
-			for(String group : oldGroups) {
-				if (! groups.contains(group) ) {
-					delGroups.add(group);
-				}
-			}
-
-			for(String g : addGroups) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")");
-				}
-			}
-			for(String g : delGroups) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("INFO: delPMXAGroupFromUser(" + userName + "," + g + ")");
-				}
-			}
-			for(String g : updateGroups) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("INFO: updatePMXAGroupToUser(" + userName + "," + g + ")");
-				}
-			}
-
-			if (isMockRun) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("PolicyMgrUserGroupBuilder.addOrUpdateUser(): Mock Run enabled and hence not sending updates to Ranger admin!");
-				}
-				return;
-			}
-
-			if (!delGroups.isEmpty()) {
-				delXUserGroupInfo(user, delGroups);
-				//Remove groups from user mapping
-				user.deleteGroups(delGroups);
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("PolicyMgrUserGroupBuilder.addUserGroupInfo(): groups for " + userName + " after delete = " + user.getGroups());
-				}
-			}
-
-			if (!delGroups.isEmpty() || !addGroups.isEmpty() || !updateGroups.isEmpty()) {
-				cumulativeGroups = new HashSet<>(user.getGroups());
-				cumulativeGroups.addAll(addGroups);
-				cumulativeGroups.addAll(updateGroups);
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("PolicyMgrUserGroupBuilder.addUserGroupInfo(): cumulative groups for " + userName + " = " + cumulativeGroups);
-				}
-
-				UserGroupInfo ugInfo = new UserGroupInfo();
-				XUserInfo obj = addXUserInfo(userName);
-				Set<String> userRoleList = new HashSet<>();
-				if (userMap.containsKey(userName)) {
-					// Add the user role that is defined in user role assignments
-					userRoleList.add(userMap.get(userName));
-				}
-
-				for (String group : cumulativeGroups) {
-					String value = groupMap.get(group);
-					if (value != null) {
-						userRoleList.add(value);
-					}
-				}
-
-				if (!userRoleList.isEmpty()) {
-					obj.setUserRoleList(new ArrayList<>(userRoleList));
-				}
-
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("PolicyMgrUserGroupBuilder.addUserGroupInfo() user role list for " + userName + " = " + obj.getUserRoleList());
-				}
-
-				ugInfo.setXuserInfo(obj);
-				ugInfo.setXgroupInfo(getXGroupInfoList(new ArrayList<>(cumulativeGroups)));
-				try {
-					// If the rest call to ranger admin fails,
-					// propagate the failure to the caller for retry in next
-					// sync cycle.
-					if (addUserGroupInfo(ugInfo) == null) {
-						String msg = "Failed to add user group info";
-						LOG.error(msg);
-						throw new Exception(msg);
-					}
-				} catch (Throwable t) {
-					LOG.error("PolicyMgrUserGroupBuilder.addUserGroupInfo failed with exception: "
-							+ t.getMessage()
-							+ ", for user-group entry: "
-							+ ugInfo);
-				}
-			}
-
-			if (isStartupFlag) {
-				UserGroupInfo ugInfo = new UserGroupInfo();
-				XUserInfo obj = addXUserInfo(userName);
-				if (obj != null && updateGroups.isEmpty()
-						&& addGroups.isEmpty() && delGroups.isEmpty()) {
-					Set<String> userRoleList = new HashSet<>();
-					if (userMap.containsKey(userName)) {
-						// Add the user role that is defined in user role assignments
-						userRoleList.add(userMap.get(userName));
-					}
-
-					for (String group : groups) {
-						String value = groupMap.get(group);
-						if (value != null) {
-							userRoleList.add(value);
-						}
-					}
-					obj.setUserRoleList(new ArrayList<>(userRoleList));
-					ugInfo.setXuserInfo(obj);
-					ugInfo.setXgroupInfo(getXGroupInfoList(groups));
-					try {
-						// If the rest call to ranger admin fails,
-						// propagate the failure to the caller for retry in next
-						// sync cycle.
-						if (addUserGroupInfo(ugInfo) == null) {
-							String msg = "Failed to add user group info";
-							LOG.error(msg);
-							throw new Exception(msg);
-						}
-					} catch (Throwable t) {
-						LOG.error("PolicyMgrUserGroupBuilder.addUserGroupInfo failed with exception: "
-								+ t.getMessage()
-								+ ", for user-group entry: "
-								+ ugInfo);
-					}
-				}
-				modifiedGroupList.addAll(oldGroups);
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("Adding user to modified user list: " + userName + ": " + oldGroups);
-				}
-				modifiedUserList.add(userName);
-
-			} else {
-				if (!addGroups.isEmpty() || !delGroups.isEmpty() || !updateGroups.isEmpty()) {
-					modifiedUserList.add(userName);
-				}
-				modifiedGroupList.addAll(updateGroups);
-				modifiedGroupList.addAll(delGroups);
-			}
+			buildGroupUserLinkList();
 		}
 	}
 
@@ -554,7 +355,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 				response = cookieBasedGetEntity(relativeUrl, retrievedCount);
 			} else {
 				try {
-					clientResp = uGSyncClient.get(relativeUrl, queryParams);
+					clientResp = ldapUgSyncClient.get(relativeUrl, queryParams);
 					if (clientResp != null) {
 						response = clientResp.getEntity(String.class);
 					}
@@ -566,20 +367,20 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 				LOG.debug("RESPONSE: [" + response + "]");
 			}
 			GetXGroupListResponse groupList = gson.fromJson(response, GetXGroupListResponse.class);
-            LOG.info("Group List : "+groupList);
+
 			totalCount = groupList.getTotalCount();
 
 			if (groupList.getXgroupInfoList() != null) {
-				xgroupList.addAll(groupList.getXgroupInfoList());
-				retrievedCount = xgroupList.size();
-
 				for (XGroupInfo g : groupList.getXgroupInfoList()) {
 					if (LOG.isDebugEnabled()) {
 						LOG.debug("GROUP:  Id:" + g.getId() + ", Name: " + g.getName() + ", Description: "
 								+ g.getDescription());
 					}
+					groupCache.put(g.getName(), g);
 				}
+				retrievedCount = groupCache.size();
 			}
+			LOG.info("PolicyMgrUserGroupBuilder.buildGroupList(): No. of groups retrieved from ranger admin " + retrievedCount);
 		}
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("<== PolicyMgrUserGroupBuilder.buildGroupList()");
@@ -607,7 +408,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 				response = cookieBasedGetEntity(relativeUrl, retrievedCount);
 			} else {
 				try {
-					clientResp = uGSyncClient.get(relativeUrl, queryParams);
+					clientResp = ldapUgSyncClient.get(relativeUrl, queryParams);
 					if (clientResp != null) {
 						response = clientResp.getEntity(String.class);
 					}
@@ -619,48 +420,40 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 				LOG.debug("RESPONSE: [" + response + "]");
 			}
 			GetXUserListResponse userList = gson.fromJson(response, GetXUserListResponse.class);
-
 			totalCount = userList.getTotalCount();
 
 			if (userList.getXuserInfoList() != null) {
-				xuserList.addAll(userList.getXuserInfoList());
-				retrievedCount = xuserList.size();
-
 				for (XUserInfo u : userList.getXuserInfoList()) {
 					if (LOG.isDebugEnabled()) {
 						LOG.debug("USER: Id:" + u.getId() + ", Name: " + u.getName() + ", Description: "
 								+ u.getDescription());
 					}
+					userCache.put(u.getName(), u);
 				}
+				retrievedCount = userCache.size();
 			}
+			LOG.info("PolicyMgrUserGroupBuilder.buildUserList(): No. of users retrieved from ranger admin = " + retrievedCount);
 		}
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("<== PolicyMgrUserGroupBuilder.buildUserList()");
 		}
 	}
 
-	private void buildUserGroupLinkList() {
+	private void buildGroupUserLinkList() {
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> PolicyMgrUserGroupBuilder.buildUserGroupLinkList()");
+			LOG.debug("==> PolicyMgrUserGroupBuilder.buildGroupUserLinkList()");
 		}
-		int totalCount = 100;
-		int retrievedCount = 0;
-		String relativeUrl = PM_USER_GROUP_MAP_LIST_URI;
+		String relativeUrl = PM_GET_ALL_GROUP_USER_MAP_LIST_URI;
 
-		while (retrievedCount < totalCount) {
-			String response = null;
+		String response = null;
 			ClientResponse clientResp = null;
 
-			Map<String, String> queryParams = new HashMap<String, String>();
-			queryParams.put("pageSize", recordsToPullPerCall);
-			queryParams.put("startIndex", String.valueOf(retrievedCount));
-
 			Gson gson = new GsonBuilder().create();
 			if (isRangerCookieEnabled) {
-				response = cookieBasedGetEntity(relativeUrl, retrievedCount);
+				response = cookieBasedGetEntity(relativeUrl, 0);
 			} else {
 				try {
-					clientResp = uGSyncClient.get(relativeUrl, queryParams);
+					clientResp = ldapUgSyncClient.get(relativeUrl, null);
 					if (clientResp != null) {
 						response = clientResp.getEntity(String.class);
 					}
@@ -672,592 +465,687 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 				LOG.debug("RESPONSE: [" + response + "]");
 			}
 
-			GetXUserGroupListResponse usergroupList = gson.fromJson(response, GetXUserGroupListResponse.class);
-
-			totalCount = usergroupList.getTotalCount();
-
-			if (usergroupList.getXusergroupInfoList() != null) {
-				xusergroupList.addAll(usergroupList.getXusergroupInfoList());
-				retrievedCount = xusergroupList.size();
+			groupUsersCache = gson.fromJson(response, Map.class);
+			if (MapUtils.isEmpty(groupUsersCache)) {
+				groupUsersCache = new HashMap<>();
+			}
 
-				for (XUserGroupInfo ug : usergroupList.getXusergroupInfoList()) {
-					if (LOG.isDebugEnabled()) {
-						LOG.debug("USER_GROUP: UserId:" + ug.getUserId() + ", Name: " + ug.getGroupName());
-					}
-				}
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Group User List : " + groupUsersCache.values());
 			}
-		}
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== PolicyMgrUserGroupBuilder.buildUserGroupLinkList()");
+			LOG.debug("<== PolicyMgrUserGroupBuilder.buildGroupUserLinkList()");
 		}
 	}
 
-	private UserGroupInfo addUserGroupInfo(String userName, List<String> groups){
-		if(LOG.isDebugEnabled()) {
-	 		LOG.debug("==> PolicyMgrUserGroupBuilder.addUserGroupInfo " + userName + " and groups");
-	 	}
-		UserGroupInfo ret = null;
-		XUserInfo user = null;
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMXAUser(" + userName + ")");
-		}
-		if (! isMockRun) {
-			user = addXUserInfo(userName);
-            if (!groups.isEmpty() && user != null) {
-                for (String group : groups) {
-                    String value = groupMap.get(group);
-                    if (value != null) {
-                        List<String> userRoleList = new ArrayList<String>();
-                        userRoleList.add(value);
-                        if (userMap.containsKey(user.getName())) {
-                            List<String> userRole = new ArrayList<String>();
-                            userRole.add(userMap.get(user.getName()));
-                            user.setUserRoleList(userRole);
-                        } else {
-                            user.setUserRoleList(userRoleList);
-                        }
-                    }
-                }
-            }
-            usergroupInfo.setXuserInfo(user);
-        }
+	private void addOrUpdateUsers(Map<String, Map<String, String>> sourceUsers) throws Throwable {
+		computeUserDelta(sourceUsers);
+		if (MapUtils.isNotEmpty(deltaUsers)) {
+			if (addOrUpdateDeltaUsers() == 0) {
+				String msg = "Failed to addorUpdate users to ranger admin";
+				LOG.error(msg);
+				throw new Exception(msg);
+			}
+		}
+	}
 
-		for(String g : groups) {
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")");
+	private void addOrUpdateGroups(Map<String, Map<String, String>> sourceGroups) throws Throwable {
+		computeGroupDelta(sourceGroups);
+		if (MapUtils.isNotEmpty(deltaGroups)) {
+			if (addOrUpdateDeltaGroups() == 0) {
+				String msg = "Failed to addorUpdate groups to ranger admin";
+				LOG.error(msg);
+				throw new Exception(msg);
 			}
 		}
-		if (! isMockRun ) {
-			addXUserGroupInfo(user, groups);
+	}
+
+	private void addOrUpdateGroupUsers(Map<String, Set<String>> sourceGroupUsers) throws Throwable {
+		List<GroupUserInfo> groupUserInfoList = computeGroupUsersDelta(sourceGroupUsers);
+		if (CollectionUtils.isNotEmpty(groupUserInfoList)) {
+			noOfModifiedGroups += groupUserInfoList.size();
+			if (addOrUpdateDeltaGroupUsers(groupUserInfoList) == 0) {
+				String msg = "Failed to addorUpdate group memberships to ranger admin";
+				LOG.error(msg);
+				throw new Exception(msg);
+			}
 		}
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UserGroupInfo result = ret;
-				ret = Subject.doAs(sub, new PrivilegedAction<UserGroupInfo>() {
-					@Override
-					public UserGroupInfo run() {
-						try {
-							return getUsergroupInfo(result);
-						} catch (Exception e) {
-							LOG.error("Failed to add User Group Info : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
+	}
+
+	private void updateUserRoles() throws Throwable {
+		if (MapUtils.isNotEmpty(groupMap) || MapUtils.isNotEmpty(userMap)) {
+			UsersGroupRoleAssignments ugRoleAssignments = new UsersGroupRoleAssignments();
+			List<String> allUsers = new ArrayList<>(computeRolesForUsers);
+
+			ugRoleAssignments.setUsers(allUsers);
+			ugRoleAssignments.setGroupRoleAssignments(groupMap);
+			ugRoleAssignments.setUserRoleAssignments(userMap);
+			if (updateRoles(ugRoleAssignments) == null) {
+				String msg = "Unable to update roles for " + allUsers;
+				LOG.error(msg);
+				throw new Exception(msg);
 			}
-			return null;
-		}else{
-			return getUsergroupInfo(ret);
 		}
 	}
 
-	private UserGroupInfo getUsergroupInfo(UserGroupInfo ret) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.getUsergroupInfo(UserGroupInfo ret)");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-		String relativeUrl = PM_ADD_USER_GROUP_INFO_URI;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(usergroupInfo);
+	private void computeGroupDelta(Map<String, Map<String, String>> sourceGroups) {
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("USER GROUP MAPPING" + jsonString);
-		}
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(usergroupInfo,relativeUrl);
-		}
-		else{
-			try {
-				clientResp = uGSyncClient.post(relativeUrl, null, usergroupInfo);
-				if (clientResp != null) {
-					response = clientResp.getEntity(String.class);
-				}
+			LOG.debug("PolicyMgrUserGroupBuilder.computeGroupDelta(" + sourceGroups.keySet() + ")");
+		}
+		deltaGroups = new HashMap<>();
+		// Check if the group exists in cache. If not, mark as new group.
+		// else check if other attributes are updated and mark as updated group
+
+		for (String groupDN : sourceGroups.keySet()) {
+			Map<String, String> newGroupAttrs = sourceGroups.get(groupDN);
+			Gson gson = new Gson();
+			String newGroupAttrsStr = gson.toJson(newGroupAttrs);
+			String groupName = groupNameMap.get(groupDN);
+			if (StringUtils.isEmpty(groupName)) {
+				groupName = groupNameTransform(newGroupAttrs.get("original_name"));
+				groupNameMap.put(groupDN, groupName);
 			}
-			catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
+			if (!groupCache.containsKey(groupName)) {
+				XGroupInfo newGroup = addXGroupInfo(groupName, newGroupAttrsStr);
+				deltaGroups.put(groupName, newGroup);
+				noOfNewGroups++;
+			} else {
+				XGroupInfo oldGroup = groupCache.get(groupName);
+				String oldGroupAttrs = oldGroup.getOtherAttributes();
+				if (!StringUtils.equalsIgnoreCase(oldGroupAttrs, newGroupAttrsStr)) {
+					oldGroup.setOtherAttributes(newGroupAttrsStr);
+					deltaGroups.put(groupName, oldGroup);
+					noOfModifiedGroups++;
+				}
 			}
 		}
-		if ( LOG.isDebugEnabled() ) {
-			LOG.debug("RESPONSE: [" + response + "]");
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== PolicyMgrUserGroupBuilder.computeGroupDelta(" + deltaGroups.keySet() + ")");
 		}
-		ret = gson.fromJson(response, UserGroupInfo.class);
+	}
 
-		if ( ret != null) {
+	private void computeUserDelta(Map<String, Map<String, String>> sourceUsers) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.computeUserDelta(" + sourceUsers.keySet() + ")");
+		}
+		deltaUsers = new HashMap<>();
+		// Check if the user exists in cache. If not, mark as new user.
+		// else check if other attributes are updated and mark as updated user
 
-			XUserInfo xUserInfo = ret.getXuserInfo();
-			addUserToList(xUserInfo);
+		for (String userDN : sourceUsers.keySet()) {
+			Map<String, String> newUserAttrs = sourceUsers.get(userDN);
+			Gson gson = new Gson();
+			String newUserAttrsStr = gson.toJson(newUserAttrs);
 
-			for(XGroupInfo xGroupInfo : ret.getXgroupInfo()) {
-				addGroupToList(xGroupInfo);
-				addUserGroupInfoToList(xUserInfo,xGroupInfo);
+			String userName = userNameMap.get(userDN);
+			if (StringUtils.isEmpty(userName)) {
+				userName = userNameTransform(newUserAttrs.get("original_name"));
+				userNameMap.put(userDN, userName);
 			}
-		}
 
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== PolicyMgrUserGroupBuilder.getUsergroupInfo (UserGroupInfo ret)");
-		}
-		return ret;
-	}
+			if (!userCache.containsKey(userName)) {
 
-	private UserGroupInfo getUserGroupInfo(UserGroupInfo usergroupInfo) {
-		UserGroupInfo ret = null;
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.getUsergroupInfo(UserGroupInfo ret, UserGroupInfo usergroupInfo)");
+				XUserInfo newUser = addXUserInfo(userName, newUserAttrsStr);
+				deltaUsers.put(userName, newUser);
+				noOfNewUsers++;
+			} else {
+				// Update other attributes if changed
+				XUserInfo oldUser = userCache.get(userName);
+				String oldUserAttrs = oldUser.getOtherAttributes();
+				if (!StringUtils.equalsIgnoreCase(oldUserAttrs, newUserAttrsStr)) {
+					oldUser.setOtherAttributes(newUserAttrsStr);
+					deltaUsers.put(userName, oldUser);
+					noOfModifiedUsers++;
+				}
+			}
 		}
-		String response = null;
-		ClientResponse clientResp = null;
-		String relativeURL = PM_ADD_USER_GROUP_INFO_URI;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(usergroupInfo);
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("USER GROUP MAPPING" + jsonString);
+			LOG.debug("<== PolicyMgrUserGroupBuilder.computeUserDelta(" + deltaUsers.keySet() + ")");
 		}
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(usergroupInfo,relativeURL);
+	}
+
+	private List<GroupUserInfo> computeGroupUsersDelta(Map<String, Set<String>> sourceGroupUsers) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.computeGroupUsersDelta(" + sourceGroupUsers.keySet() + ")");
 		}
-		else{
-			try {
-				clientResp = uGSyncClient.post(relativeURL, null, usergroupInfo);
-				if (clientResp != null) {
-					response = clientResp.getEntity(String.class);
+		deltaGroupUsers = new HashMap<>();
+		List<GroupUserInfo> deltaGroupUserInfoList = new ArrayList<>();
+		for (String groupDN : sourceGroupUsers.keySet()) {
+			String groupName = groupNameMap.get(groupDN);
+			if (StringUtils.isEmpty(groupName)) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("Ignoring group membership update for " + groupDN);
 				}
-			}catch(Throwable t){
-				LOG.error("Failed to get response, Error is : ", t);
+				continue;
+			}
+			Set<String> oldUsers = new HashSet<>();
+			Set<String> newUsers = new HashSet<>();
+			Set<String> addUsers = new HashSet<>();
+			Set<String> delUsers = new HashSet<>();
+			if (CollectionUtils.isNotEmpty(groupUsersCache.get(groupName))) {
+				oldUsers = new HashSet<>(groupUsersCache.get(groupName));
+			}
+
+			for (String userDN : sourceGroupUsers.get(groupDN)) {
+				String userName = userNameMap.get(userDN);
+				if (!StringUtils.isEmpty(userName)) {
+					newUsers.add(userName);
+					if (CollectionUtils.isEmpty(oldUsers) || !oldUsers.contains(userName)) {
+						addUsers.add(userName);
+					}
+				}
+			}
+
+			if (CollectionUtils.isNotEmpty(oldUsers)) {
+				for (String userName : oldUsers) {
+					if (CollectionUtils.isEmpty(newUsers)|| !newUsers.contains(userName)) {
+						delUsers.add(userName);
+					}
+				}
+			}
+
+			if (CollectionUtils.isNotEmpty(addUsers) || CollectionUtils.isNotEmpty(delUsers)) {
+				GroupUserInfo groupUserInfo = new GroupUserInfo();
+				groupUserInfo.setGroupName(groupName);
+				if (CollectionUtils.isNotEmpty(addUsers)) {
+					groupUserInfo.setAddUsers(addUsers);
+					if (groupMap.containsKey(groupName)) {
+						// Add users to the computeRole list only if there is a rule defined for the group.
+						computeRolesForUsers.addAll(addUsers);
+					}
+				}
+				if (CollectionUtils.isNotEmpty(delUsers)) {
+					groupUserInfo.setDelUsers(delUsers);
+					if (groupMap.containsKey(groupName)) {
+						// Add users to the computeRole list only if there is a rule defined for the group.
+						computeRolesForUsers.addAll(delUsers);
+					}
+				}
+				deltaGroupUserInfoList.add(groupUserInfo);
+				deltaGroupUsers.put(groupName, newUsers);
 			}
 		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("RESPONSE: [" + response + "]");
+		if (CollectionUtils.isNotEmpty(deltaGroupUserInfoList)) {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("<== PolicyMgrUserGroupBuilder.computeGroupUsersDelta(" + deltaGroupUserInfoList + ")");
+			}
+		} else {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("<== PolicyMgrUserGroupBuilder.computeGroupUsersDelta(0)");
+			}
 		}
-		ret = gson.fromJson(response, UserGroupInfo.class);
-		if ( ret != null) {
 
-			XUserInfo xUserInfo = ret.getXuserInfo();
-			addUserToList(xUserInfo);
+		return deltaGroupUserInfoList;
+	}
 
-            for (XGroupInfo xGroupInfo : ret.getXgroupInfo()) {
-                addGroupToList(xGroupInfo);
-                addUserGroupInfoToList(xUserInfo, xGroupInfo);
-            }
-		}
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== PolicyMgrUserGroupBuilder.getUsergroupInfo(UserGroupInfo ret, UserGroupInfo usergroupInfo)");
+	private XUserInfo addXUserInfo(String aUserName, String otherAttributes) {
+		XUserInfo xuserInfo = new XUserInfo();
+		xuserInfo.setName(aUserName);
+		xuserInfo.setDescription(aUserName + " - add from Unix box");
+		xuserInfo.setUserSource(SOURCE_EXTERNAL);
+		xuserInfo.setStatus(STATUS_ENABLED);
+		List<String> roleList = new ArrayList<String>();
+		if (userMap.containsKey(aUserName)) {
+			roleList.add(userMap.get(aUserName));
+		}else{
+			roleList.add("ROLE_USER");
 		}
-		return ret;
+		xuserInfo.setUserRoleList(roleList);
+		xuserInfo.setOtherAttributes(otherAttributes);
+
+		return xuserInfo;
 	}
 
 
-	private String tryUploadEntityWithCookie(Object obj, String apiURL) {
+	private XGroupInfo addXGroupInfo(String aGroupName, String otherAttributes) {
+
+		XGroupInfo addGroup = new XGroupInfo();
+
+		addGroup.setName(aGroupName);
+
+		addGroup.setDescription(aGroupName + " - add from Unix box");
+
+		addGroup.setGroupType("1");
+
+		addGroup.setGroupSource(SOURCE_EXTERNAL);
+		addGroup.setOtherAttributes(otherAttributes);
+
+		return addGroup;
+	}
+
+	private int addOrUpdateDeltaUsers() throws Throwable{
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> PolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
-		}
-		String response = null;
-		ClientResponse clientResp = null;
-		try{
-			clientResp = uGSyncClient.post(apiURL, null, obj, sessionId);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
+			LOG.debug("PolicyMgrUserGroupBuilder.addOrUpdateDeltaUsers(" + deltaUsers.keySet() + ")");
 		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				sessionId = null;
-				isValidRangerCookie = false;
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT || clientResp.getStatus() == HttpServletResponse.SC_OK) {
-				List<NewCookie> respCookieList = clientResp.getCookies();
-				for (NewCookie cookie : respCookieList) {
-					if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
-						if (!(sessionId.getValue().equalsIgnoreCase(cookie.toCookie().getValue()))) {
-							sessionId = cookie.toCookie();
+		int ret = 0;
+
+		GetXUserListResponse xUserList = new GetXUserListResponse();
+		xUserList.setTotalCount(deltaUsers.size());
+		xUserList.setXuserInfoList(new ArrayList<>(deltaUsers.values()));
+
+		if (authenticationType != null
+				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
+				&& SecureClientLogin.isKerberosCredentialExists(principal,
+				keytab)) {
+			try {
+				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+				final GetXUserListResponse xUserListFinal = xUserList;
+				ret = Subject.doAs(sub, new PrivilegedAction<Integer>() {
+					@Override
+					public Integer run() {
+						try {
+							return getUsers(xUserListFinal);
+						} catch (Throwable e) {
+							LOG.error("Failed to add or update Users : ", e);
 						}
-						isValidRangerCookie = true;
-						break;
+						return 0;
 					}
-				}
-			}
-
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK	&& clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
+				});
+			} catch (Exception e) {
+				LOG.error("Failed to add or update Users : " , e);
+				throw new Exception(e);
 			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
+		} else {
+			ret = getUsers(xUserList);
 		}
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== PolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
+			LOG.debug("PolicyMgrUserGroupBuilder.addOrUpdateDeltaUsers(" + deltaUsers.keySet() + ")");
 		}
-		return response;
+		return ret;
 	}
 
 
-	private String tryUploadEntityWithCred(Object obj,String apiURL){
+	private int getUsers(GetXUserListResponse xUserList) throws Throwable{
 		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
+			LOG.debug("==> PolicyMgrUserGroupBuilder.getUsers()");
 		}
-		String response = null;
-		ClientResponse clientResp = null;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(obj);
+		int ret = 0;
+		int totalCount = xUserList.getTotalCount();
+		int uploadedCount = -1;
+		int pageSize = Integer.valueOf(recordsToPullPerCall);
+		while (uploadedCount < totalCount) {
+			String response = null;
+			ClientResponse clientRes = null;
+			String relativeUrl = PM_ADD_USERS_URI;
+			GetXUserListResponse pagedXUserList = new GetXUserListResponse();
+			int pagedXUserListLen = uploadedCount+pageSize;
+			pagedXUserList.setXuserInfoList(xUserList.getXuserInfoList().subList(uploadedCount+1,
+					pagedXUserListLen>totalCount?totalCount:pagedXUserListLen));
+			pagedXUserList.setTotalCount(pageSize);
+			if (pagedXUserList.getXuserInfoList().size() == 0) {
+				LOG.info("PolicyMgrUserGroupBuilder.getUsers() done updating users");
+				return 1;
+			}
 
-		if ( LOG.isDebugEnabled() ) {
-		   LOG.debug("USER GROUP MAPPING" + jsonString);
-		}
-		try{
-			clientResp = uGSyncClient.post(apiURL, null, obj);
-		}
-		catch(Throwable t){
-			LOG.error("Failed to get response, Error is : ", t);
-		}
-		if (clientResp != null) {
-			if (!(clientResp.toString().contains(apiURL))) {
-				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-				LOG.warn("Credentials response from ranger is 401.");
-			} else if (clientResp.getStatus() == HttpServletResponse.SC_OK || clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
-				cookieList = clientResp.getCookies();
-				for (NewCookie cookie : cookieList) {
-					if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
-						sessionId = cookie.toCookie();
-						isValidRangerCookie = true;
-						LOG.info("valid cookie saved ");
-						break;
+			if (isRangerCookieEnabled) {
+				response = cookieBasedUploadEntity(pagedXUserList, relativeUrl);
+			} else {
+				try {
+					clientRes = ldapUgSyncClient.post(relativeUrl, null, pagedXUserList);
+					if (clientRes != null) {
+						response = clientRes.getEntity(String.class);
 					}
+				} catch (Throwable t) {
+					LOG.error("Failed to get response, Error is : ", t);
+					throw new Exception(t);
 				}
 			}
-			if (clientResp.getStatus() != HttpServletResponse.SC_OK && clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
-					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-				sessionId = null;
-				isValidRangerCookie = false;
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("RESPONSE[" + response + "]");
 			}
-			clientResp.bufferEntity();
-			response = clientResp.getEntity(String.class);
+
+			if (response != null) {
+				ret = Integer.valueOf(response);
+				uploadedCount += pageSize;
+			} else {
+				LOG.error("Failed to addOrUpdateUsers " + uploadedCount );
+				ret = 0;
+			}
+			LOG.info("ret = " + ret + " No. of users uploaded to ranger admin= " + (uploadedCount>totalCount?totalCount:uploadedCount));
 		}
 
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== PolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
+		if(LOG.isDebugEnabled()){
+			LOG.debug("<== PolicyMgrUserGroupBuilder.getUsers()");
 		}
-		return response;
+		return ret;
 	}
 
+	private int addOrUpdateDeltaGroups() throws Throwable{
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("PolicyMgrUserGroupBuilder.addOrUpdateDeltaGroups(" + deltaGroups.keySet() + ")");
+		}
+		int ret = 0;
 
-	private UserGroupInfo addUserGroupInfo(UserGroupInfo usergroupInfo){
-		if(LOG.isDebugEnabled()) {
-	 		LOG.debug("==> PolicyMgrUserGroupBuilder.addUserGroupInfo");
-	 	}
-		UserGroupInfo ret = null;
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
+		GetXGroupListResponse xGroupList = new GetXGroupListResponse();
+		xGroupList.setTotalCount(deltaGroups.size());
+		xGroupList.setXgroupInfoList(new ArrayList<>(deltaGroups.values()));
+
+		if (authenticationType != null
+				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
+				&& SecureClientLogin.isKerberosCredentialExists(principal,
+				keytab)) {
 			try {
 				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UserGroupInfo ugInfo = usergroupInfo;
-				ret = Subject.doAs(sub, new PrivilegedAction<UserGroupInfo>() {
+				final GetXGroupListResponse xGroupListFinal = xGroupList;
+				ret = Subject.doAs(sub, new PrivilegedAction<Integer>() {
 					@Override
-					public UserGroupInfo run() {
+					public Integer run() {
 						try {
-							return getUserGroupInfo(ugInfo);
-						} catch (Exception e) {
-							LOG.error("Failed to add User Group Info : ", e);
+							return getGroups(xGroupListFinal);
+						} catch (Throwable e) {
+							LOG.error("Failed to add or update groups : ", e);
 						}
-						return null;
+						return 0;
 					}
 				});
-				return ret;
 			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : ",e);
+				LOG.error("Failed to add or update groups : " , e);
+				throw new Exception(e);
 			}
 		} else {
-			try {
-				ret = getUserGroupInfo(usergroupInfo);
-			} catch (Throwable t) {
-				LOG.error("Failed to add User Group Info : ", t);
-			}
+			ret = getGroups(xGroupList);
 		}
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== PolicyMgrUserGroupBuilder.addUserGroupInfo");
+			LOG.debug("PolicyMgrUserGroupBuilder.addOrUpdateDeltaGroups(" + deltaGroups.keySet() + ")");
 		}
 		return ret;
 	}
-	
-	private XUserInfo addXUserInfo(String aUserName) {
-			XUserInfo xuserInfo = new XUserInfo();
-			xuserInfo.setName(aUserName);
-			xuserInfo.setDescription(aUserName + " - add from Unix box");
-			List<String> roleList = new ArrayList<String>();
-			if (userMap.containsKey(aUserName)) {
-	            roleList.add(userMap.get(aUserName));
-	        }else{
-	        	roleList.add("ROLE_USER");
-	        }
-			xuserInfo.setUserRoleList(roleList);
-			usergroupInfo.setXuserInfo(xuserInfo);
-			
-			return xuserInfo;
-		}
-
-
-	private XGroupInfo addXGroupInfo(String aGroupName) {
-
-		XGroupInfo addGroup = new XGroupInfo();
-
-		addGroup.setName(aGroupName);
-
-		addGroup.setDescription(aGroupName + " - add from Unix box");
-
-		addGroup.setGroupType("1");
-
-		addGroup.setGroupSource(GROUP_SOURCE_EXTERNAL);
-
-		return addGroup;
-	}
 
 
-	private void addXUserGroupInfo(XUserInfo aUserInfo, List<String> aGroupList) {
+	private int getGroups(GetXGroupListResponse xGroupList) throws Throwable{
+		if(LOG.isDebugEnabled()){
+			LOG.debug("==> PolicyMgrUserGroupBuilder.getGroups()");
+		}
+		int ret = 0;
+		int totalCount = xGroupList.getTotalCount();
+		int uploadedCount = -1;
+		int pageSize = Integer.valueOf(recordsToPullPerCall);
+		while (uploadedCount < totalCount) {
+			String response = null;
+			ClientResponse clientRes = null;
+			String relativeUrl = PM_ADD_GROUPS_URI;
+			GetXGroupListResponse pagedXGroupList = new GetXGroupListResponse();
+			int pagedXGroupListLen = uploadedCount+pageSize;
+			pagedXGroupList.setXgroupInfoList(xGroupList.getXgroupInfoList().subList(uploadedCount+1,
+					pagedXGroupListLen>totalCount?totalCount:pagedXGroupListLen));
+			pagedXGroupList.setTotalCount(pageSize);
 
-		List<XGroupInfo> xGroupInfoList = new ArrayList<XGroupInfo>();
+			if (isRangerCookieEnabled) {
+				response = cookieBasedUploadEntity(pagedXGroupList, relativeUrl);
+			} else {
+				try {
+					clientRes = ldapUgSyncClient.post(relativeUrl, null, pagedXGroupList);
+					if (clientRes != null) {
+						response = clientRes.getEntity(String.class);
+					}
+				} catch (Throwable t) {
+					LOG.error("Failed to get response, Error is : ", t);
+					throw new Exception(t);
+				}
+			}
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("RESPONSE[" + response + "]");
+			}
 
-		for(String groupName : aGroupList) {
-			XGroupInfo group = groupName2XGroupInfoMap.get(groupName);
-			if (group == null) {
-				group = addXGroupInfo(groupName);
+			if (response != null) {
+				ret = Integer.valueOf(response);
+				uploadedCount += pageSize;
+			} else {
+				LOG.error("Failed to addOrUpdateGroups " + uploadedCount );
+				ret = 0;
 			}
-			xGroupInfoList.add(group);
-			addXUserGroupInfo(aUserInfo, group);
+			LOG.info("ret = " + ret + " No. of groups uploaded to ranger admin= " + (uploadedCount>totalCount?totalCount:uploadedCount));
 		}
 
-		usergroupInfo.setXgroupInfo(xGroupInfoList);
+		if(LOG.isDebugEnabled()){
+			LOG.debug("<== PolicyMgrUserGroupBuilder.getGroups()");
+		}
+		return ret;
 	}
 
-	private List<XGroupInfo> getXGroupInfoList(List<String> aGroupList) {
+	private int addOrUpdateDeltaGroupUsers(List<GroupUserInfo> groupUserInfoList) throws Throwable{
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.addOrUpdateDeltaGroupUsers(" + groupUserInfoList + ")");
+		}
+		int ret = 0;
 
-		List<XGroupInfo> xGroupInfoList = new ArrayList<XGroupInfo>();
-		for(String groupName : aGroupList) {
-			XGroupInfo group = groupName2XGroupInfoMap.get(groupName);
-			if (group == null) {
-				group = addXGroupInfo(groupName);
-			}else if(!GROUP_SOURCE_EXTERNAL.equals(group.getGroupSource())){
-				group.setGroupSource(GROUP_SOURCE_EXTERNAL);
+		if (authenticationType != null
+				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
+				&& SecureClientLogin.isKerberosCredentialExists(principal,
+				keytab)) {
+			try {
+				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+				final List<GroupUserInfo> groupUserInfoListFinal = groupUserInfoList;
+				ret = Subject.doAs(sub, new PrivilegedAction<Integer>() {
+					@Override
+					public Integer run() {
+						try {
+							return getGroupUsers(groupUserInfoListFinal);
+						} catch (Throwable e) {
+							LOG.error("Failed to add or update group memberships : ", e);
+						}
+						return 0;
+					}
+				});
+			} catch (Exception e) {
+				LOG.error("Failed to add or update group memberships : " , e);
+				throw new Exception(e);
 			}
-			xGroupInfoList.add(group);
+		} else {
+			ret = getGroupUsers(groupUserInfoList);
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== PolicyMgrUserGroupBuilder.addOrUpdateDeltaGroupUsers(" + groupUserInfoList + ")");
 		}
-		return xGroupInfoList;
+		return ret;
 	}
 
 
+	private int getGroupUsers(List<GroupUserInfo> groupUserInfoList) throws Throwable{
+		if(LOG.isDebugEnabled()){
+			LOG.debug("==> PolicyMgrUserGroupBuilder.getGroupUsers()");
+		}
+		int ret = 0;
+		int totalCount = groupUserInfoList.size();
+		int uploadedCount = -1;
+		int pageSize = Integer.valueOf(recordsToPullPerCall);
+		while (uploadedCount < totalCount) {
+			String response = null;
+			ClientResponse clientRes = null;
+			String relativeUrl = PM_ADD_GROUP_USER_LIST_URI;
 
-   private XUserGroupInfo addXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
-
-
-	    XUserGroupInfo ugInfo = new XUserGroupInfo();
+			int pagedGroupUserInfoListLen = uploadedCount+pageSize;
+			List<GroupUserInfo> pagedGroupUserInfoList = groupUserInfoList.subList(uploadedCount+1,
+					pagedGroupUserInfoListLen>totalCount?totalCount:pagedGroupUserInfoListLen);
 
-		ugInfo.setUserId(aUserInfo.getId());
+			if (isRangerCookieEnabled) {
+				response = cookieBasedUploadEntity(pagedGroupUserInfoList, relativeUrl);
+			} else {
+				try {
+					clientRes = ldapUgSyncClient.post(relativeUrl, null, pagedGroupUserInfoList);
+					if (clientRes != null) {
+						response = clientRes.getEntity(String.class);
+					}
+				} catch (Throwable t) {
+					LOG.error("Failed to get response, Error is : ", t);
+					throw new Exception(t);
+				}
+			}
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("RESPONSE[" + response + "]");
+			}
 
-		ugInfo.setGroupName(aGroupInfo.getName());
+			if (response != null) {
+				ret = Integer.valueOf(response);
+				uploadedCount += pageSize;
+			} else {
+				LOG.error("Failed to addOrUpdateGroups " + uploadedCount );
+				ret = 0;
+			}
 
-		// ugInfo.setParentGroupId("1");
+			LOG.info("ret = " + ret + " No. of group memberships uploaded to ranger admin= " + (uploadedCount>totalCount?totalCount:uploadedCount));
+		}
 
-        return ugInfo;
+		if(LOG.isDebugEnabled()){
+			LOG.debug("<== PolicyMgrUserGroupBuilder.getGroupUsers()");
+		}
+		return ret;
 	}
+	private List<String> updateRoles(UsersGroupRoleAssignments ugRoleAssignments) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.updateUserRole(" + ugRoleAssignments.getUsers() + ")");
+		}
 
-
-	private void delXUserGroupInfo(final XUserInfo aUserInfo, List<String> aGroupList) {
-		for(String groupName : aGroupList) {
-			final XGroupInfo group = groupName2XGroupInfoMap.get(groupName);
-			if (group != null) {
-				if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
-					try {
-						if (LOG.isDebugEnabled()) {
-							LOG.debug("Using principal = " + principal + " and keytab = " + keytab);
+		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
+			try {
+				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+				final UsersGroupRoleAssignments result = ugRoleAssignments;
+				List<String> ret = Subject.doAs(sub, new PrivilegedAction<List<String>>() {
+					@Override
+					public List<String> run() {
+						try {
+							return updateUsersRoles(result);
+						} catch (Exception e) {
+							LOG.error("Failed to add User Group Info : ", e);
 						}
-						Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-						Subject.doAs(sub, new PrivilegedAction<Void>() {
-							@Override
-							public Void run() {
-								try {
-									delXUserGroupInfo(aUserInfo, group);
-								} catch (Exception e) {
-									LOG.error("Failed to build Group List : ", e);
-								}
-								return null;
-							}
-						});
-					} catch (Exception e) {
-						LOG.error("Failed to Authenticate Using given Principal and Keytab : ",e);
+						return null;
 					}
-				} else {
-					delXUserGroupInfo(aUserInfo, group);
-				}
+				});
+				return ret;
+			} catch (Exception e) {
+				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
 			}
+			return null;
+		}else{
+			return updateUsersRoles(ugRoleAssignments);
 		}
 	}
 
-	private void delXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> PolicyMgrUserGroupBuilder.delXUserGroupInfo()");
+	private List<String> updateUsersRoles(UsersGroupRoleAssignments ugRoleAssignments) {
+		if(LOG.isDebugEnabled()){
+			LOG.debug("==> PolicyMgrUserGroupBuilder.updateUserRoles(" + ugRoleAssignments.getUsers() + ")");
 		}
-
-		String groupName = aGroupInfo.getName();
-
-		String userName  = aUserInfo.getName();
-
+		List<String> ret = null;
 		try {
-			ClientResponse response = null;
-			String relativeURL = PM_DEL_USER_GROUP_LINK_URI.replaceAll(Pattern.quote("${groupName}"),
-					   URLEncoderUtil.encodeURIParam(groupName)).replaceAll(Pattern.quote("${userName}"), URLEncoderUtil.encodeURIParam(userName));
-			if (isRangerCookieEnabled) {
-				if (sessionId != null && isValidRangerCookie) {
-
-					response = uGSyncClient.delete(relativeURL, null, sessionId);
-					if (response != null) {
-						if (!(response.toString().contains(relativeURL))) {
-							response.setStatus(HttpServletResponse.SC_NOT_FOUND);
-							sessionId = null;
-							isValidRangerCookie = false;
-						} else if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-							LOG.warn("response from ranger is 401 unauthorized");
-							sessionId = null;
-							isValidRangerCookie = false;
-						} else if (response.getStatus() == HttpServletResponse.SC_NO_CONTENT
-								|| response.getStatus() == HttpServletResponse.SC_OK) {
-							cookieList = response.getCookies();
-							for (NewCookie cookie : cookieList) {
-								if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
-									sessionId = cookie.toCookie();
-									isValidRangerCookie = true;
-									break;
-								}
-							}
-						}
+			int totalCount = ugRoleAssignments.getUsers().size();
+			int uploadedCount = -1;
+			int pageSize = Integer.valueOf(recordsToPullPerCall);
+			while (uploadedCount < totalCount) {
+				int pagedUgRoleAssignmentsListLen = uploadedCount + pageSize;
+				UsersGroupRoleAssignments pagedUgRoleAssignmentsList = new UsersGroupRoleAssignments();
+				pagedUgRoleAssignmentsList.setUsers(ugRoleAssignments.getUsers().subList(uploadedCount + 1,
+						pagedUgRoleAssignmentsListLen > totalCount ? totalCount : pagedUgRoleAssignmentsListLen));
+				pagedUgRoleAssignmentsList.setGroupRoleAssignments(ugRoleAssignments.getGroupRoleAssignments());
+				pagedUgRoleAssignmentsList.setUserRoleAssignments(ugRoleAssignments.getUserRoleAssignments());
+				String response = null;
+				ClientResponse clientRes = null;
+				Gson gson = new GsonBuilder().create();
+				String jsonString = gson.toJson(pagedUgRoleAssignmentsList);
+				String url = PM_UPDATE_USERS_ROLES_URI;
 
-						if (response.getStatus() != HttpServletResponse.SC_OK && response.getStatus() != HttpServletResponse.SC_NO_CONTENT
-								&& response.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-							sessionId = null;
-							isValidRangerCookie = false;
-						}
-					}
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("USER role MAPPING" + jsonString);
+				}
+				if (isRangerCookieEnabled) {
+					response = cookieBasedUploadEntity(pagedUgRoleAssignmentsList, url);
 				} else {
-					response = uGSyncClient.delete(relativeURL, null);
-					if (response != null) {
-						if (!(response.toString().contains(relativeURL))) {
-							response.setStatus(HttpServletResponse.SC_NOT_FOUND);
-						} else if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
-							LOG.warn("Credentials response from ranger is 401.");
-						} else if (response.getStatus() == HttpServletResponse.SC_OK
-								|| response.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
-							cookieList = response.getCookies();
-							for (NewCookie cookie : cookieList) {
-								if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
-									sessionId = cookie.toCookie();
-									isValidRangerCookie = true;
-									LOG.info("valid cookie saved ");
-									break;
-								}
-							}
-						}
-						if (response.getStatus() != HttpServletResponse.SC_OK && response.getStatus() != HttpServletResponse.SC_NO_CONTENT
-								&& response.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
-							sessionId = null;
-							isValidRangerCookie = false;
+					try {
+						clientRes = ldapUgSyncClient.post(url, null, ugRoleAssignments);
+						if (clientRes != null) {
+							response = clientRes.getEntity(String.class);
 						}
+					} catch (Throwable t) {
+						LOG.error("Failed to get response, Error is : ", t);
 					}
 				}
-			} else {
-				response = uGSyncClient.delete(relativeURL, null);
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("RESPONSE: [" + response + "]");
+				}
+				Type listType = new TypeToken<ArrayList<String>>() {
+				}.getType();
+				ret = new Gson().fromJson(response, listType);
+				uploadedCount += pageSize;
 			}
-		    if ( LOG.isDebugEnabled() ) {
-		    	LOG.debug("RESPONSE: [" + response.toString() + "]");
-		    }
-
-		    if (response.getStatus() == 200) {
-		    	delUserGroupFromList(aUserInfo, aGroupInfo);
-		    }
 
 		} catch (Exception e) {
 
-			LOG.warn( "ERROR: Unable to delete GROUP: " + groupName  + " from USER:" + userName , e);
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== PolicyMgrUserGroupBuilder.delXUserGroupInfo()");
+			LOG.warn( "ERROR: Unable to update roles for: " + ugRoleAssignments.getUsers(), e);
 		}
 
+		if(LOG.isDebugEnabled()){
+			LOG.debug("<== PolicyMgrUserGroupBuilder.updateUserRoles(" + ret + ")");
+		}
+		return ret;
 	}
 
-	private MUserInfo addMUser(String aUserName) {
-		MUserInfo ret = null;
-		MUserInfo userInfo = new MUserInfo();
+	private void addUserGroupAuditInfo(UgsyncAuditInfo auditInfo) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.addAuditInfo(" + auditInfo.getNoOfNewUsers() + ", " + auditInfo.getNoOfNewGroups() +
+					", " + auditInfo.getNoOfModifiedUsers() + ", " + auditInfo.getNoOfModifiedGroups() +
+					", " + auditInfo.getSyncSource() + ")");
+		}
 
-		userInfo.setLoginId(aUserName);
-		userInfo.setFirstName(aUserName);
-		userInfo.setLastName(aUserName);
-        String str[] = new String[1];
-        if (userMap.containsKey(aUserName)) {
-            str[0] = userMap.get(aUserName);
-        }
-        userInfo.setUserRoleList(str);
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
+		if (authenticationType != null
+				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
+				&& SecureClientLogin.isKerberosCredentialExists(principal,
+				keytab)) {
 			try {
 				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final MUserInfo result = ret;
-				final MUserInfo userInfoFinal = userInfo;
-				ret = Subject.doAs(sub, new PrivilegedAction<MUserInfo>() {
+				final UgsyncAuditInfo auditInfoFinal = auditInfo;
+				Subject.doAs(sub, new PrivilegedAction<Void>() {
 					@Override
-					public MUserInfo run() {
+					public Void run() {
 						try {
-							return getMUser(userInfoFinal, result);
+							getUserGroupAuditInfo(auditInfoFinal);
 						} catch (Exception e) {
 							LOG.error("Failed to add User : ", e);
 						}
 						return null;
 					}
 				});
-				return ret;
+				return;
 			} catch (Exception e) {
 				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
 			}
-			return null;
+			return;
 		} else {
-			return getMUser(userInfo, ret);
+			getUserGroupAuditInfo(auditInfo);
 		}
 	}
 
 
-	private MUserInfo getMUser(MUserInfo userInfo, MUserInfo ret) {
+	private void getUserGroupAuditInfo(UgsyncAuditInfo userInfo) {
 		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.getMUser()");
+			LOG.debug("==> PolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
 		}
 		String response = null;
-		ClientResponse clientResp = null;
+		ClientResponse clientRes = null;
 		Gson gson = new GsonBuilder().create();
-		if (isRangerCookieEnabled) {
-			response = cookieBasedUploadEntity(userInfo, PM_ADD_LOGIN_USER_URI);
-		} else {
-			String relativeUrl = PM_ADD_LOGIN_USER_URI;
+		String relativeUrl = PM_AUDIT_INFO_URI;
+
+		if(isRangerCookieEnabled){
+			response = cookieBasedUploadEntity(userInfo, relativeUrl);
+		}
+		else {
 			try {
-				clientResp = uGSyncClient.post(relativeUrl, null, userInfo);
-				if (clientResp != null) {
-					response = clientResp.getEntity(String.class);
+				clientRes = ldapUgSyncClient.post(relativeUrl, null, userInfo);
+				if (clientRes != null) {
+					response = clientRes.getEntity(String.class);
 				}
-			} catch (Exception e) {
-				LOG.error("Failed to get response, Error is : " + e.getMessage());
+			}
+			catch(Throwable t){
+				LOG.error("Failed to get response, Error is : ", t);
 			}
 		}
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("RESPONSE[" + response + "]");
 		}
-		ret = gson.fromJson(response, MUserInfo.class);
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("MUser Creation successful " + ret);
-			LOG.debug("<== PolicyMgrUserGroupBuilder.getMUser()");
+		gson.fromJson(response, UgsyncAuditInfo.class);
+
+		if(LOG.isDebugEnabled()){
+			LOG.debug("AuditInfo Creation successful ");
+			LOG.debug("<== PolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
 		}
-		return ret;
 	}
 
 	private String cookieBasedUploadEntity(Object obj, String apiURL ) {
@@ -1294,6 +1182,105 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		return response;
 	}
 
+	private String tryUploadEntityWithCookie(Object obj, String apiURL) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> PolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
+		}
+		String response = null;
+		ClientResponse clientResp = null;
+
+		try {
+			clientResp = ldapUgSyncClient.post(apiURL, null, obj, sessionId);
+		}
+		catch(Throwable t){
+			LOG.error("Failed to get response, Error is : ", t);
+		}
+		if (clientResp != null) {
+			if (!(clientResp.toString().contains(apiURL))) {
+				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+				sessionId = null;
+				isValidRangerCookie = false;
+			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
+				sessionId = null;
+				isValidRangerCookie = false;
+			} else if (clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT || clientResp.getStatus() == HttpServletResponse.SC_OK) {
+				List<NewCookie> respCookieList = clientResp.getCookies();
+				for (NewCookie cookie : respCookieList) {
+					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
+						if (!(sessionId.getValue().equalsIgnoreCase(cookie.toCookie().getValue()))) {
+							sessionId = cookie.toCookie();
+						}
+						isValidRangerCookie = true;
+						break;
+					}
+				}
+			}
+
+			if (clientResp.getStatus() != HttpServletResponse.SC_OK	&& clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
+					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
+				sessionId = null;
+				isValidRangerCookie = false;
+			}
+			clientResp.bufferEntity();
+			response = clientResp.getEntity(String.class);
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== PolicyMgrUserGroupBuilder.tryUploadEntityWithCookie()");
+		}
+		return response;
+	}
+
+
+	private String tryUploadEntityWithCred(Object obj, String apiURL){
+		if(LOG.isDebugEnabled()){
+			LOG.debug("==> PolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
+		}
+		String response = null;
+		ClientResponse clientResp = null;
+
+		Gson gson = new GsonBuilder().create();
+		String jsonString = gson.toJson(obj);
+
+		if ( LOG.isDebugEnabled() ) {
+		   LOG.debug("USER GROUP MAPPING" + jsonString);
+		}
+		try{
+			clientResp = ldapUgSyncClient.post(apiURL, null, obj);
+		}
+		catch(Throwable t){
+			LOG.error("Failed to get response, Error is : ", t);
+		}
+		if (clientResp != null) {
+			if (!(clientResp.toString().contains(apiURL))) {
+				clientResp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+			} else if (clientResp.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
+				LOG.warn("Credentials response from ranger is 401.");
+			} else if (clientResp.getStatus() == HttpServletResponse.SC_OK || clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
+				cookieList = clientResp.getCookies();
+				for (NewCookie cookie : cookieList) {
+					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
+						sessionId = cookie.toCookie();
+						isValidRangerCookie = true;
+						LOG.info("valid cookie saved ");
+						break;
+					}
+				}
+			}
+			if (clientResp.getStatus() != HttpServletResponse.SC_OK && clientResp.getStatus() != HttpServletResponse.SC_NO_CONTENT
+					&& clientResp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
+				sessionId = null;
+				isValidRangerCookie = false;
+			}
+			clientResp.bufferEntity();
+			response = clientResp.getEntity(String.class);
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== PolicyMgrUserGroupBuilder.tryUploadEntityInfoWithCred()");
+		}
+		return response;
+	}
+
 	private String tryGetEntityWithCred(String apiURL, int retrievedCount) {
 		if(LOG.isDebugEnabled()){
 			LOG.debug("==> PolicyMgrUserGroupBuilder.tryGetEntityWithCred()");
@@ -1305,7 +1292,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		queryParams.put("pageSize", recordsToPullPerCall);
 		queryParams.put("startIndex", String.valueOf(retrievedCount));
 		try{
-			clientResp = uGSyncClient.get(apiURL, queryParams);
+			clientResp = ldapUgSyncClient.get(apiURL, queryParams);
 		}
 		catch(Throwable t){
 			LOG.error("Failed to get response, Error is : ", t);
@@ -1318,7 +1305,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 			} else if (clientResp.getStatus() == HttpServletResponse.SC_OK || clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT) {
 				cookieList = clientResp.getCookies();
 				for (NewCookie cookie : cookieList) {
-					if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
+					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
 						sessionId = cookie.toCookie();
 						isValidRangerCookie = true;
 						LOG.info("valid cookie saved ");
@@ -1352,8 +1339,8 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		Map<String, String> queryParams = new HashMap<String, String>();
 		queryParams.put("pageSize", recordsToPullPerCall);
 		queryParams.put("startIndex", String.valueOf(retrievedCount));
-		try{
-			clientResp = uGSyncClient.get(apiURL, queryParams, sessionId);
+		try {
+			clientResp = ldapUgSyncClient.get(apiURL, queryParams, sessionId);
 		}
 		catch(Throwable t){
 			LOG.error("Failed to get response, Error is : ", t);
@@ -1369,7 +1356,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 			} else if (clientResp.getStatus() == HttpServletResponse.SC_NO_CONTENT || clientResp.getStatus() == HttpServletResponse.SC_OK) {
 				List<NewCookie> respCookieList = clientResp.getCookies();
 				for (NewCookie cookie : respCookieList) {
-					if (cookie.getName().equalsIgnoreCase(RANGER_ADMIN_COOKIE_NAME)) {
+					if (cookie.getName().equalsIgnoreCase(rangerCookieName)) {
 						if (!(sessionId.getValue().equalsIgnoreCase(cookie.toCookie().getValue()))) {
 							sessionId = cookie.toCookie();
 						}
@@ -1393,229 +1380,7 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
 		return response;
 	}
 
-	@Override
-	public void addOrUpdateGroup(String groupName, Map<String, String> groupAttrs) throws Throwable{
-		XGroupInfo group = groupName2XGroupInfoMap.get(groupName);
-
-		if (group == null) {    // Does not exists
-
-			//* Build the group info object and do the rest call
- 			if ( ! isMockRun ) {
-				group = addGroupInfo(groupName);
- 				if ( group != null) {
- 					addGroupToList(group);
- 				} else {
- 					String msg = "Failed to add addorUpdate group info";
- 					LOG.error(msg);
- 					throw new Exception(msg);
- 				}
- 			}
-		}
-	}
-
-	private XGroupInfo addGroupInfo(final String groupName){
-		XGroupInfo ret = null;
-		XGroupInfo group = null;
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addPMXAGroup(" + groupName + ")");
-		}
-		if (! isMockRun) {
-			group = addXGroupInfo(groupName);
-		}
-		if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
-			try {
-				LOG.info("Using principal = " + principal + " and keytab = " + keytab);
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final XGroupInfo groupInfo = group;
-				ret = Subject.doAs(sub, new PrivilegedAction<XGroupInfo>() {
-					@Override
-					public XGroupInfo run() {
-						try {
-							return getAddedGroupInfo(groupInfo);
-						} catch (Exception e) {
-							LOG.error("Failed to build Group List : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : ", e);
-			}
-			return null;
-		} else {
-			return getAddedGroupInfo(group);
-		}
-	}
-
-	private XGroupInfo getAddedGroupInfo(XGroupInfo group){
-		XGroupInfo ret = null;
-		String response = null;
-		ClientResponse clientResp = null;
-		Gson gson = new GsonBuilder().create();
-		String jsonString = gson.toJson(group);
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(group,PM_ADD_GROUP_URI);
-		}
-		else{
-			String relativeURL = PM_ADD_GROUP_URI;
-			try {
-				clientResp = uGSyncClient.post(relativeURL, null, group);
-				if (clientResp != null) {
-					response = clientResp.getEntity(String.class);
-				}
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("Group" + jsonString);
-				}
-
-			} catch (Throwable t) {
-				LOG.error("Failed to get response, Error is : ", t);
-			}
-		}
-
-		if ( LOG.isDebugEnabled() ) {
-			LOG.debug("RESPONSE: [" + response + "]");
-		}
-
-		ret = gson.fromJson(response, XGroupInfo.class);
-
-		return ret;
-	}
-
-
-	@Override
-	public void addOrUpdateUser(String user) throws Throwable {
-		// TODO Auto-generated method stub
-
-	}
-
-
-	@Override
-	public void addOrUpdateGroup(String groupName, List<String> users) throws Throwable {
-		if (users == null || users.isEmpty()) {
-			if (groupName2XGroupInfoMap.containsKey(groupName)) {
-				modifiedGroupList.add(groupName);
-			} else {
-				newGroupList.add(groupName);
-			}
-		}
-		addOrUpdateGroup(groupName, new HashMap<String, String>());
-
-	}
-
-	
-	@Override
-	public void postUserGroupAuditInfo(UgsyncAuditInfo ugsyncAuditInfo) throws Throwable {
-		if (! isMockRun) {
-			addUserGroupAuditInfo(ugsyncAuditInfo);
-		}
-		noOfNewUsers = 0;
-		noOfNewGroups = 0;
-		noOfModifiedUsers = 0;
-		noOfModifiedGroups = 0;
-		isStartupFlag = false;
-		newUserList.clear();
-		modifiedUserList.clear();
-		newGroupList.clear();
-		modifiedGroupList.clear();
-	}
-
-	private UgsyncAuditInfo addUserGroupAuditInfo(UgsyncAuditInfo auditInfo) {
-		UgsyncAuditInfo ret = null;
-
-		if (auditInfo == null) {
-			LOG.error("Failed to generate user group audit info");
-			return ret;
-		}
-		noOfNewUsers = newUserList.size();
-		noOfModifiedUsers = modifiedUserList.size();
-		noOfNewGroups = newGroupList.size();
-		noOfModifiedGroups = modifiedGroupList.size();
-
-		auditInfo.setNoOfNewUsers(Integer.toUnsignedLong(noOfNewUsers));
-		auditInfo.setNoOfNewGroups(Integer.toUnsignedLong(noOfNewGroups));
-		auditInfo.setNoOfModifiedUsers(Integer.toUnsignedLong(noOfModifiedUsers));
-		auditInfo.setNoOfModifiedGroups(Integer.toUnsignedLong(noOfModifiedGroups));
-		auditInfo.setSessionId("");
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("INFO: addAuditInfo(" + auditInfo.getNoOfNewUsers() + ", " + auditInfo.getNoOfNewGroups()
-					+ ", " + auditInfo.getNoOfModifiedUsers() + ", " + auditInfo.getNoOfModifiedGroups()
-					+ ", " + auditInfo.getSyncSource() + ")");
-		}
-
-		if (authenticationType != null
-				&& AUTH_KERBEROS.equalsIgnoreCase(authenticationType)
-				&& SecureClientLogin.isKerberosCredentialExists(principal,
-				keytab)) {
-			try {
-				Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
-				final UgsyncAuditInfo auditInfoFinal = auditInfo;
-				ret = Subject.doAs(sub, new PrivilegedAction<UgsyncAuditInfo>() {
-					@Override
-					public UgsyncAuditInfo run() {
-						try {
-							return getUserGroupAuditInfo(auditInfoFinal);
-						} catch (Exception e) {
-							LOG.error("Failed to add User : ", e);
-						}
-						return null;
-					}
-				});
-				return ret;
-			} catch (Exception e) {
-				LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
-			}
-			return ret;
-		} else {
-			return getUserGroupAuditInfo(auditInfo);
-		}
-	}
-
-
-	private UgsyncAuditInfo getUserGroupAuditInfo(UgsyncAuditInfo userInfo) {
-		if(LOG.isDebugEnabled()){
-			LOG.debug("==> PolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
-		}
-
-		String response = null;
-		ClientResponse clientRes = null;
-
-		Gson gson = new GsonBuilder().create();
-		if(isRangerCookieEnabled){
-			response = cookieBasedUploadEntity(userInfo, PM_AUDIT_INFO_URI);
-		}
-		else{
-			String relativeURL = PM_AUDIT_INFO_URI;
-			try {
-				clientRes = uGSyncClient.post(relativeURL, null, userInfo);
-				if (clientRes != null) {
-					response = clientRes.getEntity(String.class);
-				}
-			}
-			catch(Throwable t){
-				LOG.error("Failed to get Response : Error is ", t);
-			}
-		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("RESPONSE[" + response + "]");
-		}
-		UgsyncAuditInfo ret = gson.fromJson(response, UgsyncAuditInfo.class);
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("AuditInfo Creation successful ");
-		}
-
-		if(LOG.isDebugEnabled()){
-			LOG.debug("<== PolicyMgrUserGroupBuilder.getUserGroupAuditInfo()");
-		}
-
-		return ret;
-	}
-
-
     private void getRoleForUserGroups(String userGroupRolesData) {
-
         String roleDelimiter = config.getRoleDelimiter();
         String userGroupDelimiter = config.getUserGroupDelimiter();
         String userNameDelimiter = config.getUserGroupNameDelimiter();
@@ -1684,13 +1449,38 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
         }
     }
 
-	@Override
-	public void addOrUpdateUser(String user, Map<String, String> userAttrs, List<String> groups) throws Throwable {
+	protected String userNameTransform(String userName) {
+		if (userNameCaseConversionFlag) {
+			if (userNameLowerCaseFlag) {
+				userName = userName.toLowerCase();
+			}
+			else {
+				userName = userName.toUpperCase();
+			}
+		}
+
+		if (userNameRegExInst != null) {
+			userName = userNameRegExInst.transform(userName);
+		}
 
+		return userName;
 	}
 
-	@Override
-	public void addOrUpdateGroup(String group, Map<String, String> groupAttrs, List<String> users) throws Throwable {
+	protected String groupNameTransform(String groupName) {
+		if (groupNameCaseConversionFlag) {
+			if (groupNameLowerCaseFlag) {
+				groupName = groupName.toLowerCase();
+			}
+			else {
+				groupName = groupName.toUpperCase();
+			}
+		}
+
+		if (groupNameRegExInst != null) {
+			groupName = groupNameRegExInst.transform(groupName);
+		}
 
+		return groupName;
 	}
+
 }
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/UnixUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/UnixUserGroupBuilder.java
index e1540c6..597cbf8 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/UnixUserGroupBuilder.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/UnixUserGroupBuilder.java
@@ -26,13 +26,21 @@ import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Date;
+import java.util.Arrays;
+import java.util.Iterator;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
 import org.apache.log4j.Logger;
+import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo;
+import org.apache.ranger.ugsyncutil.model.UnixSyncSourceInfo;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
-import org.apache.ranger.unixusersync.model.UnixSyncSourceInfo;
 import org.apache.ranger.usergroupsync.UserGroupSink;
 import org.apache.ranger.usergroupsync.UserGroupSource;
 
@@ -73,9 +81,11 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 	private long timeout = 0;
 
 	private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance();
-	private Map<String,List<String>> user2GroupListMap;
-	private Map<String,List<String>> internalUser2GroupListMap;
 	private Map<String,String> groupId2groupNameMap;
+	private Map<String, Map<String, String>> sourceUsers; // Stores username and attr name & value pairs
+	private Map<String, Map<String, String>> sourceGroups; // Stores groupname and attr name & value pairs
+	private Map<String, Set<String>> sourceGroupUsers;
+	private Table<String, String, String> groupUserTable; // groupname, username, group id
 	private int minimumUserId  = 0;
 	private int minimumGroupId = 0;
 	private String unixPasswordFile;
@@ -168,23 +178,20 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 		isUpdateSinkSucc = true;
 		if (isChanged() || isStartupFlag) {
 			buildUserGroupInfo();
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Users = " + sourceUsers.keySet());
+				LOG.debug("Groups = " + sourceGroups.keySet());
+				LOG.debug("GroupUsers = " + sourceGroupUsers.keySet());
+			}
 
-			for (Map.Entry<String, List<String>> entry : user2GroupListMap.entrySet()) {
-				String user = entry.getKey();
-				List<String> groups = entry.getValue();
-				try {
-					sink.addOrUpdateUser(user, groups);
-				} catch (Throwable t) {
-					LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
-							+ ", for user: " + user
-							+ ", groups: " + groups);
-					isUpdateSinkSucc = false;
-				}
+			try {
+				sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers);
+			} catch (Throwable t) {
+				LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t);
+				isUpdateSinkSucc = false;
 			}
 		}
 		try {
-			unixSyncSourceInfo.setTotalUsersSynced(user2GroupListMap.size());
-			unixSyncSourceInfo.setTotalGroupsSynced(allGroups.size());
 			sink.postUserGroupAuditInfo(ugsyncAuditInfo);
 		} catch (Throwable t) {
 			LOG.error("sink.postUserGroupAuditInfo failed with exception: ", t);
@@ -194,9 +201,11 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 	
 	
 	private void buildUserGroupInfo() throws Throwable {
-		user2GroupListMap = new HashMap<String,List<String>>();
 		groupId2groupNameMap = new HashMap<String, String>();
-		internalUser2GroupListMap = new HashMap<String,List<String>>();
+		sourceUsers = new HashMap<>();
+		sourceGroups = new HashMap<>();
+		sourceGroupUsers = new HashMap<>();
+		groupUserTable = HashBasedTable.create();
 		allGroups = new HashSet<>();
 
 		if (OS.startsWith("Mac")) {
@@ -210,6 +219,20 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 			buildUnixUserList(LINUX_GET_ALL_USERS_CMD);
 		}
 
+		Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator();
+		while (groupUserTableIterator.hasNext()) {
+			String groupName = groupUserTableIterator.next();
+			Map<String,String> groupUsersMap =  groupUserTable.row(groupName);
+			Set<String> userSet = new HashSet<String>();
+			for(String userName : groupUsersMap.keySet()){
+				//String transformUserName = userNameTransform(entry.getKey());
+				if (sourceUsers.containsKey(userName)) {
+					userSet.add(userName);
+				}
+			}
+			sourceGroupUsers.put(groupName, userSet);
+		}
+
 		lastUpdateTime = System.currentTimeMillis();
 
 		if (LOG.isDebugEnabled()) {
@@ -218,11 +241,11 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 	}
 	
 	private void print() {
-		for(String user : user2GroupListMap.keySet()) {
+		for(String user : sourceUsers.keySet()) {
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("USER:" + user);
 			}
-			List<String> groups = user2GroupListMap.get(user);
+			Set<String> groups = groupUserTable.column(user).keySet();
 			if (groups != null) {
 				for(String group : groups) {
 					if (LOG.isDebugEnabled()) {
@@ -292,18 +315,11 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 					userName2uid.put(userName, userId);
 					String groupName = groupId2groupNameMap.get(groupId);
 					if (groupName != null) {
-						List<String> groupList = new ArrayList<String>();
-						groupList.add(groupName);
-						// do we already know about this use's membership to other groups?  If so add those, too
-						if (internalUser2GroupListMap.containsKey(userName)) {
-							List<String> map = internalUser2GroupListMap.get(userName);
-
-							// there could be duplicates
-							map.remove(groupName);
-							groupList.addAll(map);
-						}
-						user2GroupListMap.put(userName, groupList);
-						allGroups.addAll(groupList);
+						Map<String, String> userAttrMap = new HashMap<>();
+						userAttrMap.put("original_name", userName);
+						userAttrMap.put("full_name", userName);
+						sourceUsers.put(userName, userAttrMap);
+						groupUserTable.put(groupName, userName, groupId);
 					} else {
 						// we are ignoring the possibility that this user was present in /etc/groups.
 						LOG.warn("Group Name could not be found for group id: [" + groupId + "]. Skipping adding user [" + userName + "] with id [" + userId + "].");
@@ -329,18 +345,18 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("Start drill down group members");
 			}
-			for (Map.Entry<String, List<String>> entry : internalUser2GroupListMap.entrySet()) {
+			for (String userName : groupUserTable.columnKeySet()) {
 				// skip users we already now about
-				if (user2GroupListMap.containsKey(entry.getKey()))
+				if (sourceUsers.containsKey(userName))
 					continue;
 
 				if (LOG.isDebugEnabled()) {
-					LOG.debug("Enumerating user " + entry.getKey());
+					LOG.debug("Enumerating user " + userName);
 				}
 
 				int numUserId = -1;
 				try {
-					numUserId = Integer.parseInt(userName2uid.get(entry.getKey()));
+					numUserId = Integer.parseInt(userName2uid.get(userName));
 				} catch (NumberFormatException nfe) {
 					numUserId = -1;
 				}
@@ -353,7 +369,7 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 				// "id" is same across Linux / BSD / MacOSX
 				// gids are used as id might return groups with spaces, ie "domain users"
 				Process process = Runtime.getRuntime().exec(
-						new String[]{"bash", "-c", "id -G " + entry.getKey()});
+						new String[]{"bash", "-c", "id -G " + userName});
 
 				try {
 					reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
@@ -367,26 +383,29 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 				}
 
 				if (line == null || line.trim().isEmpty()) {
-					LOG.warn("User " + entry.getKey() + " could not be resolved");
+					LOG.warn("User " + userName + " could not be resolved");
 					continue;
 				}
 
 				String[] gids = line.split(" ");
 
 				// check if all groups returned by id are visible to ranger
-				ArrayList<String> allowedGroups = new ArrayList<String>();
+				//ArrayList<String> allowedGroups = new ArrayList<String>();
 				for (String gid : gids) {
 					int numGroupId = Integer.parseInt(gid);
 					if (numGroupId < minimumGroupId)
 						continue;
 
 					String groupName = groupId2groupNameMap.get(gid);
-					if (groupName != null)
-						allowedGroups.add(groupName);
+					if (groupName != null) {
+						groupUserTable.put(groupName, userName, gid);
+						//allowedGroups.add(groupName);
+					}
 				}
-
-				user2GroupListMap.put(entry.getKey(), allowedGroups);
-				allGroups.addAll(allowedGroups);
+				Map<String, String> userAttrMap = new HashMap<>();
+				userAttrMap.put("original_name", userName);
+				userAttrMap.put("full_name", userName);
+				sourceUsers.put(userName, userAttrMap);
 			}
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("End drill down group members");
@@ -419,17 +438,14 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 			return;
 
 		groupId2groupNameMap.put(groupId, groupName);
+		Map<String, String> groupAttrMap = new HashMap<>();
+		groupAttrMap.put("original_name", groupName);
+		groupAttrMap.put("full_name", groupName);
+		sourceGroups.put(groupName, groupAttrMap);
 
 		if (groupMembers != null && !groupMembers.trim().isEmpty()) {
 			for (String user : groupMembers.split(",")) {
-				List<String> groupList = internalUser2GroupListMap.get(user);
-				if (groupList == null) {
-					groupList = new ArrayList<String>();
-					internalUser2GroupListMap.put(user, groupList);
-				}
-				if (!groupList.contains(groupName)) {
-					groupList.add(groupName);
-				}
+				groupUserTable.put(groupName, user, groupId);
 			}
 		}
 	}
@@ -552,8 +568,8 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 	}
 
 	@VisibleForTesting
-	Map<String,List<String>> getUser2GroupListMap() {
-		return user2GroupListMap;
+	Map<String, Set<String>> getGroupUserListMap() {
+		return sourceGroupUsers;
 	}
 
 	@VisibleForTesting
@@ -561,4 +577,9 @@ public class UnixUserGroupBuilder implements UserGroupSource {
 		return groupId2groupNameMap;
 	}
 
+	@VisibleForTesting
+	Set<String> getUsers() {
+		return sourceUsers.keySet();
+	}
+
 }
diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractUserGroupSource.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractUserGroupSource.java
index 4a54e57..924d41a 100644
--- a/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractUserGroupSource.java
+++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractUserGroupSource.java
@@ -21,7 +21,7 @@ package org.apache.ranger.usergroupsync;
 import org.apache.log4j.Logger;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
 
-public abstract class AbstractUserGroupSource implements UserGroupSource {
+public abstract class AbstractUserGroupSource {
 
     private static final Logger LOG = Logger.getLogger(AbstractUserGroupSource.class);
 
diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
index 368c4f8..794bc81 100644
--- a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
+++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
@@ -19,25 +19,18 @@
 
  package org.apache.ranger.usergroupsync;
 
-import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
+import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo;
 
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public interface UserGroupSink {
 	void init() throws Throwable;
 
-	void addOrUpdateUser(String user, List<String> groups) throws Throwable;
-	
-	void addOrUpdateUser(String user) throws Throwable;
-	
-	void addOrUpdateGroup(String group, Map<String, String> groupAttrs) throws Throwable;
-	
-	void addOrUpdateGroup(String group, List<String> users) throws Throwable;
-
 	void postUserGroupAuditInfo(UgsyncAuditInfo ugsyncAuditInfo) throws Throwable;
 
-	void addOrUpdateUser(String user, Map<String, String> userAttrs, List<String> groups) throws Throwable;
+	void addOrUpdateUsersGroups(Map<String, Map<String, String>> sourceGroups,
+								Map<String, Map<String, String>> sourceUsers,
+								Map<String, Set<String>> sourceGroupUsers) throws Throwable;
 
-	void addOrUpdateGroup(String group, Map<String, String> groupAttrs, List<String> users) throws Throwable;
 }
diff --git a/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestFileSourceUserGroupBuilder.java b/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestFileSourceUserGroupBuilder.java
index b29a1b0..42884af 100644
--- a/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestFileSourceUserGroupBuilder.java
+++ b/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestFileSourceUserGroupBuilder.java
@@ -18,7 +18,8 @@
  */
 package org.apache.ranger.unixusersync.process;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
 import org.apache.ranger.usergroupsync.PolicyMgrUserGroupBuilderTest;
diff --git a/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestUnixUserGroupBuilder.java b/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestUnixUserGroupBuilder.java
index 56c3f6a..21184d0 100644
--- a/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestUnixUserGroupBuilder.java
+++ b/ugsync/src/test/java/org/apache/ranger/unixusersync/process/TestUnixUserGroupBuilder.java
@@ -20,15 +20,21 @@
 package org.apache.ranger.unixusersync.process;
 
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
-import org.hamcrest.Matcher;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.List;
 import java.util.Map;
-
-import static org.junit.Assert.*;
-import static org.hamcrest.Matchers.*;
+import java.util.Set;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasValue;
 
 public class TestUnixUserGroupBuilder {
     private UserGroupSyncConfig config;
@@ -54,10 +60,10 @@ public class TestUnixUserGroupBuilder {
         String name = groups.get("0");
         assertThat(name, anyOf(equalTo("wheel"), equalTo("root")));
 
-        Map<String, List<String>> users = builder.getUser2GroupListMap();
-        List<String> usergroups = users.get("root");
-        assertNotNull(usergroups);
-        assertThat(usergroups, (Matcher)anyOf(hasItem("wheel"), hasItem("root")));
+        Map<String, Set<String>> groupUsers = builder.getGroupUserListMap();
+        Set<String> users = groupUsers.get("wheel");
+        assertNotNull(users);
+        assertThat(users, anyOf(hasItem("wheel"), hasItem("root")));
 
     }
 
@@ -72,10 +78,10 @@ public class TestUnixUserGroupBuilder {
         String name = groups.get("0");
         assertThat(name, anyOf(equalTo("wheel"), equalTo("root")));
 
-        Map<String, List<String>> users = builder.getUser2GroupListMap();
-        List<String> usergroups = users.get("root");
-        assertNotNull(usergroups);
-        assertThat(usergroups, (Matcher)anyOf(hasItem("wheel"), hasItem("root")));
+        Map<String, Set<String>> groupUsers = builder.getGroupUserListMap();
+        Set<String> users = groupUsers.get("wheel");
+        assertNotNull(users);
+        assertThat(users, anyOf(hasItem("wheel"), hasItem("root")));
     }
 
     @Test
@@ -105,8 +111,8 @@ public class TestUnixUserGroupBuilder {
         Map<String, String> groups = builder.getGroupId2groupNameMap();
         assertFalse(groups.containsValue("wheel"));
 
-        Map<String, List<String>> users = builder.getUser2GroupListMap();
-        assertNull(users.get("root"));
+        Map<String, Set<String>> groupUsers = builder.getGroupUserListMap();
+        assertNull(groupUsers.get("wheel"));
     }
     
     @Test
@@ -122,10 +128,10 @@ public class TestUnixUserGroupBuilder {
         String name = groups.get("1028");
         assertThat(name, anyOf(equalTo("wheel"), equalTo("sam")));
 
-        Map<String, List<String>> users = builder.getUser2GroupListMap();
-        List<String> usergroups = users.get("sam");
-        assertNotNull(usergroups);
-        assertThat(usergroups, (Matcher) anyOf(hasItem("wheel"), hasItem("sam")));
+        Map<String, Set<String>> groupUsers = builder.getGroupUserListMap();
+        Set<String> users = groupUsers.get("sam");
+        assertNotNull(groupUsers);
+        assertThat(users, anyOf(hasItem("wheel"), hasItem("sam")));
 
     }
 
diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
deleted file mode 100644
index e10f632..0000000
--- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.ranger.usergroupsync;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.ranger.ldapusersync.process.LdapPolicyMgrUserGroupBuilder;
-
-public class LdapPolicyMgrUserGroupBuilderTest extends LdapPolicyMgrUserGroupBuilder {
-        private Set<String> allGroups;
-        private Set<String> allUsers;
-
-        @Override
-        public void init() throws Throwable {
-                allGroups = new HashSet<>();
-                allUsers = new HashSet<>();
-        }
-
-        @Override
-        public void addOrUpdateUser(String user, Map<String, String> userAttrs, List<String> groups) {
-                allUsers.add(user);
-                //System.out.println("Username: " + user + " and associated groups: " + groups);
-        }
-
-        @Override
-        public void addOrUpdateGroup(String group, Map<String, String> groupAttrs) {
-                allGroups.add(group);
-                //System.out.println("Groupname: " + group);
-        }
-        
-        @Override
-        public void addOrUpdateUser(String user) {
-                allUsers.add(user);
-                //System.out.println("Username: " + user);
-        }
-
-        @Override
-        public void addOrUpdateGroup(String group, Map<String, String> groupAttrs, List<String> users) {
-        	boolean addGroup = false;
-        		for (String user : users) {
-        			if (allUsers.contains(user)) {
-        				addGroup = true;
-        				break;
-        			}
-        		}
-        		if (addGroup) {
-        			allGroups.add(group);
-        		}
-                //allUsers.addAll(users);
-                //System.out.println("Groupname: " + group + " and associated users: " + users);
-        }
-
-        public int getTotalUsers() {
-                return allUsers.size();
-        }
-
-        public int getTotalGroups() {
-                //System.out.println("Groups = " + allGroups);
-                return allGroups.size();
-        }
-
-        public Set<String> getAllGroups() {
-                return allGroups;
-        }
-
-        public Set<String> getAllUsers() {
-                return allUsers;
-        }
-}
\ No newline at end of file
diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
index b0ce872..5d2e62c 100644
--- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
+++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
@@ -19,35 +19,27 @@
 
 package org.apache.ranger.usergroupsync;
 
-import java.util.*;
-
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder;
 
 public class PolicyMgrUserGroupBuilderTest extends PolicyMgrUserGroupBuilder {
         private Set<String> allGroups;
         private Set<String> allUsers;
+        private Map<String, Set<String>> groupUsers;
+
+        public PolicyMgrUserGroupBuilderTest() {
+                super();
+        }
 
         @Override
         public void init() throws Throwable {
                 allGroups = new HashSet<>();
                 allUsers = new HashSet<>();
-        }
-
-        @Override
-        public void addOrUpdateUser(String user, List<String> groups) {
-                allGroups.addAll(groups);
-                allUsers.add(user);
-                //System.out.println("Username: " + user + " and associated groups: " + groups);
-        }
-
-        @Override
-        public void addOrUpdateGroup(String group, Map<String, String> groupAttrs ) {
-                allGroups.add(group);
-        }
-
-        @Override
-        public void addOrUpdateGroup(String group, List<String> users) {
-                addOrUpdateGroup(group, new HashMap<String, String>());
+                groupUsers = new HashMap<>();
         }
 
         public int getTotalUsers() {
@@ -66,4 +58,33 @@ public class PolicyMgrUserGroupBuilderTest extends PolicyMgrUserGroupBuilder {
         public Set<String> getAllUsers() {
                 return allUsers;
         }
+
+        public int getGroupsWithNoUsers() {
+                int groupsWithNoUsers = 0;
+                for (String group : groupUsers.keySet()) {
+                        if (CollectionUtils.isEmpty(groupUsers.get(group))) {
+                                groupsWithNoUsers++;
+                        }
+                }
+                return groupsWithNoUsers;
+        }
+
+        @Override
+        public void addOrUpdateUsersGroups(Map<String, Map<String, String>> sourceGroups,
+                                           Map<String, Map<String, String>> sourceUsers,
+                                           Map<String, Set<String>> sourceGroupUsers) throws Throwable {
+
+                for (String userdn : sourceUsers.keySet()) {
+                        //System.out.println("Username: " + sourceUsers.get(userdn).get("original_name"));
+                        allUsers.add(userNameTransform(sourceUsers.get(userdn).get("original_name")));
+                }
+                for (String groupdn : sourceGroups.keySet()) {
+                        //System.out.println("Groupname: " + sourceGroups.get(groupdn).get("original_name"));
+                        allGroups.add(groupNameTransform(sourceGroups.get(groupdn).get("original_name")));
+                }
+                groupUsers = sourceGroupUsers;
+                //System.out.println("Username: " + user + " and associated groups: " + groups);
+        }
+
+
 }
\ No newline at end of file
diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
index 6393b3d..e064d2b 100644
--- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
+++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
@@ -74,6 +74,7 @@ partitions =
 public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	private UserGroupSyncConfig config;
 	private UserGroupSource ldapBuilder;
+	private PolicyMgrUserGroupBuilderTest sink;
 
 	@Before
 	public void setup() throws Exception {
@@ -90,8 +91,9 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		getLdapServer().start();
 		config = UserGroupSyncConfig.getInstance();	
 		ldapBuilder = new LdapUserGroupBuilder();
+		sink = new PolicyMgrUserGroupBuilderTest();
 	}
-	
+
 	@Test
 	public void testUpdateSinkTotalUsers() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
@@ -106,7 +108,7 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchFirstEnabled(false);
 		//config.setGroupHierarchyLevel(0);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
+
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(109, sink.getTotalUsers());
@@ -126,7 +128,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchFirstEnabled(false);
 		//config.setGroupHierarchyLevel(0);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(109, sink.getTotalUsers());
@@ -145,7 +146,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(false);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(12, sink.getTotalUsers());
@@ -164,10 +164,9 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
-		assertEquals(10, sink.getTotalGroups());
+		assertEquals(12, sink.getTotalGroups());
 	}
 
 	@Test
@@ -183,32 +182,12 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(1, sink.getTotalGroups());
 	}
 
 	@Test
-	public void testUpdateSinkGroupSearchDisable() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("");
-		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=Group19");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(false);
-		config.setGroupSearchFirstEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(11, sink.getTotalGroups());
-	}
-
-	@Test
 	public void testUpdateSinkMultipleOUs() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
@@ -221,7 +200,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(111, sink.getTotalUsers());
@@ -229,46 +207,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	}
 
 	@Test
-	public void testUpdateSinkMultipleOUsNoGroupSearch() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(false);
-		config.setGroupSearchFirstEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(111, sink.getTotalUsers());
-		assertEquals(12, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testMultipleOUGroupsNoGroupSearch() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(false);
-		config.setGroupSearchFirstEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(111, sink.getTotalUsers());
-		assertEquals(12, sink.getTotalGroups());
-	}
-
-	@Test
 	public void testMultipleOUGroupsWithGroupSearch() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
@@ -281,11 +219,10 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(111, sink.getTotalUsers());
-		assertEquals(11, sink.getTotalGroups());
+		assertEquals(13, sink.getTotalGroups());
 	}
 
 	@Test
@@ -301,7 +238,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(111, sink.getTotalUsers());
@@ -309,109 +245,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	}
 
 	@Test
-	public void testGroupBasedAllUsers() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(3, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testGroupBasedWithUserFilter() throws Throwable {
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=User*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(1, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testGroupBasedWithNoUsers() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=Group2*");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(0, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testGroupBasedWithAllUsersAndGroups() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(100, sink.getTotalUsers());
-		assertEquals(13, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testGroupBasedWithSingleOU() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(99, sink.getTotalUsers());
-		assertEquals(12, sink.getTotalGroups());
-	}
-
-	@Test
 	public void testUpdateSinkWithEmptyUserSearchBase() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("");
@@ -424,55 +257,12 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setPagedResultsEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(111, sink.getTotalUsers());
 	}
 
 	@Test
-	public void testGBWithUserSearchDisabled() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=User*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(3, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testGBWithNoUsersAndUserSearchDisabled() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=Group2*");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(0, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-
-	@Test
 	public void testUpdateSinkShortUserName() throws Throwable {
 		config.setUserNameAttribute("cn");
 		config.setUserSearchBase("ou=people,DC=ranger,DC=qe,DC=hortonworks,DC=com");
@@ -486,28 +276,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupObjectClass("posixGroup");
 		config.setUserSearchEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(1, sink.getTotalUsers());
-		assertEquals(3, sink.getTotalGroups());
-	}
-
-	@Test
-	public void testShortUserNameWithGroupBased() throws Throwable {
-		config.setUserNameAttribute("cn");
-		config.setUserSearchBase("ou=people,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("uid=*");
-		config.setUserObjectClass("posixAccount");
-		config.setGroupSearchBase("OU=pGroups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserGroupMemberAttributeName("memberuid");
-		config.setGroupObjectClass("posixGroup");
-		config.setUserSearchEnabled(true);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(1, sink.getTotalUsers());
@@ -529,12 +297,13 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 
 		config.setProperty(UserGroupSyncConfig.SYNC_MAPPING_USERNAME, "s/[=]/_/g");
 		config.setProperty(UserGroupSyncConfig.SYNC_MAPPING_GROUPNAME, "s/[=]/_/g");
+		sink = new PolicyMgrUserGroupBuilderTest();
 
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
-		assertEquals(10, sink.getTotalGroups());
+		assertEquals(109, sink.getTotalUsers());
+		assertEquals(12, sink.getTotalGroups());
 
 		// no user should have an = character because of the mapping
 		for (String user : sink.getAllUsers()) {
@@ -548,27 +317,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	}
 	
 	@Test
-	public void testGBWithInvalidOU() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=User*");
-		config.setGroupSearchBase("OU=HdpGroup1,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(false);
-		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(2, sink.getTotalUsers());
-		assertEquals(1, sink.getTotalGroups());
-	}
-	
-	@Test
 	public void testMultipleOUInvalidOU() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers1,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
@@ -581,82 +329,14 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
 		ldapBuilder.init();
-		PolicyMgrUserGroupBuilderTest sink = new PolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
 		assertEquals(110, sink.getTotalUsers());
-		assertEquals(0, sink.getTotalGroups());
-	}
-	
-	@Test
-	public void testDeltaUpdateSinkTotalGroups() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("");
-		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(false);
-		config.setDeltaSync(true);
-		//UserGroupSource ldapDeltaBuilder = config.getUserGroupSource();
-		ldapBuilder = config.getUserGroupSource();
-		ldapBuilder.init();
-		LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(10, sink.getTotalGroups());
-	}
-	
-	@Test
-	public void testDeltaUpdateSinkMultipleOUGroups() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setUserSearchFilter("cn=*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(false);
-		config.setDeltaSync(true);
-		ldapBuilder = config.getUserGroupSource();
-		ldapBuilder.init();
-		LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(111, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-	
-	@Test
-	public void testDeltaGroupBasedWithUserFilter() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=User*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(true);
-		config.setDeltaSync(true);
-		ldapBuilder = config.getUserGroupSource();
-		ldapBuilder.init();
-		LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(1, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
+		assertEquals(1, sink.getTotalGroups());
 	}
 
 	@Test
-	public void testDeltaGroupBasedWithNoUsers() throws Throwable {
+	public void testGroupsWithNoUsers() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
 		config.setUserSearchFilter("cn=*");
@@ -671,34 +351,9 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setDeltaSync(true);
 		ldapBuilder = config.getUserGroupSource();
 		ldapBuilder.init();
-		LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
 		sink.init();
 		ldapBuilder.updateSink(sink);
-		assertEquals(0, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
-	}
-	
-	@Test
-	public void testDeltaGBWithUserSearchDisabled() throws Throwable {
-		config.setUserNameAttribute("sAMAccountName");
-		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
-		config.setUserSearchFilter("cn=User*");
-		config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		config.setGroupSearchFilter("cn=*Group10");
-		config.setUserGroupMemberAttributeName("member");
-		config.setUserObjectClass("organizationalPerson");
-		config.setGroupObjectClass("groupOfNames");
-		config.setGroupSearchEnabled(true);
-		config.setGroupSearchFirstEnabled(true);
-		config.setUserSearchEnabled(false);
-		config.setDeltaSync(true);
-		ldapBuilder = config.getUserGroupSource();
-		ldapBuilder.init();
-		LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
-		sink.init();
-		ldapBuilder.updateSink(sink);
-		assertEquals(3, sink.getTotalUsers());
-		assertEquals(2, sink.getTotalGroups());
+		assertEquals(2, sink.getGroupsWithNoUsers());
 	}
 
 	@After