Java tutorial
/* * 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; } }