All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.server.rule.CachingRuleFinder Maven / Gradle / Ivy

There is a newer version: 7.2.1
Show newest version
/*
 * 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.rule;

import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Ordering;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleQuery;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.markdown.Markdown;

import static com.google.common.collect.Lists.newArrayList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;

/**
 * A {@link RuleFinder} implementation that retrieves all rule definitions and their parameter when instantiated, cache
 * them in memory and provide implementation of {@link RuleFinder}'s method which only read from this data in memory.
 */
public class CachingRuleFinder implements RuleFinder {

  private static final Ordering> FIND_BY_QUERY_ORDER = Ordering.natural().reverse().onResultOf(entry -> entry.getKey().getUpdatedAt());

  private final Map rulesByRuleDefinition;
  private final Map rulesById;
  private final Map rulesByKey;

  public CachingRuleFinder(DbClient dbClient) {
    try (DbSession dbSession = dbClient.openSession(false)) {
      this.rulesByRuleDefinition = buildRulesByRuleDefinitionDto(dbClient, dbSession);
      this.rulesById = this.rulesByRuleDefinition.entrySet().stream()
        .collect(uniqueIndex(entry -> entry.getKey().getId(), Map.Entry::getValue));
      this.rulesByKey = this.rulesByRuleDefinition.entrySet().stream()
        .collect(uniqueIndex(entry -> entry.getKey().getKey(), Map.Entry::getValue));
    }
  }

  private static Map buildRulesByRuleDefinitionDto(DbClient dbClient, DbSession dbSession) {
    List dtos = dbClient.ruleDao().selectAllDefinitions(dbSession);
    Set ruleKeys = dtos.stream().map(RuleDefinitionDto::getKey).collect(toSet(dtos.size()));
    ListMultimap ruleParamsByRuleId = retrieveRuleParameters(dbClient, dbSession, ruleKeys);
    Map rulesByDefinition = new HashMap<>(dtos.size());
    for (RuleDefinitionDto definition : dtos) {
      rulesByDefinition.put(definition, toRule(definition, ruleParamsByRuleId.get(definition.getId())));
    }
    return ImmutableMap.copyOf(rulesByDefinition);
  }

  private static ImmutableListMultimap retrieveRuleParameters(DbClient dbClient, DbSession dbSession, Set ruleKeys) {
    if (ruleKeys.isEmpty()) {
      return ImmutableListMultimap.of();
    }
    return dbClient.ruleDao().selectRuleParamsByRuleKeys(dbSession, ruleKeys)
      .stream()
      .collect(MoreCollectors.index(RuleParamDto::getRuleId));
  }

  @Override
  @Deprecated
  @CheckForNull
  public Rule findById(int ruleId) {
    return rulesById.get(ruleId);
  }

  @Override
  @CheckForNull
  public Rule findByKey(@Nullable String repositoryKey, @Nullable String key) {
    if (repositoryKey == null || key == null) {
      return null;
    }
    return findByKey(RuleKey.of(repositoryKey, key));
  }

  @Override
  @CheckForNull
  public Rule findByKey(RuleKey key) {
    return rulesByKey.get(key);
  }

  @Override
  @CheckForNull
  public Rule find(@Nullable RuleQuery query) {
    if (query == null) {
      return null;
    }

    return rulesByRuleDefinition.entrySet().stream()
      .filter(entry -> matchQuery(entry.getKey(), query))
      .sorted(FIND_BY_QUERY_ORDER)
      .map(Map.Entry::getValue)
      .findFirst()
      .orElse(null);
  }

  @Override
  public Collection findAll(@Nullable RuleQuery query) {
    if (query == null) {
      return Collections.emptyList();
    }
    return rulesByRuleDefinition.entrySet().stream()
      .filter(entry -> matchQuery(entry.getKey(), query))
      .sorted(FIND_BY_QUERY_ORDER)
      .map(Map.Entry::getValue)
      .collect(MoreCollectors.toList());
  }

  private static boolean matchQuery(RuleDefinitionDto ruleDefinition, RuleQuery ruleQuery) {
    if (RuleStatus.REMOVED.equals(ruleDefinition.getStatus())) {
      return false;
    }
    String repositoryKey = ruleQuery.getRepositoryKey();
    if (ruleQuery.getRepositoryKey() != null && !repositoryKey.equals(ruleDefinition.getRepositoryKey())) {
      return false;
    }
    String key = ruleQuery.getKey();
    if (key != null && !key.equals(ruleDefinition.getRuleKey())) {
      return false;
    }
    String configKey = ruleQuery.getConfigKey();
    return configKey == null || configKey.equals(ruleDefinition.getConfigKey());
  }

  private static Rule toRule(RuleDefinitionDto ruleDefinition, List params) {
    String severity = ruleDefinition.getSeverityString();
    String description = ruleDefinition.getDescription();
    RuleDto.Format descriptionFormat = ruleDefinition.getDescriptionFormat();

    Rule apiRule = new Rule();
    String[] systemTags = ruleDefinition.getSystemTags().toArray(new String[ruleDefinition.getSystemTags().size()]);
    apiRule
      .setName(ruleDefinition.getName())
      .setLanguage(ruleDefinition.getLanguage())
      .setKey(ruleDefinition.getRuleKey())
      .setConfigKey(ruleDefinition.getConfigKey())
      .setIsTemplate(ruleDefinition.isTemplate())
      .setCreatedAt(new Date(ruleDefinition.getCreatedAt()))
      .setUpdatedAt(new Date(ruleDefinition.getUpdatedAt()))
      .setRepositoryKey(ruleDefinition.getRepositoryKey())
      .setSeverity(severity != null ? RulePriority.valueOf(severity) : null)
      .setStatus(ruleDefinition.getStatus().name())
      .setSystemTags(systemTags)
      // FIXME tags should contain user defined tags and we can't provide them without organization => tags should return []
      .setTags(systemTags)
      .setId(ruleDefinition.getId());
    if (description != null && descriptionFormat != null) {
      if (RuleDto.Format.HTML.equals(descriptionFormat)) {
        apiRule.setDescription(description);
      } else {
        apiRule.setDescription(Markdown.convertToHtml(description));
      }
    }

    List apiParams = newArrayList();
    for (RuleParamDto param : params) {
      apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType())
        .setDefaultValue(param.getDefaultValue()));
    }
    apiRule.setParams(apiParams);

    return apiRule;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy