Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 75b8742c6ad3d14e2e88f6e46a53a89c9cb5e4ba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*******************************************************************************
 * Copyright (c) 2007, 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
 *     Pascal Rapicault - Support for bundled macosx http://bugs.eclipse.org/57349
 *******************************************************************************/
package org.eclipse.equinox.internal.p2.touchpoint.eclipse;

import java.io.File;
import java.net.*;
import java.util.List;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.internal.p2.update.*;
import org.eclipse.equinox.internal.provisional.frameworkadmin.LauncherData;
import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.osgi.service.environment.Constants;
import org.eclipse.osgi.util.NLS;

/**	
 * 	This class provides a wrapper for reading and writing platform.xml.
 * 
 * 	Only a minimal set of operations is exposed.
 */
public class PlatformConfigurationWrapper {

	private Configuration configuration = null;
	private Site poolSite = null;
	private File configFile;
	private URI poolURI;
	private Manipulator manipulator;

	private static String FEATURES = "features/"; //$NON-NLS-1$

	/*
	 * Use the given manipulator to calculate the OSGi install location. We can't
	 * just use the Location service here because we may not be installing into
	 * ourselves. (see https://bugs.eclipse.org/354552)
	 * 
	 * First try and calculate the location based relative to the data provided
	 * in the manipulator's launcher data. If that doesn't work then calculate
	 * it based on the location of known JARs. If that still doesn't work then
	 * return null.
	 */
	private static URL getOSGiInstallArea(Manipulator manipulator) {

		// first see if the launcher home is set
		LauncherData launcherData = manipulator.getLauncherData();
		File home = launcherData.getHome();
		if (home != null) {
			try {
				return home.toURI().toURL();
			} catch (MalformedURLException e) {
				// ignore - shouldn't happen
			}
		}

		// next try and calculate the value based on the location of the framework (OSGi) jar.
		File fwkJar = launcherData.getFwJar();
		if (fwkJar != null) {
			try {
				return fromOSGiJarToOSGiInstallArea(fwkJar.getAbsolutePath()).toURI().toURL();
			} catch (MalformedURLException e) {
				// ignore - shouldn't happen
			}
		}

		// finally calculate the value based on the location of the launcher executable itself
		File launcherFile = launcherData.getLauncher();
		if (launcherFile != null) {
			if (Constants.OS_MACOSX.equals(launcherData.getOS())) {
				//the equinox launcher will look 3 levels up on the mac when going from executable to launcher.jar
				//see org.eclipse.equinox.executable/library/eclipse.c : findStartupJar();
				IPath launcherPath = new Path(launcherFile.getAbsolutePath());
				if (launcherPath.segmentCount() > 2) {
					//removing "Eclipse.app/Contents/MacOS/eclipse"
					launcherPath = launcherPath.removeLastSegments(2);
					try {
						return launcherPath.toFile().toURI().toURL();
					} catch (MalformedURLException e) {
						// ignore - shouldn't happen
					}
				}
			}
			try {
				return launcherFile.getParentFile().toURI().toURL();
			} catch (MalformedURLException e) {
				// ignore - shouldn't happen
			}
		}

		// we couldn't calculate it based on the info in the launcher data, so
		// try to do it based on the location of known JARs.
		final String OSGI = "org.eclipse.osgi"; //$NON-NLS-1$
		BundleInfo[] bis = manipulator.getConfigData().getBundles();
		String searchFor = "org.eclipse.equinox.launcher"; //$NON-NLS-1$
		for (int i = 0; i < bis.length; i++) {
			if (bis[i].getSymbolicName().equals(searchFor)) {
				if (bis[i].getLocation() != null) {
					try {
						if (bis[i].getLocation().getScheme().equals("file")) //$NON-NLS-1$
							return fromOSGiJarToOSGiInstallArea(bis[i].getLocation().getPath()).toURI().toURL();
					} catch (MalformedURLException e) {
						//do nothing
					}
				}
				if (searchFor.equals(OSGI))
					return null;
				searchFor = OSGI;
				i = -1;
			}
		}
		return null;
	}

	private static File fromOSGiJarToOSGiInstallArea(String path) {
		IPath parentFolder = new Path(path).removeLastSegments(1);
		if (parentFolder.lastSegment().equals("plugins")) //$NON-NLS-1$
			return parentFolder.removeLastSegments(1).toFile();
		return parentFolder.toFile();
	}

	public PlatformConfigurationWrapper(File configDir, URI featurePool, Manipulator manipulator) {
		this.configuration = null;
		this.configFile = new File(configDir, "/org.eclipse.update/platform.xml"); //$NON-NLS-1$
		this.poolURI = featurePool;
		this.manipulator = manipulator;
	}

	private void loadDelegate() {
		if (configuration != null)
			return;

		try {
			if (configFile.exists()) {
				configuration = Configuration.load(configFile, getOSGiInstallArea(manipulator));
			} else {
				configuration = new Configuration();
			}
		} catch (ProvisionException pe) {
			// TODO: Make this a real message
			throw new IllegalStateException(Messages.error_parsing_configuration);
		}
		if (poolURI == null)
			throw new IllegalStateException("Error creating platform configuration. No bundle pool defined."); //$NON-NLS-1$

		poolSite = getSite(poolURI);
		if (poolSite == null) {
			poolSite = createSite(poolURI, getDefaultPolicy());
			configuration.add(poolSite);
		}
	}

	/*
	 * Return the default policy to use when creating a new site. If there are
	 * any sites with the MANAGED-ONLY policy, then that is the default.
	 * Otherwise the default is USER-EXCLUDE.
	 */
	private String getDefaultPolicy() {
		for (Site site : configuration.getSites()) {
			if (Site.POLICY_MANAGED_ONLY.equals(site.getPolicy()))
				return Site.POLICY_MANAGED_ONLY;
		}
		return Site.POLICY_USER_EXCLUDE;
	}

	/*
	 * Create and return a site object based on the given location.
	 */
	private Site createSite(URI location, String policy) {
		Site result = new Site();
		result.setUrl(location.toString());
		result.setPolicy(policy);
		result.setEnabled(true);
		return result;
	}

	/*
	 * Look in the configuration and return the site object whose location matches
	 * the given URL. Return null if there is no match.
	 */
	private Site getSite(URI url) {
		List<Site> sites = configuration.getSites();
		File file = URIUtil.toFile(url);
		for (Site nextSite : sites) {
			try {
				File nextFile = URIUtil.toFile(new URI(nextSite.getUrl()));
				if (nextFile == null)
					continue;
				if (nextFile.equals(file))
					return nextSite;
			} catch (URISyntaxException e) {
				//ignore incorrectly formed site
			}
		}
		return null;
	}

	/*
	 * Look in the configuration and return the site which contains the feature
	 * with the given identifier and version. Return null if there is none.
	 */
	private Site getSite(String id, String version) {
		List<Site> sites = configuration.getSites();
		for (Site site : sites) {
			Feature[] features = site.getFeatures();
			for (int i = 0; i < features.length; i++) {
				if (id.equals(features[i].getId()) && version.equals(features[i].getVersion()))
					return site;
			}
		}
		return null;
	}

	public IStatus addFeatureEntry(File file, String id, String version, String pluginIdentifier, String pluginVersion, boolean primary, String application, URL[] root, String linkFile) {
		loadDelegate();
		if (configuration == null)
			return new Status(IStatus.WARNING, Activator.ID, Messages.platform_config_unavailable, null);

		URI fileURL = null;
		File featureDir = file.getParentFile();
		if (featureDir == null || !featureDir.getName().equals("features")) //$NON-NLS-1$
			return new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.parent_dir_features, file.getAbsolutePath()), null);
		File locationDir = featureDir.getParentFile();
		if (locationDir == null)
			return new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.cannot_calculate_extension_location, file.getAbsolutePath()), null);

		fileURL = locationDir.toURI();
		Site site = getSite(fileURL);
		if (site == null) {
			site = createSite(fileURL, getDefaultPolicy());
			if (linkFile != null)
				site.setLinkFile(linkFile);
			configuration.add(site);
		} else {
			// check to see if the feature already exists in this site
			if (site.getFeature(id, version) != null)
				return Status.OK_STATUS;
		}
		Feature addedFeature = new Feature(site);
		addedFeature.setId(id);
		addedFeature.setVersion(version);
		addedFeature.setUrl(makeFeatureURL(id, version));
		addedFeature.setApplication(application);
		addedFeature.setPluginIdentifier(pluginIdentifier);
		addedFeature.setPluginVersion(pluginVersion);
		addedFeature.setRoots(root);
		addedFeature.setPrimary(primary);
		site.addFeature(addedFeature);
		return Status.OK_STATUS;
	}

	public IStatus removeFeatureEntry(String id, String version) {
		loadDelegate();
		if (configuration == null)
			return new Status(IStatus.WARNING, Activator.ID, Messages.platform_config_unavailable, null);

		Site site = getSite(id, version);
		if (site == null)
			site = poolSite;
		site.removeFeature(makeFeatureURL(id, version));
		// if we weren't able to remove the feature from the site because it
		// didn't exist, then someone already did our job for us and it is ok.
		return Status.OK_STATUS;
	}

	public boolean containsFeature(URI siteURI, String featureId, String featureVersion) {
		loadDelegate();
		if (configuration == null)
			return false;

		Site site = getSite(siteURI);
		if (site == null)
			return false;

		return site.getFeature(featureId, featureVersion) != null;
	}

	public void save() throws ProvisionException {
		if (configuration != null) {
			configFile.getParentFile().mkdirs();
			configuration.save(configFile, getOSGiInstallArea(manipulator));
		}
	}

	private static String makeFeatureURL(String id, String version) {
		return FEATURES + id + "_" + version + "/"; //$NON-NLS-1$ //$NON-NLS-2$;
	}

}

Back to the top