@Override
  public void handle(Request request, Response response) {
    String query = request.mandatoryParam(Param.TEXT_QUERY);
    if (query.length() < MINIMUM_SEARCH_CHARACTERS) {
      throw new IllegalArgumentException(
          String.format("Minimum search is %s characters", MINIMUM_SEARCH_CHARACTERS));
    }
    String componentUuid = request.mandatoryParam(PARAM_COMPONENT_UUID);

    JsonWriter json = response.newJsonWriter();
    json.beginObject();

    DbSession session = dbClient.openSession(false);
    try {
      ComponentDto componentDto = componentFinder.getByUuid(session, componentUuid);
      userSession.checkProjectUuidPermission(UserRole.USER, componentDto.projectUuid());

      Set<Long> projectIds =
          newLinkedHashSet(
              dbClient
                  .componentIndexDao()
                  .selectProjectIdsFromQueryAndViewOrSubViewUuid(
                      session, query, componentDto.uuid()));
      Collection<Long> authorizedProjectIds =
          dbClient
              .authorizationDao()
              .keepAuthorizedProjectIds(
                  session, projectIds, userSession.getUserId(), UserRole.USER);

      SearchOptions options = new SearchOptions();
      options.setPage(request.mandatoryParamAsInt(PAGE), request.mandatoryParamAsInt(PAGE_SIZE));
      Set<Long> pagedProjectIds = pagedProjectIds(authorizedProjectIds, options);

      List<ComponentDto> projects = dbClient.componentDao().selectByIds(session, pagedProjectIds);

      options.writeJson(json, authorizedProjectIds.size());
      json.name("components").beginArray();
      for (ComponentDto project : projects) {
        json.beginObject();
        json.prop("uuid", project.uuid());
        json.prop("name", project.name());
        json.endObject();
      }
      json.endArray();
    } finally {
      MyBatis.closeQuietly(session);
    }

    json.endObject();
    json.close();
  }