<commit_before>package com.sequenceiq.environment.environment.service;

import static com.sequenceiq.cloudbreak.common.exception.NotFoundException.notFound;
import static com.sequenceiq.cloudbreak.common.exception.NotFoundException.notFoundException;
import static com.sequenceiq.environment.environment.dto.EnvironmentExperienceDto.fromEnvironmentDto;
import static org.apache.commons.lang3.StringUtils.isEmpty;

import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.sequenceiq.authorization.service.CompositeAuthResourcePropertyProvider;
import com.sequenceiq.authorization.service.EnvironmentPropertyProvider;
import com.sequenceiq.authorization.service.OwnerAssignmentService;
import com.sequenceiq.authorization.service.list.ResourceWithId;
import com.sequenceiq.cloudbreak.api.endpoint.v4.dto.NameOrCrn;
import com.sequenceiq.cloudbreak.auth.ThreadBasedUserCrnProvider;
import com.sequenceiq.cloudbreak.auth.altus.GrpcUmsClient;
import com.sequenceiq.cloudbreak.auth.altus.service.RoleCrnGenerator;
import com.sequenceiq.cloudbreak.auth.crn.Crn;
import com.sequenceiq.cloudbreak.auth.crn.RegionAwareInternalCrnGeneratorFactory;
import com.sequenceiq.cloudbreak.cloud.model.CloudRegions;
import com.sequenceiq.cloudbreak.cloud.model.Coordinate;
import com.sequenceiq.cloudbreak.common.dal.repository.AccountAwareResourceRepository;
import com.sequenceiq.cloudbreak.common.event.PayloadContext;
import com.sequenceiq.cloudbreak.common.exception.NotFoundException;
import com.sequenceiq.cloudbreak.common.service.TransactionService;
import com.sequenceiq.cloudbreak.common.service.account.AbstractAccountAwareResourceService;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.quartz.model.JobResource;
import com.sequenceiq.common.api.type.Tunnel;
import com.sequenceiq.environment.environment.EnvironmentStatus;
import com.sequenceiq.environment.environment.domain.Environment;
import com.sequenceiq.environment.environment.domain.ExperimentalFeatures;
import com.sequenceiq.environment.environment.domain.Region;
import com.sequenceiq.environment.environment.domain.RegionWrapper;
import com.sequenceiq.environment.environment.dto.EnvironmentDto;
import com.sequenceiq.environment.environment.dto.EnvironmentDtoConverter;
import com.sequenceiq.environment.environment.dto.SecurityAccessDto;
import com.sequenceiq.environment.environment.repository.EnvironmentRepository;
import com.sequenceiq.environment.environment.validation.EnvironmentValidatorService;
import com.sequenceiq.environment.experience.ExperienceCluster;
import com.sequenceiq.environment.experience.ExperienceConnectorService;
import com.sequenceiq.environment.platformresource.PlatformParameterService;
import com.sequenceiq.environment.platformresource.PlatformResourceRequest;
import com.sequenceiq.environment.proxy.domain.ProxyConfig;
import com.sequenceiq.flow.core.PayloadContextProvider;
import com.sequenceiq.flow.core.ResourceIdProvider;

import io.grpc.Status.Code;
import io.grpc.StatusRuntimeException;

@Service
public class EnvironmentService extends AbstractAccountAwareResourceService<Environment> implements ResourceIdProvider, EnvironmentPropertyProvider,
        PayloadContextProvider, CompositeAuthResourcePropertyProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentService.class);

    @Value("${environment.admin.group.default.prefix:}")
    private String adminGroupNamePrefix;

    private final EnvironmentValidatorService validatorService;

    private final EnvironmentRepository environmentRepository;

    private final PlatformParameterService platformParameterService;

    private final EnvironmentDtoConverter environmentDtoConverter;

    private final OwnerAssignmentService ownerAssignmentService;

    private final GrpcUmsClient grpcUmsClient;

    private final TransactionService transactionService;

    private final RoleCrnGenerator roleCrnGenerator;

    private final RegionAwareInternalCrnGeneratorFactory regionAwareInternalCrnGeneratorFactory;

    private final ExperienceConnectorService experienceConnectorService;

    public EnvironmentService(
            EnvironmentValidatorService validatorService,
            EnvironmentRepository environmentRepository,
            PlatformParameterService platformParameterService,
            EnvironmentDtoConverter environmentDtoConverter,
            OwnerAssignmentService ownerAssignmentService,
            GrpcUmsClient grpcUmsClient,
            TransactionService transactionService,
            RoleCrnGenerator roleCrnGenerator,
            RegionAwareInternalCrnGeneratorFactory regionAwareInternalCrnGeneratorFactory,
            ExperienceConnectorService experienceConnectorService) {
        this.validatorService = validatorService;
        this.environmentRepository = environmentRepository;
        this.platformParameterService = platformParameterService;
        this.environmentDtoConverter = environmentDtoConverter;
        this.ownerAssignmentService = ownerAssignmentService;
        this.grpcUmsClient = grpcUmsClient;
        this.transactionService = transactionService;
        this.roleCrnGenerator = roleCrnGenerator;
        this.experienceConnectorService = experienceConnectorService;
        this.regionAwareInternalCrnGeneratorFactory = regionAwareInternalCrnGeneratorFactory;
    }

    public Environment save(Environment environment) {
        LOGGER.debug("Saving environment '{}'.", environment);
        return environmentRepository.save(environment);
    }

    public Environment saveWithOwnerRoleAssignment(Environment environment) {
        try {
            return transactionService.required(() -> {
                Environment saved = save(environment);
                ownerAssignmentService.assignResourceOwnerRoleIfEntitled(ThreadBasedUserCrnProvider.getUserCrn(),
                        saved.getResourceCrn(), ThreadBasedUserCrnProvider.getAccountId());
                return saved;
            });
        } catch (TransactionService.TransactionExecutionException e) {
            throw new InternalServerErrorException("Error happened during saving environment state and assigned owner role: ", e);
        }
    }

    public EnvironmentDto getEnvironmentDto(Environment environment) {
        return environmentDtoConverter.environmentToDto(environment);
    }

    public EnvironmentDto getByNameAndAccountId(String environmentName, String accountId) {
        LOGGER.debug("Getting environment by name: '{}'.", environmentName);
        Optional<Environment> environment = environmentRepository.findByNameAndAccountIdAndArchivedIsFalse(environmentName, accountId);
        MDCBuilder.buildMdcContext(environment.orElseThrow(notFound("Environment with name:", environmentName)));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public EnvironmentDto getByCrnAndAccountId(String crn, String accountId) {
        LOGGER.debug("Getting environment by crn '{}' and account id '{}'.", crn, accountId);
        Optional<Environment> environment = environmentRepository
                .findByResourceCrnAndAccountIdAndArchivedIsFalse(crn, accountId);
        MDCBuilder.buildMdcContext(environment.orElseThrow(() -> new NotFoundException(String.format("No environment found with resource CRN '%s'.", crn))));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public List<EnvironmentDto> listByAccountId(String accountId) {
        LOGGER.debug("Listing environments by account id '{}'.", accountId);
        Set<Environment> environments = environmentRepository.findByAccountId(accountId);
        return environments.stream().map(environmentDtoConverter::environmentToDto).collect(Collectors.toList());
    }

    public EnvironmentDto internalGetByCrn(String crn) {
        LOGGER.debug("Listing environments by crn '{}'.", crn);
        Optional<Environment> environment = environmentRepository.findOneByResourceCrnEvenIfDeleted(crn);
        MDCBuilder.buildMdcContext(environment.orElseThrow(() -> new NotFoundException(String.format("No environment found with resource CRN '%s'.", crn))));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public void setRegions(Environment environment, Set<String> requestedRegions, CloudRegions cloudRegions) {
        Set<Region> regionSet = new HashSet<>();
        LOGGER.debug("Setting regions for environment. Regions: [{}].", String.join(", ", requestedRegions));
        setRegionsFromCloudCoordinates(requestedRegions, cloudRegions, regionSet);
        if (regionSet.isEmpty()) {
            setRegionsFromCloudRegions(requestedRegions, cloudRegions, regionSet);
        }
        environment.setRegions(regionSet);
    }

    public Map<String, Set<String>> collectExperiences(NameOrCrn environmentNameOrCrn) {
        String accountId = ThreadBasedUserCrnProvider.getAccountId();
        Map<String, Set<String>> xps = new HashMap<>();
        EnvironmentDto environment;
        if (environmentNameOrCrn.hasName()) {
            environment = getByNameAndAccountId(environmentNameOrCrn.getName(), accountId);
        } else {
            environment = getByCrnAndAccountId(environmentNameOrCrn.getCrn(), accountId);
        }
        Set<ExperienceCluster> connectedExperiences = experienceConnectorService.getConnectedExperiences(fromEnvironmentDto(environment));
        Set<String> experienceTypes = connectedExperiences.stream().map(ExperienceCluster::getPublicName).collect(Collectors.toSet());
        for (String experienceType : experienceTypes) {
            Set<String> clusters = connectedExperiences.stream().filter(experienceCluster -> experienceType.equals(experienceCluster.getPublicName()))
                    .map(experienceCluster -> experienceCluster.getName())
                    .collect(Collectors.toSet());<commit_msg>CB-18712 - improve logging for experience collection<commit_after>package com.sequenceiq.environment.environment.service;

import static com.sequenceiq.cloudbreak.common.exception.NotFoundException.notFound;
import static com.sequenceiq.cloudbreak.common.exception.NotFoundException.notFoundException;
import static com.sequenceiq.environment.environment.dto.EnvironmentExperienceDto.fromEnvironmentDto;
import static org.apache.commons.lang3.StringUtils.isEmpty;

import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.sequenceiq.authorization.service.CompositeAuthResourcePropertyProvider;
import com.sequenceiq.authorization.service.EnvironmentPropertyProvider;
import com.sequenceiq.authorization.service.OwnerAssignmentService;
import com.sequenceiq.authorization.service.list.ResourceWithId;
import com.sequenceiq.cloudbreak.api.endpoint.v4.dto.NameOrCrn;
import com.sequenceiq.cloudbreak.auth.ThreadBasedUserCrnProvider;
import com.sequenceiq.cloudbreak.auth.altus.GrpcUmsClient;
import com.sequenceiq.cloudbreak.auth.altus.service.RoleCrnGenerator;
import com.sequenceiq.cloudbreak.auth.crn.Crn;
import com.sequenceiq.cloudbreak.auth.crn.RegionAwareInternalCrnGeneratorFactory;
import com.sequenceiq.cloudbreak.cloud.model.CloudRegions;
import com.sequenceiq.cloudbreak.cloud.model.Coordinate;
import com.sequenceiq.cloudbreak.common.dal.repository.AccountAwareResourceRepository;
import com.sequenceiq.cloudbreak.common.event.PayloadContext;
import com.sequenceiq.cloudbreak.common.exception.NotFoundException;
import com.sequenceiq.cloudbreak.common.service.TransactionService;
import com.sequenceiq.cloudbreak.common.service.account.AbstractAccountAwareResourceService;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.quartz.model.JobResource;
import com.sequenceiq.common.api.type.Tunnel;
import com.sequenceiq.environment.environment.EnvironmentStatus;
import com.sequenceiq.environment.environment.domain.Environment;
import com.sequenceiq.environment.environment.domain.ExperimentalFeatures;
import com.sequenceiq.environment.environment.domain.Region;
import com.sequenceiq.environment.environment.domain.RegionWrapper;
import com.sequenceiq.environment.environment.dto.EnvironmentDto;
import com.sequenceiq.environment.environment.dto.EnvironmentDtoConverter;
import com.sequenceiq.environment.environment.dto.SecurityAccessDto;
import com.sequenceiq.environment.environment.repository.EnvironmentRepository;
import com.sequenceiq.environment.environment.validation.EnvironmentValidatorService;
import com.sequenceiq.environment.experience.ExperienceCluster;
import com.sequenceiq.environment.experience.ExperienceConnectorService;
import com.sequenceiq.environment.platformresource.PlatformParameterService;
import com.sequenceiq.environment.platformresource.PlatformResourceRequest;
import com.sequenceiq.environment.proxy.domain.ProxyConfig;
import com.sequenceiq.flow.core.PayloadContextProvider;
import com.sequenceiq.flow.core.ResourceIdProvider;

import io.grpc.Status.Code;
import io.grpc.StatusRuntimeException;

@Service
public class EnvironmentService extends AbstractAccountAwareResourceService<Environment> implements ResourceIdProvider, EnvironmentPropertyProvider,
        PayloadContextProvider, CompositeAuthResourcePropertyProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentService.class);

    @Value("${environment.admin.group.default.prefix:}")
    private String adminGroupNamePrefix;

    private final EnvironmentValidatorService validatorService;

    private final EnvironmentRepository environmentRepository;

    private final PlatformParameterService platformParameterService;

    private final EnvironmentDtoConverter environmentDtoConverter;

    private final OwnerAssignmentService ownerAssignmentService;

    private final GrpcUmsClient grpcUmsClient;

    private final TransactionService transactionService;

    private final RoleCrnGenerator roleCrnGenerator;

    private final RegionAwareInternalCrnGeneratorFactory regionAwareInternalCrnGeneratorFactory;

    private final ExperienceConnectorService experienceConnectorService;

    public EnvironmentService(
            EnvironmentValidatorService validatorService,
            EnvironmentRepository environmentRepository,
            PlatformParameterService platformParameterService,
            EnvironmentDtoConverter environmentDtoConverter,
            OwnerAssignmentService ownerAssignmentService,
            GrpcUmsClient grpcUmsClient,
            TransactionService transactionService,
            RoleCrnGenerator roleCrnGenerator,
            RegionAwareInternalCrnGeneratorFactory regionAwareInternalCrnGeneratorFactory,
            ExperienceConnectorService experienceConnectorService) {
        this.validatorService = validatorService;
        this.environmentRepository = environmentRepository;
        this.platformParameterService = platformParameterService;
        this.environmentDtoConverter = environmentDtoConverter;
        this.ownerAssignmentService = ownerAssignmentService;
        this.grpcUmsClient = grpcUmsClient;
        this.transactionService = transactionService;
        this.roleCrnGenerator = roleCrnGenerator;
        this.experienceConnectorService = experienceConnectorService;
        this.regionAwareInternalCrnGeneratorFactory = regionAwareInternalCrnGeneratorFactory;
    }

    public Environment save(Environment environment) {
        LOGGER.debug("Saving environment '{}'.", environment);
        return environmentRepository.save(environment);
    }

    public Environment saveWithOwnerRoleAssignment(Environment environment) {
        try {
            return transactionService.required(() -> {
                Environment saved = save(environment);
                ownerAssignmentService.assignResourceOwnerRoleIfEntitled(ThreadBasedUserCrnProvider.getUserCrn(),
                        saved.getResourceCrn(), ThreadBasedUserCrnProvider.getAccountId());
                return saved;
            });
        } catch (TransactionService.TransactionExecutionException e) {
            throw new InternalServerErrorException("Error happened during saving environment state and assigned owner role: ", e);
        }
    }

    public EnvironmentDto getEnvironmentDto(Environment environment) {
        return environmentDtoConverter.environmentToDto(environment);
    }

    public EnvironmentDto getByNameAndAccountId(String environmentName, String accountId) {
        LOGGER.debug("Getting environment by name: '{}'.", environmentName);
        Optional<Environment> environment = environmentRepository.findByNameAndAccountIdAndArchivedIsFalse(environmentName, accountId);
        MDCBuilder.buildMdcContext(environment.orElseThrow(notFound("Environment with name:", environmentName)));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public EnvironmentDto getByCrnAndAccountId(String crn, String accountId) {
        LOGGER.debug("Getting environment by crn '{}' and account id '{}'.", crn, accountId);
        Optional<Environment> environment = environmentRepository
                .findByResourceCrnAndAccountIdAndArchivedIsFalse(crn, accountId);
        MDCBuilder.buildMdcContext(environment.orElseThrow(() -> new NotFoundException(String.format("No environment found with resource CRN '%s'.", crn))));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public List<EnvironmentDto> listByAccountId(String accountId) {
        LOGGER.debug("Listing environments by account id '{}'.", accountId);
        Set<Environment> environments = environmentRepository.findByAccountId(accountId);
        return environments.stream().map(environmentDtoConverter::environmentToDto).collect(Collectors.toList());
    }

    public EnvironmentDto internalGetByCrn(String crn) {
        LOGGER.debug("Listing environments by crn '{}'.", crn);
        Optional<Environment> environment = environmentRepository.findOneByResourceCrnEvenIfDeleted(crn);
        MDCBuilder.buildMdcContext(environment.orElseThrow(() -> new NotFoundException(String.format("No environment found with resource CRN '%s'.", crn))));
        return environmentDtoConverter.environmentToDto(environment.get());
    }

    public void setRegions(Environment environment, Set<String> requestedRegions, CloudRegions cloudRegions) {
        Set<Region> regionSet = new HashSet<>();
        LOGGER.debug("Setting regions for environment. Regions: [{}].", String.join(", ", requestedRegions));
        setRegionsFromCloudCoordinates(requestedRegions, cloudRegions, regionSet);
        if (regionSet.isEmpty()) {
            setRegionsFromCloudRegions(requestedRegions, cloudRegions, regionSet);
        }
        environment.setRegions(regionSet);
    }

    public Map<String, Set<String>> collectExperiences(NameOrCrn environmentNameOrCrn) {
        LOGGER.debug("Collecting of connected experience(s) has been requested for environment: {}", environmentNameOrCrn.getNameOrCrn());
        String accountId = ThreadBasedUserCrnProvider.getAccountId();
        Map<String, Set<String>> xps = new HashMap<>();
        EnvironmentDto environment;
        LOGGER.debug("Attempting to fetch {} based on {} for account: {}", EnvironmentDto.class.getSimpleName(), environmentNameOrCrn.hasName()
                ? "name: " + environmentNameOrCrn.getName() : "crn: " + environmentNameOrCrn.getCrn(), accountId);
        if (environmentNameOrCrn.hasName()) {
            environment = getByNameAndAccountId(environmentNameOrCrn.getName(), accountId);
        } else {
            environment = getByCrnAndAccountId(environmentNameOrCrn.getCrn(), accountId);
        }
        LOGGER.debug("About to collect connected experiences for environment: {}", environment.getName());
        Set<ExperienceCluster> connectedExperiences = experienceConnectorService.getConnectedExperiences(fromEnvironmentDto(environment));
        LOGGER.debug(connectedExperiences.isEmpty() ? "No experience found for environment: " + environment.getName()
                : connectedExperiences.size() + " experience(s) found for environment: " + environment.getName());
        Set<String> experienceTypes = connectedExperiences.stream().map(ExperienceCluster::getPublicName).collect(Collectors.toSet());
        LOGGER.debug("The following experiences are depending on the environment [{}]: {}", environment.getName(), String.join(",", experienceTypes));
        for (String experienceType : experienceTypes) {
            Set<String> clusters = connectedExperiences.stream().filter(experienceCluster -> experienceType.equals(experienceCluster.getPublicName()))
                    .map(experienceCluster -> experienceCluster.getName())
                    .collect(Collectors.toSet());
{'fraction_non_alphanumeric': 0.08329521544232, 'fraction_numerical': 0.0006861220382398683, 'mean_word_length': 5.052879291251385, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6725584', 'n_tokens_mistral': 5275, 'n_tokens_neox': 5315, 'n_words': 936}