| 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); |
| } |
| } |