/*******************************************************************************
* Copyright (c) 2012, 2014 Wind River Systems, Inc. and others. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.launch.core.bindings;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.tcf.te.launch.core.bindings.internal.LaunchConfigTypeBinding;
import org.eclipse.tcf.te.launch.core.bindings.internal.LaunchConfigTypeUnBinding;
import org.eclipse.tcf.te.launch.core.bindings.internal.OverwritableLaunchBinding;
import org.eclipse.tcf.te.launch.core.lm.interfaces.ILaunchManagerDelegate;
import org.eclipse.tcf.te.launch.core.lm.internal.ExtensionPointManager;
import org.eclipse.tcf.te.launch.core.selection.interfaces.ILaunchSelection;
import org.eclipse.tcf.te.launch.core.selection.interfaces.ISelectionContext;
import org.eclipse.tcf.te.runtime.extensions.ExtensionPointComparator;
/**
* Manager that controls the launch configuration type bindings.
*/
public class LaunchConfigTypeBindingsManager {
// Map of all launch configuration type bindings by id
private final Map<String, LaunchConfigTypeBinding> bindings = new Hashtable<String, LaunchConfigTypeBinding>();
// Map of all launch configuration type unbindings by id
private final Map<String, LaunchConfigTypeUnBinding> unBindings = new Hashtable<String, LaunchConfigTypeUnBinding>();
/*
* Thread save singleton instance creation.
*/
private static class LazyInstanceHolder {
public static LaunchConfigTypeBindingsManager instance = new LaunchConfigTypeBindingsManager();
}
/**
* Returns the singleton instance.
*/
public static LaunchConfigTypeBindingsManager getInstance() {
return LazyInstanceHolder.instance;
}
/**
* Constructor.
*/
LaunchConfigTypeBindingsManager() {
// Load the launch configuration type bindings on instantiation.
loadBindingsExtensions();
}
/**
* Get all valid launch configuration type id's for the given selection.
*
* @param selection The selection or <code>null</code>.
* @return The list of valid launch configuration type id's for the selection or an empty list.
*/
public String[] getValidLaunchConfigTypes(ILaunchSelection selection) {
Set<String> validLaunchTypes = new HashSet<String>();
if (selection != null && selection.getSelectedContexts() != null && selection.getSelectedContexts().length > 0) {
for (String launchConfigTypeId : bindings.keySet()) {
if (isValidLaunchConfigType(launchConfigTypeId, selection)) {
validLaunchTypes.add(launchConfigTypeId);
}
}
}
return validLaunchTypes.toArray(new String[validLaunchTypes.size()]);
}
/**
* Validates the given launch selection.
*
* @param typeId The launch configuration type id. Must not be <code>null</code>.
* @param selection The selection. Must not be <code>null</code>.
*/
public boolean isValidLaunchConfigType(String typeId, ILaunchSelection selection) {
Assert.isNotNull(typeId);
Assert.isNotNull(selection);
LaunchConfigTypeBinding binding = bindings.get(typeId);
LaunchConfigTypeUnBinding unBinding = unBindings.get(typeId);
ILaunchConfigurationType launchConfigType = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(typeId);
return (launchConfigType != null &&
(selection.getLaunchMode() == null || launchConfigType.supportsMode(selection.getLaunchMode())) &&
binding != null && binding.validate(selection) == EvaluationResult.TRUE &&
(unBinding == null || unBinding.validate(selection) != EvaluationResult.TRUE));
}
/**
* Validates the given launch selection.
*
* @param typeId The launch configuration type id. Must not be <code>null</code>.
* @param mode The launch mode or <code>null</code>.
* @param context The selection context. Must not be <code>null</code>.
*/
public boolean isValidLaunchConfigType(String typeId, String mode, ISelectionContext context) {
Assert.isNotNull(typeId);
Assert.isNotNull(context);
LaunchConfigTypeBinding binding = bindings.get(typeId);
LaunchConfigTypeUnBinding unBinding = unBindings.get(typeId);
ILaunchConfigurationType launchConfigType = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(typeId);
return (launchConfigType != null &&
(mode == null || launchConfigType.supportsMode(mode)) &&
binding != null && binding.validate(mode, context) == EvaluationResult.TRUE &&
(unBinding == null || unBinding.validate(mode, context) != EvaluationResult.TRUE));
}
/**
* Get the registered launch manager delegate for the given launch configuration type and launch mode.
*
* @param typeId The launch configuration type id. Must not be <code>null</code>.
* @param mode The launch mode. Must not be <code>null</code>.
*
* @return The launch manager delegate, or a default delegate if no delegate is registered for the
* given launch configuration type id and launch mode.
*/
public ILaunchManagerDelegate getLaunchManagerDelegate(String typeId, String mode) {
Assert.isNotNull(typeId);
Assert.isNotNull(mode);
LaunchConfigTypeBinding binding = bindings.get(typeId);
if (binding != null) {
String id = binding.getLaunchManagerDelegate(mode);
if (id != null) {
return ExtensionPointManager.getInstance().getLaunchManagerDelegate(id);
}
}
return ExtensionPointManager.getInstance().getDefaultLaunchManagerDelegate();
}
/**
* Get the registered step group id for the given launch configuration type and launch mode.
*
* @param typeId The launch configuration type id. Must not be <code>null</code>.
* @param mode The launch mode. Must not be <code>null</code>.
*
* @return The launch step group id or <code>null</code> if no step group is registered for the
* given launch configuration type id and launch mode.
*/
public String getStepGroupId(String typeId, String mode) {
Assert.isNotNull(typeId);
Assert.isNotNull(mode);
LaunchConfigTypeBinding binding = bindings.get(typeId);
if (binding != null) {
return binding.getStepGroupId(mode);
}
return null;
}
/*
* Load and register all launch configuration type bindings.
*/
private void loadBindingsExtensions() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint point = registry.getExtensionPoint("org.eclipse.tcf.te.launch.core.launchConfigTypeBindings"); //$NON-NLS-1$
if (point != null) {
IExtension[] bindings = point.getExtensions();
Arrays.sort(bindings, new ExtensionPointComparator());
for (IExtension binding : bindings) {
IConfigurationElement[] elements = binding.getConfigurationElements();
for (IConfigurationElement element : elements) {
if (!loadBinding(element))
loadUnBinding(element);
}
}
}
}
/**
* Load a single launch configuration type binding.
*
* @param element The configuration element. Must not be <code>null</code>.
*/
private boolean loadBinding(IConfigurationElement element) {
Assert.isNotNull(element);
if (!element.getName().equals("launchConfigTypeBinding")) { //$NON-NLS-1$
return false;
}
String launchConfigTypeId = element.getAttribute("launchConfigTypeId"); //$NON-NLS-1$
if (!bindings.containsKey(launchConfigTypeId)) {
bindings.put(launchConfigTypeId, new LaunchConfigTypeBinding(launchConfigTypeId));
}
LaunchConfigTypeBinding binding = bindings.get(launchConfigTypeId);
IConfigurationElement[] lmDelegateBindings = element.getChildren("launchManagerDelegate"); //$NON-NLS-1$
for (IConfigurationElement lmDelegateBinding : lmDelegateBindings) {
String id = lmDelegateBinding.getAttribute("id"); //$NON-NLS-1$
String overwrites = lmDelegateBinding.getAttribute("overwrites"); //$NON-NLS-1$
String modes = lmDelegateBinding.getAttribute("modes"); //$NON-NLS-1$
binding.addLaunchManagerDelegate(new OverwritableLaunchBinding(id, overwrites, modes));
}
IConfigurationElement[] stepGroupBindings = element.getChildren("stepGroup"); //$NON-NLS-1$
for (IConfigurationElement stepGroupBinding : stepGroupBindings) {
String id = stepGroupBinding.getAttribute("id"); //$NON-NLS-1$
String overwrites = stepGroupBinding.getAttribute("overwrites"); //$NON-NLS-1$
String modes = stepGroupBinding.getAttribute("modes"); //$NON-NLS-1$
binding.addStepGroup(new OverwritableLaunchBinding(id, overwrites, modes));
}
IConfigurationElement[] enablements = element.getChildren("enablement"); //$NON-NLS-1$
for (IConfigurationElement enablement : enablements) {
Expression expression = null;
try {
expression = ExpressionConverter.getDefault().perform(enablement);
} catch (CoreException e) {
if (Platform.inDebugMode()) {
e.printStackTrace();
}
}
if (expression != null) {
binding.addEnablement(expression);
}
}
return true;
}
/**
* Load a single launch configuration type unbinding.
*
* @param element The configuration element. Must not be <code>null</code>.
*/
private boolean loadUnBinding(IConfigurationElement element) {
Assert.isNotNull(element);
if (!element.getName().equals("launchConfigTypeUnBinding")) { //$NON-NLS-1$
return false;
}
String launchConfigTypeId = element.getAttribute("launchConfigTypeId"); //$NON-NLS-1$
if (!unBindings.containsKey(launchConfigTypeId)) {
unBindings.put(launchConfigTypeId, new LaunchConfigTypeUnBinding(launchConfigTypeId));
}
LaunchConfigTypeUnBinding unBinding = unBindings.get(launchConfigTypeId);
IConfigurationElement[] enablements = element.getChildren("enablement"); //$NON-NLS-1$
for (IConfigurationElement enablement : enablements) {
Expression expression = null;
try {
expression = ExpressionConverter.getDefault().perform(enablement);
} catch (CoreException e) {
if (Platform.inDebugMode()) {
e.printStackTrace();
}
}
if (expression != null) {
unBinding.addEnablement(expression);
}
}
return true;
}
}