private static List<ComponentDto> paginateComponents(
      List<ComponentDto> components, ComponentTreeWsRequest wsRequest) {
    if (!isSortByMetric(wsRequest)) {
      return components;
    }

    return from(components)
        .skip(offset(wsRequest.getPage(), wsRequest.getPageSize()))
        .limit(wsRequest.getPageSize())
        .toList();
  }
  ComponentTreeData load(ComponentTreeWsRequest wsRequest) {
    DbSession dbSession = dbClient.openSession(false);
    try {
      ComponentDto baseComponent =
          componentFinder.getByUuidOrKey(
              dbSession,
              wsRequest.getBaseComponentId(),
              wsRequest.getBaseComponentKey(),
              BASE_COMPONENT_ID_AND_KEY);
      checkPermissions(baseComponent);
      java.util.Optional<SnapshotDto> baseSnapshot =
          dbClient
              .snapshotDao()
              .selectLastAnalysisByRootComponentUuid(dbSession, baseComponent.projectUuid());
      if (!baseSnapshot.isPresent()) {
        return ComponentTreeData.builder().setBaseComponent(baseComponent).build();
      }
      Long developerId = searchDeveloperId(dbSession, wsRequest);

      ComponentTreeQuery dbQuery = toComponentTreeQuery(wsRequest, baseComponent);
      ComponentDtosAndTotal componentDtosAndTotal = searchComponents(dbSession, dbQuery, wsRequest);
      List<ComponentDto> components = componentDtosAndTotal.componentDtos;
      List<MetricDto> metrics = searchMetrics(dbSession, wsRequest);
      List<WsMeasures.Period> periods = snapshotToWsPeriods(baseSnapshot.get());
      Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric =
          searchMeasuresByComponentUuidAndMetric(
              dbSession, baseComponent, components, metrics, periods, developerId);

      components =
          filterComponents(components, measuresByComponentUuidAndMetric, metrics, wsRequest);
      components = sortComponents(components, wsRequest, metrics, measuresByComponentUuidAndMetric);
      int componentCount =
          computeComponentCount(
              componentDtosAndTotal.total, components, componentWithMeasuresOnly(wsRequest));
      components = paginateComponents(components, wsRequest);
      Map<String, ComponentDto> referenceComponentsById =
          searchReferenceComponentsById(dbSession, components);

      return ComponentTreeData.builder()
          .setBaseComponent(baseComponent)
          .setComponentsFromDb(components)
          .setComponentCount(componentCount)
          .setMeasuresByComponentUuidAndMetric(measuresByComponentUuidAndMetric)
          .setMetrics(metrics)
          .setPeriods(periods)
          .setReferenceComponentsByUuid(referenceComponentsById)
          .build();
    } finally {
      dbClient.closeSession(dbSession);
    }
  }
  @CheckForNull
  private Long searchDeveloperId(DbSession dbSession, ComponentTreeWsRequest wsRequest) {
    if (wsRequest.getDeveloperId() == null && wsRequest.getDeveloperKey() == null) {
      return null;
    }

    return componentFinder
        .getByUuidOrKey(
            dbSession,
            wsRequest.getDeveloperId(),
            wsRequest.getDeveloperKey(),
            DEVELOPER_ID_AND_KEY)
        .getId();
  }
  private ComponentTreeQuery toComponentTreeQuery(
      ComponentTreeWsRequest wsRequest, ComponentDto baseComponent) {
    List<String> childrenQualifiers = childrenQualifiers(wsRequest, baseComponent.qualifier());

    List<String> sortsWithoutMetricSort =
        newArrayList(Iterables.filter(wsRequest.getSort(), IsNotMetricSort.INSTANCE));
    sortsWithoutMetricSort =
        sortsWithoutMetricSort.isEmpty() ? singletonList(NAME_SORT) : sortsWithoutMetricSort;

    ComponentTreeQuery.Builder dbQuery =
        ComponentTreeQuery.builder()
            .setBaseUuid(baseComponent.uuid())
            .setPage(wsRequest.getPage())
            .setPageSize(wsRequest.getPageSize())
            .setSortFields(sortsWithoutMetricSort)
            .setAsc(wsRequest.getAsc());

    if (wsRequest.getQuery() != null) {
      dbQuery.setNameOrKeyQuery(wsRequest.getQuery());
    }
    if (childrenQualifiers != null) {
      dbQuery.setQualifiers(childrenQualifiers);
    }
    // load all components if we must sort by metric value
    if (isSortByMetric(wsRequest)) {
      dbQuery.setPage(1);
      dbQuery.setPageSize(Integer.MAX_VALUE);
    }

    return dbQuery.build();
  }
  @CheckForNull
  private List<String> childrenQualifiers(ComponentTreeWsRequest request, String baseQualifier) {
    List<String> requestQualifiers = request.getQualifiers();
    List<String> childrenQualifiers = null;
    if (LEAVES_STRATEGY.equals(request.getStrategy())) {
      childrenQualifiers = resourceTypes.getLeavesQualifiers(baseQualifier);
    }

    if (requestQualifiers == null) {
      return childrenQualifiers;
    }

    if (childrenQualifiers == null) {
      return requestQualifiers;
    }

    Sets.SetView<String> qualifiersIntersection =
        Sets.intersection(
            new HashSet<>(childrenQualifiers), new HashSet<Object>(requestQualifiers));

    return new ArrayList<>(qualifiersIntersection);
  }
  private static List<ComponentDto> filterComponents(
      List<ComponentDto> components,
      Table<String, MetricDto, MeasureDto> measuresByComponentUuidAndMetric,
      List<MetricDto> metrics,
      ComponentTreeWsRequest wsRequest) {
    if (!componentWithMeasuresOnly(wsRequest)) {
      return components;
    }

    final String metricKeyToSort = wsRequest.getMetricSort();
    Optional<MetricDto> metricToSort =
        from(metrics).firstMatch(new MatchMetricKey(metricKeyToSort));
    checkState(
        metricToSort.isPresent(),
        "Metric '%s' not found",
        metricKeyToSort,
        wsRequest.getMetricKeys());

    return components
        .stream()
        .filter(new HasMeasure(measuresByComponentUuidAndMetric, metricToSort.get(), wsRequest))
        .collect(Collectors.toList());
  }
  private List<MetricDto> searchMetrics(DbSession dbSession, ComponentTreeWsRequest request) {
    List<String> metricKeys = requireNonNull(request.getMetricKeys());
    List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, metricKeys);
    if (metrics.size() < metricKeys.size()) {
      List<String> foundMetricKeys = Lists.transform(metrics, MetricDtoFunctions.toKey());
      Set<String> missingMetricKeys =
          Sets.difference(new LinkedHashSet<>(metricKeys), new LinkedHashSet<>(foundMetricKeys));

      throw new NotFoundException(
          format(
              "The following metric keys are not found: %s",
              Joiner.on(", ").join(missingMetricKeys)));
    }

    return metrics;
  }
 private ComponentDtosAndTotal searchComponents(
     DbSession dbSession, ComponentTreeQuery dbQuery, ComponentTreeWsRequest wsRequest) {
   if (dbQuery.getQualifiers() != null && dbQuery.getQualifiers().isEmpty()) {
     return new ComponentDtosAndTotal(Collections.emptyList(), 0);
   }
   String strategy = requireNonNull(wsRequest.getStrategy());
   switch (strategy) {
     case CHILDREN_STRATEGY:
       return new ComponentDtosAndTotal(
           dbClient.componentDao().selectChildren(dbSession, dbQuery),
           dbClient.componentDao().countChildren(dbSession, dbQuery));
     case LEAVES_STRATEGY:
     case ALL_STRATEGY:
       return new ComponentDtosAndTotal(
           dbClient.componentDao().selectDescendants(dbSession, dbQuery),
           dbClient.componentDao().countDescendants(dbSession, dbQuery));
     default:
       throw new IllegalStateException("Unknown component tree strategy");
   }
 }
 private static boolean isSortByMetric(ComponentTreeWsRequest wsRequest) {
   requireNonNull(wsRequest.getSort());
   return wsRequest.getSort().contains(METRIC_SORT)
       || wsRequest.getSort().contains(METRIC_PERIOD_SORT);
 }
 private static boolean componentWithMeasuresOnly(ComponentTreeWsRequest wsRequest) {
   return WITH_MEASURES_ONLY_METRIC_SORT_FILTER.equals(wsRequest.getMetricSortFilter());
 }