content: package alien4cloud.security.groups;
  
  import static alien4cloud.utils.AlienUtils.safe;
  
  import java.io.IOException;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  import java.util.UUID;
  
  import javax.annotation.Resource;
  import javax.inject.Inject;
  
  import org.apache.commons.collections4.CollectionUtils;
  import org.springframework.context.ApplicationEventPublisher;
  import org.springframework.context.event.EventListener;
  import org.springframework.stereotype.Component;
  
  import com.google.common.collect.Lists;
  import com.google.common.collect.Sets;
  
  import alien4cloud.exception.AlreadyExistException;
  import alien4cloud.exception.InvalidArgumentException;
  import alien4cloud.exception.NotFoundException;
  import alien4cloud.security.event.GroupDeletedEvent;
  import alien4cloud.security.event.UserDeletedEvent;
  import alien4cloud.security.groups.rest.UpdateGroupRequest;
  import alien4cloud.security.model.Group;
  import alien4cloud.security.model.Role;
  import alien4cloud.security.model.User;
  import alien4cloud.security.users.UserService;
  import alien4cloud.utils.ReflectionUtil;
  import lombok.extern.slf4j.Slf4j;
  
  @Slf4j
  @Component
  public class GroupService {
  
      @Resource
      private IAlienGroupDao alienGroupDao;
  
      @Resource
      private UserService userService;
  
      @Inject
      private ApplicationEventPublisher publisher;
  
      public void updateGroup(String groupId, UpdateGroupRequest groupUpdateRequest) {
          Group group = retrieveGroup(groupId);
          String currentGroupName = group.getName();
          ReflectionUtil.mergeObject(groupUpdateRequest, group);
          if (group.getName() == null || group.getName().isEmpty()) {
              throw new InvalidArgumentException("Group's name cannot be set to null or empty");
          }
          // Check with precedent value
          if (!currentGroupName.equals(group.getName())) {
              // If group name has changed, must check unicity
              checkGroupNameUniqueness(group.getName());
          }
          alienGroupDao.save(group);
      }
  
      public void deleteGroup(String groupId) throws IOException, ClassNotFoundException {
          Group group = retrieveGroup(groupId);
          alienGroupDao.delete(groupId);
          publisher.publishEvent(new GroupDeletedEvent(this, group));
      }
  
      public User addUserToGroup(String username, String groupId) {
          Group group = retrieveGroup(groupId);
          User user = userService.retrieveUser(username);
  
          Set<String> users = group.getUsers() == null ? new HashSet<String>() : group.getUsers();
          users.add(user.getUsername());
          group.setUsers(users);
  
          alienGroupDao.save(group);
  
          // update groupRoles in the user
          userService.addGroupToUser(group, user);
          return user;
      }
  
      public User removeUserFromGroup(String username, String groupId) {
          Group group = retrieveGroup(groupId);
          if (CollectionUtils.isEmpty(group.getUsers())) {
              return null;
          }
  
          User user = userService.retrieveUser(username);
  
          group.getUsers().remove(user.getUsername());
          alienGroupDao.save(group);
  
          // update groupRoles in users objects
          userService.removeGroupFromUser(user, group);
          return user;
      }
  
      public String createGroup(String name, String email, String description, Set<String> roles, Set<String> users) throws AlreadyExistException {
          checkGroupNameUniqueness(name);
          Group group = new Group(name);
          group.setId(UUID.randomUUID().toString());
          group.setDescription(description);
          group.setEmail(email);
          if (CollectionUtils.isNotEmpty(roles)) {
              Set<String> formatedRoles = Sets.newHashSet();
              for (String role : roles) {
                  formatedRoles.add(Role.getStringFormatedRole(role));
              }
              group.setRoles(formatedRoles);
          }
  
          List<User> usersList = null;
          if (CollectionUtils.isNotEmpty(users)) {
              usersList = Lists.newArrayList();
              Set<String> usersSet = Sets.newHashSet();
              for (String username : users) {
                  usersList.add(userService.retrieveUser(username));
                  usersSet.add(username);
              }
              group.setUsers(usersSet);
          }
  
          alienGroupDao.save(group);
  
          if (CollectionUtils.isNotEmpty(usersList)) {
              for (User user : usersList) {
                  userService.addGroupToUser(group, user);
              }
          }
  
          return group.getId();
      }
  
      public void addRoleToGroup(String groupId, String role) {
          Group group = retrieveGroup(groupId);
  
          Set<String> rolesSet = group.getRoles() == null ? new HashSet<String>() : group.getRoles();
          rolesSet.add(Role.getStringFormatedRole(role));
          group.setRoles(rolesSet);
  
          alienGroupDao.save(group);
  
          // update groupRoles in users objects
          if (CollectionUtils.isNotEmpty(group.getUsers())) {
              for (String username : group.getUsers()) {
                  userService.addGroupRoleToUser(username, role);
              }
          }
      }
  
      public Group retrieveGroup(String id) {
          Group group = alienGroupDao.find(id);
          if (group == null) {
              throw new NotFoundException("Group [" + id + "] cannot be found");
          }
          return group;
      }
  
      public void removeRoleFromGroup(String groupId, String role) {
          Group group = retrieveGroup(groupId);
          if (CollectionUtils.isEmpty(group.getRoles())) {
              return;
          }
  
          group.getRoles().remove(Role.getStringFormatedRole(role));
          alienGroupDao.save(group);
  
          // update groupRoles in users objects
          if (CollectionUtils.isNotEmpty(group.getUsers())) {
              for (String username : group.getUsers()) {
                  userService.updateUserGroupRoles(username);
              }
          }
  
      }
  
      /**
       * check if the given groupId is unique in the system
       * 
       * @param groupName
       */
      private void checkGroupNameUniqueness(String groupName) throws AlreadyExistException {
          if (alienGroupDao.isGroupWithNameExist(groupName)) {
              log.debug("Create group [ {} ] impossible (already exists)", groupName);
              // a group already exist with the given id.
              throw new AlreadyExistException("A Group with the given id <" + groupName + "> already exists.");
          } else {
              log.debug("Create group [ {} ]", groupName);
          }
      }
  
      /**
       * Listener for user deleted. Removes the user from all groups where he was
       * 
       * @param event
       */
      @EventListener
      public void userDeletedEventListener(UserDeletedEvent event) {
          User user = event.getUser();
          for (String groupId : safe(user.getGroups())) {
              Group group = retrieveGroup(groupId);
              if (safe(group.getUsers()).contains(user.getUsername())) {
                  group.getUsers().remove(user.getUsername());
                  alienGroupDao.save(group);
              }
          }
      }
  
  }
  