package org.eclipse.debug.internal.core.groups;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.debug.internal.core.DebugCoreMessages;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.core.groups.GroupLaunchElement.GroupElementPostLaunchAction;
import org.eclipse.debug.internal.core.groups.observer.ProcessObserver;
import org.eclipse.debug.internal.core.groups.observer.StreamObserver;
import org.eclipse.osgi.util.NLS;
public class GroupLaunchConfigurationDelegate extends LaunchConfigurationDelegate implements ILaunchConfigurationDelegate2 {
public static final int CODE_GROUP_LAUNCH_START = 233;
public static final int CODE_GROUP_LAUNCH_DONE = 234;
private static final int CODE_BUILD_BEFORE_LAUNCH = 206;
private static final String NAME_PROP = "name";
private static final String ENABLED_PROP = "enabled";
private static final String ADOPT_PROP = "adoptIfRunning";
private static final String MODE_PROP = "mode";
private static final String ACTION_PROP = "action";
private static final String ACTION_PARAM_PROP = "actionParam";
private static final String MULTI_LAUNCH_CONSTANTS_PREFIX = "org.eclipse.debug.core.launchGroup";
private static final String DEBUG_CORE = "org.eclipse.debug.core";
private static final Status UNSUPPORTED_MODE = new Status(IStatus.ERROR, DEBUG_CORE, 230, IInternalDebugCoreConstants.EMPTY_STRING, null);
private static final Status GROUP_ELEMENT_STARTED = new Status(IStatus.OK, DEBUG_CORE, 231, IInternalDebugCoreConstants.EMPTY_STRING, null);
private static final Status GROUP_CYCLE = new Status(IStatus.ERROR, DEBUG_CORE, 232, IInternalDebugCoreConstants.EMPTY_STRING, null);
private static final Status GROUP_LAUNCH_START = new Status(IStatus.INFO, DEBUG_CORE, CODE_GROUP_LAUNCH_START, IInternalDebugCoreConstants.EMPTY_STRING, null);
private static final Status GROUP_LAUNCH_DONE = new Status(IStatus.INFO, DEBUG_CORE, CODE_GROUP_LAUNCH_DONE, IInternalDebugCoreConstants.EMPTY_STRING, null);
private static final Status BUILD_BEFORE_LAUNCH = new Status(IStatus.INFO, DEBUG_CORE, CODE_BUILD_BEFORE_LAUNCH, IInternalDebugCoreConstants.EMPTY_STRING, null);
@Override
public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
return new GroupLaunch(configuration, mode);
}
@Override
public void launch(ILaunchConfiguration groupConfig, String mode, final ILaunch groupLaunch, IProgressMonitor monitor) throws CoreException {
final GroupLaunch group = (GroupLaunch) groupLaunch;
IStatusHandler groupStateHandler = DebugPlugin.getDefault().getStatusHandler(GROUP_LAUNCH_START);
groupStateHandler.handleStatus(GROUP_LAUNCH_START, group);
try {
SubMonitor progress = SubMonitor.convert(monitor, NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_Launching, groupConfig.getName()), 1000);
List<GroupLaunchElement> launches = createLaunchElements(groupConfig);
for (int i = 0; i < launches.size(); ++i) {
GroupLaunchElement le = launches.get(i);
if (!le.enabled) {
continue;
}
final ILaunchConfiguration conf = findLaunchConfiguration(le.name);
if (conf == null) {
continue;
}
final String localMode;
if (!le.mode.equals(GroupLaunchElement.MODE_INHERIT)) {
localMode = le.mode;
} else {
localMode = mode;
}
if (!conf.supportsMode(localMode)) {
IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler(UNSUPPORTED_MODE);
handler.handleStatus(UNSUPPORTED_MODE, new String[] {
conf.getName(), localMode });
continue;
}
if (groupConfig.getName().equals(conf.getName())) {
IStatusHandler cycleHandler = DebugPlugin.getDefault().getStatusHandler(GROUP_CYCLE);
cycleHandler.handleStatus(GROUP_CYCLE, conf.getName());
} else {
if (!launchChild(progress.newChild(1000 / launches.size()), group, le, conf, localMode, (i == launches.size() - 1))) {
break;
}
}
if (group.isTerminated()) {
break;
}
}
if (!group.hasChildren()) {
DebugPlugin.getDefault().getLaunchManager().removeLaunch(group);
}
} finally {
group.markLaunched();
groupStateHandler.handleStatus(GROUP_LAUNCH_DONE, group);
monitor.done();
}
}
private boolean launchChild(SubMonitor monitor, final GroupLaunch group, GroupLaunchElement le, final ILaunchConfiguration child, final String localMode, boolean lastConfig) throws CoreException {
final Set<ILaunch> running = le.adoptIfRunning ? findRunningLaunch(le.name) : Collections.emptySet();
ILaunch subLaunch = running.stream().findFirst().orElse(null);
boolean launched = false;
if (subLaunch == null) {
boolean build = true;
IStatusHandler buildHandler = DebugPlugin.getDefault().getStatusHandler(BUILD_BEFORE_LAUNCH);
try {
Object resolution = buildHandler.handleStatus(BUILD_BEFORE_LAUNCH, child);
if (resolution instanceof Boolean) {
build = ((Boolean) resolution).booleanValue();
}
} catch (Exception e) {
}
subLaunch = child.launch(localMode, monitor, build);
launched = true;
}
group.addSubLaunch(subLaunch);
group.launchChanged(subLaunch);
if (launched) {
IStatusHandler postLaunchHandler = DebugPlugin.getDefault().getStatusHandler(GROUP_ELEMENT_STARTED);
postLaunchHandler.handleStatus(GROUP_ELEMENT_STARTED, new ILaunch[] {
group, subLaunch });
}
if (lastConfig) {
group.markLaunched();
}
if (launched) {
return postLaunchAction(subLaunch, le, monitor);
} else {
return true;
}
}
private boolean postLaunchAction(ILaunch subLaunch, GroupLaunchElement le, IProgressMonitor monitor) {
switch (le.action) {
case NONE:
return true;
case WAIT_FOR_TERMINATION:
monitor.subTask(NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_Waiting_for_termination, subLaunch.getLaunchConfiguration().getName()));
while (!subLaunch.isTerminated() && !monitor.isCanceled()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
monitor.subTask("");
break;
case DELAY:
Integer waitSecs = (Integer) le.actionParam;
if (waitSecs != null) {
monitor.subTask(NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_Delaying, waitSecs.toString()));
try {
Thread.sleep(waitSecs * 1000);
} catch (InterruptedException e) {
}
}
break;
case OUTPUT_REGEXP:
String regexp = (String) le.actionParam;
if (regexp != null) {
monitor.subTask(NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_waiting, regexp, subLaunch.getLaunchConfiguration().getName()));
if (!waitForOutputMatching(subLaunch, monitor, regexp)) {
return false;
}
}
break;
default:
assert false : "new post launch action type is missing logic";
}
return true;
}
private boolean waitForOutputMatching(ILaunch launch, IProgressMonitor m, String regexp) {
int processCount = launch.getProcesses().length;
final ExecutorService executor = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(processCount);
Future<Integer> process = null;
for (IProcess p : launch.getProcesses()) {
process = executor.submit(new ProcessObserver(m, p, countDownLatch));
executor.submit(new StreamObserver(m, p, regexp, countDownLatch));
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
}
executor.shutdown();
if (process == null || process.isDone()) {
return false;
}
return true;
}
@Override
protected void buildProjects(IProject[] projects, IProgressMonitor monitor) throws CoreException {
}
@Override
public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
return false;
}
protected static ILaunchConfiguration findLaunchConfiguration(String name) throws CoreException {
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfiguration[] launchConfigurations = launchManager.getLaunchConfigurations();
for (ILaunchConfiguration config : launchConfigurations) {
if (config.getName().equals(name)) {
return config;
}
}
return null;
}
protected static Set<ILaunch> findRunningLaunch(String name) {
Set<ILaunch> result = new HashSet<>();
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
for (ILaunch l : launchManager.getLaunches()) {
if (l.isTerminated()) {
continue;
}
if (l.getLaunchConfiguration().getName().equals(name)) {
result.add(l);
}
}
return result;
}
public static List<GroupLaunchElement> createLaunchElements(ILaunchConfiguration configuration) {
List<GroupLaunchElement> result = new ArrayList<>();
try {
Map<?, ?> attrs = configuration.getAttributes();
for (Iterator<?> iterator = attrs.keySet().iterator(); iterator.hasNext();) {
String attr = (String) iterator.next();
try {
if (attr.startsWith(MULTI_LAUNCH_CONSTANTS_PREFIX)) {
String prop = attr.substring(MULTI_LAUNCH_CONSTANTS_PREFIX.length() + 1);
int k = prop.indexOf('.');
String num = prop.substring(0, k);
int index = Integer.parseInt(num);
String name = prop.substring(k + 1);
if (name.equals(NAME_PROP)) {
GroupLaunchElement el = new GroupLaunchElement();
el.index = index;
el.name = (String) attrs.get(attr);
Object actionParam = null;
String actionStr = (String) attrs.get(getProp(index, ACTION_PROP));
GroupElementPostLaunchAction action;
try {
action = GroupElementPostLaunchAction.valueOf(actionStr);
} catch (Exception e) {
action = GroupElementPostLaunchAction.NONE;
}
if (action == GroupElementPostLaunchAction.DELAY) {
try {
actionParam = Integer.parseInt((String) attrs.get(getProp(index, ACTION_PARAM_PROP)));
} catch (NumberFormatException exc) {
DebugPlugin.log(exc);
}
}
if (action == GroupElementPostLaunchAction.OUTPUT_REGEXP) {
actionParam = attrs.get(getProp(index, ACTION_PARAM_PROP));
}
el.action = action;
el.actionParam = actionParam;
if (attrs.containsKey(getProp(index, ADOPT_PROP))) {
el.adoptIfRunning = (Boolean) attrs.get(getProp(index, ADOPT_PROP));
}
el.mode = (String) attrs.get(getProp(index, MODE_PROP));
el.enabled = (Boolean) attrs.get(getProp(index, ENABLED_PROP));
try {
el.data = findLaunchConfiguration(el.name);
} catch (Exception e) {
el.data = null;
}
while (index >= result.size()) {
result.add(null);
}
result.set(index, el);
}
}
} catch (Exception e) {
DebugPlugin.log(e);
}
}
} catch (CoreException e) {
DebugPlugin.log(e);
}
return result;
}
public static void storeLaunchElements(ILaunchConfigurationWorkingCopy configuration, List<GroupLaunchElement> input) {
int i = 0;
removeLaunchElements(configuration);
for (GroupLaunchElement el : input) {
if (el == null) {
continue;
}
configuration.setAttribute(getProp(i, NAME_PROP), el.name);
configuration.setAttribute(getProp(i, ACTION_PROP), el.action.toString());
configuration.setAttribute(getProp(i, ADOPT_PROP), el.adoptIfRunning);
configuration.setAttribute(getProp(i, ACTION_PARAM_PROP), el.actionParam != null ? el.actionParam.toString() : null);
configuration.setAttribute(getProp(i, MODE_PROP), el.mode);
configuration.setAttribute(getProp(i, ENABLED_PROP), el.enabled);
i++;
}
}
public static void removeLaunchElements(ILaunchConfigurationWorkingCopy configuration) {
try {
Map<?, ?> attrs = configuration.getAttributes();
for (Iterator<?> iterator = attrs.keySet().iterator(); iterator.hasNext();) {
String attr = (String) iterator.next();
try {
if (attr.startsWith(MULTI_LAUNCH_CONSTANTS_PREFIX)) {
configuration.removeAttribute(attr);
}
} catch (Exception e) {
DebugPlugin.log(e);
}
}
} catch (CoreException e) {
DebugPlugin.log(e);
}
}
public static String getProp(int index, String string) {
return MULTI_LAUNCH_CONSTANTS_PREFIX + "." + index + "." + string;
}
}