blob: 9b4d8dc9f48bd8e87b1ba3245b4dae0e5d7fff20 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
*******************************************************************************/
package org.eclipse.debug.internal.core;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The information associated with a launch configuration handle.
*/
public class LaunchConfigurationInfo {
/**
* Constants for XML element names and attributes
*/
private static final String KEY = "key"; //$NON-NLS-1$
private static final String VALUE = "value"; //$NON-NLS-1$
private static final String SET_ENTRY = "setEntry"; //$NON-NLS-1$
private static final String LAUNCH_CONFIGURATION = "launchConfiguration"; //$NON-NLS-1$
private static final String MAP_ENTRY = "mapEntry"; //$NON-NLS-1$
private static final String LIST_ENTRY = "listEntry"; //$NON-NLS-1$
private static final String SET_ATTRIBUTE = "setAttribute"; //$NON-NLS-1$
private static final String MAP_ATTRIBUTE = "mapAttribute"; //$NON-NLS-1$
private static final String LIST_ATTRIBUTE = "listAttribute"; //$NON-NLS-1$
private static final String BOOLEAN_ATTRIBUTE = "booleanAttribute"; //$NON-NLS-1$
private static final String INT_ATTRIBUTE = "intAttribute"; //$NON-NLS-1$
private static final String STRING_ATTRIBUTE = "stringAttribute"; //$NON-NLS-1$
private static final String TYPE = "type"; //$NON-NLS-1$
private static final String PROTOTYPE = "prototype"; //$NON-NLS-1$
private static final String VISIBLE_ATTRIBUTES = "visibleAttributes"; //$NON-NLS-1$
/**
* This configurations attribute table. Keys are <code>String</code>s and
* values are one of <code>String</code>, <code>Integer</code>,
* <code>Boolean</code>, <code>Set&lt;String&gt;</code>,
* <code>List&lt;String&gt;</code>, or
* <code>Map&lt;String, String&gt;</code>
*/
private TreeMap<String, Object> fAttributes;
/**
* This launch configuration's type
*/
private ILaunchConfigurationType fType;
/**
* Whether this configuration is a prototype
*/
private boolean fIsPrototype = false;
/**
* This launch configuration's prototype (can be <code>null</code> if this launch configuration is already a prototype).
*/
private ILaunchConfiguration fPrototype;
/**
* This prototype's visible attributes (can be <code>null</code> if launch configuration is not a prototype).
*/
private Set<String> fVisibleAttributes;
/**
* Static access to the launch manager.
*/
private static LaunchManager fgLaunchManager = (LaunchManager)DebugPlugin.getDefault().getLaunchManager();
/**
* Whether running on Sun 1.4 VM - see bug 110215
*/
private static boolean fgIsSun14x = false;
static {
String vendor = System.getProperty("java.vm.vendor"); //$NON-NLS-1$
if (vendor.startsWith("Sun Microsystems")) { //$NON-NLS-1$
String version = System.getProperty("java.vm.version"); //$NON-NLS-1$
if (version.startsWith("1.4")) { //$NON-NLS-1$
fgIsSun14x = true;
}
}
}
/**
* Constructs a new empty info
*/
protected LaunchConfigurationInfo() {
setAttributeTable(new TreeMap<>());
}
/**
* Returns this configuration's attribute table.
*
* @return attribute table
*/
private TreeMap<String, Object> getAttributeTable() {
return fAttributes;
}
/**
* Sets this configuration's attribute table.
*
* @param table
* attribute table
*/
private void setAttributeTable(TreeMap<String, Object> table) {
fAttributes = table;
}
/**
* Sets the attributes in this info to those in the given map.
*
* @param map the {@link Map} of attributes to set
*/
protected void setAttributes(Map<String, ?> map) {
if (map == null) {
setAttributeTable(new TreeMap<>());
return;
}
setAttributeTable(new TreeMap<>(map));
}
/**
* Returns the <code>String</code> attribute with the given key or the
* given default value if undefined.
* @param key the attribute name
* @param defaultValue the value to be returned if the given key does not exist in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException
* if the attribute with the given key exists but is not a
* <code>String</code>
*/
protected String getStringAttribute(String key, String defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof String) {
return (String)attr;
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_Attribute__0__is_not_of_type_java_lang_String__1, key), null
)
);
}
return defaultValue;
}
/**
* Returns the <code>int</code> attribute with the given key or the given
* default value if undefined.
* @param key the name of the attribute
* @param defaultValue the default value to return if the key does not appear in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException
* if the attribute with the given key exists but is not an
* <code>int</code>
*/
protected int getIntAttribute(String key, int defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof Integer) {
return ((Integer)attr).intValue();
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_Attribute__0__is_not_of_type_int__2, key), null
)
);
}
return defaultValue;
}
/**
* Returns the <code>boolean</code> attribute with the given key or the
* given default value if undefined.
* @param key the name of the attribute
* @param defaultValue the default value to return if the key does not appear in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException
* if the attribute with the given key exists but is not a
* <code>boolean</code>
*/
protected boolean getBooleanAttribute(String key, boolean defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof Boolean) {
return ((Boolean)attr).booleanValue();
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_Attribute__0__is_not_of_type_boolean__3, key), null
)
);
}
return defaultValue;
}
/**
* Returns the <code>java.util.List</code> attribute with the given key or
* the given default value if undefined.
* @param key the name of the attribute
* @param defaultValue the default value to return if the key does not appear in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException
* if the attribute with the given key exists but is not a
* <code>java.util.List</code>
*/
@SuppressWarnings("unchecked")
protected List<String> getListAttribute(String key, List<String> defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof List) {
return (List<String>) attr;
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_Attribute__0__is_not_of_type_java_util_List__1, key), null
)
);
}
return defaultValue;
}
/**
* Returns the <code>java.util.Set</code> attribute with the given key or
* the given default value if undefined.
*
* @param key the name of the attribute
* @param defaultValue the default value to return if the key does not exist
* in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException if the attribute with the given key exists but is
* not a <code>java.util.Set</code>
*
* @since 3.3
*/
@SuppressWarnings("unchecked")
protected Set<String> getSetAttribute(String key, Set<String> defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof Set) {
return (Set<String>) attr;
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_35, key), null
)
);
}
return defaultValue;
}
/**
* Returns the raw object from the attribute table or <code>null</code> if none.
*
* @param key attribute key
* @return raw attribute value
*
* @since 3.12
*/
protected Object getObjectAttribute(String key) {
return getAttributeTable().get(key);
}
/**
* Returns the <code>java.util.Map</code> attribute with the given key or
* the given default value if undefined.
* @param key the name of the attribute
* @param defaultValue the default value to return if the key does not exist in the attribute table
*
* @return attribute specified by given key or the defaultValue if undefined
* @throws CoreException
* if the attribute with the given key exists but is not a
* <code>java.util.Map</code>
*/
@SuppressWarnings("unchecked")
protected Map<String, String> getMapAttribute(String key, Map<String, String> defaultValue) throws CoreException {
Object attr = getAttributeTable().get(key);
if (attr != null) {
if (attr instanceof Map) {
return (Map<String, String>) attr;
}
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_Attribute__0__is_not_of_type_java_util_Map__1, key), null
)
);
}
return defaultValue;
}
/**
* Sets this configuration's type.
*
* @param type
* launch configuration type
*/
protected void setType(ILaunchConfigurationType type) {
fType = type;
}
/**
* Returns this configuration's type.
*
* @return launch configuration type
*/
protected ILaunchConfigurationType getType() {
return fType;
}
/**
* Sets this configuration's prototype.
*
* @param prototype
* launch configuration prototype
*
* @since 3.12
*/
protected void setPrototype(ILaunchConfiguration prototype) {
fPrototype = prototype;
}
/**
* Returns this configuration's prototype, if it exists.
*
* @return launch configuration prototype (can be <code>null</code>)
*
* @since 3.12
*/
protected ILaunchConfiguration getPrototype() {
return fPrototype;
}
/**
* Returns a copy of this info object
*
* @return copy of this info
*/
protected LaunchConfigurationInfo getCopy() {
LaunchConfigurationInfo copy = new LaunchConfigurationInfo();
copy.setType(getType());
copy.setAttributeTable(getAttributes());
copy.setIsPrototype(isPrototype());
copy.setPrototype(getPrototype());
copy.setVisibleAttributes(getVisibleAttributes());
return copy;
}
/**
* Returns a copy of this info's attribute map.
*
* @return a copy of this info's attribute map
*/
protected TreeMap<String, Object> getAttributes() {
return new TreeMap<>(getAttributeTable());
}
/**
* Sets the given attribute to the given value. Only working copy's should
* use this API.
*
* @param key
* attribute key
* @param value
* attribute value
*/
protected void setAttribute(String key, Object value) {
if (value == null) {
getAttributeTable().remove(key);
setAttributeVisibility(key, false);
} else {
Object attribute = getAttributeTable().put(key, value);
// If attribute is new in the table and the configuration is a
// prototype, then add it to the visible attributes
if (attribute == null && fIsPrototype) {
setAttributeVisibility(key, true);
}
}
}
/**
* Returns the content of this info as XML
*
* @return the content of this info as XML
* @throws CoreException
* if a attribute has been set with a null key
* @throws IOException
* if an exception occurs creating the XML
* @throws ParserConfigurationException
* if an exception occurs creating the XML
* @throws TransformerException
* if an exception occurs creating the XML
*/
@SuppressWarnings("unchecked")
protected String getAsXML() throws CoreException, IOException, ParserConfigurationException, TransformerException {
Document doc = LaunchManager.getDocument();
Element configRootElement = doc.createElement(LAUNCH_CONFIGURATION);
doc.appendChild(configRootElement);
configRootElement.setAttribute(TYPE, getType().getIdentifier());
ILaunchConfiguration prototype = getPrototype();
if (prototype != null) {
configRootElement.setAttribute(PROTOTYPE, prototype.getName());
} else if (isPrototype()) {
configRootElement.setAttribute(VISIBLE_ATTRIBUTES, getVisibleAttributes().stream().collect(Collectors.joining(", "))); //$NON-NLS-1$
}
for (String key : getAttributeTable().keySet()) {
if (key == null) {
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, DebugCoreMessages.LaunchConfigurationInfo_36, null
)
);
}
Object value = getAttributeTable().get(key);
if (value == null) {
continue;
}
Element element = null;
String valueString = null;
if (value instanceof String) {
valueString = (String)value;
element = createKeyValueElement(doc, STRING_ATTRIBUTE, key, valueString);
} else if (value instanceof Integer) {
valueString = ((Integer)value).toString();
element = createKeyValueElement(doc, INT_ATTRIBUTE, key, valueString);
} else if (value instanceof Boolean) {
valueString = ((Boolean)value).toString();
element = createKeyValueElement(doc, BOOLEAN_ATTRIBUTE, key, valueString);
} else if (value instanceof List) {
element = createListElement(doc, LIST_ATTRIBUTE, key, (List<String>) value);
} else if (value instanceof Map) {
element = createMapElement(doc, MAP_ATTRIBUTE, key, (Map<String, String>) value);
} else if(value instanceof Set) {
element = createSetElement(doc, SET_ATTRIBUTE, key, (Set<String>) value);
}
configRootElement.appendChild(element);
}
return LaunchManager.serializeDocument(doc);
}
/**
* Helper method that creates a 'key value' element of the specified type
* with the specified attribute values.
* @param doc the {@link Document}
* @param elementType the {@link Element} type to create
* @param key the {@link Element} key
* @param value the {@link Element} value
* @return the new {@link Element}
*/
protected Element createKeyValueElement(Document doc, String elementType, String key, String value) {
Element element = doc.createElement(elementType);
element.setAttribute(KEY, key);
element.setAttribute(VALUE, value);
return element;
}
/**
* Creates a new <code>Element</code> for the specified
* <code>java.util.List</code>
*
* @param doc the doc to add the element to
* @param elementType the type of the element
* @param listKey the key for the element
* @param list the list to fill the new element with
* @return the new element
*/
protected Element createListElement(Document doc, String elementType, String listKey, List<String> list) {
Element listElement = doc.createElement(elementType);
listElement.setAttribute(KEY, listKey);
for (String value : list) {
Element element = doc.createElement(LIST_ENTRY);
element.setAttribute(VALUE, value);
listElement.appendChild(element);
}
return listElement;
}
/**
* Creates a new <code>Element</code> for the specified
* <code>java.util.Set</code>
*
* @param doc the doc to add the element to
* @param elementType the type of the element
* @param setKey the key for the element
* @param set the set to fill the new element with
* @return the new element
*
* @since 3.3
*/
protected Element createSetElement(Document doc, String elementType, String setKey, Set<String> set) {
Element setElement = doc.createElement(elementType);
setElement.setAttribute(KEY, setKey);
// persist in sorted order
List<String> list = new ArrayList<>(set);
Collections.sort(list);
Element element = null;
for (String str : list) {
element = doc.createElement(SET_ENTRY);
element.setAttribute(VALUE, str);
setElement.appendChild(element);
}
return setElement;
}
/**
* Creates a new <code>Element</code> for the specified
* <code>java.util.Map</code>
*
* @param doc the doc to add the element to
* @param elementType the type of the element
* @param mapKey the key for the element
* @param map the map to fill the new element with
* @return the new element
*
*/
protected Element createMapElement(Document doc, String elementType, String mapKey, Map<String, String> map) {
Element mapElement = doc.createElement(elementType);
mapElement.setAttribute(KEY, mapKey);
// persist in sorted order based on keys
List<String> keys = new ArrayList<>(map.keySet());
Collections.sort(keys);
for (String key : keys) {
String value = map.get(key);
Element element = doc.createElement(MAP_ENTRY);
element.setAttribute(KEY, key);
element.setAttribute(VALUE, value);
mapElement.appendChild(element);
}
return mapElement;
}
/**
* Initializes the mapping of attributes from the XML file
* @param root the root node from the XML document
* @throws CoreException if a problem is encountered
*/
protected void initializeFromXML(Element root) throws CoreException {
initializeFromXML(root, false);
}
/**
* Initializes the mapping of attributes from the XML file
*
* @param root the root node from the XML document
* @param isPrototype if the XML file corresponds to a prototype
* @throws CoreException if a problem is encountered
*
* @since 3.12
*/
protected void initializeFromXML(Element root, boolean isPrototype) throws CoreException {
if (!root.getNodeName().equalsIgnoreCase(LAUNCH_CONFIGURATION)) {
throw getInvalidFormatDebugException();
}
// read type
String id = root.getAttribute(TYPE);
if (id == null) {
throw getInvalidFormatDebugException();
}
ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(id);
if (type == null) {
String message = MessageFormat.format(DebugCoreMessages.LaunchConfigurationInfo_missing_type, id);
throw new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.MISSING_LAUNCH_CONFIGURATION_TYPE, message, null)
);
}
setType(type);
NodeList list = root.getChildNodes();
Node node = null;
Element element = null;
String nodeName = null;
for (int i = 0; i < list.getLength(); ++i) {
node = list.item(i);
short nodeType = node.getNodeType();
if (nodeType == Node.ELEMENT_NODE) {
element = (Element) node;
nodeName = element.getNodeName();
if (nodeName.equalsIgnoreCase(STRING_ATTRIBUTE)) {
setStringAttribute(element);
} else if (nodeName.equalsIgnoreCase(INT_ATTRIBUTE)) {
setIntegerAttribute(element);
} else if (nodeName.equalsIgnoreCase(BOOLEAN_ATTRIBUTE)) {
setBooleanAttribute(element);
} else if (nodeName.equalsIgnoreCase(LIST_ATTRIBUTE)) {
setListAttribute(element);
} else if (nodeName.equalsIgnoreCase(MAP_ATTRIBUTE)) {
setMapAttribute(element);
} else if(nodeName.equalsIgnoreCase(SET_ATTRIBUTE)) {
setSetAttribute(element);
}
}
}
if (isPrototype) {
setIsPrototype(true);
String visibleAttributes = root.getAttribute(VISIBLE_ATTRIBUTES);
if (visibleAttributes != null && visibleAttributes.length() > 0) {
String[] split = visibleAttributes.split(", "); //$NON-NLS-1$
setVisibleAttributes(new HashSet<>(Arrays.asList(split)));
}
} else {
setIsPrototype(false);
String prototype = root.getAttribute(PROTOTYPE);
if (prototype != null && prototype.length() > 0) {
ILaunchConfiguration[] launchConfigurations = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(ILaunchConfiguration.PROTOTYPE);
for (ILaunchConfiguration iLaunchConfiguration : launchConfigurations) {
if (prototype.equals(iLaunchConfiguration.getName())) {
setPrototype(iLaunchConfiguration);
break;
}
}
}
}
}
/**
* Loads a <code>String</code> from the specified element into the local attribute mapping
* @param element the element to load from
* @throws CoreException if a problem is encountered
*/
protected void setStringAttribute(Element element) throws CoreException {
setAttribute(getKeyAttribute(element), getValueAttribute(element));
}
/**
* Loads an <code>Integer</code> from the specified element into the local attribute mapping
* @param element the element to load from
* @throws CoreException if a problem is encountered
*/
protected void setIntegerAttribute(Element element) throws CoreException {
setAttribute(getKeyAttribute(element), Integer.valueOf(getValueAttribute(element)));
}
/**
* Loads a <code>Boolean</code> from the specified element into the local attribute mapping
* @param element the element to load from
* @throws CoreException if a problem is encountered
*/
protected void setBooleanAttribute(Element element) throws CoreException {
setAttribute(getKeyAttribute(element), Boolean.valueOf(getValueAttribute(element)));
}
/**
* Reads a <code>List</code> attribute from the specified XML node and
* loads it into the mapping of attributes
*
* @param element the element to read the list attribute from
* @throws CoreException if the element has an invalid format
*/
protected void setListAttribute(Element element) throws CoreException {
String listKey = element.getAttribute(KEY);
NodeList nodeList = element.getChildNodes();
int entryCount = nodeList.getLength();
List<String> list = new ArrayList<>(entryCount);
Node node = null;
Element selement = null;
for (int i = 0; i < entryCount; i++) {
node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
selement = (Element) node;
if (!selement.getNodeName().equalsIgnoreCase(LIST_ENTRY)) {
throw getInvalidFormatDebugException();
}
list.add(getValueAttribute(selement));
}
}
setAttribute(listKey, list);
}
/**
* Reads a <code>Set</code> attribute from the specified XML node and
* loads it into the mapping of attributes
*
* @param element the element to read the set attribute from
* @throws CoreException if the element has an invalid format
*
* @since 3.3
*/
protected void setSetAttribute(Element element) throws CoreException {
String setKey = element.getAttribute(KEY);
NodeList nodeList = element.getChildNodes();
int entryCount = nodeList.getLength();
Set<String> set = new HashSet<>(entryCount);
Node node = null;
Element selement = null;
for(int i = 0; i < entryCount; i++) {
node = nodeList.item(i);
if(node.getNodeType() == Node.ELEMENT_NODE) {
selement = (Element)node;
if(!selement.getNodeName().equalsIgnoreCase(SET_ENTRY)) {
throw getInvalidFormatDebugException();
}
set.add(getValueAttribute(selement));
}
}
setAttribute(setKey, set);
}
/**
* Reads a <code>Map</code> attribute from the specified XML node and
* loads it into the mapping of attributes
*
* @param element the element to read the map attribute from
* @throws CoreException if the element has an invalid format
*/
protected void setMapAttribute(Element element) throws CoreException {
String mapKey = element.getAttribute(KEY);
NodeList nodeList = element.getChildNodes();
int entryCount = nodeList.getLength();
Map<String, String> map = new HashMap<>(entryCount);
Node node = null;
Element selement = null;
for (int i = 0; i < entryCount; i++) {
node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
selement = (Element) node;
if (!selement.getNodeName().equalsIgnoreCase(MAP_ENTRY)) {
throw getInvalidFormatDebugException();
}
map.put(getKeyAttribute(selement), getValueAttribute(selement));
}
}
setAttribute(mapKey, map);
}
/**
* Returns the <code>String</code> representation of the 'key' attribute from the specified element
* @param element the element to read from
* @return the value
* @throws CoreException if a problem is encountered
*/
protected String getKeyAttribute(Element element) throws CoreException {
String key = element.getAttribute(KEY);
if (key == null) {
throw getInvalidFormatDebugException();
}
return key;
}
/**
* Returns the <code>String</code> representation of the 'value' attribute from the specified element
* @param element the element to read from
* @return the value
* @throws CoreException if a problem is encountered
*/
protected String getValueAttribute(Element element) throws CoreException {
String value = element.getAttribute(VALUE);
if (value == null) {
throw getInvalidFormatDebugException();
}
return value;
}
/**
* Returns an invalid format exception for reuse
* @return an invalid format exception
*/
protected DebugException getInvalidFormatDebugException() {
return
new DebugException(
new Status(
IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, DebugCoreMessages.LaunchConfigurationInfo_Invalid_launch_configuration_XML__10, null
)
);
}
/**
* Two <code>LaunchConfigurationInfo</code> objects are equal if and only
* if they have the same type and they have the same set of attributes with
* the same values.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object obj) {
// Make sure it's a LaunchConfigurationInfo object
if (!(obj instanceof LaunchConfigurationInfo)) {
return false;
}
// Make sure the types are the same
LaunchConfigurationInfo other = (LaunchConfigurationInfo) obj;
if (!fType.getIdentifier().equals(other.getType().getIdentifier())) {
return false;
}
// In case of a prototype, make sure the visible attributes are the same
if (isPrototype() != other.isPrototype()) {
return false;
} else if (isPrototype() && !getVisibleAttributes().equals(other.getVisibleAttributes())) {
return false;
}
// Make sure the attributes are the same
return compareAttributes(fAttributes, other.getAttributeTable());
}
/**
* Returns whether the two attribute maps are equal, consulting registered
* comparator extensions.
*
* @param map1 attribute map
* @param map2 attribute map
* @return whether the two attribute maps are equal
*/
protected boolean compareAttributes(TreeMap<String, Object> map1, TreeMap<String, Object> map2) {
if (map1.size() == map2.size()) {
Iterator<String> attributes = map1.keySet().iterator();
while (attributes.hasNext()) {
String key = attributes.next();
Object attr1 = map1.get(key);
Object attr2 = map2.get(key);
if (!compareAttribute(key, attr1, attr2)) {
return false;
}
}
return true;
}
return false;
}
/**
* Returns whether the two attributes are equal, considering comparator extensions.
*
* @param key attribute key
* @param attr1 attribute value
* @param attr2 attribute value to compare to, possibly <code>null</code>
* @return whether equivalent
*
* @since 3.12
*/
protected static boolean compareAttribute(String key, Object attr1, Object attr2) {
if (attr2 == null) {
return false;
}
Comparator<Object> comp = fgLaunchManager.getComparator(key);
if (comp == null) {
String strAttr1 = null;
String strAttr2 = null;
if (fgIsSun14x) {
if(attr2 instanceof String & attr1 instanceof String) {
// this is a hack for bug 110215, on SUN 1.4.x, \r
// is stripped off when the stream is written to the
// DOM
// this is not the case for 1.5.x, so to be safe we
// are stripping \r off all strings before we
// compare for equality
strAttr1 = ((String)attr1).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$
strAttr2 = ((String)attr2).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$
if (!strAttr1.equals(strAttr2)) {
return false;
}
}
}
if (strAttr1 == null && strAttr2 == null && !attr1.equals(attr2)) {
return false;
}
} else {
if (comp.compare(attr1, attr2) != 0) {
return false;
}
}
return true;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return fType.hashCode() + fAttributes.size();
}
/**
* Returns if the attribute map contains the specified key
* @param attributeName the name of the attribute to check for
* @return true if the attribute map contains the specified key, false otherwise
*
* @since 3.4.0
*/
protected boolean hasAttribute(String attributeName) {
return fAttributes.containsKey(attributeName);
}
/**
* Removes the specified attribute from the mapping and returns
* its value, or <code>null</code> if none. Does nothing
* if the attribute name is <code>null</code>
* @param attributeName the name of the attribute to remove
* @return attribute value or <code>null</code>
*
* @since 3.4.0
*/
protected Object removeAttribute(String attributeName) {
if(attributeName != null) {
return fAttributes.remove(attributeName);
}
return null;
}
/**
* Sets whether this info is a prototype.
*
* @param isPrototype
*
* @since 3.12
*/
protected void setIsPrototype(boolean isPrototype) {
fIsPrototype = isPrototype;
}
/**
* Returns whether this info is a prototype.
*
* @return whether a prototype
*
* @since 3.12
*/
protected boolean isPrototype() {
return fIsPrototype;
}
/**
* Get the visible attributes of this prototype (return <code>null</code> if
* the launch configuration is not a prototype).
*
* @return the visible attributes of this prototype (return
* <code>null</code> if the launch configuration is not a
* prototype).
*
* @since 3.12
*/
protected Set<String> getVisibleAttributes() {
if (!isPrototype()) {
return null;
} else if (fVisibleAttributes == null) {
initializeVisibleAttributes();
}
return fVisibleAttributes;
}
/**
* Initialize the visible attributes of this launch configuration. All
* attributes are visible by default.
*
* @since 3.12
*/
private void initializeVisibleAttributes() {
fVisibleAttributes = new HashSet<>(getAttributeTable().keySet());
}
/**
* Set the visible attributes of this prototype. Do not call this method on
* a launch configuration that is not a prototype.
*
* @param visibleAttributes the visible attributes
*
* @since 3.12
*/
protected void setVisibleAttributes(Set<String> visibleAttributes) {
if (visibleAttributes != null) {
fVisibleAttributes = new HashSet<>(visibleAttributes);
}
}
/**
* Set visibility of the given attribute. Do not call this method on a
* launch configuration that is not a prototype.
*
* @param attribute the given attribute
* @param visible the visibility
*
* @since 3.12
*/
protected void setAttributeVisibility(String attribute, boolean visible) {
if (fVisibleAttributes != null) {
if (visible) {
fVisibleAttributes.add(attribute);
} else {
fVisibleAttributes.remove(attribute);
}
}
}
}