--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.settings.ws;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableTable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.db.property.PropertyDto;
+
+public class Setting {
+
+ private static final Splitter DOT_SPLITTER = Splitter.on(".").omitEmptyStrings();
+
+ private final String key;
+ private final Long componentId;
+ private final String value;
+ private final PropertyDefinition definition;
+ private final List<Map<String, String>> propertySets;
+ private final boolean isDefault;
+
+ /**
+ * Use this constructor to create setting from a property dto, and that can have a definition or not
+ */
+ Setting(PropertyDto propertyDto, List<PropertyDto> propertyDtoSetValues, @Nullable PropertyDefinition definition) {
+ this.key = propertyDto.getKey();
+ this.value = propertyDto.getValue();
+ this.componentId = propertyDto.getResourceId();
+ this.definition = definition;
+ this.propertySets = buildPropertySetValuesAsMap(key, propertyDtoSetValues);
+ this.isDefault = false;
+ }
+
+ /**
+ * Use this constructor to create setting for default value
+ */
+ Setting(PropertyDefinition definition) {
+ this.key = definition.key();
+ this.value = definition.defaultValue();
+ this.componentId = null;
+ this.definition = definition;
+ this.propertySets = Collections.emptyList();
+ this.isDefault = true;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ @CheckForNull
+ public Long getComponentId() {
+ return componentId;
+ }
+
+ @CheckForNull
+ public PropertyDefinition getDefinition() {
+ return definition;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isDefault() {
+ return isDefault;
+ }
+
+ public List<Map<String, String>> getPropertySets() {
+ return propertySets;
+ }
+
+ private static List<Map<String, String>> buildPropertySetValuesAsMap(String propertyKey, List<PropertyDto> propertySets) {
+ if (propertySets.isEmpty()) {
+ return Collections.emptyList();
+ }
+ ImmutableTable.Builder<String, String, String> tableBuilder = new ImmutableTable.Builder<>();
+ propertySets.forEach(property -> {
+ List<String> setIdWithFieldKey = DOT_SPLITTER.splitToList(property.getKey().replace(propertyKey + ".", ""));
+ String setId = setIdWithFieldKey.get(0);
+ String fieldKey = setIdWithFieldKey.get(1);
+ tableBuilder.put(setId, fieldKey, property.getValue());
+ });
+ ImmutableTable<String, String, String> table = tableBuilder.build();
+ return table.rowKeySet().stream()
+ .map(table::row)
+ .collect(Collectors.toList());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.settings.ws;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.TreeMultimap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+
+import static org.sonar.api.PropertyType.PROPERTY_SET;
+
+public class SettingsFinder {
+
+ private static final Splitter DOT_SPLITTER = Splitter.on(".").omitEmptyStrings();
+ private static final Splitter COMMA_SPLITTER = Splitter.on(",");
+
+ private final DbClient dbClient;
+ private final PropertyDefinitions definitions;
+
+ public SettingsFinder(DbClient dbClient, PropertyDefinitions definitions) {
+ this.dbClient = dbClient;
+ this.definitions = definitions;
+ }
+
+ public List<Setting> loadGlobalSettings(DbSession dbSession, Set<String> keys) {
+ List<PropertyDto> properties = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys);
+ List<PropertyDto> propertySets = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, getPropertySetKeys(properties));
+ return properties.stream()
+ .map(property -> new Setting(property, getPropertySets(property.getKey(), propertySets, null), definitions.get(property.getKey())))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Return list of settings by component uuid, sorted from project to lowest module
+ */
+ public Multimap<String, Setting> loadComponentSettings(DbSession dbSession, Set<String> keys, ComponentDto component) {
+ List<String> componentUuids = DOT_SPLITTER.splitToList(component.moduleUuidPath());
+ List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, componentUuids);
+ Set<Long> componentIds = componentDtos.stream().map(ComponentDto::getId).collect(Collectors.toSet());
+ Map<Long, String> uuidsById = componentDtos.stream().collect(Collectors.toMap(ComponentDto::getId, ComponentDto::uuid));
+ List<PropertyDto> properties = dbClient.propertiesDao().selectPropertiesByKeysAndComponentIds(dbSession, keys, componentIds);
+ List<PropertyDto> propertySets = dbClient.propertiesDao().selectPropertiesByKeysAndComponentIds(dbSession, getPropertySetKeys(properties), componentIds);
+
+ Multimap<String, Setting> settingsByUuid = TreeMultimap.create(Ordering.explicit(componentUuids), Ordering.arbitrary());
+ for (PropertyDto propertyDto : properties) {
+ Long componentId = propertyDto.getResourceId();
+ String componentUuid = uuidsById.get(componentId);
+ String propertyKey = propertyDto.getKey();
+ settingsByUuid.put(componentUuid,
+ new Setting(propertyDto, getPropertySets(propertyKey, propertySets, componentId), definitions.get(propertyKey)));
+ }
+ return settingsByUuid;
+ }
+
+ private Set<String> getPropertySetKeys(List<PropertyDto> properties) {
+ Set<String> propertySetKeys = new HashSet<>();
+ properties.stream()
+ .filter(propertyDto -> definitions.get(propertyDto.getKey()) != null)
+ .filter(propertyDto -> definitions.get(propertyDto.getKey()).type().equals(PROPERTY_SET))
+ .forEach(propertyDto -> definitions.get(propertyDto.getKey()).fields()
+ .forEach(field -> COMMA_SPLITTER.splitToList(propertyDto.getValue())
+ .forEach(setId -> propertySetKeys.add(generatePropertySetKey(propertyDto.getKey(), setId, field.key())))));
+ return propertySetKeys;
+ }
+
+ private static String generatePropertySetKey(String propertyBaseKey, String id, String fieldKey) {
+ return propertyBaseKey + "." + id + "." + fieldKey;
+ }
+
+ private static List<PropertyDto> getPropertySets(String propertyKey, List<PropertyDto> propertySets, @Nullable Long componentId) {
+ return propertySets.stream()
+ .filter(propertyDto -> Objects.equals(propertyDto.getResourceId(), componentId))
+ .filter(propertyDto -> propertyDto.getKey().startsWith(propertyKey + "."))
+ .collect(Collectors.toList());
+ }
+
+}
SetAction.class,
SettingsWsComponentParameters.class,
ListDefinitionsAction.class,
- ValuesAction.class);
+ ValuesAction.class,
+ SettingsFinder.class);
}
}
package org.sonar.server.settings.ws;
import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableTable;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
+import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.property.PropertyDto;
import org.sonarqube.ws.Settings;
import org.sonarqube.ws.Settings.ValuesWsResponse;
private static final Splitter COMMA_SPLITTER = Splitter.on(",");
- static final String PARAM_KEYS = "keys";
+ private static final String PARAM_KEYS = "keys";
private final DbClient dbClient;
private final SettingsWsComponentParameters settingsWsComponentParameters;
private final PropertyDefinitions propertyDefinitions;
+ private final SettingsFinder settingsFinder;
- public ValuesAction(DbClient dbClient, SettingsWsComponentParameters settingsWsComponentParameters, PropertyDefinitions propertyDefinitions) {
+ public ValuesAction(DbClient dbClient, SettingsWsComponentParameters settingsWsComponentParameters, PropertyDefinitions propertyDefinitions, SettingsFinder settingsFinder) {
this.dbClient = dbClient;
this.settingsWsComponentParameters = settingsWsComponentParameters;
this.propertyDefinitions = propertyDefinitions;
+ this.settingsFinder = settingsFinder;
}
@Override
private ValuesWsResponse doHandle(Request request) {
DbSession dbSession = dbClient.openSession(true);
try {
- ComponentDto component = settingsWsComponentParameters.getComponent(dbSession, request);
- settingsWsComponentParameters.checkAdminPermission(component);
+ ComponentDto componentDto = settingsWsComponentParameters.getComponent(dbSession, request);
+ settingsWsComponentParameters.checkAdminPermission(componentDto);
Set<String> keys = new HashSet<>(request.mandatoryParamAsStrings(PARAM_KEYS));
-
- ValuesWsResponse.Builder valuesBuilder = ValuesWsResponse.newBuilder();
- new SettingsBuilder(dbSession, valuesBuilder, getDefinitions(keys), keys, component).build();
- ValuesWsResponse response = valuesBuilder.build();
- return response;
+ Optional<ComponentDto> component = Optional.ofNullable(componentDto);
+ return new ValuesResponseBuilder(loadSettings(dbSession, component, keys), component).build();
} finally {
dbClient.closeSession(dbSession);
}
}
- private class SettingsBuilder {
- private final DbSession dbSession;
- private final ComponentDto component;
+ private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys) {
+ if (keys.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // List of settings must be kept in the following orders : default -> global -> component
+ List<Setting> settings = new ArrayList<>();
+ settings.addAll(loadDefaultSettings(keys));
+ settings.addAll(settingsFinder.loadGlobalSettings(dbSession, keys));
+ if (component.isPresent()) {
+ settings.addAll(settingsFinder.loadComponentSettings(dbSession, keys, component.get()).values());
+ }
+ return settings;
+ }
+
+ private List<Setting> loadDefaultSettings(Set<String> keys) {
+ return propertyDefinitions.getAll().stream()
+ .filter(definition -> keys.contains(definition.key()))
+ .filter(defaultProperty -> !isNullOrEmpty(defaultProperty.defaultValue()))
+ .map(Setting::new)
+ .collect(Collectors.toList());
+ }
- private final ValuesWsResponse.Builder valuesWsBuilder;
- private final Map<String, PropertyDefinition> definitionsByKey;
- private final Set<String> keys;
- private final Set<String> propertySetKeys;
+ private class ValuesResponseBuilder {
+ private final List<Setting> settings;
+ private final Optional<ComponentDto> component;
+ private final ValuesWsResponse.Builder valuesWsBuilder = ValuesWsResponse.newBuilder();
private final Map<String, Settings.Setting.Builder> settingsBuilderByKey = new HashMap<>();
- SettingsBuilder(DbSession dbSession, ValuesWsResponse.Builder valuesWsBuilder, List<PropertyDefinition> definitions,
- Set<String> keys, @Nullable ComponentDto component) {
- this.dbSession = dbSession;
- this.valuesWsBuilder = valuesWsBuilder;
- this.definitionsByKey = definitions.stream()
- .collect(Collectors.toMap(PropertyDefinition::key, Function.identity()));
- this.keys = keys;
+ ValuesResponseBuilder(List<Setting> settings, Optional<ComponentDto> component) {
+ this.settings = settings;
this.component = component;
-
- this.propertySetKeys = definitions.stream()
- .filter(definition -> definition.type().equals(PROPERTY_SET))
- .map(PropertyDefinition::key)
- .collect(Collectors.toSet());
}
- void build() {
- processDefinitions();
- processPropertyDtos(true);
- if (component != null) {
- processPropertyDtos(false);
- }
+ ValuesWsResponse build() {
+ processSettings();
settingsBuilderByKey.values().forEach(Settings.Setting.Builder::build);
+ return valuesWsBuilder.build();
}
- private void processDefinitions() {
- definitionsByKey.values().stream()
- .filter(defaultProperty -> !isNullOrEmpty(defaultProperty.defaultValue()))
- .forEach(this::processDefaultValue);
- }
-
- private void processDefaultValue(PropertyDefinition definition) {
- Settings.Setting.Builder settingBuilder = valuesWsBuilder.addSettingsBuilder()
- .setKey(definition.key())
- .setInherited(false)
- .setDefault(true);
- setValue(settingBuilder, definition.defaultValue());
- settingsBuilderByKey.put(definition.key(), settingBuilder);
- }
-
- private void processPropertyDtos(boolean loadGlobal) {
- List<PropertyDto> properties = loadProperties(dbSession, loadGlobal, keys);
- PropertySetValues propertySetValues = new PropertySetValues(properties, loadGlobal);
-
- properties.forEach(property -> {
- String key = property.getKey();
- Settings.Setting.Builder valueBuilder = getOrCreateValueBuilder(key);
- valueBuilder.setInherited(component != null && property.getResourceId() == null);
- valueBuilder.setDefault(false);
-
- PropertyDefinition definition = definitionsByKey.get(key);
- if (definition != null && definition.type().equals(PROPERTY_SET)) {
- Settings.FieldsValues.Builder builder = Settings.FieldsValues.newBuilder();
- for (Map<String, String> propertySetMap : propertySetValues.get(key)) {
- builder.addFieldsValuesBuilder().putAllValue(propertySetMap);
- }
- valueBuilder.setFieldsValues(builder);
- } else {
- setValue(valueBuilder, property.getValue());
- }
+ private void processSettings() {
+ settings.forEach(setting -> {
+ Settings.Setting.Builder valueBuilder = getOrCreateValueBuilder(setting.getKey());
+ valueBuilder.setDefault(setting.isDefault());
+ setInherited(setting, valueBuilder);
+ setValue(setting, valueBuilder);
});
}
return valueBuilder;
}
- private void setValue(Settings.Setting.Builder valueBuilder, String value) {
- PropertyDefinition definition = definitionsByKey.get(valueBuilder.getKey());
- if (definition != null && definition.multiValues()) {
+ private void setValue(Setting setting, Settings.Setting.Builder valueBuilder) {
+ PropertyDefinition definition = setting.getDefinition();
+ String value = setting.getValue();
+ if (definition == null) {
+ valueBuilder.setValue(value);
+ return;
+ }
+ if (definition.type().equals(PROPERTY_SET)) {
+ Settings.FieldsValues.Builder builder = Settings.FieldsValues.newBuilder();
+ for (Map<String, String> propertySetMap : setting.getPropertySets()) {
+ builder.addFieldsValuesBuilder().putAllValue(propertySetMap);
+ }
+ valueBuilder.setFieldsValues(builder);
+ } else if (definition.multiValues()) {
valueBuilder.setValues(Settings.Values.newBuilder().addAllValues(COMMA_SPLITTER.split(value)));
} else {
valueBuilder.setValue(value);
}
}
- private List<PropertyDto> loadProperties(DbSession dbSession, boolean loadGlobal, Set<String> keys) {
- if (loadGlobal) {
- return dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys);
- }
- return dbClient.propertiesDao().selectComponentPropertiesByKeys(dbSession, keys, component.getId());
- }
-
- private class PropertySetValues {
- private final Map<String, PropertyKeyWithFieldAndSetId> propertyKeyWithFieldAndSetIds = new HashMap<>();
- private final Map<String, PropertySetValue> propertySetValuesByPropertyKey = new HashMap<>();
-
- PropertySetValues(List<PropertyDto> properties, boolean loadGlobal) {
- properties.stream()
- .filter(propertyDto -> propertySetKeys.contains(propertyDto.getKey()))
- .forEach(propertyDto -> definitionsByKey.get(propertyDto.getKey()).fields()
- .forEach(field -> COMMA_SPLITTER.splitToList(propertyDto.getValue())
- .forEach(value -> add(propertyDto.getKey(), field.key(), value))));
-
- loadProperties(dbSession, loadGlobal, propertyKeyWithFieldAndSetIds.keySet())
- .forEach(propertySetDto -> {
- PropertyKeyWithFieldAndSetId propertyKeyWithFieldAndSetIdKey = propertyKeyWithFieldAndSetIds.get(propertySetDto.getKey());
- PropertySetValue propertySetValue = getOrCreatePropertySetValue(propertyKeyWithFieldAndSetIdKey.getPropertyKey());
- propertySetValue.add(propertyKeyWithFieldAndSetIdKey.getSetId(), propertyKeyWithFieldAndSetIdKey.getFieldKey(), propertySetDto.getValue());
- });
- }
-
- private void add(String propertyKey, String fieldKey, String value) {
- String propertySetKey = generatePropertySetKey(propertyKey, value, fieldKey);
- propertyKeyWithFieldAndSetIds.put(propertySetKey, new PropertyKeyWithFieldAndSetId(propertyKey, fieldKey, value));
- }
-
- private PropertySetValue getOrCreatePropertySetValue(String propertyKey) {
- PropertySetValue propertySetValue = propertySetValuesByPropertyKey.get(propertyKey);
- if (propertySetValue == null) {
- propertySetValue = new PropertySetValue();
- propertySetValuesByPropertyKey.put(propertyKey, propertySetValue);
- }
- return propertySetValue;
- }
-
- List<Map<String, String>> get(String propertyKey) {
- return propertySetValuesByPropertyKey.get(propertyKey).get();
- }
-
- private String generatePropertySetKey(String propertyKey, String id, String fieldKey) {
- return propertyKey + "." + id + "." + fieldKey;
+ private void setInherited(Setting setting, Settings.Setting.Builder valueBuilder) {
+ if (setting.isDefault()) {
+ valueBuilder.setInherited(false);
+ } else {
+ valueBuilder.setInherited(component.isPresent() && !Objects.equals(setting.getComponentId(), component.get().getId()));
}
}
}
- private List<PropertyDefinition> getDefinitions(Set<String> keys) {
- return propertyDefinitions.getAll().stream()
- .filter(def -> keys.contains(def.key()))
- .collect(Collectors.toList());
- }
-
- private static class PropertyKeyWithFieldAndSetId {
- private final String propertyKey;
- private final String fieldKey;
- private final String setId;
-
- PropertyKeyWithFieldAndSetId(String propertyKey, String fieldKey, String setId) {
- this.propertyKey = propertyKey;
- this.fieldKey = fieldKey;
- this.setId = setId;
- }
-
- public String getPropertyKey() {
- return propertyKey;
- }
-
- public String getFieldKey() {
- return fieldKey;
- }
-
- public String getSetId() {
- return setId;
- }
- }
-
- private static class PropertySetValue {
- ImmutableTable.Builder<String, String, String> tableBuilder = new ImmutableTable.Builder<>();
-
- public void add(String setId, String fieldKey, String value) {
- tableBuilder.put(setId, fieldKey, value);
- }
-
- public List<Map<String, String>> get() {
- ImmutableTable<String, String, String> table = tableBuilder.build();
- return table.rowKeySet().stream()
- .map(table::row)
- .collect(Collectors.toList());
- }
- }
-
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.settings.ws;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.PropertyFieldDefinition;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+
+import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.sonar.api.PropertyType.PROPERTY_SET;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
+import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
+
+public class SettingsFinderTest {
+
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+
+ DbClient dbClient = db.getDbClient();
+ DbSession dbSession = db.getSession();
+ ComponentDbTester componentDb = new ComponentDbTester(db);
+ PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
+
+ SettingsFinder underTest = new SettingsFinder(dbClient, propertyDefinitions);
+
+ @Test
+ public void return_global_settings() throws Exception {
+ PropertyDefinition definition = PropertyDefinition.builder("foo").build();
+ addDefinitions(definition);
+ insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));
+
+ List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("foo"));
+ assertThat(settings).hasSize(1);
+ assertSetting(settings.get(0), "foo", "one", null, true);
+
+ assertThat(underTest.loadGlobalSettings(dbSession, newHashSet("unknown"))).isEmpty();
+ }
+
+ @Test
+ public void return_global_setting_even_if_no_definition() throws Exception {
+ insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));
+
+ List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("foo"));
+ assertThat(settings).hasSize(1);
+ assertSetting(settings.get(0), "foo", "one", null, false);
+ }
+
+ @Test
+ public void return_global_settings_with_property_set() throws Exception {
+ addDefinitions(PropertyDefinition.builder("set1")
+ .type(PROPERTY_SET)
+ .fields(asList(
+ PropertyFieldDefinition.build("key").name("Key").build(),
+ PropertyFieldDefinition.build("size").name("Size").build()))
+ .build(),
+ PropertyDefinition.builder("another")
+ .type(PROPERTY_SET)
+ .fields(singletonList(PropertyFieldDefinition.build("key").name("Key").build()))
+ .build());
+ insertProperties(
+ newGlobalPropertyDto().setKey("set1").setValue("1,2"),
+ newGlobalPropertyDto().setKey("set1.1.key").setValue("key1"),
+ newGlobalPropertyDto().setKey("set1.1.size").setValue("size1"),
+ newGlobalPropertyDto().setKey("set1.2.key").setValue("key2"),
+ newGlobalPropertyDto().setKey("set2").setValue("1"),
+ newGlobalPropertyDto().setKey("another.1.key").setValue("key1"));
+
+ List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("set1"));
+ assertThat(settings).hasSize(1);
+ assertSetting(settings.get(0), "set1", "1,2", null, true, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
+ }
+
+ @Test
+ public void return_component_settings() throws Exception {
+ ComponentDto project = componentDb.insertComponent(newProjectDto());
+ addDefinitions(PropertyDefinition.builder("property").defaultValue("default").build());
+ insertProperties(newComponentPropertyDto(project).setKey("property").setValue("one"));
+
+ Multimap<String, Setting> result = underTest.loadComponentSettings(dbSession, newHashSet("property"), project);
+ assertThat(result.values()).hasSize(1);
+ List<Setting> settings = new ArrayList<>(result.get(project.uuid()));
+ assertThat(settings).hasSize(1);
+ assertSetting(settings.get(0), "property", "one", project.getId(), true);
+
+ assertThat(underTest.loadComponentSettings(dbSession, newHashSet("unknown"), project)).isEmpty();
+ }
+
+ @Test
+ public void return_component_setting_even_if_no_definition() throws Exception {
+ ComponentDto project = componentDb.insertComponent(newProjectDto());
+ insertProperties(newComponentPropertyDto(project).setKey("property").setValue("one"));
+
+ Multimap<String, Setting> settings = underTest.loadComponentSettings(dbSession, newHashSet("property"), project);
+ assertThat(settings.values()).hasSize(1);
+ assertSetting(settings.get(project.uuid()).iterator().next(), "property", "one", project.getId(), false);
+ }
+
+ @Test
+ public void return_component_settings_with_property_set() throws Exception {
+ ComponentDto project = componentDb.insertComponent(newProjectDto());
+ addDefinitions(PropertyDefinition.builder("set1")
+ .type(PROPERTY_SET)
+ .fields(asList(
+ PropertyFieldDefinition.build("key").name("Key").build(),
+ PropertyFieldDefinition.build("size").name("Size").build()))
+ .build(),
+ PropertyDefinition.builder("another")
+ .type(PROPERTY_SET)
+ .fields(singletonList(PropertyFieldDefinition.build("key").name("Key").build()))
+ .build());
+ insertProperties(
+ newComponentPropertyDto(project).setKey("set1").setValue("1,2"),
+ newComponentPropertyDto(project).setKey("set1.1.key").setValue("key1"),
+ newComponentPropertyDto(project).setKey("set1.1.size").setValue("size1"),
+ newComponentPropertyDto(project).setKey("set1.2.key").setValue("key2"),
+ newComponentPropertyDto(project).setKey("set2").setValue("1"),
+ newComponentPropertyDto(project).setKey("another.1.key").setValue("key1"));
+
+ Multimap<String, Setting> settings = underTest.loadComponentSettings(dbSession, newHashSet("set1"), project);
+ assertThat(settings).hasSize(1);
+ assertSetting(settings.get(project.uuid()).iterator().next(), "set1", "1,2", project.getId(), true, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
+ }
+
+ @Test
+ public void return_module_settings() throws Exception {
+ ComponentDto project = componentDb.insertComponent(newProjectDto());
+ ComponentDto module = componentDb.insertComponent(newModuleDto(project));
+ ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
+ ComponentDto anotherProject = componentDb.insertComponent(newProjectDto());
+
+ insertProperties(
+ newComponentPropertyDto(project).setKey("property").setValue("one"),
+ newComponentPropertyDto(module).setKey("property").setValue("two"),
+ newComponentPropertyDto(subModule).setKey("property2").setValue("three"),
+ newComponentPropertyDto(anotherProject).setKey("property").setValue("another one"));
+
+ Multimap<String, Setting> result = underTest.loadComponentSettings(dbSession, newHashSet("property", "property2"), subModule);
+ assertThat(result).hasSize(3);
+ assertThat(result.keySet()).containsExactly(project.uuid(), module.uuid(), subModule.uuid());
+
+ assertSetting(result.get(subModule.uuid()).iterator().next(), "property2", "three", subModule.getId(), false);
+ assertSetting(result.get(module.uuid()).iterator().next(), "property", "two", module.getId(), false);
+ assertSetting(result.get(project.uuid()).iterator().next(), "property", "one", project.getId(), false);
+ }
+
+ private void assertSetting(Setting setting, String expectedKey, String expectedValue, @Nullable Long expectedComponentId, boolean hasPropertyDefinition,
+ Map<String, String>... propertySets) {
+ assertThat(setting.getKey()).isEqualTo(expectedKey);
+ assertThat(setting.getValue()).isEqualTo(expectedValue);
+ assertThat(setting.getComponentId()).isEqualTo(expectedComponentId);
+ if (hasPropertyDefinition) {
+ assertThat(setting.getDefinition()).isEqualTo(propertyDefinitions.get(expectedKey));
+ } else {
+ assertThat(setting.getDefinition()).isNull();
+ }
+ assertThat(setting.getPropertySets()).containsOnly(propertySets);
+ }
+
+ private void insertProperties(PropertyDto... properties) {
+ for (PropertyDto propertyDto : properties) {
+ dbClient.propertiesDao().insertProperty(dbSession, propertyDto);
+ }
+ dbSession.commit();
+ }
+
+ private void addDefinitions(PropertyDefinition... definitions) {
+ propertyDefinitions.addComponents(asList(definitions));
+ }
+}
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new SettingsWsModule().configure(container);
- assertThat(container.size()).isEqualTo(5 + 2);
+ assertThat(container.size()).isEqualTo(6 + 2);
}
}
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
ComponentDbTester componentDb = new ComponentDbTester(db);
SettingsWsComponentParameters settingsWsComponentParameters = new SettingsWsComponentParameters(new ComponentFinder(dbClient), userSession);
PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
+ SettingsFinder settingsFinder = new SettingsFinder(dbClient, propertyDefinitions);
ComponentDto project;
- WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, settingsWsComponentParameters, propertyDefinitions));
+ WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, settingsWsComponentParameters, propertyDefinitions, settingsFinder));
@Before
public void setUp() throws Exception {
ValuesWsResponse result = newRequestForGlobalProperties("foo");
assertThat(result.getSettingsList()).hasSize(1);
-
- Settings.Setting value = result.getSettings(0);
- assertThat(value.getKey()).isEqualTo("foo");
- assertThat(value.getValue()).isEqualTo("default");
- assertThat(value.getDefault()).isTrue();
- assertThat(value.getInherited()).isFalse();
+ assertSetting(result.getSettings(0), "foo", "default", true, false);
}
@Test
ValuesWsResponse result = newRequestForGlobalProperties("property");
assertThat(result.getSettingsList()).hasSize(1);
-
- Settings.Setting globalPropertyValue = result.getSettings(0);
- assertThat(globalPropertyValue.getKey()).isEqualTo("property");
- assertThat(globalPropertyValue.getValue()).isEqualTo("one");
- assertThat(globalPropertyValue.getDefault()).isFalse();
- assertThat(globalPropertyValue.getInherited()).isFalse();
+ assertSetting(result.getSettings(0), "property", "one", false, false);
}
@Test
ValuesWsResponse result = newRequestForProjectProperties("property");
assertThat(result.getSettingsList()).hasSize(1);
-
- Settings.Setting globalPropertyValue = result.getSettings(0);
- assertThat(globalPropertyValue.getKey()).isEqualTo("property");
- assertThat(globalPropertyValue.getValue()).isEqualTo("two");
- assertThat(globalPropertyValue.getDefault()).isFalse();
- assertThat(globalPropertyValue.getInherited()).isFalse();
+ assertSetting(result.getSettings(0), "property", "two", false, false);
}
@Test
ValuesWsResponse result = newRequestForProjectProperties("property");
assertThat(result.getSettingsList()).hasSize(1);
-
- Settings.Setting globalPropertyValue = result.getSettings(0);
- assertThat(globalPropertyValue.getKey()).isEqualTo("property");
- assertThat(globalPropertyValue.getValue()).isEqualTo("one");
- assertThat(globalPropertyValue.getDefault()).isFalse();
- assertThat(globalPropertyValue.getInherited()).isTrue();
+ assertSetting(result.getSettings(0), "property", "one", false, true);
}
@Test
assertThat(result.getSettingsList()).isEmpty();
}
+ @Test
+ public void return_module_values() throws Exception {
+ setUserAsSystemAdmin();
+ ComponentDto module = componentDb.insertComponent(newModuleDto(project));
+
+ propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
+ insertProperties(
+ newGlobalPropertyDto().setKey("property").setValue("one"),
+ // The property is overriding global value
+ newComponentPropertyDto(module).setKey("property").setValue("two"));
+
+ ValuesWsResponse result = newRequestForComponentProperties(module, "property");
+ assertThat(result.getSettingsList()).hasSize(1);
+ assertSetting(result.getSettings(0), "property", "two", false, false);
+ }
+
+ @Test
+ public void return_inherited_values_on_sub_module() throws Exception {
+ setUserAsSystemAdmin();
+ ComponentDto module = componentDb.insertComponent(newModuleDto(project));
+ ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
+
+ propertyDefinitions.addComponents(asList(
+ PropertyDefinition.builder("defaultProperty").defaultValue("default").build(),
+ PropertyDefinition.builder("globalProperty").build(),
+ PropertyDefinition.builder("projectProperty").build(),
+ PropertyDefinition.builder("moduleProperty").build()));
+ insertProperties(
+ newGlobalPropertyDto().setKey("globalProperty").setValue("global"),
+ newComponentPropertyDto(project).setKey("projectProperty").setValue("project"),
+ newComponentPropertyDto(module).setKey("moduleProperty").setValue("module"));
+
+ ValuesWsResponse result = newRequestForComponentProperties(subModule, "defaultProperty", "globalProperty", "projectProperty", "moduleProperty");
+ assertThat(result.getSettingsList()).hasSize(4);
+ assertSetting(result.getSettings(0), "defaultProperty", "default", true, false);
+ assertSetting(result.getSettings(1), "globalProperty", "global", false, true);
+ assertSetting(result.getSettings(2), "projectProperty", "project", false, true);
+ assertSetting(result.getSettings(3), "moduleProperty", "module", false, true);
+ }
+
@Test
public void test_example_json_response() {
setUserAsSystemAdmin();
assertThat(action.params()).hasSize(3);
}
+ private ValuesWsResponse newRequestForComponentProperties(ComponentDto componentDto, String... keys) {
+ return newRequest(componentDto.uuid(), null, keys);
+ }
+
private ValuesWsResponse newRequestForProjectProperties(String... keys) {
return newRequest(project.uuid(), null, keys);
}
dbSession.commit();
}
+ private void assertSetting(Settings.Setting setting, String expectedKey, String expectedValue, boolean expectedDefault, boolean expectedInherited) {
+ assertThat(setting.getKey()).isEqualTo(expectedKey);
+ assertThat(setting.getValue()).isEqualTo(expectedValue);
+ assertThat(setting.getDefault()).isEqualTo(expectedDefault);
+ assertThat(setting.getInherited()).isEqualTo(expectedInherited);
+ }
+
}
return selectByKeys(session, keys, null);
}
- public List<PropertyDto> selectComponentPropertiesByKeys(DbSession session, Set<String> keys, long componentId) {
+ public List<PropertyDto> selectPropertiesByKeysAndComponentId(DbSession session, Set<String> keys, long componentId) {
return selectByKeys(session, keys, componentId);
}
+ public List<PropertyDto> selectPropertiesByKeysAndComponentIds(DbSession session, Set<String> keys, Set<Long> componentIds) {
+ return executeLargeInputs(keys, partitionKeys -> executeLargeInputs(componentIds,
+ partitionComponentIds -> session.getMapper(PropertiesMapper.class).selectByKeysAndComponentIds(partitionKeys, partitionComponentIds)));
+ }
+
private List<PropertyDto> selectByKeys(DbSession session, Set<String> keys, @Nullable Long componentId) {
- return executeLargeInputs(keys, propertyKeys -> session.getMapper(PropertiesMapper.class).selectByKeys(propertyKeys, componentId));
+ return executeLargeInputs(keys, partitionKeys -> session.getMapper(PropertiesMapper.class).selectByKeys(partitionKeys, componentId));
}
public void insertProperty(DbSession session, PropertyDto property) {
List<PropertyDto> selectByKeys(@Param("keys") List<String> keys, @Nullable @Param("componentId") Long componentId);
+ List<PropertyDto> selectByKeysAndComponentIds(@Param("keys") List<String> keys, @Param("componentIds") List<Long> componentIds);
+
List<PropertyDto> selectByQuery(@Param("query") PropertyQuery query);
List<PropertyDto> selectDescendantModuleProperties(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope,
</where>
</select>
+ <select id="selectByKeysAndComponentIds" parameterType="map" resultType="Property">
+ SELECT p.id as id, p.prop_key as "key", p.text_value as value, p.resource_id as resourceId, p.user_id as userId
+ FROM properties p
+ <where>
+ AND p.prop_key in
+ <foreach collection="keys" open="(" close=")" item="key" separator=",">
+ #{key}
+ </foreach>
+ AND p.resource_id in
+ <foreach collection="componentIds" open="(" close=")" item="componentId" separator=",">
+ #{componentId}
+ </foreach>
+ AND p.user_id is null
+ </where>
+ </select>
+
<select id="selectByQuery" parameterType="map" resultType="Property">
select p.id as id, p.prop_key as "key", p.text_value as value, p.resource_id as resourceId, p.user_id as userId
from properties p
import com.google.common.collect.ImmutableMap;
import java.util.List;
+import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
newUserPropertyDto(user).setKey(key),
newComponentPropertyDto(project).setKey(anotherKey));
- assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key);
- assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey);
- assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey);
+ assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key);
+ assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey);
+ assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey);
- assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet("unknown"), project.getId())).isEmpty();
- assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key), 123456789L)).isEmpty();
+ assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet("unknown"), project.getId())).isEmpty();
+ assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key), 123456789L)).isEmpty();
+ }
+
+ @Test
+ public void select_properties_by_keys_and_component_ids() throws Exception {
+ ComponentDto project = ComponentTesting.newProjectDto();
+ dbClient.componentDao().insert(session, project);
+ ComponentDto project2 = ComponentTesting.newProjectDto();
+ dbClient.componentDao().insert(session, project2);
+
+ UserDto user = UserTesting.newUserDto();
+ dbClient.userDao().insert(session, user);
+
+ String key = "key";
+ String anotherKey = "anotherKey";
+ insertProperties(
+ newGlobalPropertyDto().setKey(key),
+ newComponentPropertyDto(project).setKey(key),
+ newComponentPropertyDto(project2).setKey(key),
+ newComponentPropertyDto(project2).setKey(anotherKey),
+ newUserPropertyDto(user).setKey(key));
+
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key), newHashSet(project.getId())))
+ .extracting("key", "resourceId").containsOnly(Tuple.tuple(key, project.getId()));
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key), newHashSet(project.getId(), project2.getId())))
+ .extracting("key", "resourceId").containsOnly(
+ Tuple.tuple(key, project.getId()),
+ Tuple.tuple(key, project2.getId()));
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key, anotherKey), newHashSet(project.getId(), project2.getId())))
+ .extracting("key", "resourceId").containsOnly(
+ Tuple.tuple(key, project.getId()),
+ Tuple.tuple(key, project2.getId()),
+ Tuple.tuple(anotherKey, project2.getId()));
+
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("unknown"), newHashSet(project.getId()))).isEmpty();
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("key"), newHashSet(123456789L))).isEmpty();
+ assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("unknown"), newHashSet(123456789L))).isEmpty();
}
@Test