org.sonar.server.computation.queue.ReportSubmitter.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.computation.queue.ReportSubmitter.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2017 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.server.computation.queue;

import com.google.common.base.Optional;
import java.io.InputStream;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ServerSide;
import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeTask;
import org.sonar.ce.queue.CeTaskSubmit;
import org.sonar.core.component.ComponentKeys;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.component.NewComponent;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.user.UserSession;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;

@ServerSide
public class ReportSubmitter {

    private final CeQueue queue;
    private final UserSession userSession;
    private final ComponentUpdater componentUpdater;
    private final PermissionTemplateService permissionTemplateService;
    private final DbClient dbClient;

    public ReportSubmitter(CeQueue queue, UserSession userSession, ComponentUpdater componentUpdater,
            PermissionTemplateService permissionTemplateService, DbClient dbClient) {
        this.queue = queue;
        this.userSession = userSession;
        this.componentUpdater = componentUpdater;
        this.permissionTemplateService = permissionTemplateService;
        this.dbClient = dbClient;
    }

    /**
     * @throws NotFoundException if the organization with the specified key does not exist
     * @throws IllegalArgumentException if the organization with the specified key is not the organization of the specified project (when it already exists in DB)
     */
    public CeTask submit(String organizationKey, String projectKey, @Nullable String projectBranch,
            @Nullable String projectName, InputStream reportInput) {
        try (DbSession dbSession = dbClient.openSession(false)) {
            String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch);
            OrganizationDto organizationDto = getOrganizationDtoOrFail(dbSession, organizationKey);
            Optional<ComponentDto> opt = dbClient.componentDao().selectByKey(dbSession, effectiveProjectKey);
            ensureOrganizationIsConsistent(opt, organizationDto);
            ComponentDto project = opt
                    .or(() -> createProject(dbSession, organizationDto, projectKey, projectBranch, projectName));
            checkScanPermission(project);
            return submitReport(dbSession, reportInput, project);
        }
    }

    private void checkScanPermission(ComponentDto project) {
        // this is a specific and inconsistent behavior. For legacy reasons, "technical users"
        // defined on an organization should be able to analyze a project even if
        // they don't have the direct permission on the project.
        // That means that dropping the permission on the project does not have any effects
        // if user has still the permission on the organization
        if (!userSession.hasComponentPermission(SCAN_EXECUTION, project)
                && !userSession.hasPermission(OrganizationPermission.SCAN, project.getOrganizationUuid())) {
            throw insufficientPrivilegesException();
        }
    }

    private OrganizationDto getOrganizationDtoOrFail(DbSession dbSession, String organizationKey) {
        return dbClient.organizationDao().selectByKey(dbSession, organizationKey).orElseThrow(
                () -> new NotFoundException(format("Organization with key '%s' does not exist", organizationKey)));
    }

    private static void ensureOrganizationIsConsistent(Optional<ComponentDto> project,
            OrganizationDto organizationDto) {
        if (project.isPresent()) {
            checkArgument(project.get().getOrganizationUuid().equals(organizationDto.getUuid()),
                    "Organization of component with key '%s' does not match specified organization '%s'",
                    project.get().key(), organizationDto.getKey());
        }
    }

    private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey,
            @Nullable String projectBranch, @Nullable String projectName) {
        userSession.checkPermission(OrganizationPermission.PROVISION_PROJECTS, organization);
        Integer userId = userSession.getUserId();

        boolean wouldCurrentUserHaveScanPermission = permissionTemplateService
                .wouldUserHaveScanPermissionWithDefaultTemplate(dbSession, organization.getUuid(), userId,
                        projectBranch, projectKey, Qualifiers.PROJECT);
        if (!wouldCurrentUserHaveScanPermission) {
            throw insufficientPrivilegesException();
        }

        boolean newProjectPrivate = dbClient.organizationDao().getNewProjectPrivate(dbSession, organization);

        NewComponent newProject = newComponentBuilder().setOrganizationUuid(organization.getUuid())
                .setKey(projectKey).setName(StringUtils.defaultIfBlank(projectName, projectKey))
                .setBranch(projectBranch).setQualifier(Qualifiers.PROJECT).setPrivate(newProjectPrivate).build();
        return componentUpdater.create(dbSession, newProject, userId);
    }

    private CeTask submitReport(DbSession dbSession, InputStream reportInput, ComponentDto project) {
        // the report file must be saved before submitting the task
        CeTaskSubmit.Builder submit = queue.prepareSubmit();
        dbClient.ceTaskInputDao().insert(dbSession, submit.getUuid(), reportInput);
        dbSession.commit();

        submit.setType(CeTaskTypes.REPORT);
        submit.setComponentUuid(project.uuid());
        submit.setSubmitterLogin(userSession.getLogin());
        return queue.submit(submit.build());
    }
}