Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Honnen2020-09-30 13:27:12 +0000
committerJulian Honnen2020-10-02 07:58:02 +0000
commitd4a49972c4610da37f102c8755a54e88d73f86b5 (patch)
treed0ebe2e2a3402c9aa6dd9b9feb66725906ec0eea
parentfab2abee988159a7e1195c976cd4af6475f4ef39 (diff)
downloadeclipse.pde.ui-d4a49972c4610da37f102c8755a54e88d73f86b5.tar.gz
eclipse.pde.ui-d4a49972c4610da37f102c8755a54e88d73f86b5.tar.xz
eclipse.pde.ui-d4a49972c4610da37f102c8755a54e88d73f86b5.zip
Bug 566642 - Copied update.configurator code to parse platform.xml
Removed code that is unnecessary for PDE's usecase of reading features. Adapted code that relied on the lifecycle of ConfigurationActivator. Changed package name to avoid conflicts. Change-Id: I9271c4da58ddbfca6d37a014342ad20aabdf791d Signed-off-by: Julian Honnen <julian.honnen@vector.com>
-rw-r--r--ui/org.eclipse.pde.core/.externalToolBuilders/org.eclipse.pde.core localbuild.xml [Builder].launch28
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Configuration.java213
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/ConfigurationParser.java417
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureEntry.java116
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureParser.java147
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/IConfigurationConstants.java77
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Messages.java65
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/PlatformConfiguration.java200
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SiteEntry.java416
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SitePolicy.java53
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Utils.java231
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/VersionedIdentifier.java67
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/XMLPrintHandler.java141
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/messages.properties57
14 files changed, 2214 insertions, 14 deletions
diff --git a/ui/org.eclipse.pde.core/.externalToolBuilders/org.eclipse.pde.core localbuild.xml [Builder].launch b/ui/org.eclipse.pde.core/.externalToolBuilders/org.eclipse.pde.core localbuild.xml [Builder].launch
index 40e01706cb..67770ef9f7 100644
--- a/ui/org.eclipse.pde.core/.externalToolBuilders/org.eclipse.pde.core localbuild.xml [Builder].launch
+++ b/ui/org.eclipse.pde.core/.externalToolBuilders/org.eclipse.pde.core localbuild.xml [Builder].launch
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
-<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="workspaceBinaries,"/>
-<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="workspaceBinaries,"/>
-<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="workspaceBinaries,"/>
-<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
-<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
-<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;resources&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/ant_tasks&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;/resources&gt;}"/>
-<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.pde.core"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;resources&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/.externalToolBuilders&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/binary&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/localbuild.xml&quot; type=&quot;1&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/src_ant&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;/resources&gt;}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/org.eclipse.pde.core/localbuild.xml}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
-<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
+ <stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="workspaceBinaries,"/>
+ <stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="workspaceBinaries,"/>
+ <stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="workspaceBinaries,"/>
+ <booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
+ <booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
+ <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;resources&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/ant_tasks&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;/resources&gt;}"/>
+ <booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
+ <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+ <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
+ <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.pde.core"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;resources&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/.externalToolBuilders&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/binary&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/localbuild.xml&quot; type=&quot;1&quot;/&gt;&#13;&#10;&lt;item path=&quot;/org.eclipse.pde.core/src_ant&quot; type=&quot;2&quot;/&gt;&#13;&#10;&lt;/resources&gt;}"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/org.eclipse.pde.core/localbuild.xml}"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
+ <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Configuration.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Configuration.java
new file mode 100644
index 0000000000..68ce85026b
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Configuration.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ * James D Miles (IBM Corp.) - bug 176250, Configurator needs to handle more platform urls
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+class Configuration implements IConfigurationConstants {
+
+ private HashMap<String, SiteEntry> sites = new HashMap<>();
+ private HashMap<String, URL> platformURLs = new HashMap<>();
+ private Date date;
+ private long lastModified; // needed to account for file system limitations
+ private URL url;
+ private boolean transientConfig;
+ private boolean isDirty;
+ private Configuration linkedConfig; // shared configuration
+ private URL associatedInstallURL = Utils.getInstallURL();
+
+ public Configuration() {
+ this(new Date());
+ // the config is created now or out of a platform.xml without a date
+ isDirty = true;
+ }
+
+ public Configuration(Date date) {
+ this.date = date;
+ }
+
+ public void setURL(URL url) {
+ this.url = url;
+ }
+
+ public URL getURL() {
+ return url;
+ }
+
+ public void setLinkedConfig(Configuration linkedConfig) {
+ this.linkedConfig = linkedConfig;
+ // make all the sites read-only
+ for (SiteEntry linkedSite : linkedConfig.getSites()) {
+ linkedSite.setUpdateable(false);
+ }
+ }
+
+ public Configuration getLinkedConfig() {
+ return linkedConfig;
+ }
+
+ /**
+ * @return true if the config needs to be saved
+ */
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ public void setDirty(boolean dirty) {
+ isDirty = dirty;
+ }
+
+ public void addSiteEntry(String url, SiteEntry site) {
+ url = Utils.canonicalizeURL(url);
+ // only add the same site once
+ if (sites.get(url) == null && (linkedConfig == null || linkedConfig.sites.get(url) == null)) {
+ site.setConfig(this);
+ sites.put(url, site);
+ if (url.startsWith("platform:")) {//$NON-NLS-1$
+ URL pURL;
+ try {
+ URL relSite = null;
+ if (url != null && url.startsWith("platform:/config")) {
+ // url for location of configuration is relative to
+ // platform.xml
+ URL config_loc = getURL();
+ relSite = new URL(config_loc, "..");
+ } else {
+ relSite = getInstallURL();
+ }
+
+ pURL = new URL(url);
+ URL rURL = PlatformConfiguration.resolvePlatformURL(pURL, relSite);
+ String resolvedURL = rURL.toExternalForm();
+ platformURLs.put(resolvedURL, pURL);
+ } catch (IOException e) {
+ // can't resolve so can't have look up.
+ }
+ }
+ }
+ }
+
+ public void removeSiteEntry(String url) {
+ url = Utils.canonicalizeURL(url);
+ sites.remove(url);
+ if (url.startsWith("platform:")) { //$NON-NLS-1$
+ URL pURL;
+ try {
+ URL relSite = null;
+ if (url != null && url.startsWith("platform:/config")) {
+ // url for location of configuration is relative to
+ // platform.xml
+ URL config_loc = getURL();
+ relSite = new URL(config_loc, "..");
+ } else {
+ relSite = getInstallURL();
+ }
+
+ pURL = new URL(url);
+ URL rURL = PlatformConfiguration.resolvePlatformURL(pURL, relSite);
+ String resolvedURL = rURL.toExternalForm();
+ platformURLs.remove(resolvedURL);
+ } catch (IOException e) {
+ // can't resolve so can't have look up.
+ }
+ }
+ }
+
+ public SiteEntry getSiteEntry(String url) {
+ url = Utils.canonicalizeURL(url);
+ SiteEntry site = sites.get(url);
+ if (site == null && linkedConfig != null) {
+ site = linkedConfig.getSiteEntry(url);
+ }
+ return site;
+ }
+
+ public SiteEntry[] getSites() {
+ if (linkedConfig == null) {
+ return sites.values().toArray(new SiteEntry[sites.size()]);
+ }
+ ArrayList<SiteEntry> combinedSites = new ArrayList<>(sites.values());
+ combinedSites.addAll(linkedConfig.sites.values());
+ return combinedSites.toArray(new SiteEntry[combinedSites.size()]);
+ }
+
+ public boolean isTransient() {
+ return transientConfig;
+ }
+
+ public void setTransient(boolean isTransient) {
+ this.transientConfig = isTransient;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public boolean unconfigureFeatureEntry(FeatureEntry feature) {
+ for (SiteEntry site : getSites()) {
+ if (site.unconfigureFeatureEntry(feature)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void setLastModified(long lastModified) {
+ this.lastModified = lastModified;
+ }
+
+ public long lastModified() {
+ return (lastModified != 0) ? lastModified : date.getTime();
+ }
+
+ /**
+ * Returns the url as a platform:/ url, if possible, else leaves it
+ * unchanged
+ *
+ * @param url
+ * @return
+ */
+ public URL asPlatformURL(URL url) {
+ try {
+ if (url.getProtocol().equals("file")) {//$NON-NLS-1$
+ String rUrl = url.toExternalForm();
+ URL pUrl = platformURLs.get(rUrl);
+ if (pUrl == null) {
+ return url;
+ }
+ return pUrl;
+ }
+ return url;
+ } catch (Exception e) {
+ return url;
+ }
+ }
+
+ public URL getInstallURL() {
+ return associatedInstallURL;
+ }
+
+ public void setInstallLocation(URL installURL) {
+ associatedInstallURL = installURL;
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/ConfigurationParser.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/ConfigurationParser.java
new file mode 100644
index 0000000000..cc7f5017a9
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/ConfigurationParser.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.StringTokenizer;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.osgi.util.NLS;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * parse the default site.xml
+ */
+
+class ConfigurationParser extends DefaultHandler implements IConfigurationConstants {
+
+ private static final String URL_PROPERTY = "org.eclipse.update.resolution_url"; //$NON-NLS-1$
+ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+ private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ private SAXParser parser;
+
+ private URL currentSiteURL;
+ private Configuration config;
+ private URL configURL;
+ private InputStream input;
+ private URL installLocation;
+
+ /**
+ * Constructor for ConfigurationParser
+ */
+ public ConfigurationParser() throws InvocationTargetException {
+
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ Utils.log(Utils.newStatus("ConfigurationParser", e)); //$NON-NLS-1$
+ throw new InvocationTargetException(e);
+ } catch (SAXException e) {
+ Utils.log(Utils.newStatus("ConfigurationParser", e)); //$NON-NLS-1$
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ public Configuration parse(URL url, URL installLocation) throws Exception {
+
+ // DEBUG:
+ //$NON-NLS-1$
+ long lastModified = 0;
+ try {
+ configURL = url;
+ this.installLocation = installLocation;
+ if ("file".equals(url.getProtocol())) { //$NON-NLS-1$
+ File inputFile = URIUtil.toFile(URIUtil.toURI(url));
+ if (!inputFile.exists() || !inputFile.canRead()) {
+ return null;
+ }
+ lastModified = inputFile.lastModified();
+ input = new FileInputStream(inputFile);
+ } else {
+ input = url.openStream();
+ }
+ parser.parse(new InputSource(input), this);
+ return config;
+ } catch (Exception e) {
+ Utils.log(Utils.newStatus("ConfigurationParser.parse() error:", e)); //$NON-NLS-1$
+ throw e;
+ } finally {
+ if (config != null) {
+ config.setLastModified(lastModified);
+ }
+ try {
+ if (input != null) {
+ input.close();
+ input = null;
+ }
+ } catch (IOException e1) {
+ Utils.log(e1.getLocalizedMessage());
+ }
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ // DEBUG:
+ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ try {
+
+ String tag = localName.trim();
+
+ if (tag.equalsIgnoreCase(CFG)) {
+ processConfig(attributes);
+ return;
+ }
+
+ if (tag.equalsIgnoreCase(CFG_SITE)) {
+ processSite(attributes);
+ return;
+ }
+
+ if (tag.equalsIgnoreCase(CFG_FEATURE_ENTRY)) {
+ processFeature(attributes);
+ return;
+ }
+
+ } catch (MalformedURLException e) {
+ throw new SAXException(
+ NLS.bind(Messages.InstalledSiteParser_UnableToCreateURL, (new String[] { e.getMessage() })), e);
+ } catch (CoreException e) {
+ throw new SAXException(
+ NLS.bind(Messages.InstalledSiteParser_ErrorParsingFile, (new String[] { e.toString() })), e);
+ }
+ }
+
+ /**
+ * process the Site info
+ */
+ private void processSite(Attributes attributes) throws MalformedURLException, CoreException {
+
+ if (config == null) {
+ return;
+ }
+
+ // reset current site
+ currentSiteURL = null;
+
+ String urlString = attributes.getValue(CFG_URL);
+ if (urlString == null) {
+ return;
+ }
+
+ URL url = null;
+ try {
+ url = new URL(urlString);
+ } catch (MalformedURLException e) {
+ // try relative to install url
+ url = new URL(PlatformConfiguration.getInstallURL(), urlString);
+ return;
+ }
+
+ // when reading externalized URLs, need to convert them to absolute form
+ String property = System.getProperty(URL_PROPERTY, EMPTY_STRING);
+ URL root = property == null || property.length() == 0 ? Utils.getInstallURL() : new URL(property);
+ url = Utils.makeAbsolute(root, url);
+
+ if (!isValidSite(url)) {
+ return;
+ }
+
+ // use this new site
+ currentSiteURL = url;
+
+ int policyType;
+ String[] policyList = null;
+ String typeString = attributes.getValue(CFG_POLICY);
+ if (typeString == null) {
+ policyType = PlatformConfiguration.getDefaultPolicy();
+ policyList = DEFAULT_POLICY_LIST;
+ } else {
+ int i;
+ for (i = 0; i < CFG_POLICY_TYPE.length; i++) {
+ if (typeString.equals(CFG_POLICY_TYPE[i])) {
+ break;
+ }
+ }
+ if (i >= CFG_POLICY_TYPE.length) {
+ policyType = PlatformConfiguration.getDefaultPolicy();
+ policyList = DEFAULT_POLICY_LIST;
+ } else {
+ policyType = i;
+ String pluginList = attributes.getValue(CFG_LIST);
+ if (pluginList != null) {
+ StringTokenizer st = new StringTokenizer(pluginList, ","); //$NON-NLS-1$
+ policyList = new String[st.countTokens()];
+ for (i = 0; i < policyList.length; i++) {
+ policyList[i] = st.nextToken();
+ }
+ }
+ }
+ }
+
+ SitePolicy sp = new SitePolicy(policyType, policyList);
+ SiteEntry site = new SiteEntry(url, sp);
+
+ String flag = attributes.getValue(CFG_UPDATEABLE);
+ if (flag != null) {
+ if (flag.equals("true")) {
+ site.setUpdateable(true);
+ } else {
+ site.setUpdateable(false);
+ }
+ }
+
+ flag = attributes.getValue(CFG_ENABLED);
+ if (flag != null && flag.equals("false")) {
+ site.setEnabled(false);
+ } else {
+ site.setEnabled(true);
+ }
+
+ String linkname = attributes.getValue(CFG_LINK_FILE);
+ if (linkname != null && !linkname.isEmpty()) {
+ site.setLinkFileName(linkname.replace('/', File.separatorChar));
+ }
+
+ // DEBUG:
+ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ currentSiteURL = site.getURL();
+ config.addSiteEntry(currentSiteURL.toExternalForm(), site);
+ }
+
+ /**
+ * process the DefaultFeature info
+ */
+ private void processFeature(Attributes attributes) throws MalformedURLException, CoreException {
+
+ if (currentSiteURL == null)
+ {
+ return; // the site was not correct
+ }
+
+ String id = attributes.getValue(CFG_FEATURE_ENTRY_ID);
+ if (id == null) {
+ return;
+ }
+ String version = attributes.getValue(CFG_FEATURE_ENTRY_VERSION);
+ String pluginVersion = attributes.getValue(CFG_FEATURE_ENTRY_PLUGIN_VERSION);
+ if (pluginVersion == null || pluginVersion.trim().length() == 0) {
+ pluginVersion = version;
+ }
+ String pluginIdentifier = attributes.getValue(CFG_FEATURE_ENTRY_PLUGIN_IDENTIFIER);
+ if (pluginIdentifier != null && pluginIdentifier.trim().length() == 0) {
+ pluginIdentifier = null;
+ }
+ String application = attributes.getValue(CFG_FEATURE_ENTRY_APPLICATION);
+
+ // get install locations
+ String locations = attributes.getValue(CFG_FEATURE_ENTRY_ROOT);
+ StringTokenizer st = locations != null ? new StringTokenizer(locations, ",") : new StringTokenizer(""); //$NON-NLS-1$ //$NON-NLS-2$
+ ArrayList<URL> rootList = new ArrayList<>(st.countTokens());
+ while (st.hasMoreTokens()) {
+ try {
+ URL rootEntry = new URL(st.nextToken());
+ rootList.add(rootEntry);
+ } catch (MalformedURLException e) {
+ // skip bad entries ...
+ }
+ }
+ URL[] roots = rootList.toArray(new URL[rootList.size()]);
+
+ // get primary flag
+ boolean primary = false;
+ String flag = attributes.getValue(CFG_FEATURE_ENTRY_PRIMARY);
+ if (flag != null) {
+ if (flag.equals("true")) {
+ primary = true;
+ }
+ }
+
+ FeatureEntry featureEntry = new FeatureEntry(id, version, pluginIdentifier, pluginVersion, primary, application,
+ roots);
+
+ // set the url
+ String url = attributes.getValue(CFG_URL);
+ if (url != null && url.trim().length() > 0) {
+ featureEntry.setURL(url);
+ }
+
+ SiteEntry site = config.getSiteEntry(currentSiteURL.toExternalForm());
+ site.addFeatureEntry(featureEntry);
+
+ // configured ?
+ // String configuredString = attributes.getValue("configured");
+ // //$NON-NLS-1$
+ // boolean configured = configuredString.trim().equalsIgnoreCase("true")
+ // ? true : false; //$NON-NLS-1$
+ }
+
+ /**
+ * process the Config info
+ */
+ private void processConfig(Attributes attributes) {
+ String date = attributes.getValue(CFG_DATE);
+ if (date == null || date.trim().length() == 0) {
+ config = new Configuration(); // constructed with current date
+ } else {
+ long time = 0;
+ try {
+ time = Long.parseLong(date);
+ config = new Configuration(new Date(time));
+ } catch (NumberFormatException e1) {
+ time = new Date().getTime();
+ Utils.log(NLS.bind(Messages.InstalledSiteParser_date, (new String[] { date })));
+ config = new Configuration(); // constructed with current date
+ }
+ }
+
+ config.setURL(configURL);
+ config.setInstallLocation(installLocation);
+
+ try {
+ String sharedURLString = attributes.getValue(CFG_SHARED_URL);
+ if (sharedURLString != null) {
+ URL sharedURL = Utils.makeAbsolute(installLocation, new URL(sharedURLString));
+ if (!sharedURL.equals(configURL)) {
+ /*
+ * Bug 490591: Avoid StackOverflowError: The linked
+ * installations URLs are relative and intended to be
+ * dereferenced against the shared installation location.
+ * But it's possible our installLocation is not the real
+ * shared installation location.
+ */
+ ConfigurationParser parser = new ConfigurationParser();
+ Configuration sharedConfig = parser.parse(sharedURL, installLocation);
+ if (sharedConfig == null) {
+ throw new Exception("Failed to parse shared configuration: " + sharedURL);
+ }
+ config.setLinkedConfig(sharedConfig);
+ }
+ }
+ } catch (Exception e) {
+ // could not load from shared install
+ Utils.log(Utils.newStatus(Messages.ConfigurationParser_cannotLoadSharedInstall, e));
+ }
+
+ String flag = attributes.getValue(CFG_TRANSIENT);
+ if (flag != null) {
+ config.setTransient(flag.equals("true")); //$NON-NLS-1$
+ }
+
+ // DEBUG:
+ //$NON-NLS-1$
+ }
+
+ private boolean isValidSite(URL url) {
+ URL resolvedURL = url;
+ if (url.getProtocol().equals("platform")) { //$NON-NLS-1$
+ try {
+ // resolve the config location relative to the configURL
+ if (url.getPath().startsWith("/config")) {
+ URL config_loc = new URL(configURL, "..");
+ resolvedURL = PlatformConfiguration.resolvePlatformURL(url, config_loc); // 19536
+ }
+ else {
+ resolvedURL = PlatformConfiguration.resolvePlatformURL(url, config.getInstallURL()); // 19536
+ }
+ } catch (IOException e) {
+ // will use the baseline URL ...
+ }
+ }
+
+ if (!PlatformConfiguration.supportsDetection(resolvedURL, config.getInstallURL())) {
+ return false;
+ }
+
+ File siteRoot = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ if (!siteRoot.exists()) {
+ //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ super.endElement(uri, localName, qName);
+
+ // DEBUG:
+ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ try {
+
+ String tag = localName.trim();
+
+ if (tag.equalsIgnoreCase(CFG)) {
+ // This is a bit of a hack.
+ // When no features were added to the site, but the site is
+ // initialized from platform.xml
+ // we need to set the feature set to empty, so we don't try to
+ // detect them.
+ for (SiteEntry site : config.getSites()) {
+ site.initialized();
+ }
+ return;
+ }
+ } catch (Exception e) {
+ // silent ignore
+ }
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureEntry.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureEntry.java
new file mode 100644
index 0000000000..bc0fc2e3b2
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureEntry.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.net.URL;
+
+/**
+ *
+ * Feature information
+ */
+class FeatureEntry implements IConfigurationConstants {
+ private String id;
+ private String version;
+ private String pluginVersion;
+ private String application;
+ private URL[] root;
+ private boolean primary;
+ private String pluginIdentifier;
+ private String url;
+ private SiteEntry site;
+
+ public FeatureEntry(String id, String version, String pluginIdentifier, String pluginVersion, boolean primary,
+ String application, URL[] root) {
+ if (id == null) {
+ throw new IllegalArgumentException();
+ }
+ this.id = id;
+ this.version = version;
+ this.pluginVersion = pluginVersion;
+ this.pluginIdentifier = pluginIdentifier;
+ this.primary = primary;
+ this.application = application;
+ this.root = (root == null ? new URL[0] : root);
+ }
+
+ public FeatureEntry(String id, String version, String pluginVersion, boolean primary, String application,
+ URL[] root) {
+ this(id, version, id, pluginVersion, primary, application, root);
+ }
+
+ public void setSite(SiteEntry site) {
+ this.site = site;
+ }
+
+ public SiteEntry getSite() {
+ return this.site;
+ }
+
+ /**
+ * Sets the url string (relative to the site url)
+ *
+ * @param url
+ */
+ public void setURL(String url) {
+ this.url = url;
+ }
+
+ /**
+ * @return the feature url (relative to the site):
+ * features/org.eclipse.platform/
+ */
+ public String getURL() {
+ // if (url == null)
+ // url = FEATURES + "/" + id + "_" + version + "/";
+ return url;
+ }
+
+ public String getFeatureIdentifier() {
+ return id;
+ }
+
+ public String getFeatureVersion() {
+ return version;
+ }
+
+ public String getFeaturePluginVersion() {
+ return pluginVersion != null && pluginVersion.length() > 0 ? pluginVersion : null;
+ }
+
+ public String getFeaturePluginIdentifier() {
+ // if no plugin is specified, use the feature id
+ return pluginIdentifier != null && pluginIdentifier.length() > 0 ? pluginIdentifier : id;
+ }
+
+ public String getFeatureApplication() {
+ return application;
+ }
+
+ public URL[] getFeatureRootURLs() {
+ return root;
+ }
+
+ public boolean canBePrimary() {
+ return primary;
+ }
+
+ public String getApplication() {
+ return application;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureParser.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureParser.java
new file mode 100644
index 0000000000..b63504c8fe
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/FeatureParser.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.eclipse.osgi.util.NLS;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Default feature parser. Parses the feature manifest file as defined by the
+ * platform.
+ *
+ * @since 3.0
+ */
+class FeatureParser extends DefaultHandler {
+
+ private SAXParser parser;
+ private FeatureEntry feature;
+ private URL url;
+
+ private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+
+ /**
+ * Constructs a feature parser.
+ */
+ public FeatureParser() {
+ super();
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ System.out.println(e);
+ } catch (SAXException e) {
+ System.out.println(e);
+ }
+ }
+
+ /**
+ * Parses the specified url and constructs a feature
+ */
+ public FeatureEntry parse(URL featureURL) {
+ feature = null;
+ InputStream in = null;
+ try {
+ this.url = featureURL;
+ in = featureURL.openStream();
+ parser.parse(new InputSource(in), this);
+ } catch (SAXException e) {
+ } catch (IOException e) {
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e1) {
+ Utils.log(e1.getLocalizedMessage());
+ }
+ }
+ }
+ return feature;
+ }
+
+ /**
+ * Handle start of element tags
+ *
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ * @since 2.0
+ */
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ if ("feature".equals(localName)) { //$NON-NLS-1$
+ processFeature(attributes);
+ // stop parsing now
+ throw new SAXException(""); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * Process feature information
+ */
+ private void processFeature(Attributes attributes) {
+
+ // identifier and version
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+
+ if (id == null || id.trim().isEmpty() || ver == null || ver.trim().isEmpty()) {
+ System.out.println(NLS.bind(Messages.FeatureParser_IdOrVersionInvalid, (new String[] { id, ver })));
+ } else {
+ // String label = attributes.getValue("label"); //$NON-NLS-1$
+ // String provider = attributes.getValue("provider-name");
+ // //$NON-NLS-1$
+ // String imageURL = attributes.getValue("image"); //$NON-NLS-1$
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ if (!Utils.isValidEnvironment(os, ws, arch, nl))
+ {
+ return;
+ // String exclusive = attributes.getValue("exclusive");
+ // //$NON-NLS-1$
+ // String affinity = attributes.getValue("colocation-affinity");
+ // //$NON-NLS-1$
+ }
+
+ String primary = attributes.getValue("primary"); //$NON-NLS-1$
+ boolean isPrimary = "true".equals(primary); //$NON-NLS-1$
+ String application = attributes.getValue("application"); //$NON-NLS-1$
+ String plugin = attributes.getValue("plugin"); //$NON-NLS-1$
+
+ // TODO rootURLs
+ feature = new FeatureEntry(id, ver, plugin, "", isPrimary, application, null); //$NON-NLS-1$
+ if ("file".equals(url.getProtocol())) { //$NON-NLS-1$
+ File f = new File(url.getFile().replace('/', File.separatorChar));
+ feature.setURL("features" + "/" + f.getParentFile().getName() + "/");// + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ // f.getName());
+ } else {
+ // externalized URLs might be in relative form, ensure they are
+ // absolute
+ feature.setURL(Utils.makeAbsolute(Utils.getInstallURL(), url).toExternalForm());
+ }
+ }
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/IConfigurationConstants.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/IConfigurationConstants.java
new file mode 100644
index 0000000000..7270f38b56
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/IConfigurationConstants.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+/**
+ * Constants
+ */
+interface IConfigurationConstants {
+ String ECLIPSE_PRODUCT = "eclipse.product"; //$NON-NLS-1$
+ String ECLIPSE_APPLICATION = "eclipse.application"; //$NON-NLS-1$
+ String CFG = "config"; //$NON-NLS-1$
+ String CFG_SITE = "site"; //$NON-NLS-1$
+ String CFG_URL = "url"; //$NON-NLS-1$
+ String CFG_POLICY = "policy"; //$NON-NLS-1$
+ String[] CFG_POLICY_TYPE = { "USER-INCLUDE", "USER-EXCLUDE", "MANAGED-ONLY" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ String CFG_POLICY_TYPE_UNKNOWN = "UNKNOWN"; //$NON-NLS-1$
+ String CFG_LIST = "list"; //$NON-NLS-1$
+ String CFG_UPDATEABLE = "updateable"; //$NON-NLS-1$
+ String CFG_LINK_FILE = "linkfile"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY = "feature"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_ID = "id"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_PRIMARY = "primary"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_VERSION = "version"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_PLUGIN_VERSION = "plugin-version"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_PLUGIN_IDENTIFIER = "plugin-identifier"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_APPLICATION = "application"; //$NON-NLS-1$
+ String CFG_FEATURE_ENTRY_ROOT = "root"; //$NON-NLS-1$
+ String CFG_DATE = "date"; //$NON-NLS-1$
+ String CFG_PLUGIN = "plugin"; //$NON-NLS-1$
+ String CFG_FRAGMENT = "fragment"; //$NON-NLS-1$
+ String CFG_ENABLED = "enabled"; //$NON-NLS-1$
+ String CFG_SHARED_URL = "shared_ur"; //$NON-NLS-1$
+
+ String CFG_VERSION = "version"; //$NON-NLS-1$
+ String CFG_TRANSIENT = "transient"; //$NON-NLS-1$
+ String VERSION = "3.0"; //$NON-NLS-1$
+
+ int DEFAULT_POLICY_TYPE = IConfigurationConstants.USER_EXCLUDE;
+ String[] DEFAULT_POLICY_LIST = new String[0];
+
+ String PLUGINS = "plugins"; //$NON-NLS-1$
+ String FEATURES = "features"; //$NON-NLS-1$
+ String PLUGIN_XML = "plugin.xml"; //$NON-NLS-1$
+ String FRAGMENT_XML = "fragment.xml"; //$NON-NLS-1$
+ String META_MANIFEST_MF = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+ String FEATURE_XML = "feature.xml"; //$NON-NLS-1$
+ /**
+ * User-defined inclusion list. The list associated with this policy
+ * type is interpreted as path entries to included plugin.xml or
+ * fragment.xml <b>relative</b> to the site URL
+ */
+ int USER_INCLUDE = 0;
+ /**
+ * User-defined exclusion list. The list associated with this policy
+ * type is interpreted as path entries to excluded plugin.xml or
+ * fragment.xml <b>relative</b> to the site URL
+ */
+ int USER_EXCLUDE = 1;
+ /**
+ * When this site policy is used, only plug-ins specified by the
+ * configured features are contributed to the runtime.
+ *
+ * @since 3.1
+ */
+ int MANAGED_ONLY = 2;
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Messages.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Messages.java
new file mode 100644
index 0000000000..a37712bfe4
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Messages.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import org.eclipse.osgi.util.NLS;
+
+final class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.update.internal.configurator.messages";//$NON-NLS-1$
+
+ private Messages() {
+ // Do not instantiate
+ }
+
+ public static String cfig_unableToLoad_noURL;
+ public static String cfig_unableToSave_noURL;
+ public static String cfig_unableToSave;
+ public static String InstalledSiteParser_UnableToCreateURL;
+ public static String InstalledSiteParser_UnableToCreateURLForFile;
+ public static String InstalledSiteParser_ErrorParsingFile;
+ public static String InstalledSiteParser_ErrorAccessing;
+ public static String InstalledSiteParser_date;
+ public static String BundleManifest_noVersion;
+ public static String FeatureParser_IdOrVersionInvalid;
+ public static String BundleGroupProvider;
+ public static String ConfigurationActivator_createConfig;
+ public static String ConfigurationParser_cannotLoadSharedInstall;
+ public static String PluginEntry_versionError;
+ public static String IniFileReader_MissingDesc;
+ public static String IniFileReader_OpenINIError;
+ public static String IniFileReader_ReadIniError;
+ public static String IniFileReader_ReadPropError;
+ public static String IniFileReader_ReadMapError;
+ public static String SiteEntry_computePluginStamp;
+ public static String SiteEntry_cannotFindFeatureInDir;
+ public static String SiteEntry_duplicateFeature;
+ public static String SiteEntry_pluginsDir;
+ public static String PlatformConfiguration_expectingPlatformXMLorDirectory;
+ public static String PlatformConfiguration_cannotBackupConfig;
+ public static String PlatformConfiguration_cannotCloseStream;
+ public static String PlatformConfiguration_cannotRenameTempFile;
+ public static String PlatformConfiguration_cannotLoadConfig;
+ public static String PlatformConfiguration_cannotLoadDefaultSite;
+ public static String PlatformConfiguration_cannotFindConfigFile;
+ public static String PlatformConfiguration_cannotSaveNonExistingConfig;
+ public static String PluginParser_plugin_no_id;
+ public static String PluginParser_plugin_no_version;
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ public static String XMLPrintHandler_unsupportedNodeType;
+} \ No newline at end of file
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/PlatformConfiguration.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/PlatformConfiguration.java
new file mode 100644
index 0000000000..670c287897
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/PlatformConfiguration.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ * James D Miles (IBM Corp.) - bug 176250, Configurator needs to handle more platform urls
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.ArrayList;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * This class is responsible for providing the features and plugins (bundles) to
+ * the runtime. Configuration data is stored in the
+ * configuration/org.eclipse.update/platform.xml file. When eclipse starts, it
+ * tries to load the config info from platform.xml. If the file does not exist,
+ * then it also tries to read it from a temp or backup file. If this does not
+ * succeed, a platform.xml is created by inspecting the eclipse installation
+ * directory (its features and plugin folders). If platform.xml already exists,
+ * a check is made to see when it was last modified and whether there are any
+ * file system changes that are newer (users may manually unzip features and
+ * plugins). In this case, the newly added features and plugins are picked up. A
+ * check for existence of features and plugins is also performed, to detect
+ * deletions.
+ */
+@Deprecated
+public class PlatformConfiguration implements IConfigurationConstants {
+
+ private Configuration config;
+ private static int defaultPolicy = DEFAULT_POLICY_TYPE;
+
+ private static final String CONFIG_FILE_TEMP_SUFFIX = ".tmp"; //$NON-NLS-1$
+
+ private static URL installURL;
+
+ public PlatformConfiguration(URL url) throws Exception {
+ URL installLocation = Utils.getInstallURL();
+ // Retrieve install location with respect to given url if possible
+ try {
+ if (url != null && url.getProtocol().equals("file")
+ && url.getPath().endsWith("configuration/org.eclipse.update/platform.xml")) {
+ installLocation = new Path(url.getPath()).removeLastSegments(3).toFile().toURL();
+ }
+ } catch (Exception e) {
+ //
+ }
+ initialize(url, installLocation);
+ }
+
+ public static int getDefaultPolicy() {
+ return defaultPolicy;
+ }
+
+ public SiteEntry[] getConfiguredSites() {
+ if (config == null) {
+ return new SiteEntry[0];
+ }
+
+ SiteEntry[] sites = config.getSites();
+ ArrayList<SiteEntry> enabledSites = new ArrayList<>(sites.length);
+ for (SiteEntry site : sites) {
+ if (site.isEnabled()) {
+ enabledSites.add(site);
+ }
+ }
+ return enabledSites.toArray(new SiteEntry[enabledSites.size()]);
+ }
+
+ private synchronized void initialize(URL url, URL installLocation) throws Exception {
+ if (url != null) {
+ config = loadConfig(url, installLocation);
+ }
+ if (config == null) {
+ config = new Configuration();
+ }
+ config.setURL(url);
+ config.setInstallLocation(installLocation);
+ }
+
+ private Configuration loadConfig(URL url, URL installLocation) throws Exception {
+ if (url == null) {
+ throw new IOException(Messages.cfig_unableToLoad_noURL);
+ }
+
+ // try to load saved configuration file (watch for failed prior save())
+ ConfigurationParser parser = null;
+ try {
+ parser = new ConfigurationParser();
+ } catch (InvocationTargetException e) {
+ throw (Exception) e.getTargetException();
+ }
+
+ config = null;
+ Exception originalException = null;
+ try {
+ config = parser.parse(url, installLocation);
+ if (config == null) {
+ throw new Exception(Messages.PlatformConfiguration_cannotFindConfigFile);
+ }
+ } catch (Exception e1) {
+ // check for save failures, so open temp and backup configurations
+ originalException = e1;
+ try {
+ URL tempURL = new URL(url.toExternalForm() + CONFIG_FILE_TEMP_SUFFIX);
+ config = parser.parse(tempURL, installLocation);
+ if (config == null) {
+ throw new Exception();
+ }
+ config.setDirty(true); // force saving to platform.xml
+ } catch (Exception e2) {
+ try {
+ // check the backup
+ if ("file".equals(url.getProtocol())) { //$NON-NLS-1$
+ File cfigFile = new File(url.getFile().replace('/', File.separatorChar));
+ File workingDir = cfigFile.getParentFile();
+ if (workingDir != null && workingDir.exists()) {
+ File[] backups = workingDir.listFiles(
+ (FileFilter) pathname -> pathname.isFile() && pathname.getName().endsWith(".xml"));
+ if (backups != null && backups.length > 0) {
+ URL backupUrl = backups[backups.length - 1].toURL();
+ config = parser.parse(backupUrl, installLocation);
+ }
+ }
+ }
+ if (config == null)
+ {
+ throw originalException; // we tried, but no config here
+ }
+ // ...
+ config.setDirty(true); // force saving to platform.xml
+ } catch (IOException e3) {
+ throw originalException; // we tried, but no config here ...
+ }
+ }
+ }
+
+ return config;
+ }
+
+ public static boolean supportsDetection(URL url, URL installLocation) {
+ String protocol = url.getProtocol();
+ if (protocol.equals("file")) {
+ return true;
+ } else if (protocol.equals("platform")) { //$NON-NLS-1$
+ URL resolved = null;
+ try {
+ resolved = resolvePlatformURL(url, installLocation); // 19536
+ } catch (IOException e) {
+ return false; // we tried but failed to resolve the platform URL
+ }
+ return resolved.getProtocol().equals("file"); //$NON-NLS-1$
+ } else {
+ return false;
+ }
+ }
+
+ public static URL resolvePlatformURL(URL url, URL base_path_Location) throws IOException {
+ if (url.getProtocol().equals("platform")) { //$NON-NLS-1$
+ if (base_path_Location == null) {
+ url = FileLocator.toFileURL(url);
+ File f = new File(url.getFile());
+ url = f.toURL();
+ } else {
+ final String BASE = "platform:/base/";
+ final String CONFIG = "platform:/config/";
+ String toResolve = url.toExternalForm();
+ if (toResolve.startsWith(BASE)) {
+ url = new URL(base_path_Location, toResolve.substring(BASE.length()));
+ } else if (toResolve.startsWith(CONFIG)) {
+ url = new URL(base_path_Location, toResolve.substring(CONFIG.length()));
+ } else {
+ url = base_path_Location;
+ }
+ }
+ }
+ return url;
+ }
+
+ public static URL getInstallURL() {
+ return installURL;
+ }
+
+ public Configuration getConfiguration() {
+ return config;
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SiteEntry.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SiteEntry.java
new file mode 100644
index 0000000000..ccde2ba016
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SiteEntry.java
@@ -0,0 +1,416 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.osgi.service.environment.Constants;
+import org.eclipse.osgi.util.NLS;
+
+@Deprecated
+public class SiteEntry implements IConfigurationConstants {
+ private static final String MAC_OS_MARKER = ".DS_Store"; //$NON-NLS-1$
+
+ private URL url; // this is the external URL for the site
+ private URL resolvedURL; // this is the resolved URL used internally
+ private SitePolicy policy;
+ private boolean updateable = true;
+ private Map<String, FeatureEntry> featureEntries;
+ private long changeStamp;
+ private long featuresChangeStamp;
+ private long pluginsChangeStamp;
+ private String linkFileName;
+ private boolean enabled = true;
+ private Configuration config;
+
+ private static FeatureParser featureParser = new FeatureParser();
+ private static boolean isMacOS = Utils.getOS().equals(Constants.OS_MACOSX);
+
+ public SiteEntry(URL url) {
+ this(url, null);
+ }
+
+ public SiteEntry(URL url, SitePolicy policy) {
+ if (url == null) {
+ try {
+ url = new URL("platform:/base/"); //$NON-NLS-1$ try using
+ // platform-relative URL
+ } catch (MalformedURLException e) {
+ url = PlatformConfiguration.getInstallURL(); // ensure we come
+ // up ... use
+ // absolute file
+ // URL
+ }
+ }
+
+ if (policy == null) {
+ policy = new SitePolicy(PlatformConfiguration.getDefaultPolicy(), DEFAULT_POLICY_LIST);
+ }
+
+ if (url.getProtocol().equals("file")) { //$NON-NLS-1$
+ try {
+ // TODO remove this when platform fixes local file url's
+ this.url = new File(url.getFile()).toURL();
+ } catch (MalformedURLException e1) {
+ this.url = url;
+ }
+ } else {
+ this.url = url;
+ }
+
+ this.policy = policy;
+ this.resolvedURL = this.url;
+ }
+
+ public void setConfig(Configuration config) {
+ this.config = config;
+ if (url.getProtocol().equals("platform")) { //$NON-NLS-1$
+ try {
+ // resolve the config location relative to the configURL
+ if (url.getPath().startsWith("/config")) {
+ URL configURL = config.getURL();
+ URL config_loc = new URL(configURL, "..");
+ resolvedURL = PlatformConfiguration.resolvePlatformURL(url, config_loc); // 19536
+ }
+ else {
+ resolvedURL = PlatformConfiguration.resolvePlatformURL(url, config.getInstallURL()); // 19536
+ }
+ } catch (IOException e) {
+ // will use the baseline URL ...
+ }
+ }
+ }
+
+ public Configuration getConfig() {
+ return config;
+ }
+
+ public URL getURL() {
+ return url;
+ }
+
+ public SitePolicy getSitePolicy() {
+ return policy;
+ }
+
+ public synchronized void setSitePolicy(SitePolicy policy) {
+ if (policy == null) {
+ throw new IllegalArgumentException();
+ }
+ this.policy = policy;
+ }
+
+ public String[] getFeatures() {
+ return getDetectedFeatures();
+ }
+
+ public long getChangeStamp() {
+ if (changeStamp == 0) {
+ computeChangeStamp();
+ }
+ return changeStamp;
+ }
+
+ public long getFeaturesChangeStamp() {
+ if (featuresChangeStamp == 0) {
+ computeFeaturesChangeStamp();
+ }
+ return featuresChangeStamp;
+ }
+
+ public long getPluginsChangeStamp() {
+ if (pluginsChangeStamp == 0) {
+ computePluginsChangeStamp();
+ }
+ return pluginsChangeStamp;
+ }
+
+ public boolean isUpdateable() {
+ return updateable;
+ }
+
+ public void setUpdateable(boolean updateable) {
+ this.updateable = updateable;
+ }
+
+ public boolean isNativelyLinked() {
+ return isExternallyLinkedSite();
+ }
+
+ public URL getResolvedURL() {
+ return resolvedURL;
+ }
+
+ /**
+ * Detect new features (timestamp &gt; current site timestamp) and validates
+ * existing features (they might have been removed)
+ */
+ private void detectFeatures() {
+
+ if (featureEntries != null) {
+ validateFeatureEntries();
+ } else {
+ featureEntries = new HashMap<>();
+ }
+
+ if (!PlatformConfiguration.supportsDetection(resolvedURL, config.getInstallURL())) {
+ return;
+ }
+
+ // locate feature entries on site
+ File siteRoot = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ File featuresDir = new File(siteRoot, FEATURES);
+ if (featuresDir.exists()) {
+ // handle the installed features under the features directory
+ File[] dirs = featuresDir.listFiles((FileFilter) f -> {
+ // mac os folders contain a file .DS_Store in each folder, and
+ // we need to skip it (bug 76869)
+ if (isMacOS && f.getName().equals(MAC_OS_MARKER)) {
+ return false;
+ }
+ boolean valid = f.isDirectory() && (new File(f, FEATURE_XML).exists());
+ if (!valid) {
+ Utils.log(NLS.bind(Messages.SiteEntry_cannotFindFeatureInDir,
+ (new String[] { f.getAbsolutePath() })));
+ }
+ return valid;
+ });
+
+ for (File dir : dirs) {
+ try {
+ File featureXML = new File(dir, FEATURE_XML);
+ if (featureXML.lastModified() <= featuresChangeStamp && dir.lastModified() <= featuresChangeStamp) {
+ continue;
+ }
+ URL featureURL = featureXML.toURL();
+ FeatureEntry featureEntry = featureParser.parse(featureURL);
+ if (featureEntry != null) {
+ addFeatureEntry(featureEntry);
+ }
+ } catch (MalformedURLException e) {
+ Utils.log(NLS.bind(Messages.InstalledSiteParser_UnableToCreateURLForFile,
+ (new String[] { featuresDir.getAbsolutePath() })));
+ }
+ }
+ }
+ }
+
+ /**
+ * @return list of feature url's (relative to site)
+ */
+ private synchronized String[] getDetectedFeatures() {
+ if (featureEntries == null) {
+ detectFeatures();
+ }
+ String[] features = new String[featureEntries.size()];
+ Iterator<FeatureEntry> iterator = featureEntries.values().iterator();
+ for (int i = 0; i < features.length; i++) {
+ features[i] = iterator.next().getURL();
+ }
+ return features;
+ }
+
+ private void computeChangeStamp() {
+ changeStamp = Math.max(computeFeaturesChangeStamp(), computePluginsChangeStamp());
+ // changeStampIsValid = true;
+ }
+
+ private synchronized long computeFeaturesChangeStamp() {
+ if (featuresChangeStamp > 0) {
+ return featuresChangeStamp;
+ }
+
+ long start = 0;
+ String[] features = getFeatures();
+
+ // compute stamp for the features directory
+ long dirStamp = 0;
+ if (PlatformConfiguration.supportsDetection(resolvedURL, config.getInstallURL())) {
+ File root = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ File featuresDir = new File(root, FEATURES);
+ dirStamp = featuresDir.lastModified();
+ }
+ featuresChangeStamp = Math.max(dirStamp, computeStamp(features));
+ return featuresChangeStamp;
+ }
+
+ private synchronized long computePluginsChangeStamp() {
+ if (pluginsChangeStamp > 0) {
+ return pluginsChangeStamp;
+ }
+
+ if (!PlatformConfiguration.supportsDetection(resolvedURL, config.getInstallURL())) {
+ Utils.log(NLS.bind(Messages.SiteEntry_computePluginStamp, (new String[] { resolvedURL.toExternalForm() })));
+ return 0;
+ }
+
+ // compute stamp for the plugins directory
+ File root = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ File pluginsDir = new File(root, PLUGINS);
+ if (!pluginsDir.exists() || !pluginsDir.isDirectory()) {
+ return 0;
+ }
+
+ pluginsChangeStamp = pluginsDir.lastModified();
+ return pluginsChangeStamp;
+ }
+
+ private long computeStamp(String[] targets) {
+
+ long result = 0;
+ if (!PlatformConfiguration.supportsDetection(resolvedURL, config.getInstallURL())) {
+ // NOTE: this path should not be executed until we support running
+ // from an arbitrary URL (in particular from http server). For
+ // now just compute stamp across the list of names. Eventually
+ // when general URLs are supported we need to do better (factor
+ // in at least the existence of the target). However, given this
+ // code executes early on the startup sequence we need to be
+ // extremely mindful of performance issues.
+ // In fact, we should get the last modified from the connection
+ for (String target : targets) {
+ result ^= target.hashCode();
+ }
+ } else {
+ // compute stamp across local targets
+ File rootFile = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ if (rootFile.exists()) {
+ File f = null;
+ for (String target : targets) {
+ f = new File(rootFile, target);
+ if (f.exists()) {
+ result = Math.max(result, f.lastModified());
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public void setLinkFileName(String linkFileName) {
+ this.linkFileName = linkFileName;
+ }
+
+ public String getLinkFileName() {
+ return linkFileName;
+ }
+
+ public boolean isExternallyLinkedSite() {
+ return (linkFileName != null && !linkFileName.trim().isEmpty());
+ }
+
+ public void addFeatureEntry(FeatureEntry feature) {
+ if (featureEntries == null) {
+ featureEntries = new HashMap<>();
+ }
+ // Make sure we keep the larger version of same feature
+ FeatureEntry existing = featureEntries.get(feature.getFeatureIdentifier());
+ if (existing != null) {
+ VersionedIdentifier existingVersion = new VersionedIdentifier(existing.getFeatureIdentifier(),
+ existing.getFeatureVersion());
+ VersionedIdentifier newVersion = new VersionedIdentifier(feature.getFeatureIdentifier(),
+ feature.getFeatureVersion());
+ if (existingVersion.getVersion().compareTo(newVersion.getVersion()) < 0) {
+ featureEntries.put(feature.getFeatureIdentifier(), feature);
+ pluginsChangeStamp = 0;
+ } else if (existingVersion.equals(newVersion)) {
+ // log error if same feature version/id but a different url
+ if (feature instanceof FeatureEntry && existing instanceof FeatureEntry
+ && !feature.getURL().equals(existing.getURL())) {
+ Utils.log(NLS.bind(Messages.SiteEntry_duplicateFeature,
+ (new String[] { getURL().toExternalForm(), existing.getFeatureIdentifier() })));
+ }
+ }
+ } else {
+ featureEntries.put(feature.getFeatureIdentifier(), feature);
+ pluginsChangeStamp = 0;
+ }
+ if (feature instanceof FeatureEntry) {
+ feature.setSite(this);
+ }
+ }
+
+ public FeatureEntry[] getFeatureEntries() {
+ if (featureEntries == null) {
+ detectFeatures();
+ }
+
+ if (featureEntries == null) {
+ return new FeatureEntry[0];
+ }
+ return featureEntries.values().toArray(new FeatureEntry[featureEntries.size()]);
+ }
+
+ private void validateFeatureEntries() {
+ File root = new File(resolvedURL.getFile().replace('/', File.separatorChar));
+ Iterator<FeatureEntry> iterator = featureEntries.values().iterator();
+ Collection<String> deletedFeatures = new ArrayList<>();
+ while (iterator.hasNext()) {
+ FeatureEntry feature = iterator.next();
+ // Note: in the future, we can check for absolute url as well.
+ // For now, feature url is features/org.eclipse.foo/feature.xml
+ File featureXML = new File(root, feature.getURL());
+ if (!featureXML.exists()) {
+ deletedFeatures.add(feature.getFeatureIdentifier());
+ }
+ }
+ for (String string : deletedFeatures) {
+ featureEntries.remove(string);
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enable) {
+ this.enabled = enable;
+ }
+
+ public FeatureEntry getFeatureEntry(String id) {
+ for (FeatureEntry feature : getFeatureEntries()) {
+ if (feature.getFeatureIdentifier().equals(id)) {
+ return feature;
+ }
+ }
+ return null;
+ }
+
+ public boolean unconfigureFeatureEntry(FeatureEntry feature) {
+ FeatureEntry existingFeature = getFeatureEntry(feature.getFeatureIdentifier());
+ if (existingFeature != null) {
+ featureEntries.remove(existingFeature.getFeatureIdentifier());
+ }
+ return existingFeature != null;
+ }
+
+ /*
+ * This is a bit of a hack. When no features were added to the site, but the
+ * site is initialized from platform.xml we need to set the feature set to
+ * empty, so we don't try to detect them.
+ */
+ public void initialized() {
+ if (featureEntries == null) {
+ featureEntries = new HashMap<>();
+ }
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SitePolicy.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SitePolicy.java
new file mode 100644
index 0000000000..f7354beb00
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/SitePolicy.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+class SitePolicy {
+
+ private int type;
+ private String[] list;
+
+ public SitePolicy() {
+ }
+
+ public SitePolicy(int type, String[] list) {
+ if (type != IConfigurationConstants.USER_INCLUDE && type != IConfigurationConstants.USER_EXCLUDE && type != IConfigurationConstants.MANAGED_ONLY) {
+ throw new IllegalArgumentException();
+ }
+ this.type = type;
+
+ if (list == null) {
+ this.list = new String[0];
+ } else {
+ this.list = list;
+ }
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String[] getList() {
+ return list;
+ }
+
+ public synchronized void setList(String[] list) {
+ if (list == null) {
+ this.list = new String[0];
+ } else {
+ this.list = list;
+ }
+ }
+
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Utils.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Utils.java
new file mode 100644
index 0000000000..07bd56aab4
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/Utils.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2017 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
+ * James D Miles (IBM Corp.) - bug 176250, Configurator needs to handle more platform urls
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.service.datalocation.Location;
+import org.eclipse.osgi.service.environment.EnvironmentInfo;
+
+class Utils {
+ // os
+ public static boolean isWindows = System.getProperty("os.name").startsWith("Win"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ public static IStatus newStatus(String message, Throwable e) {
+ return new Status(IStatus.ERROR, "org.eclipse.update.configurator", IStatus.OK, message, e); //$NON-NLS-1$
+ }
+
+ public static void log(String message) {
+ log(newStatus(message, null));
+ }
+
+ public static void log(IStatus status) {
+ Platform.getLog(Utils.class).log(status);
+ }
+
+ /**
+ *
+ */
+ public static boolean isValidEnvironment(String os, String ws, String arch, String nl) {
+ if (os != null && !isMatching(os, getOS())) {
+ return false;
+ }
+ if (ws != null && !isMatching(ws, getWS())) {
+ return false;
+ }
+ if (arch != null && !isMatching(arch, getArch())) {
+ return false;
+ }
+ if (nl != null && !isMatchingLocale(nl, getNL())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return the current operating system value.
+ *
+ * @see EnvironmentInfo#getOS()
+ */
+ public static String getOS() {
+ return Platform.getOS();
+ }
+
+ /**
+ * Return the current windowing system value.
+ *
+ * @see EnvironmentInfo#getWS()
+ */
+ public static String getWS() {
+ return Platform.getWS();
+ }
+
+ /**
+ * Return the current system architecture value.
+ *
+ * @see EnvironmentInfo#getOSArch()
+ */
+ public static String getArch() {
+ return Platform.getOSArch();
+ }
+
+ /**
+ * Return the current NL value.
+ *
+ * @see EnvironmentInfo#getNL()
+ */
+ public static String getNL() {
+ return Platform.getNL();
+ }
+
+ /**
+ * Return the configuration location.
+ *
+ * @see Location
+ */
+ public static Location getConfigurationLocation() {
+ return Platform.getConfigurationLocation();
+ }
+
+ /**
+ *
+ */
+ private static boolean isMatching(String candidateValues, String siteValues) {
+ if (siteValues == null) {
+ return false;
+ }
+ if ("*".equalsIgnoreCase(candidateValues)) {
+ return true;
+ }
+ siteValues = siteValues.toUpperCase();
+ StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$
+ while (stok.hasMoreTokens()) {
+ String token = stok.nextToken().toUpperCase();
+ if (siteValues.contains(token)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ */
+ private static boolean isMatchingLocale(String candidateValues, String locale) {
+ if (locale == null) {
+ return false;
+ }
+ if ("*".equalsIgnoreCase(candidateValues)) {
+ return true;
+ }
+
+ locale = locale.toUpperCase();
+ candidateValues = candidateValues.toUpperCase();
+ StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$
+ while (stok.hasMoreTokens()) {
+ String candidate = stok.nextToken();
+ if (locale.indexOf(candidate) == 0) {
+ return true;
+ }
+ if (candidate.indexOf(locale) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an absolute URL by combining a base absolute URL and another URL
+ * relative to the first one. If the relative URL protocol does not match
+ * the base URL protocol, or if the relative URL path is not relative,
+ * return it as is.
+ */
+ public static URL makeAbsolute(URL base, URL relativeLocation) {
+ if (!"file".equals(base.getProtocol())) {
+ // we only deal with file: URLs
+ return relativeLocation;
+ }
+ if (relativeLocation.getProtocol() != null && !relativeLocation.getProtocol().equals(base.getProtocol())) {
+ // it is not relative, return as is (avoid creating garbage)
+ return relativeLocation;
+ }
+ IPath relativePath = new Path(relativeLocation.getPath());
+ if (relativePath.isAbsolute()) {
+ return relativeLocation;
+ }
+ try {
+ IPath absolutePath = new Path(base.getPath()).append(relativeLocation.getPath());
+ // File.toURL() is the best way to create a file: URL
+ return absolutePath.toFile().toURL();
+ } catch (MalformedURLException e) {
+ // cannot happen since we are building from two existing valid URLs
+ Utils.log(e.getLocalizedMessage());
+ return relativeLocation;
+ }
+ }
+
+ /**
+ * Ensures file: URLs on Windows have the right form (i.e. '/' as segment
+ * separator, drive letter in lower case, etc)
+ */
+ public static String canonicalizeURL(String url) {
+ if (!(isWindows && url.startsWith("file:"))) {
+ return url;
+ }
+ try {
+ String path = new URL(url).getPath();
+ // normalize to not have leading / so we can check the form
+ File file = new File(path);
+ path = file.toString().replace('\\', '/');
+ if (Character.isUpperCase(path.charAt(0))) {
+ char[] chars = path.toCharArray();
+ chars[0] = Character.toLowerCase(chars[0]);
+ path = new String(chars);
+ return new File(path).toURL().toExternalForm();
+ }
+ } catch (MalformedURLException e) {
+ // default to original url
+ }
+ return url;
+ }
+
+ /**
+ * Return the install location.
+ *
+ * @see Location
+ */
+ public static URL getInstallURL() {
+ Location location = Platform.getInstallLocation();
+
+ // it is pretty much impossible for the install location to be null. If
+ // it is, the
+ // system is in a bad way so throw and exception and get the heck outta
+ // here.
+ if (location == null)
+ {
+ throw new IllegalStateException("The installation location must not be null"); //$NON-NLS-1$
+ }
+
+ return location.getURL();
+ }
+
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/VersionedIdentifier.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/VersionedIdentifier.java
new file mode 100644
index 0000000000..ec6864c473
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/VersionedIdentifier.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 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
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.update.configurator;
+
+import org.osgi.framework.Version;
+
+class VersionedIdentifier {
+ private String identifier;
+ private Version version;
+
+ public VersionedIdentifier(String id, String version) {
+ this.identifier = id;
+ this.version = Version.parseVersion(version);
+ }
+
+ public Version getVersion() {
+ return version;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ private boolean equalIdentifiers(VersionedIdentifier id) {
+ if (id == null) {
+ return identifier == null;
+ }
+ return id.identifier.equals(identifier);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof VersionedIdentifier)) {
+ return false;
+ }
+
+ VersionedIdentifier other = (VersionedIdentifier) obj;
+ if (!equalIdentifiers(other)) {
+ return false;
+ }
+ return version.equals(other.getVersion());
+ }
+
+ @Override
+ public int hashCode() {
+ return (identifier + "_" + getVersion()).hashCode(); //$NON-NLS-1$
+ }
+
+ @Override
+ public String toString() {
+ return identifier + "_" + getVersion(); //$NON-NLS-1$
+ }
+} \ No newline at end of file
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/XMLPrintHandler.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/XMLPrintHandler.java
new file mode 100644
index 0000000000..224252b3c2
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/XMLPrintHandler.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 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
+ *******************************************************************************/
+
+package org.eclipse.pde.internal.core.update.configurator;
+
+import java.io.IOException;
+import java.io.Writer;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+class XMLPrintHandler {
+ // used to print XML file
+ public static final String XML_HEAD = "<?xml version=\"1.0\" encoding=\""; //$NON-NLS-1$
+ public static final String XML_HEAD_END_TAG = "?>"; //$NON-NLS-1$
+ public static final String XML_DBL_QUOTES = "\""; //$NON-NLS-1$
+ public static final String XML_SPACE = " "; //$NON-NLS-1$
+ public static final String XML_BEGIN_TAG = "<"; //$NON-NLS-1$
+ public static final String XML_END_TAG = ">"; //$NON-NLS-1$
+ public static final String XML_EQUAL = "="; //$NON-NLS-1$
+ public static final String XML_SLASH = "/"; //$NON-NLS-1$
+
+ public static void printBeginElement(Writer xmlWriter, String elementString) throws IOException {
+ StringBuilder temp = new StringBuilder(XML_BEGIN_TAG);
+ temp.append(elementString).append(XML_END_TAG).append("\n"); //$NON-NLS-1$
+ xmlWriter.write(temp.toString());
+
+ }
+
+ public static void printEndElement(Writer xmlWriter, String elementString) throws IOException {
+ StringBuilder temp = new StringBuilder(XML_BEGIN_TAG);
+ temp.append(XML_SLASH).append(elementString).append(XML_END_TAG).append("\n"); //$NON-NLS-1$
+ xmlWriter.write(temp.toString());
+
+ }
+
+ public static void printHead(Writer xmlWriter, String encoding) throws IOException {
+ StringBuilder temp = new StringBuilder(XML_HEAD);
+ temp.append(encoding).append(XML_DBL_QUOTES).append(XML_HEAD_END_TAG).append("\n"); //$NON-NLS-1$
+ xmlWriter.write(temp.toString());
+ }
+
+ public static String wrapAttributeForPrint(String attribute, String value) throws IOException {
+ StringBuilder temp = new StringBuilder(XML_SPACE);
+ temp.append(attribute).append(XML_EQUAL).append(XML_DBL_QUOTES).append(encode(value).toString())
+ .append(XML_DBL_QUOTES);
+ return temp.toString();
+
+ }
+
+ public static void printNode(Writer xmlWriter, Node node, String encoding) throws Exception {
+ if (node == null) {
+ return;
+ }
+
+ switch (node.getNodeType())
+ {
+ case Node.DOCUMENT_NODE: {
+ printHead(xmlWriter, encoding);
+ printNode(xmlWriter, ((Document) node).getDocumentElement(), encoding);
+ break;
+ }
+ case Node.ELEMENT_NODE: {
+ // get the attribute list for this node.
+ StringBuilder tempElementString = new StringBuilder(node.getNodeName());
+ NamedNodeMap attributeList = node.getAttributes();
+ if (attributeList != null) {
+ for (int i = 0; i < attributeList.getLength(); i++) {
+ Node attribute = attributeList.item(i);
+ tempElementString
+ .append(wrapAttributeForPrint(attribute.getNodeName(), attribute.getNodeValue()));
+ }
+ }
+ printBeginElement(xmlWriter, tempElementString.toString());
+
+ // do this recursively for the child nodes.
+ NodeList childNodes = node.getChildNodes();
+ if (childNodes != null) {
+ int length = childNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ printNode(xmlWriter, childNodes.item(i), encoding);
+ }
+ }
+
+ printEndElement(xmlWriter, node.getNodeName());
+ break;
+ }
+
+ case Node.TEXT_NODE: {
+ xmlWriter.write(encode(node.getNodeValue()).toString());
+ break;
+ }
+ default: {
+ throw new UnsupportedOperationException(Messages.XMLPrintHandler_unsupportedNodeType);
+
+ }
+ }
+
+ }
+
+ public static StringBuffer encode(String value) {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ switch (c)
+ {
+ case '&':
+ buf.append("&amp;"); //$NON-NLS-1$
+ break;
+ case '<':
+ buf.append("&lt;"); //$NON-NLS-1$
+ break;
+ case '>':
+ buf.append("&gt;"); //$NON-NLS-1$
+ break;
+ case '\'':
+ buf.append("&apos;"); //$NON-NLS-1$
+ break;
+ case '\"':
+ buf.append("&quot;"); //$NON-NLS-1$
+ break;
+ default:
+ buf.append(c);
+ break;
+ }
+ }
+ return buf;
+ }
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/messages.properties b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/messages.properties
new file mode 100644
index 0000000000..47e8d1d65e
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/update/configurator/messages.properties
@@ -0,0 +1,57 @@
+###############################################################################
+# Copyright (c) 2000, 2008 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
+###############################################################################
+### Boot plugin message catalog
+
+### Platform Configuration
+cfig_unableToLoad_noURL=Configuration file location not specified
+cfig_unableToSave_noURL=Configuration file save location not specified
+cfig_unableToSave=Unable to save configuration file \"{0}\"
+
+InstalledSiteParser_UnableToCreateURL= Internal Error. Unable to create URL from \"{0}\".
+InstalledSiteParser_UnableToCreateURLForFile= Unable to create URL from \"{0}\".
+InstalledSiteParser_ErrorParsingFile= Unable to parse file \"{0}\".
+InstalledSiteParser_ErrorAccessing= Unable to access file \"{0}\".
+InstalledSiteParser_date = Invalid date attribute {0}
+BundleManifest_noVersion = {0} attribute not found in manifest for bundle \"{1}\". Bundle will be ignored.
+
+FeatureParser_IdOrVersionInvalid= Error parsing feature stream. The unique identifier or the version is null or empty: unique identifier=\"{0}\" version=\"{1}\".
+
+BundleGroupProvider=Update Manager Configurator
+
+ConfigurationActivator_createConfig=Cannot create configuration in {0}
+ConfigurationParser_cannotLoadSharedInstall=Could not load from shared install
+PluginEntry_versionError=Unable to create versioned identifier: {0} {1}
+
+IniFileReader_MissingDesc = Cannot find plugin for feature {0}
+IniFileReader_OpenINIError = Cannot open branding file {0}
+IniFileReader_ReadIniError = Error reading branding file {0}
+IniFileReader_ReadPropError = Error reading branding properties file {0}
+IniFileReader_ReadMapError = Error reading mapping files {0}
+
+SiteEntry_computePluginStamp = Cannot compute plugins change stamp for site {0} because it does not support plugin detection.
+SiteEntry_cannotFindFeatureInDir=Unable to find feature.xml in directory: {0}
+SiteEntry_duplicateFeature=Duplicate feature found on site {0} : {1}
+SiteEntry_pluginsDir = {0} is not a valid plugins directory.
+PlatformConfiguration_expectingPlatformXMLorDirectory=Either specify the configuration directory or a file named platform.xml
+PlatformConfiguration_cannotBackupConfig=Cannot backup current configuration
+PlatformConfiguration_cannotCloseStream=Could not close output stream for
+PlatformConfiguration_cannotRenameTempFile=Could not rename configuration temp file
+PlatformConfiguration_cannotLoadConfig=Cannot load configuration from
+PlatformConfiguration_cannotLoadDefaultSite=Cannot load default site
+PlatformConfiguration_cannotFindConfigFile=Platform configuration file cannot be found
+PlatformConfiguration_cannotSaveNonExistingConfig=Configuration cannot be saved because it does not exist
+
+PluginParser_plugin_no_id = Plugin does not have a valid identifier: {0}
+PluginParser_plugin_no_version = Plugin does not have a valid version: {0}
+XMLPrintHandler_unsupportedNodeType=Unsupported XML Node Type.

Back to the top