blob: f9eed1727b0d9a56fd7936ca25112c4ca6e5e45b [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.idea.blaze.base.async.executor;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Progressive;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.util.ui.UIUtil;
import java.util.concurrent.Callable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** Shared thread pool for blaze tasks. */
public abstract class BlazeExecutor {
/** The type of modality used to launch tasks */
public enum Modality {
MODAL, // This task must start in the foreground and stay there.
BACKGROUNDABLE, // This task will start in the foreground, but can be sent to the background.
ALWAYS_BACKGROUND // This task will start in the background and stay there.
}
@NotNull
public static BlazeExecutor getInstance() {
return ServiceManager.getService(BlazeExecutor.class);
}
public abstract <T> ListenableFuture<T> submit(Callable<T> callable);
public abstract ListeningExecutorService getExecutor();
public static ListenableFuture<Void> submitTask(
@Nullable final Project project, @NotNull final Progressive progressive) {
return submitTask(project, "", progressive);
}
public static ListenableFuture<Void> submitTask(
@Nullable final Project project,
@NotNull final String title,
@NotNull final Progressive progressive) {
return submitTask(
project, title, true /* cancelable */, Modality.ALWAYS_BACKGROUND, progressive);
}
public static ListenableFuture<Void> submitTask(
@Nullable final Project project,
@NotNull final String title,
final boolean cancelable,
final Modality modality,
@NotNull final Progressive progressive) {
// The progress indicator must be created on the UI thread.
final ProgressWindow indicator =
UIUtil.invokeAndWaitIfNeeded(
new Computable<ProgressWindow>() {
@Override
public ProgressWindow compute() {
if (modality == Modality.MODAL) {
ProgressWindow indicator = new ProgressWindow(cancelable, project);
indicator.setTitle(title);
return indicator;
} else {
PerformInBackgroundOption backgroundOption =
modality == Modality.BACKGROUNDABLE
? PerformInBackgroundOption.DEAF
: PerformInBackgroundOption.ALWAYS_BACKGROUND;
return new BackgroundableProcessIndicator(
project, title, backgroundOption, "Cancel", "Cancel", cancelable);
}
}
});
indicator.setIndeterminate(true);
indicator.start();
final Runnable process =
new Runnable() {
@Override
public void run() {
progressive.run(indicator);
}
};
final ListenableFuture<Void> future =
getInstance()
.submit(
new Callable<Void>() {
@Override
public Void call() throws Exception {
ProgressManager.getInstance().runProcess(process, indicator);
return null;
}
});
if (cancelable) {
indicator.addStateDelegate(
new AbstractProgressIndicatorExBase() {
@Override
public void cancel() {
super.cancel();
future.cancel(true);
}
});
}
return future;
}
}