/* ================================================================== * Created [2009-4-27 下午11:32:55] by Jon.King * ================================================================== * TSS * ================================================================== * mailTo:jinpujun@hotmail.com * Copyright (c) Jon.King, 2009-2012 * ================================================================== */ package com.jinhe.tss.um.syncdata; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.Element; import org.springframework.beans.factory.annotation.Autowired; import com.jinhe.tss.core.common.progress.Progress; import com.jinhe.tss.core.common.progress.Progressable; import com.jinhe.tss.core.exception.BusinessException; import com.jinhe.tss.core.persistence.ICommonDao; import com.jinhe.tss.core.util.XMLDocUtil; import com.jinhe.tss.um.UMConstants; import com.jinhe.tss.um.dao.IApplicationDao; import com.jinhe.tss.um.dao.IGroupDao; import com.jinhe.tss.um.entity.Application; import com.jinhe.tss.um.entity.Group; import com.jinhe.tss.um.entity.GroupUser; import com.jinhe.tss.um.entity.User; import com.jinhe.tss.um.helper.dto.GroupDTO; import com.jinhe.tss.um.helper.dto.UserDTO; import com.jinhe.tss.um.permission.ResourcePermission; public class SyncService implements ISyncService, Progressable { @Autowired private ICommonDao commonDao; @Autowired private IGroupDao groupDao; @Autowired private IApplicationDao applicationDao; @Autowired private ResourcePermission resourcePermission; public Map<String, Object> getCompleteSyncGroupData(Long groupId, String dbGroupId, String applicationId) { return getDataFromOtherApp(groupId, dbGroupId, applicationId); } public Map<String, Object> getUniDirectionalSyncGroupData(Long groupId, String dbGroupId, String applicationId) { // 保存UMS组对其它应用组 的 对应的关系 key:dbGroupId -- group Map<String, Group> groupsMap = new HashMap<String, Group>(); List<?> exsitGroups = getMappedGroups(applicationId, groupId); // "同步节点"下面的所有用户组 for(Iterator<?> it = exsitGroups.iterator();it.hasNext();){ Group group = (Group)it.next(); groupsMap.put(group.getDbGroupId(), group); } // 保存UMS用户对其它应用用户 的 ID对应的关系 key:otherAppUserId -- value:user Map<String, User> usersMap = new HashMap<String, User>(); List<?> exsitMappedUsers = getMappedUsers(applicationId, groupId); // ”同步节点“下面的所有用户 for (Iterator<?> it = exsitMappedUsers.iterator(); it.hasNext();) { User user = (User) it.next(); usersMap.put(user.getOtherAppUserId(), user); } // 保存内部组用户对应的关系 key:groupId_userId -- value:groupUser Map<String, GroupUser> groupUsersMap = new HashMap<String, GroupUser>(); List<?> mappedGroupUsers = getMappedGroupUsers(applicationId, groupId); // ”同步节点“下面的所有用户对应组的所有关系 for (Iterator<?> it = mappedGroupUsers.iterator(); it.hasNext();) { GroupUser groupUser = (GroupUser) it.next(); groupUsersMap.put(groupUser.getGroupId() + "_" + groupUser.getUserId(), groupUser); } Map<String, Object> paramsMap = getDataFromOtherApp(groupId, dbGroupId, applicationId); paramsMap.put("groupsMap", groupsMap); paramsMap.put("usersMap", usersMap); paramsMap.put("groupUsersMap", groupUsersMap); return paramsMap; } private Map<String, Object> getDataFromOtherApp(Long groupId, String dbGroupId, String applicationId){ Application application = applicationDao.getApplication(applicationId); if(application == null) { throw new BusinessException("未找到其它应用系统(" + applicationId + ")配置信息"); } // 保存UMS组对其它应用组 的 ID对应的关系 key:dbGroupId -- value:groupId Map<String, Long> groupIdsMap = new HashMap<String, Long>(); List<?> allGroups = getMappedGroups(applicationId); // 取出同步节点所在应用的所有,设置父子节点关系时用到(其实只需”同步节点“的父节点 + 同步枝) for(Iterator<?> it = allGroups.iterator();it.hasNext();){ Group group = (Group)it.next(); groupIdsMap.put(group.getDbGroupId(), group.getId()); } Map<String, String> appParams = initParam(application.getParamDesc()); List<?> groups = getGroups(application.getDataSourceType(), appParams, dbGroupId); //从其它系统获取需要同步的所有用户组 List<?> users = getUsers (application.getDataSourceType(), appParams, dbGroupId); //从其它系统获取需要同步的所有用户 // 检查是否存在同名用户。 checkMultiLoginName(applicationId, users); Map<String, Object> paramsMap = new HashMap<String, Object>(); paramsMap.put("applicationId", applicationId); paramsMap.put("groupId", groupId); paramsMap.put("groups", groups); paramsMap.put("users", users); paramsMap.put("groupIdsMap", groupIdsMap); return paramsMap; } /** * 检查是否存在登录名重名,如果有,抛出异常提示重名的用户信息。 * TODO 目前实现有问题,单向同步的时候不行。 * 除了判断是否和已有用户重名,还应判断是否是同个组下的。同个组下的重名用户会自动覆盖,无需报错。 * 如需要检查一个组里是否有重名,则检查users列表是否有重名的。 */ private void checkMultiLoginName(String applicationId, List<?> users){ // List exsitingUsers = commonDao.getEntities("select o.loginName from User o where o.applicationId = ? ", new Object[]{applicationId}); // if(exsitingUsers == null || exsitingUsers.isEmpty()){ // return; // } // // for(Iterator it = users.iterator(); it.hasNext(); ){ // UserDTO dto = (UserDTO) it.next(); // String loginName = dto.getLoginName(); // if(exsitingUsers.contains(loginName)){ // throw new BusinessException("登陆名为:" + loginName + " 的用户在其他用户组(" + applicationId + ")下已经存在!"); // } // } } @SuppressWarnings("unchecked") public void execute(Map<String, Object> paramsMap, Progress progress) { String applicationId = (String)paramsMap.get("applicationId"); Long groupId = (Long)paramsMap.get("groupId"); List<?> groups = (List<?>)paramsMap.get("groups"); List<?> users = (List<?>)paramsMap.get("users"); Map<String, Long> groupIdsMap = (Map)paramsMap.get("groupIdsMap"); if(UMConstants.ALL_SYNC.equals(paramsMap.get("mode"))){ deleteDataInSyncGroup(applicationId, groupId); // 删除um系统中同步组下的用户组、用户、以及GroupUser(包括已对应和未对应的) syncGroups(applicationId, groups, groupIdsMap, progress); syncUsers (applicationId, users, groupIdsMap, progress); }else { Map<String, Group> groupsMap = (Map)paramsMap.get("groupsMap"); Map<String, User> usersMap = (Map)paramsMap.get("usersMap"); Map<String, GroupUser> groupUsersMap = (Map)paramsMap.get("groupUsersMap"); syncGroups(applicationId, groupId, groups, groupIdsMap, groupsMap, progress); syncUsers (applicationId, users, groupIdsMap, usersMap, groupUsersMap, progress); } } private void syncGroups(String applicationId, List<?> otherGroups, Map<String, Long> groupIdsMap, Progress progress) { for (int i = 0; i < otherGroups.size(); i++) { GroupDTO groupDto = (GroupDTO) otherGroups.get(i); Group group = new Group(); group.setApplicationId(applicationId); SyncDataHelper.setGroupByDTO(group, groupDto); group.setDbGroupId(groupDto.getId()); Long parentId = (Long)groupIdsMap.get(groupDto.getParentId()); //获取其它应用组的父组对应UMS中组的ID parentId = (parentId == null) ? UMConstants.OTHER_APPLICATION_GROUP_ID : parentId; group.setParentId(parentId); group.setSeqNo(groupDao.getNextSeqNo(parentId)); commonDao.create(group); resourcePermission.addResource(group.getId(), group.getResourceType()); groupIdsMap.put(groupDto.getId(), group.getId()); // 保存对应结果 updateProgressInfo(progress, otherGroups.size(), i); } } private void syncUsers(String applicationId, List<?> otherUsers, Map<String, Long> groupIdsMap, Progress progress) { List<String> temp = new ArrayList<String>(); for (int i = 0; i < otherUsers.size(); i++) { UserDTO userDto = (UserDTO) otherUsers.get(i); Long umsGroupId = (Long) groupIdsMap.get(userDto.getGroupId()); //如果用户登陆名相同,只保存第一个 if(temp.contains(userDto.getLoginName())) continue; //如果用户所属的组不存在,则不导入该用户 if(umsGroupId == null) continue; User user = new User(); user.setApplicationId(applicationId); SyncDataHelper.setUserByDTO(user, userDto); user.setGroupId(umsGroupId); commonDao.create(user); commonDao.create(new GroupUser(user.getId(), umsGroupId, userDto.getSeqNo())); temp.add(user.getLoginName()); updateProgressInfo(progress, otherUsers.size(), i); } } private void syncGroups(String applicationId, Long groupId, List<?> otherGroups, Map<String, Long> groupIdsMap, Map<String, Group> groupsMap, Progress progress) { for (int i = 0; i < otherGroups.size(); i++) { GroupDTO groupDto = (GroupDTO) otherGroups.get(i); String appGroupId = groupDto.getId(); //Group在其它应用中的ID String appParentId = groupDto.getParentId(); Long umsParentId = (Long) groupIdsMap.get(appParentId); if (groupsMap.containsKey(appGroupId)) {// 如果组已经存在,则更新组 Group group = (Group) groupsMap.remove(appGroupId); // 从groupsMap中删除 groupDto.setSeqNo(group.getSeqNo()); SyncDataHelper.setGroupByDTO(group, groupDto); //Group在其它应用里父节点有可能变了,parentId以及seqNo需要重新设置 if (!groupId.equals(group.getId()) && !group.getParentId().equals(umsParentId)){ // 第一个节点parentId保持不变 group.setParentId(umsParentId); group.setSeqNo(groupDao.getNextSeqNo(group.getParentId())); } commonDao.create(group); } else { Group group = new Group(); group.setApplicationId(applicationId); SyncDataHelper.setGroupByDTO(group, groupDto); group.setDbGroupId(appGroupId); umsParentId = umsParentId != null ? umsParentId : UMConstants.OTHER_APPLICATION_GROUP_ID; group.setParentId(umsParentId); group.setSeqNo(groupDao.getNextSeqNo(group.getParentId())); commonDao.create(group); resourcePermission.addResource(group.getId(), group.getResourceType()); groupIdsMap.put(appGroupId, group.getId()); // 保存对应结果 } updateProgressInfo(progress, otherGroups.size(), i); } } private void syncUsers(String applicationId, List<?> otherUsers, Map<String, Long> groupIdsMap, Map<String, User> usersMap, Map<String, GroupUser> groupUsersMap, Progress progress) { for (int i = 0; i < otherUsers.size(); i++) { UserDTO userDto = (UserDTO) otherUsers.get(i); Long umsGroupId = (Long)groupIdsMap.get(userDto.getGroupId()); // 获取用户组 对应 在UMS中用户组的ID if(usersMap.containsKey(userDto.getId())){// 更新内部用户 User user = (User)usersMap.remove(userDto.getId()); // 从内部用户中删除 SyncDataHelper.setUserByDTO(user, userDto); if (!groupUsersMap.containsKey(umsGroupId + "_" + user.getId())) { // 用户对组的关系已经改变,重新维护用户对组的关系 commonDao.deleteAll(commonDao.getEntities("from GroupUser o where o.userId = ?", new Object[]{user.getId()})); commonDao.create(new GroupUser(user.getId(), umsGroupId, userDto.getSeqNo())); } commonDao.create(user); }else{// 新增内部用户 User user = new User(); user.setApplicationId(applicationId); SyncDataHelper.setUserByDTO(user, userDto); user.setGroupId(umsGroupId); commonDao.create(user); commonDao.create(new GroupUser(user.getId(), umsGroupId, userDto.getSeqNo())); } updateProgressInfo(progress, otherUsers.size(), i); } } /** * 更新进度信息 */ private void updateProgressInfo(Progress progress, long total, int index){ commonDao.flush(); index = index + 1; //index 从0开始计数 if(index % 20 == 0) progress.add(20); //每同步20个更新一次进度信息 else if(index == total) progress.add(index % 20); //如果已经同步完,则将总数除以20取余数做为本次完成个数来更新进度信息 } //----------------------------------------- 单个用户同步 --------------------------------------------------------------- public void syncUser(Long groupId, Long userId){ User user = (User) commonDao.getEntity(User.class, userId); if(null == user.getOtherAppUserId()) throw new BusinessException("当前用户没有外部应用系统中对应用户(otherAppUserId==null),无法进行同步!"); UserDTO otherAppUser = getUserFromOtherApp(user.getApplicationId(), user.getOtherAppUserId()); if(null == otherAppUser) { // 如果为空,说明用户在其它应用不存在,可能已经被删除,则将之从UMS中也删除 commonDao.delete(user); return; } SyncDataHelper.setUserByDTO(user, otherAppUser); commonDao.create(user); } private UserDTO getUserFromOtherApp(String applicationId, String otherAppUserId){ Application app = applicationDao.getApplication(applicationId); Map<String, String> param = initParam(app.getParamDesc()); return SyncDataHelper.getOutDataDao(app.getDataSourceType()).getUser(param, otherAppUserId); } //--------------------------------------------------------------------------------------------------------------------- /** * 删除同步组下所有数据,完全同步用 * * @param applicationId * @param groupId */ private void deleteDataInSyncGroup(String applicationId, Long groupId) { commonDao.deleteAll(getNotMappedGroups(applicationId, groupId)); commonDao.deleteAll(getNotMappedGroupUsers(applicationId, groupId)); commonDao.deleteAll(getNotMappedUsers(applicationId, groupId)); commonDao.deleteAll(getMappedGroups(applicationId, groupId)); commonDao.deleteAll(getMappedGroupUsers(applicationId, groupId)); commonDao.deleteAll(getMappedUsers(applicationId, groupId)); } private List<?> getGroups(Integer dataSourceType, Map<String, String> appParams, String groupId){ String sql = (String)appParams.get(SyncDataHelper.QUERY_GROUP_SQL_NAME); return SyncDataHelper.getOutDataDao(dataSourceType).getOtherGroups(appParams, sql, groupId); } private List<?> getUsers(Integer dataSourceType, Map<String, String> appParams, String groupId){ String sql = (String)appParams.get(SyncDataHelper.QUERY_USER_SQL_NAME); return SyncDataHelper.getOutDataDao(dataSourceType).getOtherUsers( appParams, sql, groupId ); } private Map<String, String> initParam(String paramDescXML){ Map<String, String> param = new HashMap<String, String>(); if (null == paramDescXML || "".equals(paramDescXML)) return param; Document doc = XMLDocUtil.dataXml2Doc(paramDescXML); for (Iterator<?> it = doc.getRootElement().elementIterator(); it.hasNext();) { Element element = (Element) it.next(); param.put(element.getName(), element.getTextTrim()); } return param; } static String queryChildrenByGroupIdSQL = "select g.id from um_group g, (select t.decode from um_group t where t.id = ?) m " + " where g.applicationId = ? and g.decode like m.decode||'%'"; //取一个应用系统已经同步的用户组 private List<?> getMappedGroups(String applicationId) { String sql = "select t.* from um_group t where t.applicationId = ? and t.dbGroupId is not null "; return commonDao.getEntitiesByNativeSql(sql, Group.class, applicationId); } // 取一个应用系统的一个组下面已经同步的用户组 private List<?> getMappedGroups(String applicationId, Long groupId) { String sql = "select t.* from um_group t, (select g.decode from um_group g where g.id = ?) m " + " where t.applicationId = ? and t.decode like m.decode||'%' and t.dbGroupId is not null "; return commonDao.getEntitiesByNativeSql(sql, Group.class, groupId, applicationId); } // 取一个应用系统里面一个组下面所有未同步的组 private List<?> getNotMappedGroups(String applicationId, Long groupId) { String sql = "select t.* from um_group t, (select g.decode from um_group g where g.id = ?)m " + " where t.applicationId = ? and t.decode like m.decode||'%' and (t.dbGroupId = '' or t.dbGroupId is null)"; return commonDao.getEntitiesByNativeSql(sql, Group.class, groupId, applicationId); } // 取一个应用系统的一个组下面未同步的用户 private List<?> getNotMappedUsers(String applicationId, Long groupId) { String sql = "select u.* from um_user u, (" + queryChildrenByGroupIdSQL + " ) x, um_groupuser gu" + " where x.id = gu.groupid and u.id = gu.userid and (u.otherAppUserId = '' or u.otherAppUserId is null)"; return commonDao.getEntitiesByNativeSql(sql, User.class, groupId, applicationId); } // 取一个应用系统的一下组下已经同步的用户 private List<?> getMappedUsers(String applicationId, Long groupId) { String sql = "select u.* from um_user u, (" + queryChildrenByGroupIdSQL + " ) x, um_groupuser gu" + " where x.id = gu.groupid and u.id = gu.userid and u.otherAppUserId is not null"; return commonDao.getEntitiesByNativeSql(sql, User.class, groupId, applicationId); } // 取一个应用系统里一个组下面所有没有同步的用户和组的关系 private List<?> getNotMappedGroupUsers(String applicationId, Long groupId) { String sql = "select gu.* from um_groupuser gu, (" + queryChildrenByGroupIdSQL + " ) x, um_user u " + " where gu.groupid = x.id and u.id = gu.userId and (u.otherAppUserId = '' or u.otherAppUserId is null)"; return commonDao.getEntitiesByNativeSql(sql, GroupUser.class, groupId, applicationId); } // 取一个应用系统的一下组下面已经同步的用户的组的关系 private List<?> getMappedGroupUsers(String applicationId, Long groupId) { String sql = "select gu.* from um_groupuser gu, (" + queryChildrenByGroupIdSQL + " ) x, um_user u " + " where gu.groupid = x.id and u.id = gu.userId and u.otherAppUserId is not null"; return commonDao.getEntitiesByNativeSql(sql, GroupUser.class, groupId, applicationId); } }