org.sonar.java.ProgressMonitor Maven / Gradle / Ivy
The newest version!
/*
* SonarQube Java
* Copyright (C) 2012-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
*
* This program 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 Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
import org.eclipse.core.runtime.IProgressMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.java.annotations.VisibleForTesting;
public class ProgressMonitor implements IProgressMonitor, Runnable {
private final Logger logger;
private final long period;
private final Thread thread;
private final BooleanSupplier isCanceled;
private boolean success = false;
private int totalWork = 0;
private boolean unknownTotalWork = false;
private int processedWork = 0;
/**
* The report loop can not rely only on Thread.interrupted() to end, according to
* interrupted() javadoc, a thread interruption can be ignored because a thread was
* not alive at the time of the interrupt. This could happen if done() is being called
* before ProgressMonitor's thread becomes alive.
* So this boolean flag ensures that ProgressMonitor never enter an infinite loop when
* Thread.interrupted() failed to be set to true.
*/
private final AtomicBoolean interrupted = new AtomicBoolean();
private final AnalysisProgress analysisProgress;
@VisibleForTesting
ProgressMonitor(BooleanSupplier isCanceled, Logger logger, long period, AnalysisProgress analysisProgress) {
interrupted.set(false);
this.isCanceled = isCanceled;
this.logger = logger;
this.period = period;
this.analysisProgress = analysisProgress;
thread = new Thread(this);
thread.setName("Report about progress of Java AST analyzer");
thread.setDaemon(true);
}
public ProgressMonitor(BooleanSupplier isCanceled, AnalysisProgress analysisProgress) {
this(isCanceled, LoggerFactory.getLogger(ProgressMonitor.class), TimeUnit.SECONDS.toMillis(10), analysisProgress);
}
@Override
public void run() {
while (!(interrupted.get() || Thread.currentThread().isInterrupted())) {
try {
Thread.sleep(period);
if (unknownTotalWork) {
log(String.format("%d/UNKNOWN unit(s) analyzed", processedWork));
} else {
double percentage = analysisProgress.toGlobalPercentage(processedWork / (double) totalWork);
log(String.format("%d%% analyzed", (int) (percentage * 100)));
}
} catch (InterruptedException e) {
interrupted.set(true);
thread.interrupt();
break;
}
}
}
@Override
public void beginTask(String name, int totalWork) {
if (totalWork <= 0) {
unknownTotalWork = true;
}
this.totalWork = totalWork;
if (analysisProgress.isFirstBatch()) {
log("Starting batch processing.");
}
thread.start();
}
@Override
public void done() {
if (success && analysisProgress.isLastBatch()) {
log("100% analyzed");
log("Batch processing: Done.");
}
interrupted.set(true);
thread.interrupt();
join();
}
@Override
public boolean isCanceled() {
if (isCanceled.getAsBoolean()) {
log("Batch processing: Cancelled!");
return true;
}
return false;
}
@Override
public void setCanceled(boolean value) {
// do nothing
}
private void join() {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void worked(int work) {
processedWork += work;
if (processedWork == totalWork) {
success = true;
}
}
@Override
public void internalWorked(double work) {
// do nothing
}
@Override
public void setTaskName(String name) {
// do nothing
}
@Override
public void subTask(String name) {
// do nothing
}
private void log(String message) {
synchronized (logger) {
logger.info(message);
logger.notifyAll();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy