/*******************************************************************************
* Copyright (c) 2013 Pivotal Software, 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 Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.commons.ui.launch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Future;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.ui.DebugUITools;
import org.springsource.ide.eclipse.commons.frameworks.core.async.ResolvableFuture;
public class LaunchUtils {
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
private static void debug(String string) {
if (DEBUG) {
System.out.println(string);
}
}
/**
* Execute some code as soon as a given list of launches are all terminated. If the launches are
* already terminated then the code is executed synchronously, otherwise it is executed asynchronously when
* a termination event is received.
*/
public static void whenTerminated(Collection<ILaunch> launches, Runnable runnable) {
new WhenTerminated(new ArrayList<ILaunch>(launches), runnable);
}
/**
* @return A future that resolves when a given launch is terminated
*/
public static Future<Void> whenTerminated(ILaunch l) {
return whenTerminated(Arrays.asList(l));
}
/**
* @return A future that resolves when a list of launches are all terminated
*/
public static Future<Void> whenTerminated(List<ILaunch> launches) {
final ResolvableFuture<Void> done = new ResolvableFuture<Void>();
whenTerminated(launches, new Runnable() {
public void run() {
done.resolve(null);
}
});
return done;
}
private static class WhenTerminated implements IDebugEventSetListener {
private final List<ILaunch> launches;
private Runnable runnable;
private final DebugPlugin debugPlugin;
public WhenTerminated(List<ILaunch> launches, Runnable runnable) {
this.launches = launches;
this.runnable = runnable;
this.debugPlugin = DebugPlugin.getDefault();
debugPlugin.addDebugEventListener(this);
//Careful... what if the launch has terminated since we last checked it...
// in that case we might not get a termination event! So start off with
// an initial check now.
checkAndRun();
}
@Override
public void handleDebugEvents(DebugEvent[] events) {
for (DebugEvent e : events) {
//Don't ckeck source==launch because we don't get termination events for launches
// only for processes in a launch.
if (e.getKind()==DebugEvent.TERMINATE) {
checkAndRun();
}
}
}
private void checkAndRun() {
Runnable runit = check();
if (runit!=null) {
debugPlugin.removeDebugEventListener(this);
runit.run();
}
}
/**
* Checks whether condition for firing the runable is satisfied. If so, then the runable
* is returned. At the same time the runnable field is nulled to ensure it can not be
* executed more than once.
* <p>
* Executing the runable does not happen in this method because it is 'synchronized'
* and we don't want to hang on to the monitor any longer than necessary (especially
* not when firing the runnable!)
*/
private synchronized Runnable check() {
if (runnable!=null) {
Iterator<ILaunch> iter = launches.iterator();
while (iter.hasNext()) {
ILaunch l = iter.next();
if (l.isTerminated()) {
iter.remove();
}
}
if (launches.isEmpty()) {
//bingo!
Runnable it = runnable;
runnable = null;
return it;
}
}
return null;
}
}
public static void terminateAndRelaunch(final ILaunchConfiguration launchConf, final String mode) throws DebugException {
List<ILaunch> launches = getLaunches(launchConf);
terminate(launches);
whenTerminated(launches, new UiRunnable() {
@Override
protected void uiRun() {
//must run in UI thread since it may popup dialogs in some cases.
DebugUITools.launch(launchConf, mode);
}
});
}
/**
* Terminate all launches in a list.
* This operation may be asynchronous. The caller can not rely
* on the launches being terminated before the method returns.
*/
public static void terminate(List<ILaunch> launches) throws DebugException {
for (ILaunch l : launches) {
if (!l.isTerminated()) {
l.terminate();
}
}
}
public static List<ILaunch> getLaunches(ILaunchConfiguration launchConf) {
ILaunch[] all = DebugPlugin.getDefault().getLaunchManager().getLaunches();
ArrayList<ILaunch> selected = new ArrayList<ILaunch>();
for (ILaunch l : all) {
ILaunchConfiguration lConf = l.getLaunchConfiguration();
if (lConf!=null && lConf.equals(launchConf)) {
selected.add(l);
}
}
return selected;
}
/**
* Terminates all launches associated with given launch config.
* This operation may be asynchronous. The caller can not rely
* on the launches being terminated before the method returns.
*/
public static void terminate(ILaunchConfiguration conf) throws DebugException {
terminate(getLaunches(conf));
}
}