com.sonymobile.jenkins.plugins.gitlab.gitlabauth.folder.GroupFolderManager.java Source code

Java tutorial

Introduction

Here is the source code for com.sonymobile.jenkins.plugins.gitlab.gitlabauth.folder.GroupFolderManager.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Andreas Alanko, Emil Nilsson, Sony Mobile Communications AB.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.sonymobile.jenkins.plugins.gitlab.gitlabauth.folder;

import com.cloudbees.hudson.plugins.folder.Folder;
import com.sonymobile.gitlab.exceptions.GitLabApiException;
import com.sonymobile.gitlab.model.GitLabGroupInfo;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.GitLab;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.authorization.GitLabFolderAuthorization;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.exceptions.ItemNameCollisionException;

import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import jenkins.model.Jenkins;
import jenkins.model.ModifiableTopLevelItemGroup;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static org.apache.commons.lang3.StringUtils.join;

/**
 * Class for managing GitLab group folders.
 *
 * @author Emil Nilsson
 */
public class GroupFolderManager {
    /**
     * Predicate used to include or exclude groups.
     *
     * If set to null all groups are included.
     */
    private final ManagesGroupPredicate managesGroupPredicate;

    /** The item group for the folders. */
    private final ModifiableTopLevelItemGroup itemGroup;

    /** The descriptor of the folder item. */
    private final TopLevelItemDescriptor folderDescriptor;

    /**
     * Creates a GitLab group folder manager.
     */
    public GroupFolderManager() {
        // include all groups
        this(getJenkinsInstance(), getFolderDescriptor());
    }

    /**
     * Creates a GitLab group folder manager.
     *
     * @param managesGroupPredicate predicate to determine whether to manage a group.
     */
    public GroupFolderManager(ManagesGroupPredicate managesGroupPredicate) {
        this(managesGroupPredicate, getJenkinsInstance(), getFolderDescriptor());
    }

    /**
     * Creates a GitLab group folder manager for customized folder creation.
     *
     * @param itemGroup        the item group
     * @param folderDescriptor the folder descriptor
     */
    /* package */ GroupFolderManager(ModifiableTopLevelItemGroup itemGroup,
            TopLevelItemDescriptor folderDescriptor) {
        // include all groups
        this(null, itemGroup, folderDescriptor);
    }

    /**
     * Creates a GitLab group folder manager for customized folder creation.
     *
     * @param managesGroupPredicate predicate to determine whether to manage a group.
     * @param itemGroup             the item group
     * @param folderDescriptor      the folder descriptor
     */
    /* package */ GroupFolderManager(ManagesGroupPredicate managesGroupPredicate,
            ModifiableTopLevelItemGroup itemGroup, TopLevelItemDescriptor folderDescriptor) {
        this.managesGroupPredicate = managesGroupPredicate;
        this.itemGroup = itemGroup;
        this.folderDescriptor = folderDescriptor;
    }

    /**
     * Returns all included group folders.
     *
     * @return the folders
     * @throws GitLabApiException if the connection against GitLab failed
     */
    public synchronized Collection<GroupFolderInfo> getFolders() throws GitLabApiException {
        return filterGroupFoldersMap(getUnfilteredFolders()).values();
    }

    /**
     * Returns all group folders.
     *
     * This returns all group folders without applying the filter.
     *
     * @return the folders
     * @throws GitLabApiException if the connection against GitLab failed
     */
    public synchronized Collection<GroupFolderInfo> getAllFolders() throws GitLabApiException {
        return getUnfilteredFolders().values();
    }

    /**
     * Returns group without a group folder.
     *
     * @return the available groups
     * @throws GitLabApiException if the connection against GitLab failed
     */
    public synchronized Collection<GitLabGroupInfo> getAvailableGroups() throws GitLabApiException {
        // get all available groups
        return getAvailableGroups(GitLab.getGroups());
    }

    /**
     * Returns group without a group folder.
     *
     * @param groups all groups
     * @return the available groups
     * @throws GitLabApiException if the connection against GitLab failed
     */
    public synchronized Collection<GitLabGroupInfo> getAvailableGroups(Collection<GitLabGroupInfo> groups)
            throws GitLabApiException {
        // filter excluded groups
        Collection<GitLabGroupInfo> availableGroups = filterGroups(groups);

        Map<Integer, GroupFolderInfo> folders = getUnfilteredFolders();
        Iterator<GitLabGroupInfo> iterator = groups.iterator();

        // remove groups having group folders
        while (iterator.hasNext()) {
            GitLabGroupInfo group = iterator.next();
            if (folders.containsKey(group.getId())) {
                iterator.remove();
            }
        }

        return availableGroups;
    }

    /**
     * Creates folders for a collection of GitLab groups.
     *
     * Checks if folders already exists before attempting to create a new folder.
     *
     * @param groups the groups
     * @throws GitLabApiException         if the connection against GitLab failed
     * @throws ItemNameCollisionException if an item names for new folders already were in use
     * @throws IOException                if saving to persistent storage failed
     */
    public synchronized void createFolders(Collection<GitLabGroupInfo> groups)
            throws GitLabApiException, ItemNameCollisionException, IOException {
        createUnfilteredFolders(filterGroups(groups));
    }

    /**
     * Gets all group folders without applying the filter.
     *
     * @return all group folders
     */
    private Map<Integer, GroupFolderInfo> getUnfilteredFolders() {
        Map<Integer, GroupFolderInfo> folders = new TreeMap<Integer, GroupFolderInfo>();
        for (TopLevelItem item : itemGroup.getItems()) {
            // check if the item is a group folder
            GroupFolderInfo groupFolderInfo = GroupFolderInfo.createFromItem(item);
            if (groupFolderInfo != null) {
                folders.put(groupFolderInfo.getGroupId(), groupFolderInfo);
            }
        }
        return folders;
    }

    /**
     * Creates group folders without applying the filter.
     *
     * This is used to create the included folders after filtering.
     *
     * @param groups the folders
     */
    private void createUnfilteredFolders(Collection<GitLabGroupInfo> groups)
            throws ItemNameCollisionException, IOException {
        // get existing group folders
        Map<Integer, GroupFolderInfo> existingFolders = getUnfilteredFolders();

        // groups which item names collide with existing items
        List<String> collidedGroupPaths = new LinkedList<String>();

        for (GitLabGroupInfo group : groups) {
            try {
                // only create folders that don't already exist
                if (!existingFolders.containsKey(group.getId())) {
                    createFolder(group);
                }
            } catch (ItemNameCollisionException e) {
                collidedGroupPaths.add(group.getPath());
            }
        }

        if (!collidedGroupPaths.isEmpty()) {
            throw new ItemNameCollisionException("Cannot create folder(s) because items with the names "
                    + join(collidedGroupPaths, ", ") + " already exist(s)");
        }
    }

    /**
     * Creates a group folder.
     *
     * Does not check if a folder already exists for the GitLab group.
     *
     * @param group the group
     * @throws ItemNameCollisionException if an item name for a new folder already was in use
     * @throws IOException                if saving to persistent storage failed
     */
    private void createFolder(GitLabGroupInfo group) throws ItemNameCollisionException, IOException {
        try {
            Folder folder = (Folder) itemGroup.createProject(folderDescriptor, group.getPath(), true);
            folder.addProperty(new GitLabFolderAuthorization(group.getId()));
        } catch (IllegalArgumentException e) {
            throw new ItemNameCollisionException(
                    "Cannot create folder because an item with the name " + group.getPath() + " already exists");
        }
    }

    /**
     * Filters groups excluded by the predicate.
     *
     * @param groups the groups
     * @return the groups
     * @throws GitLabApiException if the connection against GitLab failed
     */
    private Collection<GitLabGroupInfo> filterGroups(Collection<GitLabGroupInfo> groups) throws GitLabApiException {
        Iterator<GitLabGroupInfo> iterator = groups.iterator();

        while (iterator.hasNext()) {
            if (!managesGroup(iterator.next())) {
                iterator.remove();
            }
        }
        return groups;
    }

    /**
     * Filters group folders excluded by the predicate.
     *
     * @param groupFolders the group folders
     * @return the group folders
     * @throws GitLabApiException if the connection against GitLab failed
     */
    private Map<Integer, GroupFolderInfo> filterGroupFoldersMap(Map<Integer, GroupFolderInfo> groupFolders)
            throws GitLabApiException {
        Iterator<GroupFolderInfo> iterator = groupFolders.values().iterator();

        while (iterator.hasNext()) {
            if (!managesGroupFolder(iterator.next())) {
                iterator.remove();
            }
        }
        return groupFolders;
    }

    /**
     * Extracts the groups from a collection of group folders.
     *
     * @param groupFolders the group folders
     * @return the groups
     * @throws GitLabApiException if the connection against GitLab failed
     */
    private Collection<GitLabGroupInfo> getGroupsFromFolders(Collection<GroupFolderInfo> groupFolders)
            throws GitLabApiException {
        List<GitLabGroupInfo> groups = new ArrayList<GitLabGroupInfo>();

        for (GroupFolderInfo groupFolder : groupFolders) {
            groups.add(groupFolder.getGroup());
        }
        return groups;
    }

    /**
     * Checks whether a group folder should be included.
     *
     * @param group the group
     * @return true if the group should be included
     */
    private boolean managesGroup(GitLabGroupInfo group) throws GitLabApiException {
        return managesGroupPredicate == null || managesGroupPredicate.shouldManageGroup(group);
    }

    /**
     * Checks whether a group folder should be included.
     *
     * @param groupFolder the group folder
     * @return true if the group folder should be included
     */
    private boolean managesGroupFolder(GroupFolderInfo groupFolder) throws GitLabApiException {
        GitLabGroupInfo group = groupFolder.getGroup();
        return managesGroupPredicate == null || (group != null && managesGroupPredicate.shouldManageGroup(group));
    }

    /**
     * Gets the Jenkins instance
     *
     * @return the Jenkins instance
     */
    private static Jenkins getJenkinsInstance() {
        return Jenkins.getInstance();
    }

    /**
     * Gets the descriptor of {@link com.cloudbees.hudson.plugins.folder.Folder}
     *
     * @return the descriptor or null if Jenkins can't be accessed
     */
    private static TopLevelItemDescriptor getFolderDescriptor() {
        Jenkins jenkins = getJenkinsInstance();

        return jenkins != null ? jenkins.getDescriptorByType(Folder.DescriptorImpl.class) : null;
    }

    /**
     * Predicate for determining whether to include a certain group.
     */
    public static interface ManagesGroupPredicate {
        /**
         * Checks whether a group should be included by the folder manager.
         *
         * @param group the group
         * @return true if the group should be included
         * @throws GitLabApiException
         */
        public boolean shouldManageGroup(GitLabGroupInfo group) throws GitLabApiException;
    }
}