001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.batch.scan;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.slf4j.Logger;
024 import org.slf4j.LoggerFactory;
025 import org.sonar.api.i18n.I18n;
026 import org.sonar.api.resources.Project;
027 import org.sonar.api.utils.Semaphores;
028 import org.sonar.api.utils.SonarException;
029 import org.sonar.batch.ProjectTree;
030 import org.sonar.batch.bootstrap.AnalysisMode;
031
032 import java.util.Locale;
033
034 public class ProjectLock {
035
036 private static final Logger LOG = LoggerFactory.getLogger(ProjectLock.class);
037
038 private final Semaphores semaphores;
039 private final ProjectTree projectTree;
040 private final AnalysisMode analysisMode;
041 private final I18n i18n;
042
043 public ProjectLock(Semaphores semaphores, ProjectTree projectTree, AnalysisMode analysisMode, I18n i18n) {
044 this.semaphores = semaphores;
045 this.projectTree = projectTree;
046 this.analysisMode = analysisMode;
047 this.i18n = i18n;
048 }
049
050 public void start() {
051 if (!analysisMode.isPreview() && StringUtils.isNotBlank(getProject().getKey())) {
052 Semaphores.Semaphore semaphore = acquire();
053 if (!semaphore.isLocked()) {
054 LOG.error(getErrorMessage(semaphore));
055 throw new SonarException("The project is already being analysed.");
056 }
057 }
058 }
059
060 private String getErrorMessage(Semaphores.Semaphore semaphore) {
061 long duration = semaphore.getDurationSinceLocked();
062 String durationDisplay = i18n.age(Locale.ENGLISH, duration);
063
064 return "It looks like an analysis of '" + getProject().getName() + "' is already running (started " + durationDisplay + " ago).";
065 }
066
067 public void stop() {
068 if (!analysisMode.isPreview()) {
069 release();
070 }
071 }
072
073 private Semaphores.Semaphore acquire() {
074 LOG.debug("Acquire semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
075 return semaphores.acquire(getSemaphoreKey(), 15, 10);
076 }
077
078 private void release() {
079 LOG.debug("Release semaphore on project : {}, with key {}", getProject(), getSemaphoreKey());
080 semaphores.release(getSemaphoreKey());
081 }
082
083 private String getSemaphoreKey() {
084 return "batch-" + getProject().getKey();
085 }
086
087 private Project getProject() {
088 return projectTree.getRootProject();
089 }
090 }