]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3887 refactor semaphore API
authorSimon Brandhof <simon.brandhof@gmail.com>
Fri, 14 Dec 2012 17:27:29 +0000 (18:27 +0100)
committerSimon Brandhof <simon.brandhof@gmail.com>
Fri, 14 Dec 2012 17:27:29 +0000 (18:27 +0100)
14 files changed:
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectLockTest.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java [deleted file]
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoresImpl.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java
sonar-core/src/test/java/org/sonar/core/persistence/SemaphoresImplTest.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/utils/Semaphores.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/Platform.java

index 94448f6f16fcf68e4c1c1014ff88280b46d5fd43..bedc85782230a832b87e9d782d8940b126749903 100644 (file)
@@ -48,7 +48,7 @@ import org.sonar.core.i18n.RuleI18nManager;
 import org.sonar.core.metric.CacheMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.persistence.DaoUtils;
-import org.sonar.core.persistence.DatabaseSemaphoreImpl;
+import org.sonar.core.persistence.SemaphoresImpl;
 import org.sonar.core.persistence.DatabaseVersion;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.resource.DefaultResourcePermissions;
@@ -104,8 +104,8 @@ public class BatchModule extends Module {
     container.addSingleton(DefaultUserFinder.class);
     container.addSingleton(ResourceTypes.class);
     container.addSingleton(MetricProvider.class);
-    container.addSingleton(DatabaseSemaphoreImpl.class);
-    container.addSingleton(CheckSemaphore.class);
+    container.addSingleton(SemaphoresImpl.class);
+    container.addSingleton(ProjectLock.class);
   }
 
   private void registerDatabaseComponents() {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java
deleted file mode 100644 (file)
index 9bc4b65..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.batch.bootstrap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Project;
-import org.sonar.api.utils.DatabaseSemaphore;
-import org.sonar.api.utils.SonarException;
-import org.sonar.batch.ProjectTree;
-
-import static org.sonar.api.utils.DatabaseSemaphore.Lock;
-
-public class CheckSemaphore {
-
-  private static final Logger LOG = LoggerFactory.getLogger(CheckSemaphore.class);
-
-  private final DatabaseSemaphore databaseSemaphore;
-  private final ProjectTree projectTree;
-  private final Settings settings;
-
-  public CheckSemaphore(DatabaseSemaphore databaseSemaphore, ProjectTree projectTree, Settings settings) {
-    this.databaseSemaphore = databaseSemaphore;
-    this.projectTree = projectTree;
-    this.settings = settings;
-  }
-
-  public void start() {
-    if (!isInDryRunMode()) {
-      Lock lock = acquire();
-      if (!lock.isAcquired()) {
-        LOG.error(getErrorMessage(lock));
-        throw new SonarException("The project is already been analysing.");
-      }
-    }
-  }
-
-  private String getErrorMessage(Lock lock) {
-    long duration = lock.getDurationSinceLocked();
-    DurationLabel durationLabel = new DurationLabel();
-    String durationDisplay = durationLabel.label(duration);
-
-    return "It looks like an analysis of '"+ getProject().getName() +"' is already running (started "+ durationDisplay +"). " +
-        "If this is not the case, it probably means that previous analysis was interrupted " +
-        "and you should then force a re-run by using the option '"+ CoreProperties.FORCE_ANALYSIS +"=true'.";
-  }
-
-  public void stop() {
-    if (!isInDryRunMode()) {
-      release();
-    }
-  }
-
-  private Lock acquire() {
-    LOG.debug("Acquire semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
-    if (!isForceAnalyseActivated()) {
-      return databaseSemaphore.acquire(getSemaphoreKey());
-    } else {
-      // In force mode, we acquire the lock regardless there's a existing lock or not
-      return databaseSemaphore.acquire(getSemaphoreKey(), 0);
-    }
-  }
-
-  private void release() {
-    LOG.debug("Release semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
-    databaseSemaphore.release(getSemaphoreKey());
-  }
-
-  private String getSemaphoreKey() {
-    return "batch-" + getProject().getKey();
-  }
-
-  private Project getProject() {
-    return projectTree.getRootProject();
-  }
-
-  private boolean isInDryRunMode() {
-    return settings.getBoolean(CoreProperties.DRY_RUN);
-  }
-
-  private boolean isForceAnalyseActivated() {
-    return settings.getBoolean(CoreProperties.FORCE_ANALYSIS);
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java
new file mode 100644 (file)
index 0000000..33a4620
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.batch.bootstrap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.Semaphores;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.ProjectTree;
+
+public class ProjectLock {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ProjectLock.class);
+
+  private final Semaphores semaphores;
+  private final ProjectTree projectTree;
+  private final Settings settings;
+
+  public ProjectLock(Semaphores semaphores, ProjectTree projectTree, Settings settings) {
+    this.semaphores = semaphores;
+    this.projectTree = projectTree;
+    this.settings = settings;
+  }
+
+  public void start() {
+    if (!isInDryRunMode()) {
+      Semaphores.Semaphore semaphore = acquire();
+      if (!semaphore.isLocked()) {
+        LOG.error(getErrorMessage(semaphore));
+        throw new SonarException("The project is already been analysing.");
+      }
+    }
+  }
+
+  private String getErrorMessage(Semaphores.Semaphore semaphore) {
+    long duration = semaphore.getDurationSinceLocked();
+    DurationLabel durationLabel = new DurationLabel();
+    String durationDisplay = durationLabel.label(duration);
+
+    return "It looks like an analysis of '" + getProject().getName() + "' is already running (started " + durationDisplay + "). " +
+      "If this is not the case, it probably means that previous analysis was interrupted " +
+      "and you should then force a re-run by using the option '" + CoreProperties.FORCE_ANALYSIS + "=true'.";
+  }
+
+  public void stop() {
+    if (!isInDryRunMode()) {
+      release();
+    }
+  }
+
+  private Semaphores.Semaphore acquire() {
+    LOG.debug("Acquire semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
+    if (shouldForce()) {
+      // In force mode, we acquire the lock regardless there's a existing lock or not
+      return semaphores.acquire(getSemaphoreKey(), 0);
+    }
+    return semaphores.acquire(getSemaphoreKey());
+  }
+
+  private void release() {
+    LOG.debug("Release semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
+    semaphores.release(getSemaphoreKey());
+  }
+
+  private String getSemaphoreKey() {
+    return "batch-" + getProject().getKey();
+  }
+
+  private Project getProject() {
+    return projectTree.getRootProject();
+  }
+
+  private boolean isInDryRunMode() {
+    return settings.getBoolean(CoreProperties.DRY_RUN);
+  }
+
+  private boolean shouldForce() {
+    return settings.getBoolean(CoreProperties.FORCE_ANALYSIS);
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java
deleted file mode 100644 (file)
index e3d0986..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.batch.bootstrap;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Project;
-import org.sonar.api.utils.DatabaseSemaphore;
-import org.sonar.api.utils.SonarException;
-import org.sonar.batch.ProjectTree;
-
-import java.util.Date;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.sonar.api.utils.DatabaseSemaphore.Lock;
-
-public class CheckSemaphoreTest {
-
-  private CheckSemaphore checkSemaphore;
-
-  private DatabaseSemaphore databaseSemaphore;
-  private ProjectTree projectTree;
-  private Settings settings;
-
-  private Project project;
-  private Lock lock;
-
-  @Before
-  public void setUp() {
-    lock = mock(Lock.class);
-
-    databaseSemaphore = mock(DatabaseSemaphore.class);
-    when(databaseSemaphore.acquire(anyString())).thenReturn(lock);
-    when(databaseSemaphore.acquire(anyString(), anyInt())).thenReturn(lock);
-
-    projectTree = mock(ProjectTree.class);
-    settings = new Settings();
-    setDryRunMode(false);
-    setForceMode(false);
-
-    project = new Project("key", "branch", "name");
-    when(projectTree.getRootProject()).thenReturn(project);
-
-    checkSemaphore = new CheckSemaphore(databaseSemaphore, projectTree, settings);
-  }
-
-  @Test
-  public void shouldAcquireSemaphore() {
-    when(lock.isAcquired()).thenReturn(true);
-    checkSemaphore.start();
-
-    verify(databaseSemaphore).acquire(anyString());
-  }
-
-  @Test
-  public void shouldUseProjectKeyInTheKeyOfTheSemaphore() {
-    project = new Project("key");
-    when(projectTree.getRootProject()).thenReturn(project);
-
-    when(lock.isAcquired()).thenReturn(true);
-    checkSemaphore.start();
-
-    verify(databaseSemaphore).acquire("batch-key");
-  }
-
-  @Test
-  public void shouldUseProjectKeyAndBranchIfExistingInTheKeyOfTheSemaphore() {
-    when(lock.isAcquired()).thenReturn(true);
-    checkSemaphore.start();
-
-    verify(databaseSemaphore).acquire("batch-key:branch");
-  }
-
-  @Test
-  public void shouldAcquireSemaphoreIfForceAnalyseActivated() {
-    setForceMode(true);
-    when(lock.isAcquired()).thenReturn(true);
-    checkSemaphore.start();
-    verify(databaseSemaphore).acquire(anyString(), anyInt());
-  }
-
-  @Test(expected = SonarException.class)
-  public void shouldNotAcquireSemaphoreIfTheProjectIsAlreadyBeenAnalysing() {
-    when(lock.getLocketAt()).thenReturn(new Date());
-    when(lock.isAcquired()).thenReturn(false);
-    checkSemaphore.start();
-    verify(databaseSemaphore, never()).acquire(anyString());
-  }
-
-  @Test
-  public void shouldNotAcquireSemaphoreInDryRunMode() {
-    setDryRunMode(true);
-    settings = new Settings().setProperty(CoreProperties.DRY_RUN, true);
-    checkSemaphore.start();
-    verify(databaseSemaphore, never()).acquire(anyString());
-    verify(databaseSemaphore, never()).acquire(anyString(), anyInt());
-  }
-
-  @Test
-  public void shouldReleaseSemaphore() {
-    checkSemaphore.stop();
-    verify(databaseSemaphore).release(anyString());
-  }
-
-  @Test
-  public void shouldNotReleaseSemaphoreInDryRunMode() {
-    setDryRunMode(true);
-    checkSemaphore.stop();
-    verify(databaseSemaphore, never()).release(anyString());
-  }
-
-  private void setDryRunMode(boolean isInDryRunMode) {
-    settings.setProperty(CoreProperties.DRY_RUN, isInDryRunMode);
-  }
-
-  private void setForceMode(boolean isInForcedMode) {
-    settings.setProperty(CoreProperties.FORCE_ANALYSIS, isInForcedMode);
-  }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectLockTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectLockTest.java
new file mode 100644 (file)
index 0000000..f47061a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.batch.bootstrap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.Semaphores;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.ProjectTree;
+
+import java.util.Date;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class ProjectLockTest {
+
+  private ProjectLock projectLock;
+
+  private Semaphores semaphores;
+  private ProjectTree projectTree;
+  private Settings settings;
+
+  private Project project;
+
+  @Before
+  public void setUp() {
+    semaphores = mock(Semaphores.class);
+
+    projectTree = mock(ProjectTree.class);
+    settings = new Settings();
+    setDryRunMode(false);
+    setForceMode(false);
+    project = new Project("my-project-key");
+    when(projectTree.getRootProject()).thenReturn(project);
+
+    projectLock = new ProjectLock(semaphores, projectTree, settings);
+  }
+
+  @Test
+  public void shouldAcquireSemaphore() {
+    when(semaphores.acquire(anyString())).thenReturn(new Semaphores.Semaphore().setLocked(true));
+    projectLock.start();
+
+    verify(semaphores).acquire("batch-my-project-key");
+  }
+
+  @Test
+  public void shouldAcquireSemaphoreIfForceAnalyseActivated() {
+    setForceMode(true);
+    when(semaphores.acquire("batch-my-project-key", 0)).thenReturn(new Semaphores.Semaphore().setLocked(true));
+
+    projectLock.start();
+  }
+
+  @Test(expected = SonarException.class)
+  public void shouldNotAcquireSemaphoreIfTheProjectIsAlreadyBeenAnalysing() {
+    when(semaphores.acquire(anyString())).thenReturn(new Semaphores.Semaphore().setLocked(false).setDurationSinceLocked(1234L));
+    projectLock.start();
+  }
+
+  @Test
+  public void shouldNotAcquireSemaphoreInDryRunMode() {
+    setDryRunMode(true);
+    settings = new Settings().setProperty(CoreProperties.DRY_RUN, true);
+    projectLock.start();
+    verifyZeroInteractions(semaphores);
+  }
+
+  @Test
+  public void shouldReleaseSemaphore() {
+    projectLock.stop();
+    verify(semaphores).release("batch-my-project-key");
+  }
+
+  @Test
+  public void shouldNotReleaseSemaphoreInDryRunMode() {
+    setDryRunMode(true);
+    projectLock.stop();
+    verifyZeroInteractions(semaphores);
+  }
+
+  private void setDryRunMode(boolean isInDryRunMode) {
+    settings.setProperty(CoreProperties.DRY_RUN, isInDryRunMode);
+  }
+
+  private void setForceMode(boolean isInForcedMode) {
+    settings.setProperty(CoreProperties.FORCE_ANALYSIS, isInForcedMode);
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java
deleted file mode 100644 (file)
index 75a5bb7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.core.persistence;
-
-import org.sonar.api.utils.DatabaseSemaphore;
-
-/**
- * @since 3.4
- */
-public class DatabaseSemaphoreImpl implements DatabaseSemaphore {
-
-  private SemaphoreDao dao;
-
-  public DatabaseSemaphoreImpl(SemaphoreDao dao) {
-    this.dao = dao;
-  }
-
-  public Lock acquire(String name, int maxDurationInSeconds) {
-    return dao.acquire(name, maxDurationInSeconds);
-  }
-
-  public Lock acquire(String name) {
-    return dao.acquire(name);
-  }
-
-  public void release(String name) {
-    dao.release(name);
-  }
-}
index 471315c2d40ac53fc3fda0979f878217efbe750b..3e36545012b9ff52624130407c89ae60e66d6f17 100644 (file)
@@ -23,11 +23,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import org.apache.commons.lang.time.DateUtils;
 import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.utils.Semaphores;
 
 import java.util.Date;
 
-import static org.sonar.api.utils.DatabaseSemaphore.Lock;
-
 /**
  * @since 3.4
  */
@@ -39,7 +38,7 @@ public class SemaphoreDao {
     this.mybatis = mybatis;
   }
 
-  public Lock acquire(String name, int maxDurationInSeconds) {
+  public Semaphores.Semaphore acquire(String name, int maxDurationInSeconds) {
     Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Semaphore name must not be empty");
     Preconditions.checkArgument(maxDurationInSeconds >= 0, "Semaphore max duration must be positive: " + maxDurationInSeconds);
 
@@ -47,7 +46,7 @@ public class SemaphoreDao {
     try {
       SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
       Date lockedAt = org.sonar.api.utils.DateUtils.parseDate("2001-01-01");
-      createSemaphore(name, lockedAt, session);
+      createDto(name, lockedAt, session);
       boolean isAcquired = doAcquire(name, maxDurationInSeconds, session, mapper);
       SemaphoreDto semaphore = selectSemaphore(name, session);
       return createLock(semaphore, session, isAcquired);
@@ -56,7 +55,7 @@ public class SemaphoreDao {
     }
   }
 
-  public Lock acquire(String name) {
+  public Semaphores.Semaphore acquire(String name) {
     Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Semaphore name must not be empty");
 
     SqlSession session = mybatis.openSession();
@@ -67,7 +66,7 @@ public class SemaphoreDao {
       if (semaphore != null) {
         return createLock(semaphore, session, false);
       } else {
-        semaphore = createSemaphore(name, now, session);
+        semaphore = createDto(name, now, session);
         return createLock(semaphore, session, true);
       }
     } finally {
@@ -93,12 +92,12 @@ public class SemaphoreDao {
     return ok;
   }
 
-  private SemaphoreDto createSemaphore(String name, Date lockedAt, SqlSession session) {
+  private SemaphoreDto createDto(String name, Date lockedAt, SqlSession session) {
     try {
       SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
       SemaphoreDto semaphore = new SemaphoreDto()
-          .setName(name)
-          .setLockedAt(lockedAt);
+        .setName(name)
+        .setLockedAt(lockedAt);
       mapper.initialize(semaphore);
       session.commit();
       return semaphore;
@@ -109,12 +108,17 @@ public class SemaphoreDao {
     }
   }
 
-  private Lock createLock(SemaphoreDto semaphore, SqlSession session, boolean acquired) {
-    Lock lock = new Lock(semaphore.getName(), acquired, semaphore.getLockedAt(), semaphore.getCreatedAt(), semaphore.getUpdatedAt());
+  private Semaphores.Semaphore createLock(SemaphoreDto dto, SqlSession session, boolean acquired) {
+    Semaphores.Semaphore semaphore = new Semaphores.Semaphore()
+      .setName(dto.getName())
+      .setLocked(acquired)
+      .setLocketAt(dto.getLockedAt())
+      .setCreatedAt(dto.getCreatedAt())
+      .setUpdatedAt(dto.getUpdatedAt());
     if (!acquired) {
-      lock.setDurationSinceLocked(getDurationSinceLocked(semaphore, session));
+      semaphore.setDurationSinceLocked(getDurationSinceLocked(dto, session));
     }
-    return lock;
+    return semaphore;
   }
 
   private long getDurationSinceLocked(SemaphoreDto semaphore, SqlSession session) {
@@ -124,12 +128,12 @@ public class SemaphoreDao {
     return now - locketAt;
   }
 
-  protected SemaphoreDto selectSemaphore(String name, SqlSession session){
+  protected SemaphoreDto selectSemaphore(String name, SqlSession session) {
     SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
     return mapper.selectSemaphore(name);
   }
 
-  protected Date now(SqlSession session){
+  protected Date now(SqlSession session) {
     SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
     return mapper.now();
   }
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoresImpl.java b/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoresImpl.java
new file mode 100644 (file)
index 0000000..b69cff9
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.core.persistence;
+
+import org.sonar.api.utils.Semaphores;
+
+/**
+ * @since 3.4
+ */
+public class SemaphoresImpl implements Semaphores {
+
+  private SemaphoreDao dao;
+
+  public SemaphoresImpl(SemaphoreDao dao) {
+    this.dao = dao;
+  }
+
+  public Semaphore acquire(String name, int maxDurationInSeconds) {
+    return dao.acquire(name, maxDurationInSeconds);
+  }
+
+  public Semaphore acquire(String name) {
+    return dao.acquire(name);
+  }
+
+  public void release(String name) {
+    dao.release(name);
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java
deleted file mode 100644 (file)
index 73a7d61..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.core.persistence;
-
-import org.junit.Test;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.sonar.api.utils.DatabaseSemaphore.Lock;
-
-public class DatabaseSemaphoreImplTest {
-
-  @Test
-  public void should_be_a_bridge_over_dao() {
-    Lock lock = mock(Lock.class);
-    SemaphoreDao dao = mock(SemaphoreDao.class);
-    when(dao.acquire(anyString(), anyInt())).thenReturn(lock);
-
-    DatabaseSemaphoreImpl impl = new DatabaseSemaphoreImpl(dao);
-
-    impl.acquire("do-xxx", 50000);
-    verify(dao).acquire("do-xxx", 50000);
-
-    impl.acquire("do-xxx");
-    verify(dao).acquire("do-xxx");
-
-    impl.release("do-xxx");
-    verify(dao).release("do-xxx");
-  }
-}
index 948afed4a59611a467762ab65bb082b7860783fe..ccfcb6336c3ec167e92c4ee9c5374f800e935d24 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.Semaphores;
 
 import java.util.Date;
 import java.util.concurrent.CountDownLatch;
@@ -32,7 +33,6 @@ import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.sonar.api.utils.DatabaseSemaphore.Lock;
 
 public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
@@ -75,8 +75,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void create_and_acquire_semaphore() throws Exception {
-    Lock lock = dao.acquire("foo", 60);
-    assertThat(lock.isAcquired()).isTrue();
+    Semaphores.Semaphore lock = dao.acquire("foo", 60);
+    assertThat(lock.isLocked()).isTrue();
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -92,8 +92,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void create_and_acquire_semaphore_when_timeout_is_zeo() throws Exception {
-    Lock lock = dao.acquire("foo", 0);
-    assertThat(lock.isAcquired()).isTrue();
+    Semaphores.Semaphore lock = dao.acquire("foo", 0);
+    assertThat(lock.isLocked()).isTrue();
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -109,8 +109,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void create_and_acquire_semaphore_when_no_timeout() throws Exception {
-    Lock lock = dao.acquire("foo");
-    assertThat(lock.isAcquired()).isTrue();
+    Semaphores.Semaphore lock = dao.acquire("foo");
+    assertThat(lock.isLocked()).isTrue();
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -127,8 +127,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   @Test
   public void fail_to_acquire_locked_semaphore() throws Exception {
     setupData("old_semaphore");
-    Lock lock = dao.acquire("foo", Integer.MAX_VALUE);
-    assertThat(lock.isAcquired()).isFalse();
+    Semaphores.Semaphore lock = dao.acquire("foo", Integer.MAX_VALUE);
+    assertThat(lock.isLocked()).isFalse();
     assertThat(lock.getDurationSinceLocked()).isNotNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -142,8 +142,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   @Test
   public void acquire_long_locked_semaphore() throws Exception {
     setupData("old_semaphore");
-    Lock lock = dao.acquire("foo", 60);
-    assertThat(lock.isAcquired()).isTrue();
+    Semaphores.Semaphore lock = dao.acquire("foo", 60);
+    assertThat(lock.isLocked()).isTrue();
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -157,8 +157,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   @Test
   public void acquire_locked_semaphore_when_timeout_is_zeo() throws Exception {
     setupData("old_semaphore");
-    Lock lock = dao.acquire("foo", 0);
-    assertThat(lock.isAcquired()).isTrue();
+    Semaphores.Semaphore lock = dao.acquire("foo", 0);
+    assertThat(lock.isLocked()).isTrue();
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -175,8 +175,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   @Test
   public void fail_to_acquire_locked_semaphore_when_no_timeout() throws Exception {
     setupData("old_semaphore");
-    Lock lock = dao.acquire("foo");
-    assertThat(lock.isAcquired()).isFalse();
+    Semaphores.Semaphore lock = dao.acquire("foo");
+    assertThat(lock.isLocked()).isFalse();
     assertThat(lock.getDurationSinceLocked()).isNotNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
@@ -259,7 +259,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
       try {
         barrier.await();
         for (int i = 0; i < 100; i++) {
-          if (dao.acquire("my-lock", 60 * 5).isAcquired()) {
+          if (dao.acquire("my-lock", 60 * 5).isLocked()) {
             locks.incrementAndGet();
           }
         }
diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoresImplTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoresImplTest.java
new file mode 100644 (file)
index 0000000..a09b49a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.core.persistence;
+
+import org.junit.Test;
+import org.sonar.api.utils.Semaphores;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SemaphoresImplTest {
+
+  @Test
+  public void should_be_a_bridge_over_dao() {
+    SemaphoreDao dao = mock(SemaphoreDao.class);
+    Semaphores.Semaphore semaphore = new Semaphores.Semaphore();
+    when(dao.acquire(anyString(), anyInt())).thenReturn(semaphore);
+
+    SemaphoresImpl impl = new SemaphoresImpl(dao);
+
+    impl.acquire("do-xxx", 50000);
+    verify(dao).acquire("do-xxx", 50000);
+
+    impl.acquire("do-xxx");
+    verify(dao).acquire("do-xxx");
+
+    impl.release("do-xxx");
+    verify(dao).release("do-xxx");
+  }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java
deleted file mode 100644 (file)
index 93d8ef9..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.api.utils;
-
-import org.sonar.api.BatchComponent;
-import org.sonar.api.ServerComponent;
-
-import java.util.Date;
-
-/**
- * A semaphore shared among all the processes that can connect to the central database.
- *
- * @since 3.4
- */
-public interface DatabaseSemaphore extends BatchComponent, ServerComponent {
-
-  /**
-   * Try to acquire a lock on a name, for a given duration.
-   * The lock will be acquired if there's no existing lock on this name or if a lock exists but the max duration is reached.
-   *
-   * @param name the key of the semaphore
-   * @param maxDurationInSeconds the max duration in seconds the semaphore will be acquired (a value of zero can be used to always acquire a lock)
-   * @return a lock containing information if the lock could be acquired or not, the duration since locked, etc.
-   */
-  Lock acquire(String name, int maxDurationInSeconds);
-
-  /**
-   * Try to acquire the lock on a name.
-   * The lock will be acquired only if there's no existing lock.
-   *
-   * @param name the key of the semaphore
-   * @return a lock containing information if the lock could be acquired or not, the duration since locked, etc.
-   */
-  Lock acquire(String name);
-
-  /**
-   * Release the lock on a semaphore by its name.
-   *
-   * @param name the key of the semaphore
-   */
-  void release(String name);
-
-  class Lock {
-
-    private String name;
-    private boolean acquired;
-    private Date locketAt;
-    private Date createdAt;
-    private Date updatedAt;
-    private Long durationSinceLocked;
-
-    public Lock(String name, boolean acquired, Date locketAt, Date createdAt, Date updatedAt) {
-      this.name = name;
-      this.acquired = acquired;
-      this.locketAt = locketAt;
-      this.createdAt = createdAt;
-      this.updatedAt = updatedAt;
-    }
-
-    public String getName() {
-      return name;
-    }
-
-    public Date getLocketAt() {
-      return locketAt;
-    }
-
-    public Date getCreatedAt() {
-      return createdAt;
-    }
-
-    public Date getUpdatedAt() {
-      return updatedAt;
-    }
-
-    public boolean isAcquired() {
-      return acquired;
-    }
-
-    public Long getDurationSinceLocked() {
-      return durationSinceLocked;
-    }
-
-    public void setDurationSinceLocked(Long durationSinceLocked) {
-      this.durationSinceLocked = durationSinceLocked;
-    }
-
-  }
-
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Semaphores.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Semaphores.java
new file mode 100644 (file)
index 0000000..1b3a711
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.api.utils;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+
+import java.util.Date;
+
+/**
+ * A semaphore shared among all the processes that can connect to the central database.
+ * It's ignored when enabling the dry run mode.
+ *
+ * @since 3.4
+ */
+public interface Semaphores extends BatchComponent, ServerComponent {
+
+  /**
+   * Try to acquire a semaphore for a given duration.
+   * The semaphore is acquired if it's unlocked or if the max locking duration is reached.
+   *
+   * @param name                 the key of the semaphore
+   * @param maxDurationInSeconds the max duration in seconds the semaphore will be acquired. The value zero forces the semaphore to be acquired, whatever its status.
+   * @return the semaphore, whatever its status (locked or unlocked). Can't be null.
+   */
+  Semaphore acquire(String name, int maxDurationInSeconds);
+
+  /**
+   * Try to acquire a semaphore.
+   * The lock will be acquired only if there's no existing lock.
+   *
+   * @param name the key of the semaphore
+   * @return a lock containing information if the lock could be acquired or not, the duration since locked, etc.
+   */
+  Semaphore acquire(String name);
+
+  /**
+   * Release the lock on a semaphore by its name. Does nothing if the lock is already released.
+   *
+   * @param name the key of the semaphore
+   */
+  void release(String name);
+
+  class Semaphore {
+
+    private String name;
+    private boolean locked;
+    private Date locketAt;
+    private Date createdAt;
+    private Date updatedAt;
+    private Long durationSinceLocked;
+
+    public String getName() {
+      return name;
+    }
+
+    public Semaphore setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    public boolean isLocked() {
+      return locked;
+    }
+
+    public Semaphore setLocked(boolean locked) {
+      this.locked = locked;
+      return this;
+    }
+
+    public Date getLocketAt() {
+      return locketAt;
+    }
+
+    public Semaphore setLocketAt(Date locketAt) {
+      this.locketAt = locketAt;
+      return this;
+    }
+
+    public Date getCreatedAt() {
+      return createdAt;
+    }
+
+    public Semaphore setCreatedAt(Date createdAt) {
+      this.createdAt = createdAt;
+      return this;
+    }
+
+    public Date getUpdatedAt() {
+      return updatedAt;
+    }
+
+    public Semaphore setUpdatedAt(Date updatedAt) {
+      this.updatedAt = updatedAt;
+      return this;
+    }
+
+    public Long getDurationSinceLocked() {
+      return durationSinceLocked;
+    }
+
+    public Semaphore setDurationSinceLocked(Long durationSinceLocked) {
+      this.durationSinceLocked = durationSinceLocked;
+      return this;
+    }
+  }
+
+}
index 9809d4816c63ce2f6c61b632bd5d176a8244ed78..eff0770fcf3a6aafff5f522e59cc6b68d4ad2c19 100644 (file)
@@ -51,6 +51,7 @@ import org.sonar.core.persistence.DatabaseVersion;
 import org.sonar.core.persistence.DefaultDatabase;
 import org.sonar.core.persistence.DryRunDatabaseFactory;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.persistence.SemaphoresImpl;
 import org.sonar.core.qualitymodel.DefaultModelFinder;
 import org.sonar.core.resource.DefaultResourcePermissions;
 import org.sonar.core.rule.DefaultRuleFinder;
@@ -181,6 +182,7 @@ public final class Platform {
     rootContainer.addSingleton(RuleI18nManager.class);
     rootContainer.addSingleton(GwtI18n.class);
     rootContainer.addSingleton(DryRunDatabaseFactory.class);
+    rootContainer.addSingleton(SemaphoresImpl.class);
     rootContainer.startComponents();
   }