/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.cloudfoundry;
import javax.inject.Provider;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.internal.codeassist.ThrownExceptionFinder;
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.OperationTracker.Task;
import org.springframework.ide.eclipse.boot.dash.livexp.LiveCounter;
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
/**
* Keeps track of whether a certain 'operation' is currently in progress.
*
* @author Kris De Volder
*/
public class OperationTracker {
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
private static void debug(String string) {
if (DEBUG) {
System.out.println(string);
}
}
@FunctionalInterface
public interface Task {
void run() throws Exception;
}
private LiveVariable<Throwable> error;
/**
* Counter that keeps a count of the number of 'nested' operations are
* currently in progress (i.e. operation was started but not yet ended)
*/
public final LiveCounter inProgress = new LiveCounter();
private Provider<String> name;
public OperationTracker(Provider<String> name, LiveVariable<Throwable> error) {
this.name = name;
this.error = error;
}
private void start() {
setError(null);
inProgress.increment();
debug("starting: "+name.get()+" ["+inProgress.getValue()+"]");
}
private void setError(Throwable e) {
error.setValue(e);
}
public void whileExecuting(UserInteractions ui, CancelationToken cancelationToken, IProgressMonitor monitor, Task task) throws Exception {
Throwable error = null;
start();
try {
task.run();
} catch (Throwable e) {
error = e;
} finally {
end(error, ui, cancelationToken, monitor);
}
}
private void end(Throwable error, UserInteractions ui, CancelationToken cancelationToken, IProgressMonitor monitor) throws Exception {
Assert.isLegal(inProgress.getValue()>0);
int level = inProgress.decrement();
debug("ended: "+name.get()+" ["+inProgress.getValue()+"]");
if (cancelationToken.isCanceled() || monitor.isCanceled()) {
//Avoid setting error results for canceled operation. If an op is canceled
// its errors should simply be ignored.
throw new OperationCanceledException();
}
if (level==0 && !(error instanceof OperationCanceledException)) {
setError(error);
}
if (error != null) {
throw ExceptionUtil.exception(error);
}
}
}