blob: 305114cad264616c41604f6997b51afd49b4cc88 [file] [log] [blame]
package com.intellij.openapi.externalSystem.service.internal;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.task.*;
import com.intellij.openapi.externalSystem.service.ExternalSystemFacadeManager;
import com.intellij.openapi.externalSystem.service.RemoteExternalSystemFacade;
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.atomic.AtomicReference;
/**
* Encapsulates particular task performed by external system integration.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since 1/24/12 7:03 AM
*/
public abstract class AbstractExternalSystemTask implements ExternalSystemTask {
private static final Logger LOG = Logger.getInstance("#" + AbstractExternalSystemTask.class.getName());
private final AtomicReference<ExternalSystemTaskState> myState =
new AtomicReference<ExternalSystemTaskState>(ExternalSystemTaskState.NOT_STARTED);
private final AtomicReference<Throwable> myError = new AtomicReference<Throwable>();
@NotNull private final transient Project myIdeProject;
@NotNull private final ExternalSystemTaskId myId;
@NotNull private final ProjectSystemId myExternalSystemId;
@NotNull private final String myExternalProjectPath;
protected AbstractExternalSystemTask(@NotNull ProjectSystemId id,
@NotNull ExternalSystemTaskType type,
@NotNull Project project,
@NotNull String externalProjectPath) {
myExternalSystemId = id;
myIdeProject = project;
myId = ExternalSystemTaskId.create(id, type, myIdeProject);
myExternalProjectPath = externalProjectPath;
}
@NotNull
public ProjectSystemId getExternalSystemId() {
return myExternalSystemId;
}
@NotNull
public ExternalSystemTaskId getId() {
return myId;
}
@NotNull
public ExternalSystemTaskState getState() {
return myState.get();
}
protected void setState(@NotNull ExternalSystemTaskState state) {
myState.set(state);
}
protected boolean compareAndSetState(@NotNull ExternalSystemTaskState expect, @NotNull ExternalSystemTaskState update) {
return myState.compareAndSet(expect, update);
}
@Override
public Throwable getError() {
return myError.get();
}
@NotNull
public Project getIdeProject() {
return myIdeProject;
}
@NotNull
public String getExternalProjectPath() {
return myExternalProjectPath;
}
public void refreshState() {
if (getState() != ExternalSystemTaskState.IN_PROGRESS) {
return;
}
final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
try {
final RemoteExternalSystemFacade facade = manager.getFacade(myIdeProject, myExternalProjectPath, myExternalSystemId);
setState(facade.isTaskInProgress(getId()) ? ExternalSystemTaskState.IN_PROGRESS : ExternalSystemTaskState.FAILED);
}
catch (Throwable e) {
setState(ExternalSystemTaskState.FAILED);
myError.set(e);
if (!myIdeProject.isDisposed()) {
LOG.warn(e);
}
}
}
@Override
public void execute(@NotNull final ProgressIndicator indicator, @NotNull ExternalSystemTaskNotificationListener... listeners) {
indicator.setIndeterminate(true);
ExternalSystemTaskNotificationListenerAdapter adapter = new ExternalSystemTaskNotificationListenerAdapter() {
@Override
public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
indicator.setText(wrapProgressText(event.getDescription()));
}
};
final ExternalSystemTaskNotificationListener[] ls;
if (listeners.length > 0) {
ls = ArrayUtil.append(listeners, adapter);
}
else {
ls = new ExternalSystemTaskNotificationListener[]{adapter};
}
execute(ls);
}
@Override
public void execute(@NotNull ExternalSystemTaskNotificationListener... listeners) {
if (!compareAndSetState(ExternalSystemTaskState.NOT_STARTED, ExternalSystemTaskState.IN_PROGRESS)) return;
ExternalSystemProgressNotificationManager progressManager = ServiceManager.getService(ExternalSystemProgressNotificationManager.class);
for (ExternalSystemTaskNotificationListener listener : listeners) {
progressManager.addNotificationListener(getId(), listener);
}
ExternalSystemProcessingManager processingManager = ServiceManager.getService(ExternalSystemProcessingManager.class);
try {
processingManager.add(this);
doExecute();
setState(ExternalSystemTaskState.FINISHED);
}
catch (Throwable e) {
setState(ExternalSystemTaskState.FAILED);
myError.set(e);
LOG.warn(e);
}
finally {
for (ExternalSystemTaskNotificationListener listener : listeners) {
progressManager.removeNotificationListener(listener);
}
processingManager.release(getId());
}
}
protected abstract void doExecute() throws Exception;
@Override
public boolean cancel(@NotNull final ProgressIndicator indicator, @NotNull ExternalSystemTaskNotificationListener... listeners) {
indicator.setIndeterminate(true);
ExternalSystemTaskNotificationListenerAdapter adapter = new ExternalSystemTaskNotificationListenerAdapter() {
@Override
public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
indicator.setText(wrapProgressText(event.getDescription()));
}
};
final ExternalSystemTaskNotificationListener[] ls;
if (listeners.length > 0) {
ls = ArrayUtil.append(listeners, adapter);
}
else {
ls = new ExternalSystemTaskNotificationListener[]{adapter};
}
return cancel(ls);
}
@Override
public boolean cancel(@NotNull ExternalSystemTaskNotificationListener... listeners) {
ExternalSystemTaskState currentTaskState = getState();
if (currentTaskState.isStopped()) return true;
ExternalSystemProgressNotificationManager progressManager = ServiceManager.getService(ExternalSystemProgressNotificationManager.class);
for (ExternalSystemTaskNotificationListener listener : listeners) {
progressManager.addNotificationListener(getId(), listener);
}
if (!compareAndSetState(currentTaskState, ExternalSystemTaskState.CANCELING)) return false;
boolean result = false;
try {
result = doCancel();
setState(result ? ExternalSystemTaskState.CANCELED : ExternalSystemTaskState.CANCELLATION_FAILED);
return result;
}
catch (Throwable e) {
setState(ExternalSystemTaskState.CANCELLATION_FAILED);
myError.set(e);
LOG.warn(e);
}
finally {
for (ExternalSystemTaskNotificationListener listener : listeners) {
progressManager.removeNotificationListener(listener);
}
}
return result;
}
protected abstract boolean doCancel() throws Exception;
@NotNull
protected String wrapProgressText(@NotNull String text) {
return ExternalSystemBundle.message("progress.update.text", getExternalSystemId(), text);
}
@Override
public int hashCode() {
return myId.hashCode() + myExternalSystemId.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AbstractExternalSystemTask task = (AbstractExternalSystemTask)o;
return myId.equals(task.myId) && myExternalSystemId.equals(task.myExternalSystemId);
}
@Override
public String toString() {
return String.format("%s task %s: %s", myExternalSystemId.getReadableName(), myId, myState);
}
}