]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6649 Move initialization of persistit cache to global context
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Fri, 12 Jun 2015 08:40:59 +0000 (10:40 +0200)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 24 Jun 2015 12:34:21 +0000 (14:34 +0200)
24 files changed:
pom.xml
server/sonar-server/src/main/java/org/sonar/server/platform/TempFolderProvider.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java
sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java
sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
sonar-batch/src/test/java/org/sonar/batch/index/AbstractCachesTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/index/CacheTest.java
sonar-batch/src/test/java/org/sonar/batch/index/CachesManagerTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssueCacheTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStackTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/ProjectTempFolder.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/utils/TempFolder.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/DefaultTempFolder.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/JUnitTempFolder.java

diff --git a/pom.xml b/pom.xml
index eecb91688d7fed57fac29dd2eb9bbc4f1eea6ca5..eae7b1b6c72710ac24515c486223878d9b7985d6 100644 (file)
--- a/pom.xml
+++ b/pom.xml
       <dependency>
         <groupId>org.codehaus.sonar</groupId>
         <artifactId>sonar-persistit</artifactId>
-        <version>3.3.1</version>
+        <version>3.3.2-SNAPSHOT</version>
         <exclusions>
           <exclusion>
             <groupId>commons-logging</groupId>
index 2d2f598db803b2a7b130146cff31222395e8ef01..6c21893338c5a2c559d641a06659c4a7c780aab7 100644 (file)
@@ -44,5 +44,4 @@ public class TempFolderProvider extends ProviderAdapter {
     }
     return tempFolder;
   }
-
 }
index 32e6aa6ce81bddc2c1060175eabe7bd7c6765e46..08d9cbb9a7c398ddad2e2e524f482c902e9c560b 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
+import org.sonar.batch.index.CachesManager;
+
 import java.util.List;
 import java.util.Map;
+
 import org.sonar.api.CoreProperties;
 import org.sonar.api.Plugin;
 import org.sonar.api.utils.Durations;
@@ -98,6 +101,7 @@ public class GlobalContainer extends ComponentContainer {
       BatchPluginPredicate.class,
       ExtensionInstaller.class,
 
+      CachesManager.class,
       GlobalSettings.class,
       ServerClient.class,
       Logback.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java
new file mode 100644 (file)
index 0000000..e830133
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.batch.bootstrap;
+
+import org.sonar.api.utils.ProjectTempFolder;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.internal.DefaultTempFolder;
+
+import java.io.File;
+import java.io.IOException;
+
+public class ProjectTempFolderProvider extends ProviderAdapter {
+  static final String TMP_NAME = ".sonartmp";
+  private ProjectTempFolder projectTempFolder;
+
+  public ProjectTempFolder provide(BootstrapProperties bootstrapProps) {
+    if (projectTempFolder == null) {
+      String workingDirPath = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.WORKING_DIRECTORY), CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
+      File workingDir = new File(workingDirPath).getAbsoluteFile();
+      File tempDir = new File(workingDir, TMP_NAME);
+      try {
+        FileUtils.forceMkdir(tempDir);
+      } catch (IOException e) {
+        throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
+      }
+      projectTempFolder = new DefaultTempFolder(tempDir, true);
+    }
+    return projectTempFolder;
+  }
+
+}
index b665d9d32796e602a4a2f88bf137203fce4b952c..971a4a2b1f59828e0a29ea7bda507710afdb2ac1 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.TempFolder;
 import org.picocontainer.injectors.ProviderAdapter;
+import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
-import org.sonar.api.utils.TempFolder;
 import org.sonar.api.utils.internal.DefaultTempFolder;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 
 public class TempFolderProvider extends ProviderAdapter {
-
+  static final String TMP_NAME = ".sonartmp";
   private TempFolder tempFolder;
 
   public TempFolder provide(BootstrapProperties bootstrapProps) {
     if (tempFolder == null) {
-      String workingDirPath = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.WORKING_DIRECTORY), CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
-      File workingDir = new File(workingDirPath).getAbsoluteFile();
-      File tempDir = new File(workingDir, ".sonartmp");
+
+      String workingPathName = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.GLOBAL_WORKING_DIRECTORY), CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
+      Path workingPath = Paths.get(workingPathName).normalize();
+
+      if (!workingPath.isAbsolute()) {
+        Path home = findHome(bootstrapProps);
+        workingPath = home.resolve(workingPath).normalize();
+      }
+
+      Path tempDir = workingPath.resolve(TMP_NAME);
       try {
-        FileUtils.forceMkdir(tempDir);
+        Files.createDirectories(tempDir);
       } catch (IOException e) {
         throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
       }
-      tempFolder = new DefaultTempFolder(tempDir);
+      tempFolder = new DefaultTempFolder(tempDir.toFile(), true);
     }
     return tempFolder;
   }
 
+  private static Path findHome(BootstrapProperties props) {
+    String home = props.property("sonar.userHome");
+    if (home != null) {
+      return Paths.get(home);
+    }
+
+    home = System.getenv("SONAR_USER_HOME");
+
+    if (home != null) {
+      return Paths.get(home);
+    }
+
+    home = System.getProperty("user.home");
+    return Paths.get(home, ".sonar");
+  }
+
 }
index 3d1250eeba6fe97f19b90fad6c3effd5400fd549..da83b54becbfd85263e4327c79c6a5de757d072b 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.core.config.Logback;
 import javax.annotation.Nullable;
 
 import java.io.File;
+import java.io.PrintStream;
 import java.util.Map;
 
 /**
@@ -72,6 +73,11 @@ public final class LoggingConfiguration {
     setVerbose(verbose);
     return this;
   }
+  
+  public LoggingConfiguration setStreams(PrintStream out, PrintStream err) {
+    
+    return this;
+  }
 
   public LoggingConfiguration setVerbose(boolean verbose) {
     return setRootLevel(verbose ? LEVEL_ROOT_VERBOSE : LEVEL_ROOT_DEFAULT);
index bc6314d747535329e4b5078cdc1ff3a7b631027a..209ec7792aa36732e6f8bb4f650b14567b524b75 100644 (file)
  */
 package org.sonar.batch.index;
 
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
 import com.persistit.Exchange;
-import com.persistit.Persistit;
 import com.persistit.Value;
-import com.persistit.Volume;
 import com.persistit.encoding.CoderManager;
+import com.persistit.Persistit;
 import com.persistit.encoding.ValueCoder;
 import com.persistit.exception.PersistitException;
-import com.persistit.logging.Slf4jAdapter;
-import org.apache.commons.io.FileUtils;
+import com.persistit.Volume;
 import org.picocontainer.Startable;
-import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.utils.TempFolder;
 
-import java.io.File;
-import java.util.Properties;
-import java.util.Set;
-
-/**
- * Factory of caches
- *
- * @since 3.6
- */
 @BatchSide
 public class Caches implements Startable {
-
-  private final Set<String> cacheNames = Sets.newHashSet();
-  private File tempDir;
+  private final Map<String, Exchange> caches = Maps.newHashMap();
   private Persistit persistit;
   private Volume volume;
-  private final TempFolder tempFolder;
 
-  public Caches(TempFolder tempFolder) {
-    this.tempFolder = tempFolder;
-    initPersistit();
+  public Caches(CachesManager caches) {
+    persistit = caches.persistit();
+    start();
   }
 
-  private void initPersistit() {
+  @Override
+  public void start() {
     try {
-      tempDir = tempFolder.newDir("caches");
-      persistit = new Persistit();
-      persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT")));
-      Properties props = new Properties();
-      props.setProperty("datapath", tempDir.getAbsolutePath());
-      props.setProperty("logpath", "${datapath}/log");
-      props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log");
-      props.setProperty("buffer.count.8192", "10");
-      props.setProperty("journalpath", "${datapath}/journal");
-      props.setProperty("tmpvoldir", "${datapath}");
-      props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000");
-      persistit.setProperties(props);
-      persistit.initialize();
+      persistit.flush();
       volume = persistit.createTemporaryVolume();
-
     } catch (Exception e) {
-      throw new IllegalStateException("Fail to start caches", e);
+      throw new IllegalStateException("Fail to create a cache volume", e);
     }
   }
 
@@ -87,44 +63,34 @@ public class Caches implements Startable {
 
   public <V> Cache<V> createCache(String cacheName) {
     Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
-    Preconditions.checkState(!cacheNames.contains(cacheName), "Cache is already created: " + cacheName);
+    Preconditions.checkState(!caches.containsKey(cacheName), "Cache is already created: " + cacheName);
     try {
       Exchange exchange = persistit.getExchange(volume, cacheName, true);
       exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
       Cache<V> cache = new Cache<>(cacheName, exchange);
-      cacheNames.add(cacheName);
+      caches.put(cacheName, exchange);
       return cache;
     } catch (Exception e) {
       throw new IllegalStateException("Fail to create cache: " + cacheName, e);
     }
   }
 
-  @Override
-  public void start() {
-    // already started in constructor
-  }
-
   @Override
   public void stop() {
-    if (persistit != null) {
+    for (Entry<String, Exchange> e : caches.entrySet()) {
+      persistit.releaseExchange(e.getValue());
+    }
+
+    caches.clear();
+
+    if (volume != null) {
       try {
-        persistit.close(false);
-        persistit = null;
-        volume = null;
+        volume.close();
+        volume.delete();
       } catch (PersistitException e) {
         throw new IllegalStateException("Fail to close caches", e);
       }
+      volume = null;
     }
-    FileUtils.deleteQuietly(tempDir);
-    tempDir = null;
-    cacheNames.clear();
-  }
-
-  File tempDir() {
-    return tempDir;
-  }
-
-  Persistit persistit() {
-    return persistit;
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java
new file mode 100644 (file)
index 0000000..107c62a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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.batch.index;
+
+import org.sonar.api.utils.TempFolder;
+
+import com.persistit.Persistit;
+import com.persistit.exception.PersistitException;
+import com.persistit.logging.Slf4jAdapter;
+import org.apache.commons.io.FileUtils;
+import org.picocontainer.Startable;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.BatchSide;
+
+import java.io.File;
+import java.util.Properties;
+
+/**
+ * Factory of caches
+ *
+ * @since 3.6
+ */
+@BatchSide
+public class CachesManager implements Startable {
+  private File tempDir;
+  private Persistit persistit;
+  private final TempFolder tempFolder;
+
+  public CachesManager(TempFolder tempFolder) {
+    this.tempFolder = tempFolder;
+    initPersistit();
+  }
+
+  private void initPersistit() {
+    try {
+      tempDir = tempFolder.newDir("caches");
+      persistit = new Persistit();
+      persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT")));
+      Properties props = new Properties();
+      props.setProperty("datapath", tempDir.getAbsolutePath());
+      props.setProperty("logpath", "${datapath}/log");
+      props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log");
+      props.setProperty("buffer.count.8192", "10");
+      props.setProperty("journalpath", "${datapath}/journal");
+      props.setProperty("tmpvoldir", "${datapath}");
+      props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000");
+      persistit.setProperties(props);
+      persistit.initialize();
+
+    } catch (Exception e) {
+      throw new IllegalStateException("Fail to start caches", e);
+    }
+  }
+
+  @Override
+  public void start() {
+    // already started in constructor
+  }
+
+  @Override
+  public void stop() {
+    if (persistit != null) {
+      try {
+        persistit.close(false);
+        persistit = null;
+      } catch (PersistitException e) {
+        throw new IllegalStateException("Fail to close caches", e);
+      }
+    }
+    FileUtils.deleteQuietly(tempDir);
+    tempDir = null;
+  }
+
+  File tempDir() {
+    return tempDir;
+  }
+
+  Persistit persistit() {
+    return persistit;
+  }
+}
index 59eae4f930333fd6740ca94209cb5fca6da74f04..623fd0fa90ee166b406c893af4e36c4bf30e44cd 100644 (file)
  */
 package org.sonar.batch.scan;
 
+import org.sonar.batch.bootstrap.ProjectTempFolderProvider;
+
+import org.sonar.api.utils.internal.TempFolderCleaner;
+import org.sonar.batch.bootstrap.TempFolderProvider;
 import com.google.common.annotations.VisibleForTesting;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.InstantiationStrategy;
@@ -151,7 +155,10 @@ public class ProjectScanContainer extends ComponentContainer {
       Caches.class,
       BatchComponentCache.class,
 
-    // file system
+      //temp
+      new ProjectTempFolderProvider(),
+      
+      // file system
       InputPathCache.class,
       PathResolver.class,
 
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java
new file mode 100644 (file)
index 0000000..e79f051
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.batch.bootstrap;
+
+import org.apache.commons.io.FileUtils;
+
+import org.sonar.api.utils.ProjectTempFolder;
+import com.google.common.collect.ImmutableMap;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectTempFolderProviderTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  private ProjectTempFolderProvider tempFolderProvider = new ProjectTempFolderProvider();
+
+  @Test
+  public void createTempFolderWithProps() throws Exception {
+    File workingDir = temp.newFolder();
+    File tmpDir = new File(workingDir, ProjectTempFolderProvider.TMP_NAME);
+
+    ProjectTempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+    tempFolder.newDir();
+    tempFolder.newFile();
+    assertThat(tmpDir).exists();
+    assertThat(tmpDir.list()).hasSize(2);
+  }
+
+  @Test
+  public void createTempFolder() throws IOException {
+    File defaultDir = new File(CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE, ProjectTempFolderProvider.TMP_NAME);
+
+    try {
+      ProjectTempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(Collections.<String, String>emptyMap()));
+      tempFolder.newDir();
+      tempFolder.newFile();
+      assertThat(defaultDir).exists();
+      assertThat(defaultDir.list()).hasSize(2);
+    } finally {
+      FileUtils.deleteDirectory(defaultDir);
+    }
+  }
+}
index 9db9e6d1013c6c7383f1c9dbb759e25be987bcc9..ce64074d9a699d6af5a442ad5d2e35566bb37790 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.utils.TempFolder;
 import com.google.common.collect.ImmutableMap;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
 import org.sonar.api.CoreProperties;
-import org.sonar.api.utils.TempFolder;
 
 import java.io.File;
+import java.util.Collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 
 public class TempFolderProviderTest {
-
-  @Rule
-  public ExpectedException throwable = ExpectedException.none();
-
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
+  private TempFolderProvider tempFolderProvider = new TempFolderProvider();
+
   @Test
-  public void createTempFolder() throws Exception {
+  public void createTempFolderProps() throws Exception {
     File workingDir = temp.newFolder();
-    TempFolderProvider tempFolderProvider = new TempFolderProvider();
-    TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+
+    TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
-    assertThat(new File(workingDir, ".sonartmp")).exists();
+    assertThat(new File(workingDir, TempFolderProvider.TMP_NAME)).exists();
     assertThat(new File(workingDir, ".sonartmp").list()).hasSize(2);
   }
+
+  @Test
+  public void createTempFolderSonarHome() throws Exception {
+    // with sonar home, it will be in {sonar.home}/.sonartmp
+    File sonarHome = temp.newFolder();
+    File tmpDir = new File(new File(sonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE), TempFolderProvider.TMP_NAME);
+
+    TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath())));
+    tempFolder.newDir();
+    tempFolder.newFile();
+    assertThat(tmpDir).exists();
+    assertThat(tmpDir.list()).hasSize(2);
+  }
+
+  @Test
+  public void createTempFolderDefault() throws Exception {
+    // if nothing is defined, it will be in {user.home}/.sonar/.sonartmp
+    File defaultSonarHome = new File(System.getProperty("user.home"), ".sonar");
+    File tmpDir = new File(new File(defaultSonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE), TempFolderProvider.TMP_NAME);
+
+    try {
+      TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(Collections.<String, String>emptyMap()));
+      tempFolder.newDir();
+      tempFolder.newFile();
+      assertThat(tmpDir).exists();
+      assertThat(tmpDir.list()).hasSize(2);
+    } finally {
+      FileUtils.deleteDirectory(tmpDir);
+    }
+  }
 }
index 14254a9d9f601fb991cf632545ff37d00b5e8ea1..f591381474048f91afed56d1309d48e4a2977f04 100644 (file)
  */
 package org.sonar.batch.duplication;
 
-import org.junit.After;
-import org.junit.Before;
+import org.sonar.batch.index.AbstractCachesTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.sensor.duplication.Duplication;
 import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.CachesTest;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class DuplicationCacheTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
+public class DuplicationCacheTest extends AbstractCachesTest {
 
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  Caches caches;
-
-  @Before
-  public void start() {
-    caches = CachesTest.createCacheOnTemp(temp);
-    caches.start();
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
-  }
-
   @Test
   public void should_add_clone_groups() {
     DuplicationCache cache = new DuplicationCache(caches);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/AbstractCachesTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/AbstractCachesTest.java
new file mode 100644 (file)
index 0000000..0811678
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.batch.index;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.rules.TemporaryFolder;
+
+public abstract class AbstractCachesTest {
+  @ClassRule
+  public static TemporaryFolder temp = new TemporaryFolder();
+
+  protected Caches caches;
+  protected static CachesManager cachesManager;
+
+  @BeforeClass
+  public static void startClass() {
+    cachesManager = CachesManagerTest.createCacheOnTemp(temp);
+    cachesManager.start();
+  }
+
+  @Before
+  public void start() {
+    caches = new Caches(cachesManager);
+    caches.start();
+  }
+
+  @After
+  public void stop() {
+    caches.stop();
+    caches = null;
+  }
+
+  @AfterClass
+  public static void stopClass() {
+    cachesManager.stop();
+    cachesManager = null;
+  }
+}
index 9c85d02c0fd2aad547b0e84d962d9fcf446336a9..64aaf4f0ad2aa3fa74eb413b1cd378201606a7d3 100644 (file)
 package org.sonar.batch.index;
 
 import com.google.common.collect.Iterables;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
 import org.sonar.batch.index.Cache.Entry;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class CacheTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  Caches caches;
-
-  @Before
-  public void start() {
-    caches = CachesTest.createCacheOnTemp(temp);
-    caches.start();
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
-  }
+public class CacheTest extends AbstractCachesTest {
 
   @Test
   public void one_part_key() {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/CachesManagerTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/CachesManagerTest.java
new file mode 100644 (file)
index 0000000..6d301a7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.batch.index;
+
+import org.sonar.batch.bootstrap.TempFolderProvider;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.batch.bootstrap.BootstrapProperties;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CachesManagerTest {
+
+  @ClassRule
+  public static TemporaryFolder temp = new TemporaryFolder();
+
+  public static CachesManager createCacheOnTemp(TemporaryFolder temp) {
+    try {
+      BootstrapProperties bootstrapProps = new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.newFolder().getAbsolutePath()));
+      return new CachesManager(new TempFolderProvider().provide(bootstrapProps));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  CachesManager cachesMgr;
+
+  @Before
+  public void prepare() {
+    cachesMgr = createCacheOnTemp(temp);
+    cachesMgr.start();
+  }
+
+  @Test
+  public void should_stop_and_clean_temp_dir() {
+    File tempDir = cachesMgr.tempDir();
+    assertThat(tempDir).isDirectory().exists();
+    assertThat(cachesMgr.persistit()).isNotNull();
+    assertThat(cachesMgr.persistit().isInitialized()).isTrue();
+
+    cachesMgr.stop();
+
+    assertThat(tempDir).doesNotExist();
+    assertThat(cachesMgr.tempDir()).isNull();
+    assertThat(cachesMgr.persistit()).isNull();
+  }
+}
index 83e2a99b94888971d9c2e4416ac771412b5b9140..801d0f3d5ed3da2a3b621827a274e4f32bcab82a 100644 (file)
  */
 package org.sonar.batch.index;
 
-import com.google.common.collect.ImmutableMap;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.batch.bootstrap.BootstrapProperties;
-import org.sonar.batch.bootstrap.TempFolderProvider;
-
-import java.io.File;
-import java.io.IOException;
 import java.io.Serializable;
 
+import com.persistit.exception.PersistitException;
+import org.junit.Test;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
 
-public class CachesTest {
-
-  @ClassRule
-  public static TemporaryFolder temp = new TemporaryFolder();
-
-  public static Caches createCacheOnTemp(TemporaryFolder temp) {
-    try {
-      BootstrapProperties bootstrapProps = new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.newFolder().getAbsolutePath()));
-      return new Caches(new TempFolderProvider().provide(bootstrapProps));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  Caches caches;
-
-  @Before
-  public void prepare() {
-    caches = createCacheOnTemp(temp);
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
-  }
-
-  @Test
-  public void should_stop_and_clean_temp_dir() {
-    File tempDir = caches.tempDir();
-    assertThat(tempDir).isDirectory().exists();
-    assertThat(caches.persistit()).isNotNull();
-    assertThat(caches.persistit().isInitialized()).isTrue();
-
-    caches.stop();
-
-    assertThat(tempDir).doesNotExist();
-    assertThat(caches.tempDir()).isNull();
-    assertThat(caches.persistit()).isNull();
-  }
-
+public class CachesTest extends AbstractCachesTest {
   @Test
   public void should_create_cache() {
-    caches.start();
     Cache<Element> cache = caches.createCache("foo");
     assertThat(cache).isNotNull();
   }
 
   @Test
   public void should_not_create_cache_twice() {
-    caches.start();
     caches.<Element>createCache("foo");
     try {
       caches.<Element>createCache("foo");
@@ -95,7 +44,48 @@ public class CachesTest {
     }
   }
 
-  static class Element implements Serializable {
+  @Test
+  public void should_clean_resources() throws PersistitException {
+    Cache<String> c = caches.<String>createCache("test1");
+    for (int i = 0; i < 1_000_000; i++) {
+      c.put("a" + i, "a" + i);
+    }
+
+    caches.stop();
+
+    // manager continues up
+    assertThat(cachesManager.persistit().isInitialized()).isTrue();
+
+    caches = new Caches(cachesManager);
+    caches.start();
+    caches.createCache("test1");
+  }
+
+  @Test
+  public void leak_test() throws PersistitException {
+    caches.stop();
+
+    System.out.println(cachesManager.tempDir());
+
+    int len = 1 * 1024 * 1024;
+    StringBuilder sb = new StringBuilder(len);
+    for (int i = 0; i < len; i++) {
+      sb.append("a");
+    }
+
+    for (int i = 0; i < 3; i++) {
+      caches = new Caches(cachesManager);
+      caches.start();
+      Cache<String> c = caches.<String>createCache("test" + i);
+      c.put("key" + i, sb.toString());
+      cachesManager.persistit().flush();
+
+      caches.stop();
+    }
+  }
+
+  private static class Element implements Serializable {
+    private static final long serialVersionUID = 1L;
 
   }
 }
index 46e297f2e4e0f644b9d1347e37b1763a8c5623ff..25fefe6f13d653a0a98a22bb05ecfdd6ddf46ec6 100644 (file)
  */
 package org.sonar.batch.issue;
 
+import org.sonar.batch.index.AbstractCachesTest;
+
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.Severity;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.CachesTest;
 
 import javax.annotation.Nullable;
 
@@ -41,23 +37,7 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class IssueCacheTest {
-
-  @ClassRule
-  public static TemporaryFolder temp = new TemporaryFolder();
-
-  Caches caches;
-
-  @Before
-  public void start() {
-    caches = CachesTest.createCacheOnTemp(temp);
-    caches.start();
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
-  }
+public class IssueCacheTest extends AbstractCachesTest {
 
   @Test
   public void should_add_new_issue() {
index 046f37840f90d5977d317b42dc43f264e3d45677..c6f42f12b6a80747d95185d4feaf982ae64d9f19 100644 (file)
 
 package org.sonar.batch.issue.tracking;
 
+import org.sonar.batch.index.AbstractCachesTest;
+
 import org.junit.After;
 import org.junit.Before;
-import org.junit.ClassRule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.batch.bootstrap.BootstrapProperties;
-import org.sonar.batch.bootstrap.TempFolderProvider;
-import org.sonar.batch.index.Caches;
 import org.sonar.core.issue.db.IssueChangeDto;
 import org.sonar.core.issue.db.IssueDto;
 
-import java.io.IOException;
-import java.util.Collections;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class InitialOpenIssuesStackTest {
-
-  @ClassRule
-  public static TemporaryFolder temp = new TemporaryFolder();
-
-  public static Caches createCacheOnTemp(TemporaryFolder temp) {
-    BootstrapProperties bootstrapSettings = new BootstrapProperties(Collections.<String, String>emptyMap());
-    try {
-      bootstrapSettings.properties().put(CoreProperties.WORKING_DIRECTORY, temp.newFolder().getAbsolutePath());
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-    return new Caches(new TempFolderProvider().provide(bootstrapSettings));
-  }
+public class InitialOpenIssuesStackTest extends AbstractCachesTest {
 
   InitialOpenIssuesStack stack;
-  Caches caches;
 
   @Before
   public void before() {
-    caches = createCacheOnTemp(temp);
-    caches.start();
     stack = new InitialOpenIssuesStack(caches);
   }
 
index 598f2a5ce2e8acf1afdf0ce0795ba1e23342b656..0575a850182a5c3de96b3f9e669952c827850d91 100644 (file)
  */
 package org.sonar.batch.scan.measure;
 
+import org.sonar.batch.index.AbstractCachesTest;
 import org.apache.commons.lang.builder.EqualsBuilder;
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.measure.MetricFinder;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
@@ -42,8 +41,6 @@ import org.sonar.api.technicaldebt.batch.Requirement;
 import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
 import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
 import org.sonar.batch.index.Cache.Entry;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.CachesTest;
 
 import java.util.Date;
 import java.util.Iterator;
@@ -52,101 +49,90 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class MeasureCacheTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
+public class MeasureCacheTest extends AbstractCachesTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  Caches caches;
-
   private MetricFinder metricFinder;
 
   private TechnicalDebtModel techDebtModel;
 
-  private MeasureCache cache;
+  private MeasureCache measureCache;
 
   @Before
   public void start() {
-    caches = CachesTest.createCacheOnTemp(temp);
-    caches.start();
+    super.start();
     metricFinder = mock(MetricFinder.class);
     when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC);
     techDebtModel = mock(TechnicalDebtModel.class);
-    cache = new MeasureCache(caches, metricFinder, techDebtModel);
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
+    measureCache = new MeasureCache(caches, metricFinder, techDebtModel);
   }
 
   @Test
   public void should_add_measure() {
     Project p = new Project("struts");
 
-    assertThat(cache.entries()).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
 
-    assertThat(cache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m = new Measure(CoreMetrics.NCLOC, 1.0);
-    cache.put(p, m);
+    measureCache.put(p, m);
 
-    assertThat(cache.contains(p, m)).isTrue();
-    assertThat(cache.entries()).hasSize(1);
-    Iterator<Entry<Measure>> iterator = cache.entries().iterator();
+    assertThat(measureCache.contains(p, m)).isTrue();
+    assertThat(measureCache.entries()).hasSize(1);
+    Iterator<Entry<Measure>> iterator = measureCache.entries().iterator();
     iterator.hasNext();
     Entry<Measure> next = iterator.next();
     assertThat(next.value()).isEqualTo(m);
     assertThat(next.key()[0]).isEqualTo("struts");
 
-    assertThat(cache.byResource(p)).hasSize(1);
-    assertThat(cache.byResource(p).iterator().next()).isEqualTo(m);
+    assertThat(measureCache.byResource(p)).hasSize(1);
+    assertThat(measureCache.byResource(p).iterator().next()).isEqualTo(m);
 
     Measure mRule = RuleMeasure.createForPriority(CoreMetrics.CRITICAL_VIOLATIONS, RulePriority.BLOCKER, 1.0);
-    cache.put(p, mRule);
+    measureCache.put(p, mRule);
 
-    assertThat(cache.entries()).hasSize(2);
+    assertThat(measureCache.entries()).hasSize(2);
 
-    assertThat(cache.byResource(p)).hasSize(2);
+    assertThat(measureCache.byResource(p)).hasSize(2);
   }
 
   @Test
-  public void should_add_measure_with_big_data() {
+  public void should_add_measure_with_big_data() throws InterruptedException {
     Project p = new Project("struts");
 
-    assertThat(cache.entries()).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
 
-    assertThat(cache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m = new Measure(CoreMetrics.NCLOC, 1.0).setDate(new Date());
     m.setAlertText("foooooooooooooooooooooooooooooooooooo");
     StringBuilder data = new StringBuilder();
-    for (int i = 0; i < 1048575; i++) {
+    for (int i = 0; i < 1_048_575; i++) {
       data.append("a");
     }
+    
     m.setData(data.toString());
 
-    cache.put(p, m);
+    measureCache.put(p, m);
 
-    assertThat(cache.contains(p, m)).isTrue();
-    assertThat(cache.entries()).hasSize(1);
-    Iterator<Entry<Measure>> iterator = cache.entries().iterator();
+    assertThat(measureCache.contains(p, m)).isTrue();
+    assertThat(measureCache.entries()).hasSize(1);
+    Iterator<Entry<Measure>> iterator = measureCache.entries().iterator();
     iterator.hasNext();
     Entry<Measure> next = iterator.next();
     assertThat(next.value()).isEqualTo(m);
     assertThat(next.key()[0]).isEqualTo("struts");
 
-    assertThat(cache.byResource(p)).hasSize(1);
-    assertThat(cache.byResource(p).iterator().next()).isEqualTo(m);
+    assertThat(measureCache.byResource(p)).hasSize(1);
+    assertThat(measureCache.byResource(p).iterator().next()).isEqualTo(m);
 
     RuleMeasure mRule = RuleMeasure.createForPriority(CoreMetrics.CRITICAL_VIOLATIONS, RulePriority.BLOCKER, 1.0);
     mRule.setRuleKey(RuleKey.of("repo", "rule"));
-    cache.put(p, mRule);
+    measureCache.put(p, mRule);
 
-    assertThat(cache.entries()).hasSize(2);
+    assertThat(measureCache.entries()).hasSize(2);
   }
 
   /**
@@ -156,9 +142,9 @@ public class MeasureCacheTest {
   public void should_add_measure_with_too_big_data_for_persistit_pre_patch() {
     Project p = new Project("struts");
 
-    assertThat(cache.entries()).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
 
-    assertThat(cache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m = new Measure(CoreMetrics.NCLOC, 1.0).setDate(new Date());
     StringBuilder data = new StringBuilder();
@@ -167,33 +153,33 @@ public class MeasureCacheTest {
     }
     m.setData(data.toString());
 
-    cache.put(p, m);
+    measureCache.put(p, m);
 
-    assertThat(cache.contains(p, m)).isTrue();
-    assertThat(cache.entries()).hasSize(1);
-    Iterator<Entry<Measure>> iterator = cache.entries().iterator();
+    assertThat(measureCache.contains(p, m)).isTrue();
+    assertThat(measureCache.entries()).hasSize(1);
+    Iterator<Entry<Measure>> iterator = measureCache.entries().iterator();
     iterator.hasNext();
     Entry<Measure> next = iterator.next();
     assertThat(next.value()).isEqualTo(m);
     assertThat(next.key()[0]).isEqualTo("struts");
 
-    assertThat(cache.byResource(p)).hasSize(1);
-    assertThat(cache.byResource(p).iterator().next()).isEqualTo(m);
+    assertThat(measureCache.byResource(p)).hasSize(1);
+    assertThat(measureCache.byResource(p).iterator().next()).isEqualTo(m);
 
     RuleMeasure mRule = RuleMeasure.createForPriority(CoreMetrics.CRITICAL_VIOLATIONS, RulePriority.BLOCKER, 1.0);
     mRule.setRuleKey(RuleKey.of("repo", "rule"));
-    cache.put(p, mRule);
+    measureCache.put(p, mRule);
 
-    assertThat(cache.entries()).hasSize(2);
+    assertThat(measureCache.entries()).hasSize(2);
   }
 
   @Test
   public void should_add_measure_with_too_big_data_for_persistit() {
     Project p = new Project("struts");
 
-    assertThat(cache.entries()).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
 
-    assertThat(cache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m = new Measure(CoreMetrics.NCLOC, 1.0).setDate(new Date());
     StringBuilder data = new StringBuilder(64 * 1024 * 1024 + 1);
@@ -206,28 +192,28 @@ public class MeasureCacheTest {
     thrown.expect(IllegalStateException.class);
     thrown.expectMessage("Fail to put element in the cache measures");
 
-    cache.put(p, m);
+    measureCache.put(p, m);
   }
 
   @Test
   public void should_add_measure_with_same_metric() {
     Project p = new Project("struts");
 
-    assertThat(cache.entries()).hasSize(0);
-    assertThat(cache.byResource(p)).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m1 = new Measure(CoreMetrics.NCLOC, 1.0);
     Measure m2 = new Measure(CoreMetrics.NCLOC, 1.0).setCharacteristic(new DefaultCharacteristic().setKey("charac"));
     Measure m3 = new Measure(CoreMetrics.NCLOC, 1.0).setPersonId(2);
     Measure m4 = new RuleMeasure(CoreMetrics.NCLOC, RuleKey.of("repo", "rule"), RulePriority.BLOCKER, null);
-    cache.put(p, m1);
-    cache.put(p, m2);
-    cache.put(p, m3);
-    cache.put(p, m4);
+    measureCache.put(p, m1);
+    measureCache.put(p, m2);
+    measureCache.put(p, m3);
+    measureCache.put(p, m4);
 
-    assertThat(cache.entries()).hasSize(4);
+    assertThat(measureCache.entries()).hasSize(4);
 
-    assertThat(cache.byResource(p)).hasSize(4);
+    assertThat(measureCache.byResource(p)).hasSize(4);
   }
 
   @Test
@@ -237,36 +223,36 @@ public class MeasureCacheTest {
     Resource file1 = Directory.create("foo/bar/File1.txt").setEffectiveKey("struts:foo/bar/File1.txt");
     Resource file2 = Directory.create("foo/bar/File2.txt").setEffectiveKey("struts:foo/bar/File2.txt");
 
-    assertThat(cache.entries()).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(0);
 
-    assertThat(cache.byResource(p)).hasSize(0);
-    assertThat(cache.byResource(dir)).hasSize(0);
+    assertThat(measureCache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(dir)).hasSize(0);
 
     Measure mFile1 = new Measure(CoreMetrics.NCLOC, 1.0);
-    cache.put(file1, mFile1);
+    measureCache.put(file1, mFile1);
     Measure mFile2 = new Measure(CoreMetrics.NCLOC, 3.0);
-    cache.put(file2, mFile2);
+    measureCache.put(file2, mFile2);
 
-    assertThat(cache.entries()).hasSize(2);
-    assertThat(cache.byResource(p)).hasSize(0);
-    assertThat(cache.byResource(dir)).hasSize(0);
+    assertThat(measureCache.entries()).hasSize(2);
+    assertThat(measureCache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(dir)).hasSize(0);
 
     Measure mDir = new Measure(CoreMetrics.NCLOC, 4.0);
-    cache.put(dir, mDir);
+    measureCache.put(dir, mDir);
 
-    assertThat(cache.entries()).hasSize(3);
-    assertThat(cache.byResource(p)).hasSize(0);
-    assertThat(cache.byResource(dir)).hasSize(1);
-    assertThat(cache.byResource(dir).iterator().next()).isEqualTo(mDir);
+    assertThat(measureCache.entries()).hasSize(3);
+    assertThat(measureCache.byResource(p)).hasSize(0);
+    assertThat(measureCache.byResource(dir)).hasSize(1);
+    assertThat(measureCache.byResource(dir).iterator().next()).isEqualTo(mDir);
 
     Measure mProj = new Measure(CoreMetrics.NCLOC, 4.0);
-    cache.put(p, mProj);
+    measureCache.put(p, mProj);
 
-    assertThat(cache.entries()).hasSize(4);
-    assertThat(cache.byResource(p)).hasSize(1);
-    assertThat(cache.byResource(p).iterator().next()).isEqualTo(mProj);
-    assertThat(cache.byResource(dir)).hasSize(1);
-    assertThat(cache.byResource(dir).iterator().next()).isEqualTo(mDir);
+    assertThat(measureCache.entries()).hasSize(4);
+    assertThat(measureCache.byResource(p)).hasSize(1);
+    assertThat(measureCache.byResource(p).iterator().next()).isEqualTo(mProj);
+    assertThat(measureCache.byResource(dir)).hasSize(1);
+    assertThat(measureCache.byResource(dir).iterator().next()).isEqualTo(mDir);
   }
 
   @Test
@@ -274,9 +260,9 @@ public class MeasureCacheTest {
     Resource file1 = File.create("foo/bar/File1.txt").setEffectiveKey("struts:foo/bar/File1.txt");
 
     Measure measure = new Measure(CoreMetrics.NCLOC, 1.786, 5);
-    cache.put(file1, measure);
+    measureCache.put(file1, measure);
 
-    Measure savedMeasure = cache.byResource(file1).iterator().next();
+    Measure savedMeasure = measureCache.byResource(file1).iterator().next();
 
     assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
 
@@ -302,9 +288,9 @@ public class MeasureCacheTest {
     measure.setVariation3(13.0);
     measure.setVariation4(14.0);
     measure.setVariation5(15.0);
-    cache.put(file1, measure);
+    measureCache.put(file1, measure);
 
-    savedMeasure = cache.byResource(file1).iterator().next();
+    savedMeasure = measureCache.byResource(file1).iterator().next();
     assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
 
   }
index 4df298671096d1899d1e7dd9d3e3b95e4454a132..88553184e8210c136faabc784ab6b53a56089417 100644 (file)
@@ -467,7 +467,15 @@ public interface CoreProperties {
    * @since 4.0
    */
   String WORKING_DIRECTORY = "sonar.working.directory";
+  
   String WORKING_DIRECTORY_DEFAULT_VALUE = ".sonar";
+  
+  /**
+   * @since 5.2
+   */
+  String GLOBAL_WORKING_DIRECTORY = "sonar.globalWorking.directory";
+  String GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE = ".";
+  
 
   /**
    * @since 3.4
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/ProjectTempFolder.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/ProjectTempFolder.java
new file mode 100644 (file)
index 0000000..276be83
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.api.utils;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+
+import org.sonar.api.batch.BatchSide;
+
+
+/**
+ * Use this component to deal with temp files/folders that have a scope linked to each
+ * project analysis.
+ * Root location will typically be the working directory (see sonar.working.directory)
+
+ * @since 5.2
+ *
+ */
+@BatchSide
+public interface ProjectTempFolder {
+
+  /**
+   * Create a directory in temp folder with a random unique name.
+   */
+  File newDir();
+
+  /**
+   * Create a directory in temp folder using provided name.
+   */
+  File newDir(String name);
+
+  File newFile();
+
+  File newFile(@Nullable String prefix, @Nullable String suffix);
+
+}
\ No newline at end of file
index c456a020fc9ce8dabd052f93cad7f58157493a42..de63fadbfe4646d375df75b1f80765f7be9cabe6 100644 (file)
@@ -31,7 +31,7 @@ import java.io.File;
  * depends on situation:
  * <ul>
  * <li>${SONAR_HOME}/temp on server side</li>
- * <li>Working directory on batch side (see sonar.working.directory)</li>
+ * <li>${SONAR_HOME}/.sonartmp<rnd> on the batch side</li>
  * </ul>
  * @since 4.0
  *
index c96ecc3e488d7234b463d6cf63847ee1a1aeac2f..865821924077a10190d93cab73847e5750663116 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.api.utils.internal;
 
+import org.sonar.api.utils.ProjectTempFolder;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.utils.TempFolder;
@@ -29,15 +30,21 @@ import java.io.File;
 import java.io.IOException;
 import java.text.MessageFormat;
 
-public class DefaultTempFolder implements TempFolder {
+public class DefaultTempFolder implements TempFolder, ProjectTempFolder {
 
   /** Maximum loop count when creating temp directories. */
   private static final int TEMP_DIR_ATTEMPTS = 10000;
 
   private final File tempDir;
+  private final boolean cleanUp;
 
   public DefaultTempFolder(File tempDir) {
+    this(tempDir, false);
+  }
+
+  public DefaultTempFolder(File tempDir, boolean cleanUp) {
     this.tempDir = tempDir;
+    this.cleanUp = cleanUp;
   }
 
   @Override
@@ -106,4 +113,10 @@ public class DefaultTempFolder implements TempFolder {
     FileUtils.deleteQuietly(tempDir);
   }
 
+  public void stop() {
+    if(cleanUp) {
+      clean();
+    }
+  }
+
 }
index 3a8c15bf474cb8759b91fade250cd75828af6603..e5cda14785f4336da7f8af8bc981657a15dfa94c 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.api.utils.internal;
 
+import org.sonar.api.utils.ProjectTempFolder;
+
 import org.apache.commons.lang.StringUtils;
 import org.junit.rules.ExternalResource;
 import org.junit.rules.TemporaryFolder;
@@ -51,7 +53,7 @@ import java.io.IOException;
  *
  * @since 5.1
  */
-public class JUnitTempFolder extends ExternalResource implements TempFolder {
+public class JUnitTempFolder extends ExternalResource implements TempFolder, ProjectTempFolder {
 
   private final TemporaryFolder junit = new TemporaryFolder();