org.sonar.server.ce.ws.TaskFormatter.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.ce.ws.TaskFormatter.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.ce.ws;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonarqube.ws.WsCe;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.emptyMap;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.util.Protobuf.setNullable;

/**
 * Converts {@link CeActivityDto} and {@link CeQueueDto} to the protobuf objects
 * used to write WS responses (see ws-ce.proto in module sonar-ws)
 */
public class TaskFormatter {

    private final DbClient dbClient;
    private final System2 system2;

    public TaskFormatter(DbClient dbClient, System2 system2) {
        this.dbClient = dbClient;
        this.system2 = system2;
    }

    public List<WsCe.Task> formatQueue(DbSession dbSession, List<CeQueueDto> dtos) {
        ComponentDtoCache cache = ComponentDtoCache.forQueueDtos(dbClient, dbSession, dtos);
        return dtos.stream().map(input -> formatQueue(input, cache)).collect(MoreCollectors.toList(dtos.size()));
    }

    public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto dto) {
        return formatQueue(dto, ComponentDtoCache.forUuid(dbClient, dbSession, dto.getComponentUuid()));
    }

    public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto dto, Optional<ComponentDto> component) {
        checkArgument(Objects.equals(dto.getComponentUuid(), component.transform(ComponentDto::uuid).orNull()));
        return formatQueue(dto, ComponentDtoCache.forComponentDto(dbClient, dbSession, component));
    }

    private WsCe.Task formatQueue(CeQueueDto dto, ComponentDtoCache componentDtoCache) {
        WsCe.Task.Builder builder = WsCe.Task.newBuilder();
        String organizationKey = componentDtoCache.getOrganizationKey(dto.getComponentUuid());
        // FIXME organization field should be set from the CeQueueDto rather than from the ComponentDto
        setNullable(organizationKey, builder::setOrganization);
        if (dto.getComponentUuid() != null) {
            builder.setComponentId(dto.getComponentUuid());
            buildComponent(builder, componentDtoCache.getComponent(dto.getComponentUuid()));
        }
        builder.setId(dto.getUuid());
        builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
        builder.setType(dto.getTaskType());
        builder.setLogs(false);
        setNullable(dto.getSubmitterLogin(), builder::setSubmitterLogin);
        builder.setSubmittedAt(formatDateTime(new Date(dto.getCreatedAt())));
        setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime);
        setNullable(computeExecutionTimeMs(dto), builder::setExecutionTimeMs);
        return builder.build();
    }

    public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto) {
        return formatActivity(dto, ComponentDtoCache.forUuid(dbClient, dbSession, dto.getComponentUuid()), null);
    }

    public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto, Optional<ComponentDto> component,
            @Nullable String scannerContext) {
        return formatActivity(dto, ComponentDtoCache.forComponentDto(dbClient, dbSession, component),
                scannerContext);
    }

    public List<WsCe.Task> formatActivity(DbSession dbSession, List<CeActivityDto> dtos) {
        ComponentDtoCache cache = ComponentDtoCache.forActivityDtos(dbClient, dbSession, dtos);
        return dtos.stream().map(input -> formatActivity(input, cache, null))
                .collect(MoreCollectors.toList(dtos.size()));
    }

    private static WsCe.Task formatActivity(CeActivityDto dto, ComponentDtoCache componentDtoCache,
            @Nullable String scannerContext) {
        WsCe.Task.Builder builder = WsCe.Task.newBuilder();
        String organizationKey = componentDtoCache.getOrganizationKey(dto.getComponentUuid());
        // FIXME organization field should be set from the CeActivityDto rather than from the ComponentDto
        setNullable(organizationKey, builder::setOrganization);
        builder.setId(dto.getUuid());
        builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
        builder.setType(dto.getTaskType());
        builder.setLogs(false);
        if (dto.getComponentUuid() != null) {
            builder.setComponentId(dto.getComponentUuid());
            buildComponent(builder, componentDtoCache.getComponent(dto.getComponentUuid()));
        }
        setNullable(dto.getAnalysisUuid(), builder::setAnalysisId);
        setNullable(dto.getSubmitterLogin(), builder::setSubmitterLogin);
        builder.setSubmittedAt(formatDateTime(new Date(dto.getSubmittedAt())));
        setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime);
        setNullable(dto.getExecutedAt(), builder::setExecutedAt, DateUtils::formatDateTime);
        setNullable(dto.getExecutionTimeMs(), builder::setExecutionTimeMs);
        setNullable(dto.getErrorMessage(), builder::setErrorMessage);
        setNullable(dto.getErrorStacktrace(), builder::setErrorStacktrace);
        setNullable(scannerContext, builder::setScannerContext);
        builder.setHasScannerContext(dto.isHasScannerContext());
        return builder.build();
    }

    private static void buildComponent(WsCe.Task.Builder builder, @Nullable ComponentDto componentDto) {
        if (componentDto != null) {
            builder.setComponentKey(componentDto.getKey());
            builder.setComponentName(componentDto.name());
            builder.setComponentQualifier(componentDto.qualifier());
        }
    }

    private static class ComponentDtoCache {
        private final Map<String, ComponentDto> componentsByUuid;
        private final Map<String, OrganizationDto> organizationsByUuid;

        private ComponentDtoCache(Map<String, ComponentDto> componentsByUuid,
                Map<String, OrganizationDto> organizationsByUuid) {
            this.componentsByUuid = componentsByUuid;
            this.organizationsByUuid = organizationsByUuid;
        }

        static ComponentDtoCache forQueueDtos(DbClient dbClient, DbSession dbSession,
                Collection<CeQueueDto> ceQueueDtos) {
            Map<String, ComponentDto> componentsByUuid = dbClient.componentDao()
                    .selectByUuids(dbSession, uuidOfCeQueueDtos(ceQueueDtos)).stream()
                    .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
            return new ComponentDtoCache(componentsByUuid,
                    buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid));
        }

        private static Set<String> uuidOfCeQueueDtos(Collection<CeQueueDto> ceQueueDtos) {
            return ceQueueDtos.stream().filter(Objects::nonNull).map(CeQueueDto::getComponentUuid)
                    .filter(Objects::nonNull).collect(MoreCollectors.toSet(ceQueueDtos.size()));
        }

        static ComponentDtoCache forActivityDtos(DbClient dbClient, DbSession dbSession,
                Collection<CeActivityDto> ceActivityDtos) {
            Map<String, ComponentDto> componentsByUuid = dbClient.componentDao()
                    .selectByUuids(dbSession, uuidOfCeActivityDtos(ceActivityDtos)).stream()
                    .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
            return new ComponentDtoCache(componentsByUuid,
                    buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid));
        }

        private static Set<String> uuidOfCeActivityDtos(Collection<CeActivityDto> ceActivityDtos) {
            return ceActivityDtos.stream().filter(Objects::nonNull).map(CeActivityDto::getComponentUuid)
                    .filter(Objects::nonNull).collect(MoreCollectors.toSet(ceActivityDtos.size()));
        }

        static ComponentDtoCache forUuid(DbClient dbClient, DbSession dbSession, String uuid) {
            Optional<ComponentDto> component = dbClient.componentDao().selectByUuid(dbSession, uuid);
            return forComponentDto(dbClient, dbSession, component);
        }

        static ComponentDtoCache forComponentDto(DbClient dbClient, DbSession dbSession,
                Optional<ComponentDto> component) {
            Map<String, ComponentDto> componentsByUuid = component.isPresent()
                    ? ImmutableMap.of(component.get().uuid(), component.get())
                    : emptyMap();
            return new ComponentDtoCache(componentsByUuid,
                    buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid));
        }

        private static Map<String, OrganizationDto> buildOrganizationsByUuid(DbClient dbClient, DbSession dbSession,
                Map<String, ComponentDto> componentsByUuid) {
            return dbClient.organizationDao()
                    .selectByUuids(dbSession,
                            componentsByUuid.values().stream().map(ComponentDto::getOrganizationUuid)
                                    .collect(MoreCollectors.toSet(componentsByUuid.size())))
                    .stream().collect(MoreCollectors.uniqueIndex(OrganizationDto::getUuid));
        }

        @CheckForNull
        ComponentDto getComponent(@Nullable String uuid) {
            if (uuid == null) {
                return null;
            }
            return componentsByUuid.get(uuid);
        }

        @CheckForNull
        String getOrganizationKey(@Nullable String componentUuid) {
            if (componentUuid == null) {
                return null;
            }
            ComponentDto componentDto = componentsByUuid.get(componentUuid);
            if (componentDto == null) {
                return null;
            }
            String organizationUuid = componentDto.getOrganizationUuid();
            OrganizationDto organizationDto = organizationsByUuid.get(organizationUuid);
            checkState(organizationDto != null, "Organization with uuid '%s' not found", organizationUuid);
            return organizationDto.getKey();
        }
    }

    /**
     * now - startedAt
     */
    @CheckForNull
    private Long computeExecutionTimeMs(CeQueueDto dto) {
        Long startedAt = dto.getStartedAt();
        if (startedAt == null) {
            return null;
        }
        return system2.now() - startedAt;
    }

}