]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5878 More improvement concerning memory consumption
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 3 Dec 2014 22:51:05 +0000 (23:51 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Wed, 3 Dec 2014 22:55:44 +0000 (23:55 +0100)
  * replace all Properties objects by Map<String, String>
  * release Settings after each module analysis

sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java
sonar-batch/src/test/java/org/sonar/batch/scan/ProjectReactorBuilderTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/bootstrap/ProjectDefinitionTest.java

index 0ba55b20c9d77bcb0c2710e9ae961585646c98ad..6edd826ab037e1c47d13818479ab64ec216ceea1 100644 (file)
@@ -76,6 +76,8 @@ public class TaskContainer extends ComponentContainer {
 
   void installCoreTasks() {
     add(new TaskProperties(taskProperties, getParent().getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)));
+    // Release memory
+    taskProperties.clear();
     add(
       ScanTask.DEFINITION, ScanTask.class,
       ListTask.DEFINITION, ListTask.class,
index 7d04d8e24d0ade7b2134d188ddbaee6b26627727..6050f938d55c372c3eeaf00ffa9dae29e647da1b 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.batch.bootstrap.TaskProperties;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 
@@ -43,10 +44,10 @@ public class DeprecatedProjectReactorBuilder extends ProjectReactorBuilder {
   }
 
   @Override
-  protected ProjectDefinition loadChildProject(ProjectDefinition parentProject, Properties moduleProps, String moduleId) {
+  protected ProjectDefinition loadChildProject(ProjectDefinition parentProject, Map<String, String> moduleProps, String moduleId) {
     final File baseDir;
     if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
-      baseDir = resolvePath(parentProject.getBaseDir(), moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+      baseDir = resolvePath(parentProject.getBaseDir(), moduleProps.get(PROPERTY_PROJECT_BASEDIR));
       setProjectBaseDir(baseDir, moduleProps, moduleId);
       try {
         if (!parentProject.getBaseDir().getCanonicalFile().equals(baseDir.getCanonicalFile())) {
@@ -69,7 +70,7 @@ public class DeprecatedProjectReactorBuilder extends ProjectReactorBuilder {
     checkMandatoryProperties(moduleProps, MANDATORY_PROPERTIES_FOR_CHILD);
     validateDirectories(moduleProps, baseDir, moduleId);
 
-    mergeParentProperties(moduleProps, parentProject.getProperties());
+    mergeParentProperties(moduleProps, parentProject.properties());
 
     return defineRootProject(moduleProps, parentProject);
   }
@@ -77,16 +78,16 @@ public class DeprecatedProjectReactorBuilder extends ProjectReactorBuilder {
   /**
    * @return baseDir
    */
-  private File loadPropsFile(ProjectDefinition parentProject, Properties moduleProps, String moduleId) {
-    File propertyFile = resolvePath(parentProject.getBaseDir(), moduleProps.getProperty(PROPERTY_PROJECT_CONFIG_FILE));
+  private File loadPropsFile(ProjectDefinition parentProject, Map<String, String> moduleProps, String moduleId) {
+    File propertyFile = resolvePath(parentProject.getBaseDir(), moduleProps.get(PROPERTY_PROJECT_CONFIG_FILE));
     if (propertyFile.isFile()) {
       Properties propsFromFile = toProperties(propertyFile);
       for (Entry<Object, Object> entry : propsFromFile.entrySet()) {
-        moduleProps.put(entry.getKey(), entry.getValue());
+        moduleProps.put(entry.getKey().toString(), entry.getValue().toString());
       }
       File baseDir = null;
       if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
-        baseDir = resolvePath(propertyFile.getParentFile(), moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+        baseDir = resolvePath(propertyFile.getParentFile(), moduleProps.get(PROPERTY_PROJECT_BASEDIR));
       } else {
         baseDir = propertyFile.getParentFile();
       }
@@ -97,15 +98,15 @@ public class DeprecatedProjectReactorBuilder extends ProjectReactorBuilder {
     }
   }
 
-  private void tryToFindAndLoadPropsFile(File baseDir, Properties moduleProps, String moduleId) {
+  private void tryToFindAndLoadPropsFile(File baseDir, Map<String, String> moduleProps, String moduleId) {
     File propertyFile = new File(baseDir, "sonar-project.properties");
     if (propertyFile.isFile()) {
       Properties propsFromFile = toProperties(propertyFile);
       for (Entry<Object, Object> entry : propsFromFile.entrySet()) {
-        moduleProps.put(entry.getKey(), entry.getValue());
+        moduleProps.put(entry.getKey().toString(), entry.getValue().toString());
       }
       if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
-        File overwrittenBaseDir = resolvePath(propertyFile.getParentFile(), moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+        File overwrittenBaseDir = resolvePath(propertyFile.getParentFile(), moduleProps.get(PROPERTY_PROJECT_BASEDIR));
         setProjectBaseDir(overwrittenBaseDir, moduleProps, moduleId);
       }
     }
index e2b782691759debf7b564ddaaee7f4619a543927..21bb31470bd0331039b3ae051c4e2f55e3297bde 100644 (file)
@@ -220,6 +220,9 @@ public class ModuleScanContainer extends ComponentContainer {
       getComponentByType(ModuleIssues.class));
 
     getComponentByType(PhaseExecutor.class).execute(module);
+
+    // Free memory since module settings are no more used
+    module.setSettings(null);
   }
 
 }
index 202c2a23061cb49ee70cae0857c3f45d82ae292a..58417768e005071c6178517cc1c99295c9006cb4 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.commons.io.filefilter.AndFileFilter;
 import org.apache.commons.io.filefilter.FileFileFilter;
 import org.apache.commons.io.filefilter.IOFileFilter;
 import org.apache.commons.io.filefilter.WildcardFileFilter;
+import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -109,28 +110,26 @@ public class ProjectReactorBuilder {
   }
 
   public ProjectReactor execute() {
-    Properties allProperties = new Properties();
-    allProperties.putAll(taskProps.properties());
-    Map<String, Properties> propertiesByModuleId = extractPropertiesByModule("", allProperties);
+    Map<String, Map<String, String>> propertiesByModuleId = extractPropertiesByModule("", taskProps.properties());
     ProjectDefinition rootProject = defineRootProject(propertiesByModuleId.get(""), null);
     rootProjectWorkDir = rootProject.getWorkDir();
     defineChildren(rootProject, propertiesByModuleId);
     cleanAndCheckProjectDefinitions(rootProject);
     // Optimization remove all children properties from taskProps
     taskProps.properties().clear();
-    for (Map.Entry<Object, Object> entry : propertiesByModuleId.get("").entrySet()) {
+    for (Map.Entry<String, String> entry : propertiesByModuleId.get("").entrySet()) {
       taskProps.properties().put((String) entry.getKey(), (String) entry.getValue());
     }
     return new ProjectReactor(rootProject);
   }
 
-  private Map<String, Properties> extractPropertiesByModule(String currentModuleId, Properties parentProperties) {
-    Properties allProperties = new Properties();
+  private Map<String, Map<String, String>> extractPropertiesByModule(String currentModuleId, Map<String, String> parentProperties) {
+    Map<String, String> allProperties = new HashMap<String, String>();
     allProperties.putAll(parentProperties);
-    Properties currentModuleProperties = new Properties();
+    Map<String, String> currentModuleProperties = new HashMap<String, String>();
     String prefix = !currentModuleId.isEmpty() ? currentModuleId + "." : "";
     // By default all properties starting with module prefix belong to current module
-    for (Map.Entry<Object, Object> entry : allProperties.entrySet()) {
+    for (Map.Entry<String, String> entry : allProperties.entrySet()) {
       String key = (String) entry.getKey();
       int prefixLength = prefix.length();
       if (key.startsWith(prefix)) {
@@ -139,7 +138,7 @@ public class ProjectReactorBuilder {
       }
     }
     String[] moduleIds = getListFromProperty(currentModuleProperties, PROPERTY_MODULES);
-    Map<String, Properties> result = new HashMap<String, Properties>();
+    Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
     for (String moduleId : moduleIds) {
       result.putAll(extractPropertiesByModule(moduleId, currentModuleProperties));
     }
@@ -147,14 +146,14 @@ public class ProjectReactorBuilder {
     return result;
   }
 
-  protected ProjectDefinition defineRootProject(Properties rootProperties, @Nullable ProjectDefinition parent) {
+  protected ProjectDefinition defineRootProject(Map<String, String> rootProperties, @Nullable ProjectDefinition parent) {
     if (rootProperties.containsKey(PROPERTY_MODULES)) {
       checkMandatoryProperties(rootProperties, MANDATORY_PROPERTIES_FOR_MULTIMODULE_PROJECT);
     } else {
       checkMandatoryProperties(rootProperties, MANDATORY_PROPERTIES_FOR_SIMPLE_PROJECT);
     }
-    File baseDir = new File(rootProperties.getProperty(PROPERTY_PROJECT_BASEDIR));
-    final String projectKey = rootProperties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
+    File baseDir = new File(rootProperties.get(PROPERTY_PROJECT_BASEDIR));
+    final String projectKey = rootProperties.get(CoreProperties.PROJECT_KEY_PROPERTY);
     File workDir;
     if (parent == null) {
       validateDirectories(rootProperties, baseDir, projectKey);
@@ -184,10 +183,10 @@ public class ProjectReactorBuilder {
   }
 
   @VisibleForTesting
-  protected File initModuleWorkDir(File moduleBaseDir, Properties moduleProperties) {
-    String workDir = moduleProperties.getProperty(CoreProperties.WORKING_DIRECTORY);
+  protected File initModuleWorkDir(File moduleBaseDir, Map<String, String> moduleProperties) {
+    String workDir = moduleProperties.get(CoreProperties.WORKING_DIRECTORY);
     if (StringUtils.isBlank(workDir)) {
-      String cleanKey = StringUtils.deleteWhitespace(moduleProperties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY));
+      String cleanKey = StringUtils.deleteWhitespace(moduleProperties.get(CoreProperties.PROJECT_KEY_PROPERTY));
       cleanKey = StringUtils.replace(cleanKey, ":", "_");
       return new File(rootProjectWorkDir, cleanKey);
     }
@@ -200,8 +199,8 @@ public class ProjectReactorBuilder {
   }
 
   @CheckForNull
-  private File initModuleBuildDir(File moduleBaseDir, Properties moduleProperties) {
-    String buildDir = moduleProperties.getProperty(PROPERTY_PROJECT_BUILDDIR);
+  private File initModuleBuildDir(File moduleBaseDir, Map<String, String> moduleProperties) {
+    String buildDir = moduleProperties.get(PROPERTY_PROJECT_BUILDDIR);
     if (StringUtils.isBlank(buildDir)) {
       return null;
     }
@@ -213,11 +212,11 @@ public class ProjectReactorBuilder {
     return new File(moduleBaseDir, customBuildDir.getPath());
   }
 
-  private void defineChildren(ProjectDefinition parentProject, Map<String, Properties> propertiesByModuleId) {
-    Properties parentProps = parentProject.getProperties();
+  private void defineChildren(ProjectDefinition parentProject, Map<String, Map<String, String>> propertiesByModuleId) {
+    Map<String, String> parentProps = parentProject.properties();
     if (parentProps.containsKey(PROPERTY_MODULES)) {
       for (String moduleId : getListFromProperty(parentProps, PROPERTY_MODULES)) {
-        Properties moduleProps = propertiesByModuleId.get(moduleId);
+        Map<String, String> moduleProps = propertiesByModuleId.get(moduleId);
         ProjectDefinition childProject = loadChildProject(parentProject, moduleProps, moduleId);
         // check the uniqueness of the child key
         checkUniquenessOfChildKey(childProject, parentProject);
@@ -229,10 +228,10 @@ public class ProjectReactorBuilder {
     }
   }
 
-  protected ProjectDefinition loadChildProject(ProjectDefinition parentProject, Properties moduleProps, String moduleId) {
+  protected ProjectDefinition loadChildProject(ProjectDefinition parentProject, Map<String, String> moduleProps, String moduleId) {
     final File baseDir;
     if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
-      baseDir = resolvePath(parentProject.getBaseDir(), moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+      baseDir = resolvePath(parentProject.getBaseDir(), moduleProps.get(PROPERTY_PROJECT_BASEDIR));
       setProjectBaseDir(baseDir, moduleProps, moduleId);
     } else {
       baseDir = new File(parentProject.getBaseDir(), moduleId);
@@ -245,7 +244,7 @@ public class ProjectReactorBuilder {
     checkMandatoryProperties(moduleProps, MANDATORY_PROPERTIES_FOR_CHILD);
     validateDirectories(moduleProps, baseDir, moduleId);
 
-    mergeParentProperties(moduleProps, parentProject.getProperties());
+    mergeParentProperties(moduleProps, parentProject.properties());
 
     return defineRootProject(moduleProps, parentProject);
   }
@@ -270,12 +269,12 @@ public class ProjectReactorBuilder {
   }
 
   @VisibleForTesting
-  protected static void setModuleKeyAndNameIfNotDefined(Properties childProps, String moduleId, String parentKey) {
+  protected static void setModuleKeyAndNameIfNotDefined(Map<String, String> childProps, String moduleId, String parentKey) {
     if (!childProps.containsKey(MODULE_KEY_PROPERTY)) {
       if (!childProps.containsKey(CoreProperties.PROJECT_KEY_PROPERTY)) {
         childProps.put(MODULE_KEY_PROPERTY, parentKey + ":" + moduleId);
       } else {
-        String childKey = childProps.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
+        String childKey = childProps.get(CoreProperties.PROJECT_KEY_PROPERTY);
         childProps.put(MODULE_KEY_PROPERTY, parentKey + ":" + childKey);
       }
     }
@@ -283,7 +282,7 @@ public class ProjectReactorBuilder {
       childProps.put(CoreProperties.PROJECT_NAME_PROPERTY, moduleId);
     }
     // For backward compatibility with ProjectDefinition
-    childProps.put(CoreProperties.PROJECT_KEY_PROPERTY, childProps.getProperty(MODULE_KEY_PROPERTY));
+    childProps.put(CoreProperties.PROJECT_KEY_PROPERTY, childProps.get(MODULE_KEY_PROPERTY));
   }
 
   @VisibleForTesting
@@ -295,7 +294,7 @@ public class ProjectReactorBuilder {
     }
   }
 
-  protected static void setProjectBaseDir(File baseDir, Properties childProps, String moduleId) {
+  protected static void setProjectBaseDir(File baseDir, Map<String, String> childProps, String moduleId) {
     if (!baseDir.isDirectory()) {
       throw new IllegalStateException("The base directory of the module '" + moduleId + "' does not exist: " + baseDir.getAbsolutePath());
     }
@@ -303,7 +302,7 @@ public class ProjectReactorBuilder {
   }
 
   @VisibleForTesting
-  protected static void checkMandatoryProperties(Properties props, String[] mandatoryProps) {
+  protected static void checkMandatoryProperties(Map<String, String> props, String[] mandatoryProps) {
     StringBuilder missing = new StringBuilder();
     for (String mandatoryProperty : mandatoryProps) {
       if (!props.containsKey(mandatoryProperty)) {
@@ -313,13 +312,13 @@ public class ProjectReactorBuilder {
         missing.append(mandatoryProperty);
       }
     }
-    String moduleKey = StringUtils.defaultIfBlank(props.getProperty(MODULE_KEY_PROPERTY), props.getProperty(CoreProperties.PROJECT_KEY_PROPERTY));
+    String moduleKey = StringUtils.defaultIfBlank(props.get(MODULE_KEY_PROPERTY), props.get(CoreProperties.PROJECT_KEY_PROPERTY));
     if (missing.length() != 0) {
       throw new IllegalStateException("You must define the following mandatory properties for '" + (moduleKey == null ? "Unknown" : moduleKey) + "': " + missing);
     }
   }
 
-  protected static void validateDirectories(Properties props, File baseDir, String projectId) {
+  protected static void validateDirectories(Map<String, String> props, File baseDir, String projectId) {
     if (!props.containsKey(PROPERTY_MODULES)) {
       // SONARPLUGINS-2285 Not an aggregator project so we can validate that paths are correct if defined
 
@@ -358,7 +357,7 @@ public class ProjectReactorBuilder {
 
   @VisibleForTesting
   protected static void cleanAndCheckModuleProperties(ProjectDefinition project) {
-    Properties properties = project.getProperties();
+    Map<String, String> properties = project.properties();
 
     // We need to check the existence of source directories
     String[] sourcePaths = getListFromProperty(properties, PROPERTY_SOURCES);
@@ -377,7 +376,7 @@ public class ProjectReactorBuilder {
 
   @VisibleForTesting
   protected static void cleanAndCheckAggregatorProjectProperties(ProjectDefinition project) {
-    Properties properties = project.getProperties();
+    Map<String, String> properties = project.properties();
 
     // SONARPLUGINS-2295
     String[] sourceDirs = getListFromProperty(properties, PROPERTY_SOURCES);
@@ -398,8 +397,8 @@ public class ProjectReactorBuilder {
   }
 
   @VisibleForTesting
-  protected static void mergeParentProperties(Properties childProps, Properties parentProps) {
-    for (Map.Entry<Object, Object> entry : parentProps.entrySet()) {
+  protected static void mergeParentProperties(Map<String, String> childProps, Map<String, String> parentProps) {
+    for (Map.Entry<String, String> entry : parentProps.entrySet()) {
       String key = (String) entry.getKey();
       if ((!childProps.containsKey(key) || childProps.get(key).equals(entry.getValue()))
         && !NON_HERITED_PROPERTIES_FOR_CHILD.contains(key)) {
@@ -479,8 +478,8 @@ public class ProjectReactorBuilder {
    * This works even if they are separated by whitespace characters (space char, EOL, ...)
    *
    */
-  static String[] getListFromProperty(Properties properties, String key) {
-    return StringUtils.stripAll(StringUtils.split(properties.getProperty(key, ""), ','));
+  static String[] getListFromProperty(Map<String, String> properties, String key) {
+    return (String[]) ObjectUtils.defaultIfNull(StringUtils.stripAll(StringUtils.split(properties.get(key), ',')), new String[0]);
   }
 
 }
index 93288b17e4b94f28fbf120d1f3c0a88a70399def..fe0ee966ec5cf523c6c2ef5e2739d9aee21d4c61 100644 (file)
@@ -342,9 +342,9 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldFailIfMandatoryPropertiesAreNotPresent() {
-    Properties props = new Properties();
-    props.setProperty("foo1", "bla");
-    props.setProperty("foo4", "bla");
+    Map<String, String> props = new HashMap<String, String>();
+    props.put("foo1", "bla");
+    props.put("foo4", "bla");
 
     thrown.expect(IllegalStateException.class);
     thrown.expectMessage("You must define the following mandatory properties for 'Unknown': foo2, foo3");
@@ -354,9 +354,9 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldFailIfMandatoryPropertiesAreNotPresentButWithProjectKey() {
-    Properties props = new Properties();
-    props.setProperty("foo1", "bla");
-    props.setProperty("sonar.projectKey", "my-project");
+    Map<String, String> props = new HashMap<String, String>();
+    props.put("foo1", "bla");
+    props.put("sonar.projectKey", "my-project");
 
     thrown.expect(IllegalStateException.class);
     thrown.expectMessage("You must define the following mandatory properties for 'my-project': foo2, foo3");
@@ -366,9 +366,9 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldNotFailIfMandatoryPropertiesArePresent() {
-    Properties props = new Properties();
-    props.setProperty("foo1", "bla");
-    props.setProperty("foo4", "bla");
+    Map<String, String> props = new HashMap<String, String>();
+    props.put("foo1", "bla");
+    props.put("foo4", "bla");
 
     ProjectReactorBuilder.checkMandatoryProperties(props, new String[] {"foo1"});
 
@@ -411,25 +411,25 @@ public class ProjectReactorBuilderTest {
     int i = (int) Math.random() * 10;
     String s1 = "value" + i;
     String s2 = "value" + i;
-    Properties parentProps = new Properties();
-    parentProps.setProperty("toBeMergeProps", "fooParent");
-    parentProps.setProperty("existingChildProp", "barParent");
-    parentProps.setProperty("duplicatedProp", s1);
-    parentProps.setProperty("sonar.projectDescription", "Desc from Parent");
+    Map<String, String> parentProps = new HashMap<String, String>();
+    parentProps.put("toBeMergeProps", "fooParent");
+    parentProps.put("existingChildProp", "barParent");
+    parentProps.put("duplicatedProp", s1);
+    parentProps.put("sonar.projectDescription", "Desc from Parent");
 
-    Properties childProps = new Properties();
-    childProps.setProperty("existingChildProp", "barChild");
-    childProps.setProperty("otherProp", "tutuChild");
-    childProps.setProperty("duplicatedProp", s2);
+    Map<String, String> childProps = new HashMap<String, String>();
+    childProps.put("existingChildProp", "barChild");
+    childProps.put("otherProp", "tutuChild");
+    childProps.put("duplicatedProp", s2);
 
     ProjectReactorBuilder.mergeParentProperties(childProps, parentProps);
 
     assertThat(childProps).hasSize(4);
-    assertThat(childProps.getProperty("toBeMergeProps")).isEqualTo("fooParent");
-    assertThat(childProps.getProperty("existingChildProp")).isEqualTo("barChild");
-    assertThat(childProps.getProperty("otherProp")).isEqualTo("tutuChild");
-    assertThat(childProps.getProperty("sonar.projectDescription")).isNull();
-    assertThat(childProps.getProperty("duplicatedProp")).isSameAs(parentProps.getProperty("duplicatedProp"));
+    assertThat(childProps.get("toBeMergeProps")).isEqualTo("fooParent");
+    assertThat(childProps.get("existingChildProp")).isEqualTo("barChild");
+    assertThat(childProps.get("otherProp")).isEqualTo("tutuChild");
+    assertThat(childProps.get("sonar.projectDescription")).isNull();
+    assertThat(childProps.get("duplicatedProp")).isSameAs(parentProps.get("duplicatedProp"));
   }
 
   @Test
@@ -493,18 +493,18 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldSetModuleKeyIfNotPresent() {
-    Properties props = new Properties();
+    Map<String, String> props = new HashMap<String, String>();
     props.put("sonar.projectVersion", "1.0");
 
     // should be set
     ProjectReactorBuilder.setModuleKeyAndNameIfNotDefined(props, "foo", "parent");
-    assertThat(props.getProperty("sonar.moduleKey")).isEqualTo("parent:foo");
-    assertThat(props.getProperty("sonar.projectName")).isEqualTo("foo");
+    assertThat(props.get("sonar.moduleKey")).isEqualTo("parent:foo");
+    assertThat(props.get("sonar.projectName")).isEqualTo("foo");
 
     // but not this 2nd time
     ProjectReactorBuilder.setModuleKeyAndNameIfNotDefined(props, "bar", "parent");
-    assertThat(props.getProperty("sonar.moduleKey")).isEqualTo("parent:foo");
-    assertThat(props.getProperty("sonar.projectName")).isEqualTo("foo");
+    assertThat(props.get("sonar.moduleKey")).isEqualTo("parent:foo");
+    assertThat(props.get("sonar.projectName")).isEqualTo("foo");
   }
 
   @Test
@@ -542,7 +542,7 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldGetList() {
-    Properties props = new Properties();
+    Map<String, String> props = new HashMap<String, String>();
 
     props.put("prop", "  foo  ,  bar  , \n\ntoto,tutu");
     assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
@@ -551,7 +551,7 @@ public class ProjectReactorBuilderTest {
   @Test
   public void shouldGetListFromFile() throws IOException {
     String filePath = "shouldGetList/foo.properties";
-    Properties props = loadPropsFromFile(filePath);
+    Map<String, String> props = loadPropsFromFile(filePath);
 
     assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
   }
@@ -565,7 +565,7 @@ public class ProjectReactorBuilderTest {
     assertThat(buildDir.getName()).isEqualTo("build");
   }
 
-  private Properties loadPropsFromFile(String filePath) throws IOException {
+  private Map<String, String> loadPropsFromFile(String filePath) throws IOException {
     Properties props = new Properties();
     FileInputStream fileInputStream = null;
     try {
@@ -574,7 +574,11 @@ public class ProjectReactorBuilderTest {
     } finally {
       IOUtils.closeQuietly(fileInputStream);
     }
-    return props;
+    Map<String, String> result = new HashMap<String, String>();
+    for (Map.Entry<Object, Object> entry : props.entrySet()) {
+      result.put(entry.getKey().toString(), entry.getValue().toString());
+    }
+    return result;
   }
 
 }
index 65ac737e31e0e73d89e5f7d8efb1ebebb6b3f547..e527f649b7beea80c529060ecbcfc21a7b3c0885 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.api.batch.bootstrap;
 
 import com.google.common.collect.Lists;
+import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
 
@@ -27,7 +28,10 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
 import java.io.File;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
 
 /**
@@ -77,15 +81,21 @@ public class ProjectDefinition {
   private static final char SEPARATOR = ',';
 
   private File baseDir, workDir, buildDir;
-  private Properties properties = new Properties();
+  private Map<String, String> properties = new HashMap<String, String>();
   private ProjectDefinition parent = null;
   private List<ProjectDefinition> subProjects = Lists.newArrayList();
   private List<Object> containerExtensions = Lists.newArrayList();
 
-  private ProjectDefinition(Properties p) {
+  private ProjectDefinition(Map<String, String> p) {
     this.properties = p;
   }
 
+  private ProjectDefinition(Properties p) {
+    for (Entry<Object, Object> entry : p.entrySet()) {
+      this.properties.put(entry.getKey().toString(), entry.getValue().toString());
+    }
+  }
+
   /**
    * @deprecated in 2.12, because it uses external object to represent internal state.
    *             To ensure backward-compatibility with Ant task this method cannot clone properties,
@@ -130,7 +140,19 @@ public class ProjectDefinition {
     return buildDir;
   }
 
+  /**
+   * @deprecated since 5.0 use {@link #properties()}
+   */
+  @Deprecated
   public Properties getProperties() {
+    Properties result = new Properties();
+    for (Map.Entry<String, String> entry : properties.entrySet()) {
+      result.setProperty(entry.getKey(), entry.getValue());
+    }
+    return result;
+  }
+
+  public Map<String, String> properties() {
     return properties;
   }
 
@@ -138,46 +160,54 @@ public class ProjectDefinition {
    * Copies specified properties into this object.
    *
    * @since 2.12
+   * @deprecated since 5.0 use {@link #setProperties(Map)}
    */
   public ProjectDefinition setProperties(Properties properties) {
+    for (Entry<Object, Object> entry : properties.entrySet()) {
+      this.properties.put(entry.getKey().toString(), entry.getValue().toString());
+    }
+    return this;
+  }
+
+  public ProjectDefinition setProperties(Map<String, String> properties) {
     this.properties.putAll(properties);
     return this;
   }
 
   public ProjectDefinition setProperty(String key, String value) {
-    properties.setProperty(key, value);
+    properties.put(key, value);
     return this;
   }
 
   public ProjectDefinition setKey(String key) {
-    properties.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, key);
+    properties.put(CoreProperties.PROJECT_KEY_PROPERTY, key);
     return this;
   }
 
   public ProjectDefinition setVersion(String s) {
-    properties.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s));
+    properties.put(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s));
     return this;
   }
 
   public ProjectDefinition setName(String s) {
-    properties.setProperty(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s));
+    properties.put(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s));
     return this;
   }
 
   public ProjectDefinition setDescription(String s) {
-    properties.setProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s));
+    properties.put(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s));
     return this;
   }
 
   public String getKey() {
-    return properties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
+    return properties.get(CoreProperties.PROJECT_KEY_PROPERTY);
   }
 
   /**
    * @since 4.5
    */
   public String getKeyWithBranch() {
-    String branch = properties.getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY);
+    String branch = properties.get(CoreProperties.PROJECT_BRANCH_PROPERTY);
     String projectKey = getKey();
     if (StringUtils.isNotBlank(branch)) {
       projectKey = String.format("%s:%s", projectKey, branch);
@@ -186,11 +216,11 @@ public class ProjectDefinition {
   }
 
   public String getVersion() {
-    return properties.getProperty(CoreProperties.PROJECT_VERSION_PROPERTY);
+    return properties.get(CoreProperties.PROJECT_VERSION_PROPERTY);
   }
 
   public String getName() {
-    String name = properties.getProperty(CoreProperties.PROJECT_NAME_PROPERTY);
+    String name = properties.get(CoreProperties.PROJECT_NAME_PROPERTY);
     if (StringUtils.isBlank(name)) {
       name = "Unnamed - " + getKey();
     }
@@ -198,11 +228,11 @@ public class ProjectDefinition {
   }
 
   public String getDescription() {
-    return properties.getProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY);
+    return properties.get(CoreProperties.PROJECT_DESCRIPTION_PROPERTY);
   }
 
   private void appendProperty(String key, String value) {
-    String current = properties.getProperty(key, "");
+    String current = (String) ObjectUtils.defaultIfNull(properties.get(key), "");
     if (StringUtils.isBlank(current)) {
       properties.put(key, value);
     } else {
@@ -214,7 +244,7 @@ public class ProjectDefinition {
    * @return Source files and folders.
    */
   public List<String> sources() {
-    String sources = properties.getProperty(SOURCES_PROPERTY, "");
+    String sources = (String) ObjectUtils.defaultIfNull(properties.get(SOURCES_PROPERTY), "");
     return trim(StringUtils.split(sources, SEPARATOR));
   }
 
@@ -341,7 +371,7 @@ public class ProjectDefinition {
   }
 
   public List<String> tests() {
-    String sources = properties.getProperty(TESTS_PROPERTY, "");
+    String sources = (String) ObjectUtils.defaultIfNull(properties.get(TESTS_PROPERTY), "");
     return trim(StringUtils.split(sources, SEPARATOR));
   }
 
@@ -476,7 +506,7 @@ public class ProjectDefinition {
    */
   @Deprecated
   public List<String> getBinaries() {
-    String sources = properties.getProperty(BINARIES_PROPERTY, "");
+    String sources = (String) ObjectUtils.defaultIfNull(properties.get(BINARIES_PROPERTY), "");
     return trim(StringUtils.split(sources, SEPARATOR));
   }
 
@@ -504,7 +534,7 @@ public class ProjectDefinition {
    */
   @Deprecated
   public List<String> getLibraries() {
-    String sources = properties.getProperty(LIBRARIES_PROPERTY, "");
+    String sources = (String) ObjectUtils.defaultIfNull(properties.get(LIBRARIES_PROPERTY), "");
     return trim(StringUtils.split(sources, SEPARATOR));
   }
 
index 28802165afc7b91359eff6b70dde2b2c23fd74a8..f1a5abfe5e866b78e6ac7c373ebb2e8f95261f92 100644 (file)
@@ -53,20 +53,6 @@ public class ProjectDefinitionTest {
     assertThat(def.getVersion(), is("2.0-SNAPSHOT"));
   }
 
-  /**
-   * Compatibility with Ant task.
-   */
-  @Test
-  public void shouldNotCloneProperties() {
-    Properties props = new Properties();
-
-    ProjectDefinition def = ProjectDefinition.create(props);
-    assertThat(def.getKey(), nullValue());
-
-    props.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, "mykey");
-    assertThat(def.getKey(), is("mykey"));
-  }
-
   @Test
   public void shouldSetOptionalFields() {
     ProjectDefinition def = ProjectDefinition.create();