]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5849 Extract logic from ProjectReferentialsAction to ProjectReferentialsLoader
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 30 Dec 2014 17:07:24 +0000 (18:07 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 30 Dec 2014 17:57:54 +0000 (18:57 +0100)
47 files changed:
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsAction.java
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsLoader.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsQuery.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/persistence/SnapshotDao.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterContext.java
server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/test/java/org/sonar/server/batch/BatchWsTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsLoaderMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/persistence/SnapshotDaoTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterExecutorTest.java
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/not_returned_secured_settings_with_only_preview_permission.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_active_rules.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_settings.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings_inherited_from_project.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_with_sub_module.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_two_modules.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_provisioned_project_profile.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_given_profile_name.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles_even_when_project_does_not_exists.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_including_settings_from_parent_modules.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project_and_module.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/empty.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/insert-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/shared.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/snapshots.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/component/db/SnapshotMapper.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java
sonar-core/src/main/java/org/sonar/core/resource/SnapshotDto.java [deleted file]
sonar-core/src/main/resources/org/sonar/core/component/db/SnapshotMapper.xml [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml
sonar-core/src/test/java/org/sonar/core/resource/ResourceDaoTest.java
sonar-core/src/test/java/org/sonar/core/resource/SnapshotDtoTest.java [deleted file]

index 6988fda03b512eaee0047952755582756e94810f..34a51d73aba4ce8fb59a51469668106bcc8ca7c6 100644 (file)
 
 package org.sonar.server.batch;
 
-import com.google.common.collect.Maps;
 import org.apache.commons.io.IOUtils;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.batch.protocol.input.ProjectReferentials;
-import org.sonar.core.UtcDateUtils;
-import org.sonar.core.component.AuthorizedComponentDto;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.properties.PropertiesDao;
-import org.sonar.core.properties.PropertyDto;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.plugins.MimeTypes;
-import org.sonar.server.qualityprofile.ActiveRule;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.rule.Rule;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.user.UserSession;
-
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
 
 public class ProjectReferentialsAction implements RequestHandler {
 
@@ -63,21 +34,10 @@ public class ProjectReferentialsAction implements RequestHandler {
   private static final String PARAM_PROFILE = "profile";
   private static final String PARAM_PREVIEW = "preview";
 
-  private final DbClient dbClient;
-  private final PropertiesDao propertiesDao;
-  private final QProfileFactory qProfileFactory;
-  private final QProfileLoader qProfileLoader;
-  private final RuleService ruleService;
-  private final Languages languages;
+  private final ProjectReferentialsLoader projectReferentialsLoader;
 
-  public ProjectReferentialsAction(DbClient dbClient, PropertiesDao propertiesDao, QProfileFactory qProfileFactory, QProfileLoader qProfileLoader,
-    RuleService ruleService, Languages languages) {
-    this.dbClient = dbClient;
-    this.propertiesDao = propertiesDao;
-    this.qProfileFactory = qProfileFactory;
-    this.qProfileLoader = qProfileLoader;
-    this.ruleService = ruleService;
-    this.languages = languages;
+  public ProjectReferentialsAction(ProjectReferentialsLoader projectReferentialsLoader) {
+    this.projectReferentialsLoader = projectReferentialsLoader;
   }
 
   void define(WebService.NewController controller) {
@@ -107,162 +67,11 @@ public class ProjectReferentialsAction implements RequestHandler {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    boolean hasScanPerm = UserSession.get().hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
-    boolean preview = request.mandatoryParamAsBoolean(PARAM_PREVIEW);
-    checkPermission(preview);
-
-    DbSession session = dbClient.openSession(false);
-    try {
-      ProjectReferentials ref = new ProjectReferentials();
-
-      String projectOrModuleKey = request.mandatoryParam(PARAM_KEY);
-      String profileName = request.param(PARAM_PROFILE);
-
-      String projectKey = null;
-      AuthorizedComponentDto module = dbClient.componentDao().getNullableAuthorizedComponentByKey(projectOrModuleKey, session);
-      // Current project can be null when analysing a new project
-      if (module != null) {
-        ComponentDto project = dbClient.componentDao().getNullableRootProjectByKey(projectOrModuleKey, session);
-        // Can be null if the given project is a provisioned one
-        if (project != null) {
-          if (!project.key().equals(module.key())) {
-            addSettings(ref, module.getKey(), getSettingsFromParents(module.key(), hasScanPerm, session));
-          }
-          projectKey = project.key();
-          addSettingsToChildrenModules(ref, projectOrModuleKey, Maps.<String, String>newHashMap(), hasScanPerm, session);
-        } else {
-          // Add settings of the provisioned project
-          addSettings(ref, projectOrModuleKey, getPropertiesMap(propertiesDao.selectProjectProperties(projectOrModuleKey, session), hasScanPerm));
-          projectKey = projectOrModuleKey;
-        }
-      }
-
-      addProfiles(ref, projectKey, profileName, session);
-      addActiveRules(ref);
-
-      response.stream().setMediaType(MimeTypes.JSON);
-      IOUtils.write(ref.toJson(), response.stream().output());
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  private Map<String, String> getSettingsFromParents(String moduleKey, boolean hasScanPerm, DbSession session) {
-    List<ComponentDto> parents = newArrayList();
-    aggregateParentModules(moduleKey, parents, session);
-    Collections.reverse(parents);
-
-    Map<String, String> parentProperties = newHashMap();
-    for (ComponentDto parent : parents) {
-      parentProperties.putAll(getPropertiesMap(propertiesDao.selectProjectProperties(parent.key(), session), hasScanPerm));
-    }
-    return parentProperties;
-  }
-
-  private void aggregateParentModules(String component, List<ComponentDto> parents, DbSession session){
-    ComponentDto parent = dbClient.componentDao().getParentModuleByKey(component, session);
-    if (parent != null) {
-      parents.add(parent);
-      aggregateParentModules(parent.key(), parents, session);
-    }
-  }
-
-  private void addSettingsToChildrenModules(ProjectReferentials ref, String projectKey, Map<String, String> parentProperties, boolean hasScanPerm, DbSession session) {
-    Map<String, String> currentParentProperties = newHashMap();
-    currentParentProperties.putAll(parentProperties);
-    currentParentProperties.putAll(getPropertiesMap(propertiesDao.selectProjectProperties(projectKey, session), hasScanPerm));
-    addSettings(ref, projectKey, currentParentProperties);
-
-    for (ComponentDto module : dbClient.componentDao().findModulesByProject(projectKey, session)) {
-      addSettings(ref, module.key(), currentParentProperties);
-      addSettingsToChildrenModules(ref, module.key(), currentParentProperties, hasScanPerm, session);
-    }
+    ProjectReferentials ref = projectReferentialsLoader.load(ProjectReferentialsQuery.create()
+      .setModuleKey(request.mandatoryParam(PARAM_KEY))
+      .setProfileName(request.param(PARAM_PROFILE))
+      .setPreview(request.mandatoryParamAsBoolean(PARAM_PREVIEW)));
+    response.stream().setMediaType(MimeTypes.JSON);
+    IOUtils.write(ref.toJson(), response.stream().output());
   }
-
-  private void addSettings(ProjectReferentials ref, String module, Map<String, String> properties) {
-    if (!properties.isEmpty()) {
-      ref.addSettings(module, properties);
-    }
-  }
-
-  private Map<String, String> getPropertiesMap(List<PropertyDto> propertyDtos, boolean hasScanPerm) {
-    Map<String, String> properties = newHashMap();
-    for (PropertyDto propertyDto : propertyDtos) {
-      String key = propertyDto.getKey();
-      String value = propertyDto.getValue();
-      if (isPropertyAllowed(key, hasScanPerm)) {
-        properties.put(key, value);
-      }
-    }
-    return properties;
-  }
-
-  private static boolean isPropertyAllowed(String key, boolean hasScanPerm) {
-    return !key.contains(".secured") || hasScanPerm;
-  }
-
-  private void addProfiles(ProjectReferentials ref, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
-    for (Language language : languages.all()) {
-      String languageKey = language.getKey();
-      QualityProfileDto qualityProfileDto = getProfile(languageKey, projectKey, profileName, session);
-      ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(
-        qualityProfileDto.getKey(),
-        qualityProfileDto.getName(),
-        qualityProfileDto.getLanguage(),
-        UtcDateUtils.parseDateTime(qualityProfileDto.getRulesUpdatedAt())));
-    }
-  }
-
-  /**
-   * First try to find a quality profile matching the given name (if provided) and current language
-   * If no profile found, try to find the quality profile set on the project (if provided)
-   * If still no profile found, try to find the default profile of the language
-   *
-   * Never return null because a default profile should always be set on ech language
-   */
-  private QualityProfileDto getProfile(String languageKey, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
-    QualityProfileDto qualityProfileDto = profileName != null ? qProfileFactory.getByNameAndLanguage(session, profileName, languageKey) : null;
-    if (qualityProfileDto == null && projectKey != null) {
-      qualityProfileDto = qProfileFactory.getByProjectAndLanguage(session, projectKey, languageKey);
-    }
-    qualityProfileDto = qualityProfileDto != null ? qualityProfileDto : qProfileFactory.getDefault(session, languageKey);
-    if (qualityProfileDto != null) {
-      return qualityProfileDto;
-    } else {
-      throw new IllegalStateException(String.format("No quality profile can been found on language '%s' for project '%s'", languageKey, projectKey));
-    }
-  }
-
-  private void addActiveRules(ProjectReferentials ref) {
-    for (org.sonar.batch.protocol.input.QProfile qProfile : ref.qProfiles()) {
-      for (ActiveRule activeRule : qProfileLoader.findActiveRulesByProfile(qProfile.key())) {
-        Rule rule = ruleService.getNonNullByKey(activeRule.key().ruleKey());
-        org.sonar.batch.protocol.input.ActiveRule inputActiveRule = new org.sonar.batch.protocol.input.ActiveRule(
-          activeRule.key().ruleKey().repository(),
-          activeRule.key().ruleKey().rule(),
-          rule.name(),
-          activeRule.severity(),
-          rule.internalKey(),
-          qProfile.language());
-        for (Map.Entry<String, String> entry : activeRule.params().entrySet()) {
-          inputActiveRule.addParam(entry.getKey(), entry.getValue());
-        }
-        ref.addActiveRule(inputActiveRule);
-      }
-    }
-  }
-
-  private void checkPermission(boolean preview){
-    UserSession userSession = UserSession.get();
-    boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
-    boolean hasPreviewPerm = userSession.hasGlobalPermission(GlobalPermissions.DRY_RUN_EXECUTION);
-    if (!hasPreviewPerm && !hasScanPerm) {
-      throw new ForbiddenException("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.");
-    }
-    if (!preview && !hasScanPerm) {
-      throw new ForbiddenException("You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " +
-        "Please contact your SonarQube administrator.");
-    }
-  }
-
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsLoader.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsLoader.java
new file mode 100644 (file)
index 0000000..1200ec0
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch;
+
+import com.google.common.collect.Maps;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.batch.protocol.input.ProjectReferentials;
+import org.sonar.core.UtcDateUtils;
+import org.sonar.core.component.AuthorizedComponentDto;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.qualityprofile.ActiveRule;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileLoader;
+import org.sonar.server.rule.Rule;
+import org.sonar.server.rule.RuleService;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+
+public class ProjectReferentialsLoader implements ServerComponent {
+
+  private final DbClient dbClient;
+  private final QProfileFactory qProfileFactory;
+  private final QProfileLoader qProfileLoader;
+  private final RuleService ruleService;
+  private final Languages languages;
+
+  public ProjectReferentialsLoader(DbClient dbClient, QProfileFactory qProfileFactory, QProfileLoader qProfileLoader, RuleService ruleService,
+                                   Languages languages) {
+    this.dbClient = dbClient;
+    this.qProfileFactory = qProfileFactory;
+    this.qProfileLoader = qProfileLoader;
+    this.ruleService = ruleService;
+    this.languages = languages;
+  }
+
+  public ProjectReferentials load(ProjectReferentialsQuery query) {
+    boolean hasScanPerm = UserSession.get().hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
+    checkPermission(query.isPreview());
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      ProjectReferentials ref = new ProjectReferentials();
+      String projectKey = null;
+      AuthorizedComponentDto module = dbClient.componentDao().getNullableAuthorizedComponentByKey(query.getModuleKey(), session);
+      // Current project/module can be null when analysing a new project
+      if (module != null) {
+        ComponentDto project = dbClient.componentDao().getNullableRootProjectByKey(query.getModuleKey(), session);
+        // Can be null if the given project is a provisioned one
+        if (project != null) {
+          if (!project.key().equals(module.key())) {
+            addSettings(ref, module.getKey(), getSettingsFromParents(module.key(), hasScanPerm, session));
+          }
+          projectKey = project.key();
+          addSettingsToChildrenModules(ref, query.getModuleKey(), Maps.<String, String>newHashMap(), hasScanPerm, session);
+        } else {
+          // Add settings of the provisioned project
+          addSettings(ref, query.getModuleKey(), getPropertiesMap(dbClient.propertiesDao().selectProjectProperties(query.getModuleKey(), session), hasScanPerm));
+          projectKey = query.getModuleKey();
+        }
+      }
+
+      addProfiles(ref, projectKey, query.getProfileName(), session);
+      addActiveRules(ref);
+      return ref;
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  private Map<String, String> getSettingsFromParents(String moduleKey, boolean hasScanPerm, DbSession session) {
+    List<ComponentDto> parents = newArrayList();
+    aggregateParentModules(moduleKey, parents, session);
+    Collections.reverse(parents);
+
+    Map<String, String> parentProperties = newHashMap();
+    for (ComponentDto parent : parents) {
+      parentProperties.putAll(getPropertiesMap(dbClient.propertiesDao().selectProjectProperties(parent.key(), session), hasScanPerm));
+    }
+    return parentProperties;
+  }
+
+  private void aggregateParentModules(String component, List<ComponentDto> parents, DbSession session) {
+    ComponentDto parent = dbClient.componentDao().getParentModuleByKey(component, session);
+    if (parent != null) {
+      parents.add(parent);
+      aggregateParentModules(parent.key(), parents, session);
+    }
+  }
+
+  private void addSettingsToChildrenModules(ProjectReferentials ref, String projectKey, Map<String, String> parentProperties, boolean hasScanPerm, DbSession session) {
+    Map<String, String> currentParentProperties = newHashMap();
+    currentParentProperties.putAll(parentProperties);
+    currentParentProperties.putAll(getPropertiesMap(dbClient.propertiesDao().selectProjectProperties(projectKey, session), hasScanPerm));
+    addSettings(ref, projectKey, currentParentProperties);
+
+    for (ComponentDto module : dbClient.componentDao().findModulesByProject(projectKey, session)) {
+      addSettings(ref, module.key(), currentParentProperties);
+      addSettingsToChildrenModules(ref, module.key(), currentParentProperties, hasScanPerm, session);
+    }
+  }
+
+  private void addSettings(ProjectReferentials ref, String module, Map<String, String> properties) {
+    if (!properties.isEmpty()) {
+      ref.addSettings(module, properties);
+    }
+  }
+
+  private Map<String, String> getPropertiesMap(List<PropertyDto> propertyDtos, boolean hasScanPerm) {
+    Map<String, String> properties = newHashMap();
+    for (PropertyDto propertyDto : propertyDtos) {
+      String key = propertyDto.getKey();
+      String value = propertyDto.getValue();
+      if (isPropertyAllowed(key, hasScanPerm)) {
+        properties.put(key, value);
+      }
+    }
+    return properties;
+  }
+
+  private static boolean isPropertyAllowed(String key, boolean hasScanPerm) {
+    return !key.contains(".secured") || hasScanPerm;
+  }
+
+  private void addProfiles(ProjectReferentials ref, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
+    for (Language language : languages.all()) {
+      String languageKey = language.getKey();
+      QualityProfileDto qualityProfileDto = getProfile(languageKey, projectKey, profileName, session);
+      ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(
+        qualityProfileDto.getKey(),
+        qualityProfileDto.getName(),
+        qualityProfileDto.getLanguage(),
+        UtcDateUtils.parseDateTime(qualityProfileDto.getRulesUpdatedAt())));
+    }
+  }
+
+  /**
+   * First try to find a quality profile matching the given name (if provided) and current language
+   * If no profile found, try to find the quality profile set on the project (if provided)
+   * If still no profile found, try to find the default profile of the language
+   * <p/>
+   * Never return null because a default profile should always be set on ech language
+   */
+  private QualityProfileDto getProfile(String languageKey, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
+    QualityProfileDto qualityProfileDto = profileName != null ? qProfileFactory.getByNameAndLanguage(session, profileName, languageKey) : null;
+    if (qualityProfileDto == null && projectKey != null) {
+      qualityProfileDto = qProfileFactory.getByProjectAndLanguage(session, projectKey, languageKey);
+    }
+    qualityProfileDto = qualityProfileDto != null ? qualityProfileDto : qProfileFactory.getDefault(session, languageKey);
+    if (qualityProfileDto != null) {
+      return qualityProfileDto;
+    } else {
+      throw new IllegalStateException(String.format("No quality profile can been found on language '%s' for project '%s'", languageKey, projectKey));
+    }
+  }
+
+  private void addActiveRules(ProjectReferentials ref) {
+    for (org.sonar.batch.protocol.input.QProfile qProfile : ref.qProfiles()) {
+      for (ActiveRule activeRule : qProfileLoader.findActiveRulesByProfile(qProfile.key())) {
+        Rule rule = ruleService.getNonNullByKey(activeRule.key().ruleKey());
+        org.sonar.batch.protocol.input.ActiveRule inputActiveRule = new org.sonar.batch.protocol.input.ActiveRule(
+          activeRule.key().ruleKey().repository(),
+          activeRule.key().ruleKey().rule(),
+          rule.name(),
+          activeRule.severity(),
+          rule.internalKey(),
+          qProfile.language());
+        for (Map.Entry<String, String> entry : activeRule.params().entrySet()) {
+          inputActiveRule.addParam(entry.getKey(), entry.getValue());
+        }
+        ref.addActiveRule(inputActiveRule);
+      }
+    }
+  }
+
+  private void checkPermission(boolean preview) {
+    UserSession userSession = UserSession.get();
+    boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
+    boolean hasPreviewPerm = userSession.hasGlobalPermission(GlobalPermissions.DRY_RUN_EXECUTION);
+    if (!hasPreviewPerm && !hasScanPerm) {
+      throw new ForbiddenException("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.");
+    }
+    if (!preview && !hasScanPerm) {
+      throw new ForbiddenException("You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " +
+        "Please contact your SonarQube administrator.");
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsQuery.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsQuery.java
new file mode 100644 (file)
index 0000000..301e2b0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class ProjectReferentialsQuery {
+
+  private String projectOrModuleKey;
+  private String profileName;
+  private boolean preview;
+
+  private ProjectReferentialsQuery() {
+    // No direct call
+  }
+
+  public boolean isPreview() {
+    return preview;
+  }
+
+  public ProjectReferentialsQuery setPreview(boolean preview) {
+    this.preview = preview;
+    return this;
+  }
+
+  @CheckForNull
+  public String getProfileName() {
+    return profileName;
+  }
+
+  public ProjectReferentialsQuery setProfileName(@Nullable String profileName) {
+    this.profileName = profileName;
+    return this;
+  }
+
+  public String getModuleKey() {
+    return projectOrModuleKey;
+  }
+
+  public ProjectReferentialsQuery setModuleKey(String projectOrModuleKey) {
+    this.projectOrModuleKey = projectOrModuleKey;
+    return this;
+  }
+
+  public static ProjectReferentialsQuery create(){
+    return new ProjectReferentialsQuery();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/persistence/SnapshotDao.java b/server/sonar-server/src/main/java/org/sonar/server/component/persistence/SnapshotDao.java
new file mode 100644 (file)
index 0000000..0d2db65
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component.persistence;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.System2;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.component.db.SnapshotMapper;
+import org.sonar.core.persistence.DaoComponent;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.BaseDao;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+public class SnapshotDao extends BaseDao<SnapshotMapper, SnapshotDto, Long> implements ServerComponent, DaoComponent {
+
+  public SnapshotDao(System2 system) {
+    super(SnapshotMapper.class, system);
+  }
+
+  @Override
+  @CheckForNull
+  protected SnapshotDto doGetNullableByKey(DbSession session, Long id) {
+    return mapper(session).selectByKey(id);
+  }
+
+  @Override
+  protected SnapshotDto doInsert(DbSession session, SnapshotDto item) {
+    mapper(session).insert(item);
+    return item;
+  }
+
+  @CheckForNull
+  public SnapshotDto getLastSnapshot(DbSession session, SnapshotDto snapshot) {
+    return mapper(session).selectLastSnapshot(snapshot.getResourceId());
+  }
+
+  @CheckForNull
+  public SnapshotDto getLastSnapshotOlderThan(DbSession session, SnapshotDto snapshot) {
+    return mapper(session).selectLastSnapshotOlderThan(snapshot.getResourceId(), snapshot.getCreatedAt());
+  }
+
+  public List<SnapshotDto> findSnapshotAndChildrenOfProjectScope(DbSession session, SnapshotDto snapshot) {
+    return mapper(session).selectSnapshotAndChildrenOfScope(snapshot.getId(), Scopes.PROJECT);
+  }
+
+  public int updateSnapshotAndChildrenLastFlagAndStatus(DbSession session, SnapshotDto snapshot, boolean isLast, String status) {
+    Long rootId = snapshot.getId();
+    String path = snapshot.getPath() + snapshot.getId() + ".%";
+    Long pathRootId = snapshot.getRootIdOrSelf();
+
+    return mapper(session).updateSnapshotAndChildrenLastFlagAndStatus(rootId, pathRootId, path, isLast, status);
+  }
+
+  public int updateSnapshotAndChildrenLastFlag(DbSession session, SnapshotDto snapshot, boolean isLast) {
+    Long rootId = snapshot.getId();
+    String path = snapshot.getPath() + snapshot.getId() + ".%";
+    Long pathRootId = snapshot.getRootIdOrSelf();
+
+    return mapper(session).updateSnapshotAndChildrenLastFlag(rootId, pathRootId, path, isLast);
+  }
+
+  public boolean isLast(SnapshotDto snapshotTested, @Nullable SnapshotDto previousLastSnapshot) {
+    return previousLastSnapshot == null || previousLastSnapshot.getCreatedAt().before(snapshotTested.getCreatedAt());
+  }
+}
index 4cd7bfe2dafcb590843af5c0441bb6aeeb82f069..50343be38459b29489b1fbf0d19a1858c7f227b3 100644 (file)
@@ -40,12 +40,12 @@ import org.sonar.api.web.NavigationSection;
 import org.sonar.api.web.Page;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.properties.PropertyQuery;
-import org.sonar.core.resource.SnapshotDto;
 import org.sonar.core.timemachine.Periods;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.NotFoundException;
index 846357d0bc4f45a76c540d8b21abe90ab2ae9031..cce75a5222804940fdcd8b3f4a08cc8dce882728 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.core.user.AuthorizationDao;
 import org.sonar.core.user.UserDao;
 import org.sonar.server.activity.db.ActivityDao;
 import org.sonar.server.component.persistence.ComponentDao;
+import org.sonar.server.component.persistence.SnapshotDao;
 import org.sonar.server.issue.db.IssueDao;
 import org.sonar.server.measure.persistence.MeasureDao;
 import org.sonar.server.measure.persistence.MetricDao;
@@ -56,6 +57,7 @@ public class DbClient implements ServerComponent {
   private final LoadedTemplateDao loadedTemplateDao;
   private final PropertiesDao propertiesDao;
   private final ComponentDao componentDao;
+  private final SnapshotDao snapshotDao;
   private final ResourceDao resourceDao;
   private final MeasureDao measureDao;
   private final MetricDao metricDao;
@@ -79,6 +81,7 @@ public class DbClient implements ServerComponent {
     loadedTemplateDao = getDao(map, LoadedTemplateDao.class);
     propertiesDao = getDao(map, PropertiesDao.class);
     componentDao = getDao(map, ComponentDao.class);
+    snapshotDao = getDao(map, SnapshotDao.class);
     resourceDao = getDao(map, ResourceDao.class);
     measureDao = getDao(map, MeasureDao.class);
     metricDao = getDao(map, MetricDao.class);
@@ -127,6 +130,9 @@ public class DbClient implements ServerComponent {
   public ComponentDao componentDao() {
     return componentDao;
   }
+  public SnapshotDao snapshotDao() {
+    return snapshotDao;
+  }
 
   public ResourceDao resourceDao() {
     return resourceDao;
index 12d5cb0afc9427e0693e3abfbd471affa4adce1e..4f9cf8cacfee64d5a5465f7f99eae976dad393af 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.measure;
 
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.core.resource.SnapshotDto;
+import org.sonar.core.component.SnapshotDto;
 
 import javax.annotation.Nullable;
 
index fdb42960eb4b3783274cfd9d614a978309ee8571..3c005c026f91b5f65858c90eed29b8d59e5ad1ad 100644 (file)
@@ -26,16 +26,16 @@ import com.google.common.collect.Ordering;
 import org.apache.commons.dbutils.DbUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.StringUtils;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.Database;
 import org.sonar.core.persistence.dialect.MsSql;
 import org.sonar.core.persistence.dialect.Oracle;
-import org.sonar.core.resource.SnapshotDto;
 
 import javax.annotation.Nullable;
 
 import java.sql.*;
-import java.sql.Date;
-import java.util.*;
+import java.util.Comparator;
+import java.util.List;
 
 class MeasureFilterSql {
 
index c30bf37d6bfaf6a6e82b964620f856ee0df26793..8ed0d7b5abc9865d509a639fa3a996bde51690ac 100644 (file)
@@ -78,14 +78,12 @@ import org.sonar.server.activity.index.ActivityNormalizer;
 import org.sonar.server.activity.ws.ActivitiesWebService;
 import org.sonar.server.activity.ws.ActivityMapping;
 import org.sonar.server.authentication.ws.AuthenticationWs;
-import org.sonar.server.batch.BatchIndex;
-import org.sonar.server.batch.BatchWs;
-import org.sonar.server.batch.GlobalReferentialsAction;
-import org.sonar.server.batch.ProjectReferentialsAction;
+import org.sonar.server.batch.*;
 import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.persistence.ComponentDao;
+import org.sonar.server.component.persistence.SnapshotDao;
 import org.sonar.server.component.ws.*;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.db.DatabaseChecker;
@@ -214,6 +212,7 @@ class ServerComponents {
       MeasureDao.class,
       MetricDao.class,
       ComponentDao.class,
+      SnapshotDao.class,
       DbClient.class,
       MeasureFilterDao.class,
       ActivityDao.class,
@@ -305,6 +304,7 @@ class ServerComponents {
     pico.addSingleton(BatchIndex.class);
     pico.addSingleton(GlobalReferentialsAction.class);
     pico.addSingleton(ProjectReferentialsAction.class);
+    pico.addSingleton(ProjectReferentialsLoader.class);
     pico.addSingleton(BatchWs.class);
 
     // update center
index 1a497bb014aff22ef0c6d358147e49d33feb0d0a..a51eee53dd0a7d7bd2f469e004a02949133889c9 100644 (file)
@@ -28,12 +28,8 @@ import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.resources.Languages;
 import org.sonar.core.properties.PropertiesDao;
 import org.sonar.server.db.DbClient;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.rule.RuleService;
 import org.sonar.server.ws.WsTester;
 
 import java.io.File;
@@ -61,7 +57,7 @@ public class BatchWsTest {
   public void before() throws IOException {
     tester = new WsTester(new BatchWs(batchIndex,
       new GlobalReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class)),
-      new ProjectReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class), mock(QProfileFactory.class), mock(QProfileLoader.class), mock(RuleService.class), mock(Languages.class))));
+      new ProjectReferentialsAction(mock(ProjectReferentialsLoader.class))));
   }
 
   @Test
index 34125be594b8581eee91e7cc8dd80bf6bd92928e..cffed5b6aa9ade4c8b0463095f6890c6a8529e15 100644 (file)
 
 package org.sonar.server.batch;
 
-import com.google.common.collect.ImmutableMap;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.properties.PropertiesDao;
-import org.sonar.core.properties.PropertyDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleKey;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
-import org.sonar.server.component.persistence.ComponentDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.qualityprofile.ActiveRule;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.rule.Rule;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.user.MockUserSession;
+import org.sonar.batch.protocol.input.ProjectReferentials;
 import org.sonar.server.ws.WsTester;
 
-import java.util.Collections;
-
-import static com.google.common.collect.Lists.newArrayList;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -60,415 +37,35 @@ import static org.mockito.Mockito.when;
 public class ProjectReferentialsActionTest {
 
   @Mock
-  DbSession session;
-
-  @Mock
-  ComponentDao componentDao;
-
-  @Mock
-  PropertiesDao propertiesDao;
-
-  @Mock
-  QProfileFactory qProfileFactory;
-
-  @Mock
-  QProfileLoader qProfileLoader;
-
-  @Mock
-  RuleService ruleService;
-
-  @Mock
-  Languages languages;
-
-  @Mock
-  Language language;
+  ProjectReferentialsLoader projectReferentialsLoader;
 
   WsTester tester;
 
-  ComponentDto project;
-  ComponentDto module;
-  ComponentDto subModule;
-
   @Before
   public void setUp() throws Exception {
-    DbClient dbClient = mock(DbClient.class);
-    when(dbClient.openSession(false)).thenReturn(session);
-    when(dbClient.componentDao()).thenReturn(componentDao);
-
-    project = new ComponentDto().setKey("org.codehaus.sonar:sonar").setQualifier(Qualifiers.PROJECT);
-    module = new ComponentDto().setKey("org.codehaus.sonar:sonar-server").setQualifier(Qualifiers.MODULE);
-    subModule = new ComponentDto().setKey("org.codehaus.sonar:sonar-server-dao").setQualifier(Qualifiers.MODULE);
-
-    when(componentDao.getNullableAuthorizedComponentByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.getNullableAuthorizedComponentByKey(module.key(), session)).thenReturn(module);
-    when(componentDao.getNullableAuthorizedComponentByKey(subModule.key(), session)).thenReturn(subModule);
-
-    when(language.getKey()).thenReturn("java");
-    when(languages.all()).thenReturn(new Language[] {language});
-
-    when(qProfileFactory.getDefault(session, "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-      );
-
     tester = new WsTester(new BatchWs(mock(BatchIndex.class), mock(GlobalReferentialsAction.class),
-      new ProjectReferentialsAction(dbClient, propertiesDao, qProfileFactory, qProfileLoader, ruleService, languages)));
-  }
-
-  @Test
-  public void return_project_settings() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    // Project without modules
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(Collections.<ComponentDto>emptyList());
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-      ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_settings.json");
-  }
-
-  @Test
-  public void not_returned_secured_settings_with_only_preview_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
-
-    // Project without modules
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(Collections.<ComponentDto>emptyList());
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-    ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key()).setParam("preview", "true");
-    request.execute().assertJson(getClass(), "not_returned_secured_settings_with_only_preview_permission.json");
-  }
-
-  @Test
-  public void return_project_with_module_settings() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(newArrayList(module));
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-    ));
-
-    when(propertiesDao.selectProjectProperties(module.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER"),
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-      ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_with_module_settings.json");
-  }
-
-  @Test
-  public void return_project_with_module_settings_inherited_from_project() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(newArrayList(module));
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-      ));
-    // No property on module -> should have the same than project
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_with_module_settings_inherited_from_project.json");
-  }
-
-  @Test
-  public void return_project_with_module_with_sub_module() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(newArrayList(module));
-    when(componentDao.findModulesByProject(module.key(), session)).thenReturn(newArrayList(subModule));
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-      ));
-
-    when(propertiesDao.selectProjectProperties(module.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER"),
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-      ));
-
-    when(propertiesDao.selectProjectProperties(subModule.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER-DAO")
-      ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_with_module_with_sub_module.json");
-  }
-
-  @Test
-  public void return_project_with_two_modules() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    ComponentDto module2 = new ComponentDto().setKey("org.codehaus.sonar:sonar-application").setQualifier(Qualifiers.MODULE);
-
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(project);
-    when(componentDao.findModulesByProject(project.key(), session)).thenReturn(newArrayList(module, module2));
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-    ));
-
-    when(propertiesDao.selectProjectProperties(module.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER"),
-      // This property should not be found on the other module
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-    ));
-
-    when(propertiesDao.selectProjectProperties(module2.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-APPLICATION")
-    ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_with_two_modules.json");
-  }
-
-  @Test
-  public void return_provisioned_project_settings() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    // No root project will be found on provisioned project
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(null);
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-    ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_project_settings.json");
-  }
-
-  @Test
-  public void return_provisioned_project_profile() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    // No root project will be found on provisioned project
-    when(componentDao.getNullableRootProjectByKey(project.key(), session)).thenReturn(null);
-
-    when(qProfileFactory.getByProjectAndLanguage(session, project.key(), "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("SonarQube way").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-    );
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-    request.execute().assertJson(getClass(), "return_provisioned_project_profile.json");
-  }
-
-  @Test
-  public void return_sub_module_settings() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(subModule.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(module.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(subModule.key(), session)).thenReturn(module);
-
-    when(propertiesDao.selectProjectProperties(subModule.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john"),
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-    ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", subModule.key());
-    request.execute().assertJson(getClass(), "return_sub_module_settings.json");
-  }
-
-  @Test
-  public void return_sub_module_settings_including_settings_from_parent_modules() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(subModule.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(module.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(subModule.key(), session)).thenReturn(module);
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR")
-    ));
-
-    when(propertiesDao.selectProjectProperties(module.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
-    ));
-
-    when(propertiesDao.selectProjectProperties(subModule.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-    ));
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", subModule.key());
-    request.execute().assertJson(getClass(), "return_sub_module_settings_including_settings_from_parent_modules.json");
-  }
-
-  @Test
-  public void return_sub_module_settings_only_inherited_from_project() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(subModule.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(module.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(subModule.key(), session)).thenReturn(module);
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john"),
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-      ));
-    // No settings on module or sub module -> All setting should come from the project
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", subModule.key());
-    request.execute().assertJson(getClass(), "return_sub_module_settings_inherited_from_project.json");
-  }
-
-  @Test
-  public void return_sub_module_settings_inherited_from_project_and_module() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    when(componentDao.getNullableRootProjectByKey(subModule.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(module.key(), session)).thenReturn(project);
-    when(componentDao.getParentModuleByKey(subModule.key(), session)).thenReturn(module);
-
-    when(propertiesDao.selectProjectProperties(project.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john"),
-      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
-    ));
-
-    when(propertiesDao.selectProjectProperties(module.key(), session)).thenReturn(newArrayList(
-      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER")
-    ));
-
-    // No settings on sub module -> All setting should come from the project and the module
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", subModule.key());
-    request.execute().assertJson(getClass(), "return_sub_module_settings_inherited_from_project_and_module.json");
-  }
-
-  @Test
-  public void return_quality_profiles() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-    String projectKey = "org.codehaus.sonar:sonar";
-
-    when(qProfileFactory.getByProjectAndLanguage(session, projectKey, "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("SonarQube way").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-      );
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
-    request.execute().assertJson(getClass(), "return_quality_profiles.json");
-  }
-
-  @Test
-  public void fail_when_quality_profile_for_a_language() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", "org.codehaus.sonar:sonar");
-
-    try {
-      request.execute();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("No quality profile can been found on language 'java' for project 'org.codehaus.sonar:sonar'");
-    }
+      new ProjectReferentialsAction(projectReferentialsLoader)));
   }
 
   @Test
-  public void return_quality_profile_from_default_profile() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+  public void project_referentials() throws Exception {
     String projectKey = "org.codehaus.sonar:sonar";
 
-    when(qProfileFactory.getDefault(session, "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-      );
+    ProjectReferentials projectReferentials = mock(ProjectReferentials.class);
+    when(projectReferentials.toJson()).thenReturn("{\"settingsByModule\": {}}");
 
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
-    request.execute().assertJson(getClass(), "return_quality_profile_from_default_profile.json");
-  }
-
-  @Test
-  public void return_quality_profile_from_given_profile_name() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-    String projectKey = "org.codehaus.sonar:sonar";
-
-    when(qProfileFactory.getByNameAndLanguage(session, "Default", "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-      );
+    ArgumentCaptor<ProjectReferentialsQuery> queryArgumentCaptor = ArgumentCaptor.forClass(ProjectReferentialsQuery.class);
+    when(projectReferentialsLoader.load(queryArgumentCaptor.capture())).thenReturn(projectReferentials);
 
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey).setParam("profile", "Default");
-    request.execute().assertJson(getClass(), "return_quality_profile_from_given_profile_name.json");
-  }
-
-  @Test
-  public void return_quality_profiles_even_when_project_does_not_exists() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-    String projectKey = "org.codehaus.sonar:sonar";
-    when(componentDao.getNullableByKey(session, projectKey)).thenReturn(null);
-
-    when(qProfileFactory.getDefault(session, "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-    );
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
-    request.execute().assertJson(getClass(), "return_quality_profiles_even_when_project_does_not_exists.json");
-  }
-
-  @Test
-  public void return_active_rules() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-    String projectKey = "org.codehaus.sonar:sonar";
-
-    when(qProfileFactory.getByProjectAndLanguage(session, projectKey, "java")).thenReturn(
-      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
-      );
-
-    RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.key()).thenReturn(ActiveRuleKey.of("abcd", ruleKey));
-    when(activeRule.severity()).thenReturn(Severity.MINOR);
-    when(activeRule.params()).thenReturn(ImmutableMap.of("max", "2"));
-    when(qProfileLoader.findActiveRulesByProfile("abcd")).thenReturn(newArrayList(activeRule));
-
-    Rule rule = mock(Rule.class);
-    when(rule.name()).thenReturn("Avoid Cycle");
-    when(rule.internalKey()).thenReturn("squid-1");
-    when(ruleService.getNonNullByKey(ruleKey)).thenReturn(rule);
-
-    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
-    request.execute().assertJson(getClass(), "return_active_rules.json");
-  }
-
-  @Test
-  public void fail_if_no_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions();
-
-    try {
-      WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key());
-      request.execute();
-    } catch(Exception e){
-      assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.");
-    }
-  }
-
-  @Test
-  public void fail_when_not_preview_and_only_dry_run_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+    WsTester.TestRequest request = tester.newGetRequest("batch", "project")
+      .setParam("key", projectKey)
+      .setParam("profile", "Default")
+      .setParam("preview", "false");
+    request.execute().assertJson("{\"settingsByModule\": {}}");
 
-    try {
-      WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", project.key()).setParam("preview", "false");
-      request.execute();
-    } catch(Exception e){
-      assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " +
-        "Please contact your SonarQube administrator.");
-    }
+    assertThat(queryArgumentCaptor.getValue().getModuleKey()).isEqualTo(projectKey);
+    assertThat(queryArgumentCaptor.getValue().getProfileName()).isEqualTo("Default");
+    assertThat(queryArgumentCaptor.getValue().isPreview()).isFalse();
   }
 
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsLoaderMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsLoaderMediumTest.java
new file mode 100644 (file)
index 0000000..3eae77a
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.protocol.input.ActiveRule;
+import org.sonar.batch.protocol.input.ProjectReferentials;
+import org.sonar.batch.protocol.input.QProfile;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.SnapshotTesting;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.qualityprofile.QProfileName;
+import org.sonar.server.qualityprofile.QProfileTesting;
+import org.sonar.server.qualityprofile.RuleActivation;
+import org.sonar.server.qualityprofile.RuleActivator;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class ProjectReferentialsLoaderMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester().addXoo();
+
+  DbSession dbSession;
+
+  ProjectReferentialsLoader loader;
+
+  @Before
+  public void before() {
+    tester.clearDbAndIndexes();
+    dbSession = tester.get(DbClient.class).openSession(false);
+    loader = tester.get(ProjectReferentialsLoader.class);
+  }
+
+  @After
+  public void after() {
+    dbSession.close();
+  }
+
+  @Test
+  public void return_project_settings() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()),
+      dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()),
+      dbSession);
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    Map<String, String> projectSettings = ref.settings(project.key());
+    assertThat(projectSettings).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+  }
+
+  @Test
+  public void not_returned_secured_settings_with_only_preview_permission() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()),
+      dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()),
+      dbSession);
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()).setPreview(true));
+    Map<String, String> projectSettings = ref.settings(project.key());
+    assertThat(projectSettings).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR"
+    ));
+  }
+
+  @Test
+  public void return_project_with_module_settings() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(module, project, projectSnapshot));
+
+    // Module properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(module.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+    assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-SERVER",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_project_with_module_settings_inherited_from_project() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(module, project, projectSnapshot));
+
+    // No property on module -> should have the same as project
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+    assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+  }
+
+  @Test
+  public void return_project_with_module_with_sub_module() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(module, project, projectSnapshot);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, moduleSnapshot);
+
+    // Module properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(module.getId()), dbSession);
+
+    ComponentDto subModule = ComponentTesting.newModuleDto(module);
+    tester.get(DbClient.class).componentDao().insert(dbSession, subModule);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(subModule, module, moduleSnapshot));
+
+    // Sub module properties
+    tester.get(DbClient.class).propertiesDao().setProperty(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER-DAO").setResourceId(subModule.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+    assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-SERVER",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+    assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-SERVER-DAO",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_project_with_two_modules() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module1 = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module1);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(module1, project, projectSnapshot));
+
+    // Module 1 properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module1.getId()), dbSession);
+    // This property should not be found on the other module
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(module1.getId()), dbSession);
+
+    ComponentDto module2 = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module2);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(module2, project, projectSnapshot));
+
+    // Module 2 property
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-APPLICATION").setResourceId(module2.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+    assertThat(ref.settings(module1.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-SERVER",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+    assertThat(ref.settings(module2.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-APPLICATION",
+      "sonar.jira.login.secured", "john"
+    ));
+  }
+
+  @Test
+  public void return_provisioned_project_settings() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    // No snapshot attached on the project -> provisioned project
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john"
+    ));
+  }
+
+  @Test
+  public void return_sub_module_settings() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+    // No project properties
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(module, project, projectSnapshot);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, moduleSnapshot);
+    // No module properties
+
+    ComponentDto subModule = ComponentTesting.newModuleDto(module);
+    tester.get(DbClient.class).componentDao().insert(dbSession, subModule);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(subModule, module, moduleSnapshot));
+
+    // Sub module properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(subModule.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(subModule.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(subModule.key()));
+    assertThat(ref.settings(project.key())).isEmpty();
+    assertThat(ref.settings(module.key())).isEmpty();
+    assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_sub_module_settings_including_settings_from_parent_modules() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project property
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(module, project, projectSnapshot);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, moduleSnapshot);
+
+    // Module property
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(module.getId()), dbSession);
+
+    ComponentDto subModule = ComponentTesting.newModuleDto(module);
+    tester.get(DbClient.class).componentDao().insert(dbSession, subModule);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(subModule, module, moduleSnapshot));
+
+    // Sub module properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(subModule.key()));
+    assertThat(ref.settings(project.key())).isEmpty();
+    assertThat(ref.settings(module.key())).isEmpty();
+    assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_sub_module_settings_only_inherited_from_project() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(module, project, projectSnapshot);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, moduleSnapshot);
+    // No module property
+
+    ComponentDto subModule = ComponentTesting.newModuleDto(module);
+    tester.get(DbClient.class).componentDao().insert(dbSession, subModule);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(subModule, module, moduleSnapshot));
+    // No sub module property
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(subModule.key()));
+    assertThat(ref.settings(project.key())).isEmpty();
+    assertThat(ref.settings(module.key())).isEmpty();
+    assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_sub_module_settings_inherited_from_project_and_module() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, projectSnapshot);
+    addDefaultProfile();
+
+    // Project properties
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()), dbSession);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()), dbSession);
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+    SnapshotDto moduleSnapshot = SnapshotTesting.createForComponent(module, project, projectSnapshot);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, moduleSnapshot);
+
+    // Module property
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module.getId()), dbSession);
+
+    ComponentDto subModule = ComponentTesting.newModuleDto(module);
+    tester.get(DbClient.class).componentDao().insert(dbSession, subModule);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForComponent(subModule, module, moduleSnapshot));
+    // No sub module property
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(subModule.key()));
+    assertThat(ref.settings(project.key())).isEmpty();
+    assertThat(ref.settings(module.key())).isEmpty();
+    assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
+      "sonar.jira.project.key", "SONAR-SERVER",
+      "sonar.jira.login.secured", "john",
+      "sonar.coverage.exclusions", "**/*.java"
+    ));
+  }
+
+  @Test
+  public void return_quality_profile_from_project_profile() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way").setResourceId(project.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    List<QProfile> profiles = newArrayList(ref.qProfiles());
+    assertThat(profiles).hasSize(1);
+    assertThat(profiles.get(0).key()).isEqualTo("abcd");
+    assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
+    assertThat(profiles.get(0).language()).isEqualTo("xoo");
+    assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
+  }
+
+  @Test
+  public void return_quality_profile_from_default_profile() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way"), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    List<QProfile> profiles = newArrayList(ref.qProfiles());
+    assertThat(profiles).hasSize(1);
+    assertThat(profiles.get(0).key()).isEqualTo("abcd");
+    assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
+    assertThat(profiles.get(0).language()).isEqualTo("xoo");
+    assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
+  }
+
+  @Test
+  public void return_quality_profile_from_given_profile_name() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way"), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()).setProfileName("SonarQube way"));
+    List<QProfile> profiles = newArrayList(ref.qProfiles());
+    assertThat(profiles).hasSize(1);
+    assertThat(profiles.get(0).key()).isEqualTo("abcd");
+    assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
+    assertThat(profiles.get(0).language()).isEqualTo("xoo");
+    assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
+  }
+
+  @Test
+  public void return_quality_profiles_even_when_project_does_not_exists() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way"), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey("project"));
+    List<QProfile> profiles = newArrayList(ref.qProfiles());
+    assertThat(profiles).hasSize(1);
+    assertThat(profiles.get(0).key()).isEqualTo("abcd");
+    assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
+    assertThat(profiles.get(0).language()).isEqualTo("xoo");
+    assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
+  }
+
+
+  @Test
+  public void return_provisioned_project_profile() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    // No snapshot attached on the project -> provisioned project
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way").setResourceId(project.getId()), dbSession);
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    List<QProfile> profiles = newArrayList(ref.qProfiles());
+    assertThat(profiles).hasSize(1);
+    assertThat(profiles.get(0).key()).isEqualTo("abcd");
+    assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
+    assertThat(profiles.get(0).language()).isEqualTo("xoo");
+    assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
+  }
+
+  @Test
+  public void fail_when_no_quality_profile_for_a_language() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto().setKey("org.codehaus.sonar:sonar");
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    dbSession.commit();
+
+    try {
+      loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("No quality profile can been found on language 'xoo' for project 'org.codehaus.sonar:sonar'");
+    }
+  }
+
+  @Test
+  public void return_active_rules() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    tester.get(DbClient.class).snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project));
+
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(ruleUpdatedAt));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way"), dbSession);
+
+    RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
+    RuleDto rule = RuleTesting.newDto(ruleKey).setName("Avoid Cycle").setConfigKey("squid-1").setLanguage(ServerTester.Xoo.KEY);
+    tester.get(DbClient.class).ruleDao().insert(dbSession, rule);
+    tester.get(DbClient.class).ruleDao().addRuleParam(dbSession, rule, RuleParamDto.createFor(rule)
+      .setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type()));
+
+    RuleActivation activation = new RuleActivation(ruleKey);
+    activation.setSeverity(Severity.MINOR);
+    activation.setParameter("max", "2");
+    tester.get(RuleActivator.class).activate(dbSession, activation, profileDto.getKey());
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+    List<ActiveRule> activeRules = newArrayList(ref.activeRules());
+    assertThat(activeRules).hasSize(1);
+    assertThat(activeRules.get(0).repositoryKey()).isEqualTo("squid");
+    assertThat(activeRules.get(0).ruleKey()).isEqualTo("AvoidCycle");
+    assertThat(activeRules.get(0).name()).isEqualTo("Avoid Cycle");
+    assertThat(activeRules.get(0).language()).isEqualTo("xoo");
+    assertThat(activeRules.get(0).severity()).isEqualTo("MINOR");
+    assertThat(activeRules.get(0).internalKey()).isEqualTo("squid-1");
+    assertThat(activeRules.get(0).language()).isEqualTo("xoo");
+    assertThat(activeRules.get(0).params()).isEqualTo(ImmutableMap.of("max", "2"));
+  }
+
+  @Test
+  public void fail_if_no_permission() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions();
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    dbSession.commit();
+
+    try {
+      loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.");
+    }
+  }
+
+  @Test
+  public void fail_when_not_preview_and_only_dry_run_permission() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    dbSession.commit();
+
+    try {
+      loader.load(ProjectReferentialsQuery.create().setModuleKey(project.key()).setPreview(false));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage(
+        "You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " +
+          "Please contact your SonarQube administrator.");
+    }
+  }
+
+  private void addDefaultProfile() {
+    QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(DateUtils.formatDateTime(new Date()));
+    tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
+    tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.profile.xoo").setValue("SonarQube way"), dbSession);
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
new file mode 100644 (file)
index 0000000..fc6a21a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component;
+
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.core.component.ComponentDto;
+
+import java.util.UUID;
+
+public class ComponentTesting {
+
+  public static ComponentDto newFileDto(ComponentDto subProjectOrProject) {
+    return new ComponentDto()
+      .setKey("file")
+      .setName("File")
+      .setLongName("File")
+      .setSubProjectId(subProjectOrProject.getId())
+      .setScope(Scopes.FILE)
+      .setQualifier(Qualifiers.FILE)
+      .setPath("src/main/xoo/org/sonar/samples/File.xoo")
+      .setLanguage("xoo")
+      .setEnabled(true);
+  }
+
+  public static ComponentDto newFileDto(ComponentDto module, String fileUuid) {
+    return new ComponentDto()
+      .setKey("KEY_" + fileUuid)
+      .setName("NAME_" + fileUuid)
+      .setLongName("LONG_NAME_" + fileUuid)
+      .setSubProjectId(module.getId())
+      .setScope(Scopes.FILE)
+      .setQualifier(Qualifiers.FILE)
+      .setPath("src/main/xoo/org/sonar/samples/File.xoo")
+      .setLanguage("xoo")
+      .setEnabled(true);
+  }
+
+  public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) {
+    String uuid = UUID.randomUUID().toString();
+    return new ComponentDto()
+      .setKey("KEY_" + uuid)
+      .setName("NAME_" + uuid)
+      .setLongName("LONG_NAME_" + uuid)
+      .setSubProjectId(subProjectOrProject.getId())
+      .setScope(Scopes.PROJECT)
+      .setQualifier(Qualifiers.MODULE)
+      .setPath("module")
+      .setLanguage(null)
+      .setEnabled(true);
+  }
+
+  public static ComponentDto newProjectDto() {
+    String uuid = UUID.randomUUID().toString();
+    return new ComponentDto()
+      .setKey("KEY_" + uuid)
+      .setName("NAME_" + uuid)
+      .setLongName("LONG_NAME_" + uuid)
+      .setSubProjectId(null)
+      .setScope(Scopes.PROJECT)
+      .setQualifier(Qualifiers.PROJECT)
+      .setPath(null)
+      .setLanguage(null)
+      .setEnabled(true);
+  }
+
+  public static ComponentDto newProjectDto(String uuid) {
+    return new ComponentDto()
+      .setKey("KEY_" + uuid)
+      .setName("NAME_" + uuid)
+      .setLongName("LONG_NAME_" + uuid)
+      .setSubProjectId(null)
+      .setScope(Scopes.PROJECT)
+      .setQualifier(Qualifiers.PROJECT)
+      .setPath(null)
+      .setLanguage(null)
+      .setEnabled(true);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java
new file mode 100644 (file)
index 0000000..8785d3d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component;
+
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+
+public class SnapshotTesting {
+
+  /**
+   * Can be used for modules and files
+   */
+  public static SnapshotDto createForComponent(ComponentDto component, ComponentDto parentProject, SnapshotDto parentSnapshot) {
+    Long parentRootId = parentSnapshot.getRootId();
+    return new SnapshotDto()
+      .setResourceId(component.getId())
+      .setRootProjectId(parentSnapshot.getRootProjectId())
+      .setRootId(parentRootId != null ? parentRootId : parentSnapshot.getId())
+      .setStatus(SnapshotDto.STATUS_PROCESSED)
+      .setQualifier(component.qualifier())
+      .setScope(component.scope())
+      .setParentId(parentSnapshot.getId())
+      .setLast(true);
+  }
+
+  public static SnapshotDto createForProject(ComponentDto project) {
+    return new SnapshotDto()
+      .setResourceId(project.getId())
+      .setRootProjectId(project.getId())
+      .setStatus(SnapshotDto.STATUS_PROCESSED)
+      .setQualifier(project.qualifier())
+      .setScope(project.scope())
+      .setLast(true);
+  }
+
+  public static SnapshotDto defaultSnapshot() {
+    return new SnapshotDto()
+      .setResourceId(3L)
+      .setRootProjectId(1L)
+      .setParentId(2L)
+      .setRootId(1L)
+      .setStatus("P")
+      .setLast(true)
+      .setPurgeStatus(1)
+      .setDepth(1)
+      .setScope("DIR")
+      .setQualifier("PAC")
+      .setVersion("2.1-SNAPSHOT")
+      .setPath("1.2.")
+      .setPeriodMode(1, "days1")
+      .setPeriodMode(2, "days2")
+      .setPeriodMode(3, "days3")
+      .setPeriodMode(4, "days4")
+      .setPeriodMode(5, "days5")
+      .setPeriodParam(1, "30")
+      .setPeriodParam(2, "31")
+      .setPeriodParam(3, "32")
+      .setPeriodParam(4, "33")
+      .setPeriodParam(5, "34")
+      .setPeriodDate(1, DateUtils.parseDate("2011-09-24"))
+      .setPeriodDate(2, DateUtils.parseDate("2011-09-25"))
+      .setPeriodDate(3, DateUtils.parseDate("2011-09-26"))
+      .setPeriodDate(4, DateUtils.parseDate("2011-09-27"))
+      .setPeriodDate(5, DateUtils.parseDate("2011-09-28"))
+      .setBuildDate(DateUtils.parseDate("2011-09-29"));
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/persistence/SnapshotDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/persistence/SnapshotDaoTest.java
new file mode 100644 (file)
index 0000000..e77aa0a
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.component.persistence;
+
+import org.apache.commons.lang.time.DateUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.persistence.DbSession;
+
+import java.util.Date;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SnapshotDaoTest extends AbstractDaoTestCase {
+
+  DbSession session;
+
+  SnapshotDao sut;
+
+  System2 system2;
+
+  @Before
+  public void createDao() throws Exception {
+    session = getMyBatis().openSession(false);
+    system2 = mock(System2.class);
+    sut = new SnapshotDao(system2);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    session.close();
+  }
+
+  @Test
+  public void get_by_key() {
+    setupData("shared");
+
+    SnapshotDto result = sut.getNullableByKey(session, 3L);
+    assertThat(result).isNotNull();
+    assertThat(result.getId()).isEqualTo(3L);
+    assertThat(result.getResourceId()).isEqualTo(3L);
+    assertThat(result.getRootProjectId()).isEqualTo(1L);
+    assertThat(result.getParentId()).isEqualTo(2L);
+    assertThat(result.getRootId()).isEqualTo(1L);
+    assertThat(result.getStatus()).isEqualTo("P");
+    assertThat(result.getLast()).isTrue();
+    assertThat(result.getPurgeStatus()).isEqualTo(1);
+    assertThat(result.getDepth()).isEqualTo(1);
+    assertThat(result.getScope()).isEqualTo("DIR");
+    assertThat(result.getQualifier()).isEqualTo("PAC");
+    assertThat(result.getVersion()).isEqualTo("2.1-SNAPSHOT");
+    assertThat(result.getPath()).isEqualTo("1.2.");
+
+    assertThat(result.getPeriodMode(1)).isEqualTo("days1");
+    assertThat(result.getPeriodModeParameter(1)).isEqualTo("30");
+    assertThat(result.getPeriodDate(1)).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-24"));
+    assertThat(result.getPeriodMode(2)).isEqualTo("days2");
+    assertThat(result.getPeriodModeParameter(2)).isEqualTo("31");
+    assertThat(result.getPeriodDate(2)).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-25"));
+    assertThat(result.getPeriodMode(3)).isEqualTo("days3");
+    assertThat(result.getPeriodModeParameter(3)).isEqualTo("32");
+    assertThat(result.getPeriodDate(3)).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-26"));
+    assertThat(result.getPeriodMode(4)).isEqualTo("days4");
+    assertThat(result.getPeriodModeParameter(4)).isEqualTo("33");
+    assertThat(result.getPeriodDate(4)).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-27"));
+    assertThat(result.getPeriodMode(5)).isEqualTo("days5");
+    assertThat(result.getPeriodModeParameter(5)).isEqualTo("34");
+    assertThat(result.getPeriodDate(5)).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-28"));
+
+    assertThat(result.getCreatedAt()).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2008-12-02"));
+    assertThat(result.getBuildDate()).isEqualTo(org.sonar.api.utils.DateUtils.parseDate("2011-09-29"));
+
+    assertThat(sut.getNullableByKey(session, 999L)).isNull();
+  }
+
+  @Test
+  public void insert() {
+    setupData("empty");
+
+    when(system2.now()).thenReturn(org.sonar.api.utils.DateUtils.parseDate("2014-06-18").getTime());
+
+    SnapshotDto dto = defaultSnapshot();
+
+    sut.insert(session, dto);
+    session.commit();
+
+    assertThat(dto.getId()).isNotNull();
+    checkTables("insert", "snapshots");
+  }
+
+  @Test
+  public void lastSnapshot_returns_null_when_no_last_snapshot() {
+    setupData("empty");
+
+    SnapshotDto snapshot = sut.getLastSnapshot(session, defaultSnapshot());
+
+    assertThat(snapshot).isNull();
+  }
+
+  @Test
+  public void lastSnapshot_from_one_resource() {
+    setupData("snapshots");
+
+    SnapshotDto snapshot = sut.getLastSnapshot(session, defaultSnapshot().setResourceId(2L));
+
+    assertThat(snapshot).isNotNull();
+    assertThat(snapshot.getId()).isEqualTo(4L);
+  }
+
+  @Test
+  public void lastSnapshot_from_one_resource_without_last_is_null() {
+    setupData("snapshots");
+
+    SnapshotDto snapshot = sut.getLastSnapshot(session, defaultSnapshot().setResourceId(5L));
+
+    assertThat(snapshot).isNull();
+  }
+
+  @Test
+  public void no_last_snapshot_older_than_another_one_in_a_empty_table() {
+    setupData("empty");
+
+    SnapshotDto snapshot = sut.getLastSnapshotOlderThan(session, defaultSnapshot());
+
+    assertThat(snapshot).isNull();
+  }
+
+  @Test
+  public void last_snapshot_older__than_a_reference() {
+    setupData("snapshots");
+
+    SnapshotDto referenceSnapshot = defaultSnapshot().setResourceId(1L);
+    referenceSnapshot.setCreatedAt(org.sonar.api.utils.DateUtils.parseDate("2008-12-03"));
+    SnapshotDto snapshot = sut.getLastSnapshotOlderThan(session, referenceSnapshot);
+
+    assertThat(snapshot).isNotNull();
+    assertThat(snapshot.getId()).isEqualTo(1L);
+  }
+
+  @Test
+  public void last_snapshot_earlier__than_a_reference() {
+    setupData("snapshots");
+
+    SnapshotDto referenceSnapshot = defaultSnapshot().setResourceId(1L);
+    referenceSnapshot.setCreatedAt(org.sonar.api.utils.DateUtils.parseDate("2008-12-01"));
+    SnapshotDto snapshot = sut.getLastSnapshotOlderThan(session, referenceSnapshot);
+
+    assertThat(snapshot).isNull();
+  }
+
+  @Test
+  public void snapshot_and_child_retrieved() {
+    setupData("snapshots");
+
+    List<SnapshotDto> snapshots = sut.findSnapshotAndChildrenOfProjectScope(session, defaultSnapshot().setId(1L));
+
+    assertThat(snapshots).isNotEmpty();
+    assertThat(snapshots).onProperty("id").containsOnly(1L, 6L);
+  }
+
+  @Test
+  public void set_snapshot_and_children_to_false_and_status_processed() {
+    setupData("snapshots");
+    SnapshotDto snapshot = defaultSnapshot().setId(1L);
+
+    sut.updateSnapshotAndChildrenLastFlagAndStatus(session, snapshot, false, SnapshotDto.STATUS_PROCESSED);
+    session.commit();
+
+    List<SnapshotDto> snapshots = sut.findSnapshotAndChildrenOfProjectScope(session, snapshot);
+    assertThat(snapshots).hasSize(2);
+    assertThat(snapshots).onProperty("id").containsOnly(1L, 6L);
+    assertThat(snapshots).onProperty("last").containsOnly(false);
+    assertThat(snapshots).onProperty("status").containsOnly(SnapshotDto.STATUS_PROCESSED);
+  }
+
+  @Test
+  public void set_snapshot_and_children_isLast_flag_to_false() {
+    setupData("snapshots");
+    SnapshotDto snapshot = defaultSnapshot().setId(1L);
+
+    sut.updateSnapshotAndChildrenLastFlag(session, snapshot, false);
+    session.commit();
+
+    List<SnapshotDto> snapshots = sut.findSnapshotAndChildrenOfProjectScope(session, snapshot);
+    assertThat(snapshots).hasSize(2);
+    assertThat(snapshots).onProperty("id").containsOnly(1L, 6L);
+    assertThat(snapshots).onProperty("last").containsOnly(false);
+  }
+
+  @Test
+  public void is_last_snapshot_when_no_previous_snapshot() {
+    SnapshotDto snapshot = defaultSnapshot();
+
+    boolean isLast = sut.isLast(snapshot, null);
+
+    assertThat(isLast).isTrue();
+  }
+
+  @Test
+  public void is_last_snapshot_when_previous_snapshot_is_older() {
+    Date today = new Date();
+    Date yesterday = DateUtils.addDays(today, -1);
+
+    SnapshotDto snapshot = defaultSnapshot().setCreatedAt(today);
+    SnapshotDto previousLastSnapshot = defaultSnapshot().setCreatedAt(yesterday);
+
+    boolean isLast = sut.isLast(snapshot, previousLastSnapshot);
+
+    assertThat(isLast).isTrue();
+  }
+
+  @Test
+  public void is_not_last_snapshot_when_previous_snapshot_is_newer() {
+    Date today = new Date();
+    Date yesterday = DateUtils.addDays(today, -1);
+
+    SnapshotDto snapshot = defaultSnapshot().setCreatedAt(yesterday);
+    SnapshotDto previousLastSnapshot = defaultSnapshot().setCreatedAt(today);
+
+    boolean isLast = sut.isLast(snapshot, previousLastSnapshot);
+
+    assertThat(isLast).isFalse();
+  }
+
+  public static SnapshotDto defaultSnapshot() {
+    return new SnapshotDto()
+      .setResourceId(3L)
+      .setRootProjectId(1L)
+      .setParentId(2L)
+      .setRootId(1L)
+      .setStatus("P")
+      .setLast(true)
+      .setPurgeStatus(1)
+      .setDepth(1)
+      .setScope("DIR")
+      .setQualifier("PAC")
+      .setVersion("2.1-SNAPSHOT")
+      .setPath("1.2.")
+      .setPeriodMode(1, "days1")
+      .setPeriodMode(2, "days2")
+      .setPeriodMode(3, "days3")
+      .setPeriodMode(4, "days4")
+      .setPeriodMode(5, "days5")
+      .setPeriodParam(1, "30")
+      .setPeriodParam(2, "31")
+      .setPeriodParam(3, "32")
+      .setPeriodParam(4, "33")
+      .setPeriodParam(5, "34")
+      .setPeriodDate(1, org.sonar.api.utils.DateUtils.parseDate("2011-09-24"))
+      .setPeriodDate(2, org.sonar.api.utils.DateUtils.parseDate("2011-09-25"))
+      .setPeriodDate(3, org.sonar.api.utils.DateUtils.parseDate("2011-09-26"))
+      .setPeriodDate(4, org.sonar.api.utils.DateUtils.parseDate("2011-09-27"))
+      .setPeriodDate(5, org.sonar.api.utils.DateUtils.parseDate("2011-09-28"))
+      .setBuildDate(org.sonar.api.utils.DateUtils.parseDate("2011-09-29"));
+  }
+}
index c24e6e36ebf421adbeb1de6b879eeb72fc830b63..eef6dcced535d3edd805f911a2bfc17aa3b66189 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.api.web.NavigationSection;
 import org.sonar.api.web.Page;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.core.measure.db.MeasureKey;
 import org.sonar.core.persistence.DbSession;
@@ -48,7 +49,6 @@ import org.sonar.core.properties.PropertiesDao;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.properties.PropertyQuery;
 import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.SnapshotDto;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.core.timemachine.Periods;
 import org.sonar.server.component.persistence.ComponentDao;
index 8edc2aa6b5ae926583f217889bdc29ed1a8060e1..83c6c69e11d1ce76f6b276f029f93d0bea6d3db7 100644 (file)
@@ -25,9 +25,9 @@ import org.junit.Test;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.TestDatabase;
 import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.SnapshotDto;
 
 import java.sql.SQLException;
 import java.util.Arrays;
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/not_returned_secured_settings_with_only_preview_permission.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/not_returned_secured_settings_with_only_preview_permission.json
deleted file mode 100644 (file)
index 8037eff..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_active_rules.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_active_rules.json
deleted file mode 100644 (file)
index f7f8faf..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [
-    {
-      "repositoryKey": "squid",
-      "ruleKey": "AvoidCycle",
-      "name": "Avoid Cycle",
-      "severity": "MINOR",
-      "internalKey": "squid-1",
-      "language": "java",
-      "params": {
-        "max" : "2"
-      }
-    }
-  ],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_settings.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_settings.json
deleted file mode 100644 (file)
index 4b56289..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings.json
deleted file mode 100644 (file)
index d1b864a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    },
-    "org.codehaus.sonar:sonar-server": {
-      "sonar.jira.project.key": "SONAR-SERVER",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings_inherited_from_project.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_settings_inherited_from_project.json
deleted file mode 100644 (file)
index deaea79..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    },
-    "org.codehaus.sonar:sonar-server": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_with_sub_module.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_module_with_sub_module.json
deleted file mode 100644 (file)
index ef8ef13..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    },
-    "org.codehaus.sonar:sonar-server": {
-      "sonar.jira.project.key": "SONAR-SERVER",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    },
-    "org.codehaus.sonar:sonar-server-dao": {
-      "sonar.jira.project.key": "SONAR-SERVER-DAO",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_two_modules.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_project_with_two_modules.json
deleted file mode 100644 (file)
index 302176c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john"
-    },
-    "org.codehaus.sonar:sonar-server": {
-      "sonar.jira.project.key": "SONAR-SERVER",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    },
-    "org.codehaus.sonar:sonar-application": {
-      "sonar.jira.project.key": "SONAR-APPLICATION",
-      "sonar.jira.login.secured": "john"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_provisioned_project_profile.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_provisioned_project_profile.json
deleted file mode 100644 (file)
index 282fafa..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "SonarQube way",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json
deleted file mode 100644 (file)
index a1bb33b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_given_profile_name.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_given_profile_name.json
deleted file mode 100644 (file)
index a1bb33b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json
deleted file mode 100644 (file)
index 282fafa..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "SonarQube way",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles_even_when_project_does_not_exists.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles_even_when_project_does_not_exists.json
deleted file mode 100644 (file)
index a1bb33b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {}
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings.json
deleted file mode 100644 (file)
index f2a89a9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar-server-dao": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_including_settings_from_parent_modules.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_including_settings_from_parent_modules.json
deleted file mode 100644 (file)
index f2a89a9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar-server-dao": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project.json
deleted file mode 100644 (file)
index f2a89a9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar-server-dao": {
-      "sonar.jira.project.key": "SONAR",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project_and_module.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_sub_module_settings_inherited_from_project_and_module.json
deleted file mode 100644 (file)
index c99fd8e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "timestamp": 0,
-  "qprofilesByLanguage": {
-    "java": {
-      "key": "abcd",
-      "name": "Default",
-      "language": "java",
-      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
-    }
-  },
-  "activeRules": [],
-  "settingsByModule": {
-    "org.codehaus.sonar:sonar-server-dao": {
-      "sonar.jira.project.key": "SONAR-SERVER",
-      "sonar.jira.login.secured": "john",
-      "sonar.coverage.exclusions": "**/*.java"
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/empty.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/empty.xml
new file mode 100644 (file)
index 0000000..871dedc
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/insert-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/insert-result.xml
new file mode 100644 (file)
index 0000000..2dfd09d
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <snapshots id="1" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2014-06-18" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/shared.xml
new file mode 100644 (file)
index 0000000..b651e75
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/snapshots.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/persistence/SnapshotDaoTest/snapshots.xml
new file mode 100644 (file)
index 0000000..9781e12
--- /dev/null
@@ -0,0 +1,65 @@
+<dataset>
+
+  <!-- PROJECT_ID = 1 -->
+  <snapshots id="1" project_id="1" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="2" project_id="1" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="3"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="3" project_id="1" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="3"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+
+  <!-- PROJECT_ID = 2 -->
+  <snapshots id="4" project_id="2" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="3"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+  <!-- PROJECT_ID = 3 â€“ no last snapshot -->
+  <snapshots id="5" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="3"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+  <!-- Child of snapshot id=1 -->
+  <snapshots id="6" project_id="55" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+</dataset>
diff --git a/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java b/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java
new file mode 100644 (file)
index 0000000..a9b5aaa
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.core.component;
+
+import org.sonar.core.persistence.Dto;
+
+import java.util.Date;
+
+public final class SnapshotDto extends Dto<Long> {
+
+  /**
+   * This status is set on the snapshot at the beginning of the batch
+   */
+  public static final String STATUS_UNPROCESSED = "U";
+  public static final String STATUS_PROCESSED = "P";
+
+  private static final String INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5 = "Index should be in range from 1 to 5";
+
+  private Long id;
+  private Long parentId;
+  private Long rootId;
+  private Long rootProjectId;
+
+  private Date buildDate;
+  private Long resourceId;
+  private String status = STATUS_UNPROCESSED;
+  private Integer purgeStatus;
+  private Boolean last;
+  private String scope;
+  private String qualifier;
+  private String version;
+  private String path;
+  private Integer depth;
+
+  private String period1Mode;
+  private String period2Mode;
+  private String period3Mode;
+  private String period4Mode;
+  private String period5Mode;
+
+  private String period1Param;
+  private String period2Param;
+  private String period3Param;
+  private String period4Param;
+  private String period5Param;
+
+  private Date period1Date;
+  private Date period2Date;
+  private Date period3Date;
+  private Date period4Date;
+  private Date period5Date;
+
+  public Long getId() {
+    return id;
+  }
+
+  public SnapshotDto setId(Long id) {
+    this.id = id;
+    return this;
+  }
+
+  public Long getParentId() {
+    return parentId;
+  }
+
+  public SnapshotDto setParentId(Long parentId) {
+    this.parentId = parentId;
+    return this;
+  }
+
+  public Long getRootId() {
+    return rootId;
+  }
+
+  public SnapshotDto setRootId(Long rootId) {
+    this.rootId = rootId;
+    return this;
+  }
+
+  public Date getBuildDate() {
+    return buildDate;
+  }
+
+  public SnapshotDto setBuildDate(Date buildDate) {
+    this.buildDate = buildDate;
+    return this;
+  }
+
+  public Long getResourceId() {
+    return resourceId;
+  }
+
+  public SnapshotDto setResourceId(Long resourceId) {
+    this.resourceId = resourceId;
+    return this;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public SnapshotDto setStatus(String status) {
+    this.status = status;
+    return this;
+  }
+
+  public Integer getPurgeStatus() {
+    return purgeStatus;
+  }
+
+  public SnapshotDto setPurgeStatus(Integer purgeStatus) {
+    this.purgeStatus = purgeStatus;
+    return this;
+  }
+
+  public Boolean getLast() {
+    return last;
+  }
+
+  public SnapshotDto setLast(Boolean last) {
+    this.last = last;
+    return this;
+  }
+
+  public String getScope() {
+    return scope;
+  }
+
+  public SnapshotDto setScope(String scope) {
+    this.scope = scope;
+    return this;
+  }
+
+  public String getQualifier() {
+    return qualifier;
+  }
+
+  public SnapshotDto setQualifier(String qualifier) {
+    this.qualifier = qualifier;
+    return this;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public SnapshotDto setVersion(String version) {
+    this.version = version;
+    return this;
+  }
+
+  public String getPath() {
+    return path;
+  }
+
+  public SnapshotDto setPath(String path) {
+    this.path = path;
+    return this;
+  }
+
+  public Integer getDepth() {
+    return depth;
+  }
+
+  public SnapshotDto setDepth(Integer depth) {
+    this.depth = depth;
+    return this;
+  }
+
+  public Long getRootProjectId() {
+    return rootProjectId;
+  }
+
+  public SnapshotDto setRootProjectId(Long rootProjectId) {
+    this.rootProjectId = rootProjectId;
+    return this;
+  }
+
+  public SnapshotDto setPeriodMode(int index, String p) {
+    switch (index) {
+      case 1:
+        period1Mode = p;
+        break;
+      case 2:
+        period2Mode = p;
+        break;
+      case 3:
+        period3Mode = p;
+        break;
+      case 4:
+        period4Mode = p;
+        break;
+      case 5:
+        period5Mode = p;
+        break;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+    return this;
+  }
+
+  public String getPeriodMode(int index) {
+    switch (index) {
+      case 1:
+        return period1Mode;
+      case 2:
+        return period2Mode;
+      case 3:
+        return period3Mode;
+      case 4:
+        return period4Mode;
+      case 5:
+        return period5Mode;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+  }
+
+  public SnapshotDto setPeriodParam(int index, String p) {
+    switch (index) {
+      case 1:
+        period1Param = p;
+        break;
+      case 2:
+        period2Param = p;
+        break;
+      case 3:
+        period3Param = p;
+        break;
+      case 4:
+        period4Param = p;
+        break;
+      case 5:
+        period5Param = p;
+        break;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+    return this;
+  }
+
+  public String getPeriodModeParameter(int periodIndex) {
+    switch (periodIndex) {
+      case 1:
+        return period1Param;
+      case 2:
+        return period2Param;
+      case 3:
+        return period3Param;
+      case 4:
+        return period4Param;
+      case 5:
+        return period5Param;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+  }
+
+  public SnapshotDto setPeriodDate(int index, Date d) {
+    switch (index) {
+      case 1:
+        period1Date = d;
+        break;
+      case 2:
+        period2Date = d;
+        break;
+      case 3:
+        period3Date = d;
+        break;
+      case 4:
+        period4Date = d;
+        break;
+      case 5:
+        period5Date = d;
+        break;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+    return this;
+  }
+
+  public Date getPeriodDate(int periodIndex) {
+    switch (periodIndex) {
+      case 1:
+        return period1Date;
+      case 2:
+        return period2Date;
+      case 3:
+        return period3Date;
+      case 4:
+        return period4Date;
+      case 5:
+        return period5Date;
+      default:
+        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
+    }
+  }
+
+  @Override
+  public Long getKey() {
+    return id;
+  }
+
+  @Override
+  public SnapshotDto setCreatedAt(Date datetime) {
+    super.setCreatedAt(datetime);
+    return this;
+  }
+
+  @Override
+  public SnapshotDto setUpdatedAt(Date datetime) {
+    super.setUpdatedAt(datetime);
+    return this;
+  }
+
+  public Long getRootIdOrSelf() {
+    return getRootId() == null ? getId() : getRootId();
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/db/SnapshotMapper.java b/sonar-core/src/main/java/org/sonar/core/component/db/SnapshotMapper.java
new file mode 100644 (file)
index 0000000..ba98cfb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.core.component.db;
+
+import org.apache.ibatis.annotations.Param;
+import org.sonar.core.component.SnapshotDto;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Date;
+import java.util.List;
+
+public interface SnapshotMapper {
+
+  @CheckForNull
+  SnapshotDto selectByKey(long id);
+
+  void insert(SnapshotDto rule);
+
+  @CheckForNull
+  SnapshotDto selectLastSnapshot(Long resourceId);
+
+  @CheckForNull
+  SnapshotDto selectLastSnapshotOlderThan(@Param(value = "resource") Long resourceId, @Param(value = "createdAt") Date createdAtBefore);
+
+  List<SnapshotDto> selectSnapshotAndChildrenOfScope(@Param(value = "snapshot") Long resourceId, @Param(value = "scope") String scope);
+
+  int updateSnapshotAndChildrenLastFlagAndStatus(@Param(value = "root") Long rootId, @Param(value = "pathRootId") Long pathRootId,
+                                                 @Param(value = "path") String path, @Param(value = "isLast") boolean isLast, @Param(value = "status") String status);
+
+  int updateSnapshotAndChildrenLastFlag(@Param(value = "root") Long rootId, @Param(value = "pathRootId") Long pathRootId,
+                                        @Param(value = "path") String path, @Param(value = "isLast") boolean isLast);
+}
index 58cf793f0e1ea2a3d87fe5d0d9dcbe0e8b72d883..0c348064e44cfd64ce4116d4d26b85653a09c156 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.core.cluster.WorkQueue;
 import org.sonar.core.component.AuthorizedComponentDto;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.db.ComponentMapper;
+import org.sonar.core.component.db.SnapshotMapper;
 import org.sonar.core.config.Logback;
 import org.sonar.core.dashboard.*;
 import org.sonar.core.dependency.DependencyDto;
@@ -127,7 +128,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
     loadAlias(conf, "ResourceSnapshot", ResourceSnapshotDto.class);
     loadAlias(conf, "Rule", RuleDto.class);
     loadAlias(conf, "RuleParam", RuleParamDto.class);
-    loadAlias(conf, "Snapshot", SnapshotDto.class);
+    loadAlias(conf, "Snapshot", org.sonar.core.component.SnapshotDto.class);
     loadAlias(conf, "Semaphore", SemaphoreDto.class);
     loadAlias(conf, "SchemaMigration", SchemaMigrationDto.class);
     loadAlias(conf, "User", UserDto.class);
@@ -171,7 +172,8 @@ public class MyBatis implements BatchComponent, ServerComponent {
       org.sonar.api.database.model.MeasureMapper.class, SnapshotDataMapper.class, SnapshotSourceMapper.class, ActionPlanMapper.class, ActionPlanStatsMapper.class,
       NotificationQueueMapper.class, CharacteristicMapper.class,
       GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
-      MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, ProjectQgateAssociationMapper.class,
+      MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class,  SnapshotMapper.class,
+      ProjectQgateAssociationMapper.class,
       Migration45Mapper.class
     };
     loadMappers(conf, mappers);
index 94b54f042b65266c13b2898a113d6582d9960c17..c6bd92404f2f0ab4e5b33e1096f470547a06e923 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.collect.Lists;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.component.Component;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
@@ -203,7 +204,7 @@ public class ResourceDao implements DaoComponent {
    * Return the root project of a component.
    * Will return the component itself if it's already the root project
    * Can return null if the component does not exists.
-   *
+   * <p/>
    * The implementation should rather use a new column already containing the root project, see https://jira.codehaus.org/browse/SONAR-5188.
    */
   @CheckForNull
@@ -243,7 +244,7 @@ public class ResourceDao implements DaoComponent {
    * Return the root project of a component.
    * Will return the component itself if it's already the root project
    * Can return null if the component that does exists.
-   *
+   * <p/>
    * The implementation should rather use a new column already containing the root project, see https://jira.codehaus.org/browse/SONAR-5188.
    */
   @CheckForNull
index f40caa1a42649666e545ec2a78b02e4b6445cfd4..18c2191772dfa4cd5c3fbeb56b7f8d4e1a00d93d 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.core.resource;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.session.ResultHandler;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
 
 import javax.annotation.Nullable;
 
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/SnapshotDto.java b/sonar-core/src/main/java/org/sonar/core/resource/SnapshotDto.java
deleted file mode 100644 (file)
index 54e1805..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.resource;
-
-import java.util.Date;
-
-public final class SnapshotDto {
-
-  private static final String INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5 = "Index should be in range from 1 to 5";
-
-  private Long id;
-  private Long parentId;
-  private Long rootId;
-  private Long rootProjectId;
-
-  private Date date;
-  private Date buildDate;
-  private Long resourceId;
-  private String status;
-  private Integer purgeStatus;
-  private Boolean last;
-  private String scope;
-  private String qualifier;
-  private String version;
-  private String path;
-  private Integer depth;
-
-  private String period1Mode;
-  private String period2Mode;
-  private String period3Mode;
-  private String period4Mode;
-  private String period5Mode;
-
-  private String period1Param;
-  private String period2Param;
-  private String period3Param;
-  private String period4Param;
-  private String period5Param;
-
-  private Date period1Date;
-  private Date period2Date;
-  private Date period3Date;
-  private Date period4Date;
-  private Date period5Date;
-
-  public Long getId() {
-    return id;
-  }
-
-  public SnapshotDto setId(Long id) {
-    this.id = id;
-    return this;
-  }
-
-  public Long getParentId() {
-    return parentId;
-  }
-
-  public SnapshotDto setParentId(Long parentId) {
-    this.parentId = parentId;
-    return this;
-  }
-
-  public Long getRootId() {
-    return rootId;
-  }
-
-  public SnapshotDto setRootId(Long rootId) {
-    this.rootId = rootId;
-    return this;
-  }
-
-  public Date getDate() {
-    return date;
-  }
-
-  public SnapshotDto setDate(Date date) {
-    this.date = date;
-    return this;
-  }
-
-  public Date getBuildDate() {
-    return buildDate;
-  }
-
-  public SnapshotDto setBuildDate(Date buildDate) {
-    this.buildDate = buildDate;
-    return this;
-  }
-
-  public Long getResourceId() {
-    return resourceId;
-  }
-
-  public SnapshotDto setResourceId(Long resourceId) {
-    this.resourceId = resourceId;
-    return this;
-  }
-
-  public String getStatus() {
-    return status;
-  }
-
-  public SnapshotDto setStatus(String status) {
-    this.status = status;
-    return this;
-  }
-
-  public Integer getPurgeStatus() {
-    return purgeStatus;
-  }
-
-  public SnapshotDto setPurgeStatus(Integer purgeStatus) {
-    this.purgeStatus = purgeStatus;
-    return this;
-  }
-
-  public Boolean getLast() {
-    return last;
-  }
-
-  public SnapshotDto setLast(Boolean last) {
-    this.last = last;
-    return this;
-  }
-
-  public String getScope() {
-    return scope;
-  }
-
-  public SnapshotDto setScope(String scope) {
-    this.scope = scope;
-    return this;
-  }
-
-  public String getQualifier() {
-    return qualifier;
-  }
-
-  public SnapshotDto setQualifier(String qualifier) {
-    this.qualifier = qualifier;
-    return this;
-  }
-
-  public String getVersion() {
-    return version;
-  }
-
-  public SnapshotDto setVersion(String version) {
-    this.version = version;
-    return this;
-  }
-
-  public String getPath() {
-    return path;
-  }
-
-  public SnapshotDto setPath(String path) {
-    this.path = path;
-    return this;
-  }
-
-  public Integer getDepth() {
-    return depth;
-  }
-
-  public SnapshotDto setDepth(Integer depth) {
-    this.depth = depth;
-    return this;
-  }
-
-  public Long getRootProjectId() {
-    return rootProjectId;
-  }
-
-  public SnapshotDto setRootProjectId(Long rootProjectId) {
-    this.rootProjectId = rootProjectId;
-    return this;
-  }
-
-  public SnapshotDto setPeriodMode(int index, String p) {
-    switch (index) {
-      case 1:
-        period1Mode = p;
-        break;
-      case 2:
-        period2Mode = p;
-        break;
-      case 3:
-        period3Mode = p;
-        break;
-      case 4:
-        period4Mode = p;
-        break;
-      case 5:
-        period5Mode = p;
-        break;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-    return this;
-  }
-
-  public String getPeriodMode(int index) {
-    switch (index) {
-      case 1:
-        return period1Mode;
-      case 2:
-        return period2Mode;
-      case 3:
-        return period3Mode;
-      case 4:
-        return period4Mode;
-      case 5:
-        return period5Mode;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-  }
-
-  public SnapshotDto setPeriodParam(int index, String p) {
-    switch (index) {
-      case 1:
-        period1Param = p;
-        break;
-      case 2:
-        period2Param = p;
-        break;
-      case 3:
-        period3Param = p;
-        break;
-      case 4:
-        period4Param = p;
-        break;
-      case 5:
-        period5Param = p;
-        break;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-    return this;
-  }
-
-  public String getPeriodModeParameter(int periodIndex) {
-    switch (periodIndex) {
-      case 1:
-        return period1Param;
-      case 2:
-        return period2Param;
-      case 3:
-        return period3Param;
-      case 4:
-        return period4Param;
-      case 5:
-        return period5Param;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-  }
-
-  public SnapshotDto setPeriodDate(int index, Date d) {
-    switch (index) {
-      case 1:
-        period1Date = d;
-        break;
-      case 2:
-        period2Date = d;
-        break;
-      case 3:
-        period3Date = d;
-        break;
-      case 4:
-        period4Date = d;
-        break;
-      case 5:
-        period5Date = d;
-        break;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-    return this;
-  }
-
-  public Date getPeriodDate(int periodIndex) {
-    switch (periodIndex) {
-      case 1:
-        return period1Date;
-      case 2:
-        return period2Date;
-      case 3:
-        return period3Date;
-      case 4:
-        return period4Date;
-      case 5:
-        return period5Date;
-      default:
-        throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5);
-    }
-  }
-
-}
diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/SnapshotMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/SnapshotMapper.xml
new file mode 100644 (file)
index 0000000..c011219
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.sonar.core.component.db.SnapshotMapper">
+
+  <sql id="snapshotColumns">
+    s.id,
+    s.parent_snapshot_id as parentId,
+    s.root_snapshot_id as rootId,
+    s.root_project_id as rootProjectId,
+    s.project_id as resourceId,
+    s.created_at as createdAt,
+    s.build_date as buildDate,
+    s.status as status,
+    s.purge_status as purgeStatus,
+    s.islast as last,
+    s.scope as scope,
+    s.qualifier as qualifier,
+    s.version as version,
+    s.path as path,
+    s.depth as depth,
+    s.period1_mode as period1Mode,
+    s.period2_mode as period2Mode,
+    s.period3_mode as period3Mode,
+    s.period4_mode as period4Mode,
+    s.period5_mode as period5Mode,
+    s.period1_param as period1Param,
+    s.period2_param as period2Param,
+    s.period3_param as period3Param,
+    s.period4_param as period4Param,
+    s.period5_param as period5Param,
+    s.period1_date as period1Date,
+    s.period2_date as period2Date,
+    s.period3_date as period3Date,
+    s.period4_date as period4Date,
+    s.period5_date as period5Date
+  </sql>
+
+  <select id="selectByKey" parameterType="Long" resultType="Snapshot">
+    SELECT
+    <include refid="snapshotColumns"/>
+    FROM snapshots s
+    <where>
+      AND s.id=#{key}
+    </where>
+  </select>
+
+  <select id="selectLastSnapshot" resultType="Snapshot">
+    select
+    <include refid="snapshotColumns"/>
+    from snapshots s
+    where s.islast=${_true} and s.project_id = #{resource}
+  </select>
+
+  <select id="selectLastSnapshotOlderThan" parameterType="map" resultType="Snapshot">
+    select
+    <include refid="snapshotColumns"/>
+    from snapshots s
+    where s.islast=${_true}
+    and s.project_id = #{resource}
+    and s.created_at &lt; #{createdAt}
+  </select>
+
+  <select id="selectSnapshotAndChildrenOfScope" parameterType="map" resultType="Snapshot">
+    select
+    <include refid="snapshotColumns"/>
+    from snapshots s
+    where s.scope = #{scope}
+    AND (s.id = #{snapshot} or s.root_snapshot_id = #{snapshot})
+  </select>
+
+  <sql id="insertColumns">
+    (parent_snapshot_id, root_snapshot_id, root_project_id, project_id, created_at, build_date, status, purge_status,
+    islast, scope, qualifier, version, path, depth,
+    period1_mode, period2_mode, period3_mode, period4_mode, period5_mode,
+    period1_param, period2_param, period3_param, period4_param, period5_param,
+    period1_date, period2_date, period3_date, period4_date, period5_date)
+  </sql>
+
+  <update id="updateSnapshotAndChildrenLastFlagAndStatus" parameterType="map">
+    update snapshots
+    set islast = #{isLast}, status = #{status}
+    where root_snapshot_id=#{root} or id=#{root} or (path like #{path} and root_snapshot_id=#{pathRootId})
+  </update>
+
+  <update id="updateSnapshotAndChildrenLastFlag" parameterType="map">
+    update snapshots
+    set islast = #{isLast}
+    where root_snapshot_id=#{root} or id=#{root} or (path like #{path} and root_snapshot_id=#{pathRootId})
+  </update>
+
+  <insert id="insert" parameterType="Component" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
+    insert into snapshots
+    <include refid="insertColumns"/>
+    values (#{parentId}, #{rootId}, #{rootProjectId}, #{resourceId}, #{createdAt}, #{buildDate}, #{status},
+    #{purgeStatus}, #{last}, #{scope}, #{qualifier}, #{version}, #{path}, #{depth},
+    #{period1Mode}, #{period2Mode}, #{period3Mode}, #{period4Mode}, #{period5Mode},
+    #{period1Param}, #{period2Param}, #{period3Param}, #{period4Param}, #{period5Param},
+    #{period1Date}, #{period2Date}, #{period3Date}, #{period4Date}, #{period5Date})
+  </insert>
+
+</mapper>
+
index f32095b71dab393bf907140bebe594251c806add..ee2073a06bac7de04d5358ff489c749e206b1281 100644 (file)
@@ -36,7 +36,7 @@
     <id property="id" column="id"/>
     <result property="parentId" column="parent_snapshot_id"/>
     <result property="rootId" column="root_snapshot_id"/>
-    <result property="date" column="created_at"/>
+    <result property="createdAt" column="created_at"/>
     <result property="buildDate" column="build_date"/>
     <result property="resourceId" column="project_id"/>
     <result property="status" column="status"/>
index 756136fd3800fa998b225a7e3c10260f9a4842c5..8bb3c116efc35a9564952a00eba1e19488625384 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
 
diff --git a/sonar-core/src/test/java/org/sonar/core/resource/SnapshotDtoTest.java b/sonar-core/src/test/java/org/sonar/core/resource/SnapshotDtoTest.java
deleted file mode 100644 (file)
index 94ce880..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.resource;
-
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class SnapshotDtoTest {
-
-  @Test
-  public void test_getter_and_setter() throws Exception {
-    SnapshotDto snapshotDto = new SnapshotDto()
-      .setId(10L)
-      .setParentId(2L)
-      .setRootId(3L)
-      .setRootProjectId(20L)
-      .setDate(DateUtils.parseDate("2014-07-01"))
-      .setBuildDate(DateUtils.parseDate("2014-07-02"))
-      .setResourceId(21L)
-      .setLast(true)
-      .setScope("FIL")
-      .setQualifier("FIL")
-      .setVersion("1.0")
-      .setPath("3.2.")
-      .setDepth(1)
-      .setPeriodMode(1, "mode1")
-      .setPeriodMode(2, "mode2")
-      .setPeriodMode(3, "mode3")
-      .setPeriodMode(4, "mode4")
-      .setPeriodMode(5, "mode5")
-      .setPeriodParam(1, "param1")
-      .setPeriodParam(2, "param2")
-      .setPeriodParam(3, "param3")
-      .setPeriodParam(4, "param4")
-      .setPeriodParam(5, "param5")
-      .setPeriodDate(1, DateUtils.parseDate("2014-06-01"))
-      .setPeriodDate(2, DateUtils.parseDate("2014-06-02"))
-      .setPeriodDate(3, DateUtils.parseDate("2014-06-03"))
-      .setPeriodDate(4, DateUtils.parseDate("2014-06-04"))
-      .setPeriodDate(5, DateUtils.parseDate("2014-06-05"));
-
-    assertThat(snapshotDto.getId()).isEqualTo(10L);
-    assertThat(snapshotDto.getParentId()).isEqualTo(2L);
-    assertThat(snapshotDto.getRootId()).isEqualTo(3L);
-    assertThat(snapshotDto.getRootProjectId()).isEqualTo(20L);
-    assertThat(snapshotDto.getDate()).isEqualTo(DateUtils.parseDate("2014-07-01"));
-    assertThat(snapshotDto.getBuildDate()).isEqualTo(DateUtils.parseDate("2014-07-02"));
-    assertThat(snapshotDto.getResourceId()).isEqualTo(21L);
-    assertThat(snapshotDto.getLast()).isTrue();
-    assertThat(snapshotDto.getScope()).isEqualTo("FIL");
-    assertThat(snapshotDto.getQualifier()).isEqualTo("FIL");
-    assertThat(snapshotDto.getVersion()).isEqualTo("1.0");
-    assertThat(snapshotDto.getPath()).isEqualTo("3.2.");
-    assertThat(snapshotDto.getDepth()).isEqualTo(1);
-    assertThat(snapshotDto.getPeriodMode(1)).isEqualTo("mode1");
-    assertThat(snapshotDto.getPeriodMode(2)).isEqualTo("mode2");
-    assertThat(snapshotDto.getPeriodMode(3)).isEqualTo("mode3");
-    assertThat(snapshotDto.getPeriodMode(4)).isEqualTo("mode4");
-    assertThat(snapshotDto.getPeriodMode(5)).isEqualTo("mode5");
-    assertThat(snapshotDto.getPeriodModeParameter(1)).isEqualTo("param1");
-    assertThat(snapshotDto.getPeriodModeParameter(2)).isEqualTo("param2");
-    assertThat(snapshotDto.getPeriodModeParameter(3)).isEqualTo("param3");
-    assertThat(snapshotDto.getPeriodModeParameter(4)).isEqualTo("param4");
-    assertThat(snapshotDto.getPeriodModeParameter(5)).isEqualTo("param5");
-    assertThat(snapshotDto.getPeriodDate(1)).isEqualTo(DateUtils.parseDate("2014-06-01"));
-    assertThat(snapshotDto.getPeriodDate(2)).isEqualTo(DateUtils.parseDate("2014-06-02"));
-    assertThat(snapshotDto.getPeriodDate(3)).isEqualTo(DateUtils.parseDate("2014-06-03"));
-    assertThat(snapshotDto.getPeriodDate(4)).isEqualTo(DateUtils.parseDate("2014-06-04"));
-    assertThat(snapshotDto.getPeriodDate(5)).isEqualTo(DateUtils.parseDate("2014-06-05"));
-  }
-
-}