import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
-import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.Dao;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleParamDto;
import static com.google.common.base.Preconditions.checkArgument;
return mapper(dbSession).selectByRuleProfileUuid(ruleProfileDto.getKee());
}
- public Collection<ActiveRuleDto> selectByRulesAndRuleProfileUuids(DbSession dbSession, Collection<RuleDefinitionDto> rules, Collection<String> ruleProfileUuids) {
- if (rules.isEmpty() || ruleProfileUuids.isEmpty()) {
+ public Collection<ActiveRuleDto> selectByRulesAndRuleProfileUuids(DbSession dbSession, Collection<Integer> ruleIds, Collection<String> ruleProfileUuids) {
+ if (ruleIds.isEmpty() || ruleProfileUuids.isEmpty()) {
return emptyList();
}
- List<Integer> ruleIds = rules.stream().map(RuleDefinitionDto::getId).collect(MoreCollectors.toArrayList(rules.size()));
ActiveRuleMapper mapper = mapper(dbSession);
return executeLargeInputs(ruleIds, ruleIdsChunk -> executeLargeInputs(ruleProfileUuids, chunk -> mapper.selectByRuleIdsAndRuleProfileUuids(ruleIdsChunk, chunk)));
}
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
assertThat(result).isEmpty();
// empty profiles
- result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1), emptyList());
+ result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1.getId()), emptyList());
assertThat(result).isEmpty();
// match
- result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
+ result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1.getId()), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
assertThat(result)
.extracting(ActiveRuleDto::getId)
.containsExactlyInAnyOrder(rule1P1.getId(), rule1P2.getId());
- result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1, rule2), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
+ result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1.getId(), rule2.getId()), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
assertThat(result)
.extracting(ActiveRuleDto::getId)
.containsExactlyInAnyOrder(rule1P1.getId(), rule1P2.getId(), rule2P1.getId());
// do not match
- result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule3), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
+ result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule3.getId()), asList(profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()));
assertThat(result).isEmpty();
- result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1), asList("unknown"));
+ result = underTest.selectByRulesAndRuleProfileUuids(dbSession, asList(rule1.getId()), asList("unknown"));
assertThat(result).isEmpty();
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.qualityprofile;
+
+import java.util.Collection;
+import org.sonar.db.qualityprofile.ActiveRuleDto;
+import org.sonar.db.qualityprofile.ActiveRuleParamDto;
+import org.sonar.db.qualityprofile.QProfileDto;
+
+@FunctionalInterface
+public interface DescendantProfilesSupplier {
+
+ Result get(Collection<QProfileDto> profiles, Collection<Integer> ruleIds);
+
+ final class Result {
+ private final Collection<QProfileDto> profiles;
+ private final Collection<ActiveRuleDto> activeRules;
+ private final Collection<ActiveRuleParamDto> activeRuleParams;
+
+ public Result(Collection<QProfileDto> profiles, Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) {
+ this.profiles = profiles;
+ this.activeRules = activeRules;
+ this.activeRuleParams = activeRuleParams;
+ }
+
+ public Collection<QProfileDto> getProfiles() {
+ return profiles;
+ }
+
+ public Collection<ActiveRuleDto> getActiveRules() {
+ return activeRules;
+ }
+
+ public Collection<ActiveRuleParamDto> getActiveRuleParams() {
+ return activeRuleParams;
+ }
+ }
+}
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.core.util.stream.MoreCollectors.index;
+import static org.sonar.core.util.stream.MoreCollectors.toArrayList;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.server.ws.WsUtils.checkRequest;
private final ListMultimap<String, QProfileDto> profilesByParentUuid = ArrayListMultimap.create();
// The rules/active rules involved in the group of activations/de-activations
- private final Map<Integer, RuleWrapper> rulesById;
- private final Map<ActiveRuleKey, ActiveRuleWrapper> activeRulesByKey;
+ private final Map<Integer, RuleWrapper> rulesById = new HashMap<>();
+ private final Map<ActiveRuleKey, ActiveRuleWrapper> activeRulesByKey = new HashMap<>();
// Cursors used to move in the rules and in the tree of profiles.
private ActiveRuleWrapper currentActiveRule;
private ActiveRuleWrapper currentParentActiveRule;
+ private boolean descendantsLoaded = false;
+ private final DescendantProfilesSupplier descendantProfilesSupplier;
+
private RuleActivationContext(Builder builder) {
this.date = builder.date;
+ this.descendantProfilesSupplier = builder.descendantProfilesSupplier;
- this.rulesById = Maps.newHashMapWithExpectedSize(builder.rules.size());
ListMultimap<Integer, RuleParamDto> paramsByRuleId = builder.ruleParams.stream().collect(index(RuleParamDto::getRuleId));
for (RuleDefinitionDto rule : builder.rules) {
RuleWrapper wrapper = new RuleWrapper(rule, paramsByRuleId.get(rule.getId()));
}
this.baseRulesProfile = builder.baseRulesProfile;
- for (QProfileDto profile : builder.profiles) {
+ register(builder.profiles);
+ register(builder.activeRules, builder.activeRuleParams);
+ }
+
+ private void register(Collection<QProfileDto> profiles) {
+ for (QProfileDto profile : profiles) {
profilesByUuid.put(profile.getKee(), profile);
if (profile.getParentKee() != null) {
profilesByParentUuid.put(profile.getParentKee(), profile);
}
}
+ }
- this.activeRulesByKey = Maps.newHashMapWithExpectedSize(builder.activeRules.size());
- ListMultimap<Integer, ActiveRuleParamDto> paramsByActiveRuleId = builder.activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleId));
- for (ActiveRuleDto activeRule : builder.activeRules) {
+ private void register(Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) {
+ ListMultimap<Integer, ActiveRuleParamDto> paramsByActiveRuleId = activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleId));
+ for (ActiveRuleDto activeRule : activeRules) {
ActiveRuleWrapper wrapper = new ActiveRuleWrapper(activeRule, paramsByActiveRuleId.get(activeRule.getId()));
this.activeRulesByKey.put(activeRule.getKey(), wrapper);
}
* The children of {@link #getProfiles()}
*/
Collection<QProfileDto> getChildProfiles() {
+ loadDescendants();
return getProfiles().stream()
.flatMap(p -> profilesByParentUuid.get(p.getKee()).stream())
.collect(Collectors.toList());
}
+ private void loadDescendants() {
+ if (descendantsLoaded) {
+ return;
+ }
+ Collection<QProfileDto> baseProfiles = profilesByUuid.values().stream()
+ .filter(p -> p.getRulesProfileUuid().equals(baseRulesProfile.getKee()))
+ .collect(toArrayList(profilesByUuid.size()));
+ DescendantProfilesSupplier.Result result = descendantProfilesSupplier.get(baseProfiles, rulesById.keySet());
+ register(result.getProfiles());
+ register(result.getActiveRules(), result.getActiveRuleParams());
+ descendantsLoaded = true;
+ }
+
/**
* Move the cursor to the given rule and back to the base profile.
*/
private Collection<QProfileDto> profiles;
private Collection<ActiveRuleDto> activeRules;
private Collection<ActiveRuleParamDto> activeRuleParams;
+ private DescendantProfilesSupplier descendantProfilesSupplier;
Builder setDate(long l) {
this.date = l;
return this;
}
+ Builder setDescendantProfilesSupplier(DescendantProfilesSupplier d) {
+ this.descendantProfilesSupplier = d;
+ return this;
+ }
+
RuleActivationContext build() {
checkArgument(date > 0, "date is not set");
requireNonNull(baseRulesProfile, "baseRulesProfile is null");
import java.util.Date;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.server.util.TypeValidations;
import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Collections.singleton;
import static org.sonar.server.ws.WsUtils.checkRequest;
/**
String parentValue = parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null;
String activeRuleValue = activeRule == null ? null : activeRule.getParamValue(paramKey);
paramValue = context.hasRequestedParamValue(request, paramKey) ?
- // If the request contains the parameter then we're using either value from request, or parent value, or default value
+ // If the request contains the parameter then we're using either value from request, or parent value, or default value
firstNonNull(
context.getRequestedParamValue(request, paramKey),
parentValue,
rule.getParamDefaultValue(paramKey))
// If the request doesn't contain the parameter, then we're using either value in DB, or parent value, or default value
: firstNonNull(
- activeRuleValue,
- parentValue,
- rule.getParamDefaultValue(paramKey));
+ activeRuleValue,
+ parentValue,
+ rule.getParamDefaultValue(paramKey));
}
change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
checkArgument(builtInProfile.isBuiltIn(), "Rules profile with UUID %s is not built-in", builtInProfile.getKee());
RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
+ builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
// load rules
List<RuleDefinitionDto> rules = completeWithRules(dbSession, builder, ruleIds);
- // load org profiles
- List<QProfileDto> aliasedBuiltInProfiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile);
- List<QProfileDto> profiles = new ArrayList<>(aliasedBuiltInProfiles);
- profiles.addAll(db.qualityProfileDao().selectDescendants(dbSession, aliasedBuiltInProfiles));
+ // load org profiles. Their parents are null by nature.
+ List<QProfileDto> profiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile);
builder.setProfiles(profiles);
builder.setBaseProfile(builtInProfile);
Collection<String> ruleProfileUuids = Stream
.concat(Stream.of(builtInProfile.getKee()), profiles.stream().map(QProfileDto::getRulesProfileUuid))
.collect(MoreCollectors.toHashSet(profiles.size() + 1));
- completeWithActiveRules(dbSession, builder, rules, ruleProfileUuids);
-
+ completeWithActiveRules(dbSession, builder, ruleIds, ruleProfileUuids);
return builder.build();
}
public RuleActivationContext createContextForUserProfile(DbSession dbSession, QProfileDto profile, Collection<Integer> ruleIds) {
checkArgument(!profile.isBuiltIn(), "Profile with UUID %s is built-in", profile.getKee());
RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
+ builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
// load rules
- List<RuleDefinitionDto> rules = completeWithRules(dbSession, builder, ruleIds);
+ completeWithRules(dbSession, builder, ruleIds);
- // load descendant profiles
- List<QProfileDto> profiles = new ArrayList<>(db.qualityProfileDao().selectDescendants(dbSession, singleton(profile)));
+ // load profiles
+ List<QProfileDto> profiles = new ArrayList<>();
profiles.add(profile);
if (profile.getParentKee() != null) {
profiles.add(db.qualityProfileDao().selectByUuid(dbSession, profile.getParentKee()));
Collection<String> ruleProfileUuids = profiles.stream()
.map(QProfileDto::getRulesProfileUuid)
.collect(MoreCollectors.toHashSet(profiles.size()));
- completeWithActiveRules(dbSession, builder, rules, ruleProfileUuids);
+ completeWithActiveRules(dbSession, builder, ruleIds, ruleProfileUuids);
return builder.build();
}
+ private DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
+ return (parents, ruleIds) -> {
+ Collection<QProfileDto> profiles = db.qualityProfileDao().selectDescendants(dbSession, parents);
+ Set<String> ruleProfileUuids = profiles.stream()
+ .map(QProfileDto::getRulesProfileUuid)
+ .collect(MoreCollectors.toHashSet());
+ Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleIds, ruleProfileUuids);
+ List<Integer> activeRuleIds = activeRules.stream().map(ActiveRuleDto::getId).collect(MoreCollectors.toArrayList(activeRules.size()));
+ List<ActiveRuleParamDto> activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds);
+ return new DescendantProfilesSupplier.Result(profiles, activeRules, activeRuleParams);
+ };
+ }
+
private List<RuleDefinitionDto> completeWithRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<Integer> ruleIds) {
List<RuleDefinitionDto> rules = db.ruleDao().selectDefinitionByIds(dbSession, ruleIds);
builder.setRules(rules);
return rules;
}
- private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<RuleDefinitionDto> rules, Collection<String> ruleProfileUuids) {
- Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, rules, ruleProfileUuids);
+ private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<Integer> ruleIds, Collection<String> ruleProfileUuids) {
+ Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleIds, ruleProfileUuids);
builder.setActiveRules(activeRules);
List<Integer> activeRuleIds = activeRules.stream().map(ActiveRuleDto::getId).collect(MoreCollectors.toArrayList(activeRules.size()));
builder.setActiveRuleParams(db.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds));