1 /*******************************************************************************
2  * Copyright (c) 2005, 2018 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Code 9 - Additional function and fixes
14  *     EclipseSource - ongoing development
15  *     Felix Riegger (SAP AG) - consolidation of publishers for PDE formats (bug 331974)
16  *     SAP AG - ongoing development
17  *     Rapicorp - additional features
18  *     Red Hat Inc. - Bug 460967
19  *******************************************************************************/
20 
21 package org.eclipse.equinox.internal.p2.publisher.eclipse;
22 
23 import java.io.*;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.*;
27 import java.util.Map.Entry;
28 import javax.xml.parsers.*;
29 import org.eclipse.core.runtime.*;
30 import org.eclipse.equinox.frameworkadmin.BundleInfo;
31 import org.eclipse.equinox.internal.p2.core.helpers.*;
32 import org.eclipse.equinox.p2.metadata.IVersionedId;
33 import org.eclipse.equinox.p2.metadata.VersionedId;
34 import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry;
35 import org.eclipse.equinox.p2.repository.IRepository;
36 import org.eclipse.equinox.p2.repository.IRepositoryReference;
37 import org.eclipse.equinox.p2.repository.spi.RepositoryReference;
38 import org.eclipse.osgi.service.datalocation.Location;
39 import org.eclipse.osgi.util.NLS;
40 import org.eclipse.pde.internal.publishing.Activator;
41 import org.xml.sax.*;
42 import org.xml.sax.helpers.DefaultHandler;
43 
44 /**
45  *  Used to parse a .product file.
46  */
47 public class ProductFile extends DefaultHandler implements IProductDescriptor {
48 	public final static String GENERIC_VERSION_NUMBER = "0.0.0"; //$NON-NLS-1$
49 
50 	private static final String ATTRIBUTE_PATH = "path"; //$NON-NLS-1$
51 	private static final String ATTRIBUTE_ICON = "icon"; //$NON-NLS-1$
52 	protected static final String ATTRIBUTE_FRAGMENT = "fragment"; //$NON-NLS-1$
53 	private static final String ATTRIBUTE_APPLICATION = "application"; //$NON-NLS-1$
54 	private static final String ATTRIBUTE_INCLUDE_LAUNCHERS = "includeLaunchers"; //$NON-NLS-1$
55 	private static final String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
56 	private static final String ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
57 	private static final String ATTRIBUTE_LOCATION = "location"; //$NON-NLS-1$
58 	private static final String ATTRIBUTE_AUTO_START = "autoStart"; //$NON-NLS-1$
59 	private static final String ATTRIBUTE_START_LEVEL = "startLevel"; //$NON-NLS-1$
60 	protected static final String ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$
61 	protected static final String ATTRIBUTE_ID = "id"; //$NON-NLS-1$
62 	private static final String ATTRIBUTE_UID = "uid"; //$NON-NLS-1$
63 	private static final String ATTRIBUTE_CONTENT_TYPE = "type"; //$NON-NLS-1$
64 	private static final String ATTRIBUTE_OS = "os"; //$NON-NLS-1$
65 	private static final String ATTRIBUTE_ARCH = "arch"; //$NON-NLS-1$
66 	private static final String ATTRIBUTE_ENABLED = "enabled"; //$NON-NLS-1$
67 	private static final String ATTRIBUTE_FEATURE_INSTALL_MODE = "installMode"; //$NON-NLS-1$
68 
69 	private static final String PROPERTY_ECLIPSE_APPLICATION = "eclipse.application"; //$NON-NLS-1$
70 	private static final String PROPERTY_ECLIPSE_PRODUCT = "eclipse.product"; //$NON-NLS-1$
71 
72 	private static final String PROGRAM_ARGS = "programArgs"; //$NON-NLS-1$
73 	private static final String PROGRAM_ARGS_LINUX = "programArgsLin"; //$NON-NLS-1$
74 	private static final String PROGRAM_ARGS_MAC = "programArgsMac"; //$NON-NLS-1$
75 	private static final String PROGRAM_ARGS_SOLARIS = "programArgsSol"; //$NON-NLS-1$
76 	private static final String PROGRAM_ARGS_WIN = "programArgsWin"; //$NON-NLS-1$
77 	private static final String VM = "vm"; //$NON-NLS-1$
78 	private static final String VM_ARGS = "vmArgs"; //$NON-NLS-1$
79 	private static final String VM_ARGS_LINUX = "vmArgsLin"; //$NON-NLS-1$
80 	private static final String VM_ARGS_MAC = "vmArgsMac"; //$NON-NLS-1$
81 	private static final String VM_ARGS_SOLARIS = "vmArgsSol"; //$NON-NLS-1$
82 	private static final String VM_ARGS_WIN = "vmArgsWin"; //$NON-NLS-1$
83 
84 	private static final String SOLARIS_LARGE = "solarisLarge"; //$NON-NLS-1$
85 	private static final String SOLARIS_MEDIUM = "solarisMedium"; //$NON-NLS-1$
86 	private static final String SOLARIS_SMALL = "solarisSmall"; //$NON-NLS-1$
87 	private static final String SOLARIS_TINY = "solarisTiny"; //$NON-NLS-1$
88 	private static final String WIN32_16_LOW = "winSmallLow"; //$NON-NLS-1$
89 	private static final String WIN32_16_HIGH = "winSmallHigh"; //$NON-NLS-1$
90 	private static final String WIN32_24_LOW = "win24Low"; //$NON-NLS-1$
91 	private static final String WIN32_32_LOW = "winMediumLow"; //$NON-NLS-1$
92 	private static final String WIN32_32_HIGH = "winMediumHigh"; //$NON-NLS-1$
93 	private static final String WIN32_48_LOW = "winLargeLow"; //$NON-NLS-1$
94 	private static final String WIN32_48_HIGH = "winLargeHigh"; //$NON-NLS-1$
95 	private static final String WIN32_256_HIGH = "winExtraLargeHigh"; //$NON-NLS-1$
96 
97 	private static final String OS_WIN32 = "win32";//$NON-NLS-1$
98 	private static final String OS_LINUX = "linux";//$NON-NLS-1$
99 	private static final String OS_SOLARIS = "solaris";//$NON-NLS-1$
100 	private static final String OS_MACOSX = "macosx";//$NON-NLS-1$
101 	private static final String OS_MACOS = "macos";//$NON-NLS-1$
102 	private static final String OS_WINDOWS = "windows";//$NON-NLS-1$
103 
104 	// These must match Platform constant values
105 	private static final String ARCH_X86 = "x86"; //$NON-NLS-1$
106 	private static final String ARCH_X86_64 = "x86_64"; //$NON-NLS-1$
107 	private static final String ARCH_PPC = "ppc"; //$NON-NLS-1$
108 	private static final String ARCH_IA_64 = "ia64"; //$NON-NLS-1$
109 	private static final String ARCH_IA_64_32 = "ia64_32"; //$NON-NLS-1$
110 	private static final String ARCH_PA_RISC = "PA_RISC"; //$NON-NLS-1$
111 	private static final String ARCH_SPARC = "sparc"; //$NON-NLS-1$
112 
113 	//element names
114 	private static final String EL_FEATURES = "features"; //$NON-NLS-1$
115 	private static final String EL_FEATURE = "feature"; //$NON-NLS-1$
116 	private static final String EL_PLUGINS = "plugins"; //$NON-NLS-1$
117 	private static final String EL_PLUGIN = "plugin"; //$NON-NLS-1$
118 	private static final String EL_PRODUCT = "product"; //$NON-NLS-1$
119 	private static final String EL_PROPERTY = "property"; //$NON-NLS-1$
120 	private static final String EL_CONFIG_INI = "configIni"; //$NON-NLS-1$
121 	private static final String EL_LAUNCHER = "launcher"; //$NON-NLS-1$
122 	private static final String EL_LAUNCHER_ARGS = "launcherArgs"; //$NON-NLS-1$
123 	private static final String EL_SPLASH = "splash"; //$NON-NLS-1$
124 	private static final String EL_CONFIGURATIONS = "configurations"; //$NON-NLS-1$
125 	private static final String EL_LICENSE = "license"; //$NON-NLS-1$
126 	private static final String EL_URL = "url"; //$NON-NLS-1$
127 	private static final String EL_TEXT = "text"; //$NON-NLS-1$
128 	private static final String EL_ARCH_X86 = "argsX86"; //$NON-NLS-1$
129 	private static final String EL_ARCH_X86_64 = "argsX86_64"; //$NON-NLS-1$
130 	private static final String EL_ARCH_PPC = "argsPPC"; //$NON-NLS-1$
131 	private static final String EL_ARCH_IA_64 = "argsIA_64"; //$NON-NLS-1$
132 	private static final String EL_ARCH_IA_64_32 = "argsIA_64_32"; //$NON-NLS-1$
133 	private static final String EL_ARCH_PA_RISC = "argsPA_RISC"; //$NON-NLS-1$
134 	private static final String EL_ARCH_SPARC = "argsSPARC"; //$NON-NLS-1$
135 	private static final String EL_REPOSITORIES = "repositories"; //$NON-NLS-1$
136 	private static final String EL_REPOSITORY = "repository"; //$NON-NLS-1$
137 
138 	//These constants form a small state machine to parse the .product file
139 	private static final int STATE_START = 0;
140 	private static final int STATE_PRODUCT = 1;
141 	private static final int STATE_LAUNCHER = 2;
142 	private static final int STATE_LAUNCHER_ARGS = 3;
143 	private static final int STATE_PLUGINS = 4;
144 	private static final int STATE_FEATURES = 5;
145 	private static final int STATE_PROGRAM_ARGS = 6;
146 	private static final int STATE_PROGRAM_ARGS_LINUX = 7;
147 	private static final int STATE_PROGRAM_ARGS_MAC = 8;
148 	private static final int STATE_PROGRAM_ARGS_SOLARIS = 9;
149 	private static final int STATE_PROGRAM_ARGS_WIN = 10;
150 	private static final int STATE_VM_ARGS = 11;
151 	private static final int STATE_VM_ARGS_LINUX = 12;
152 	private static final int STATE_VM_ARGS_MAC = 13;
153 	private static final int STATE_VM_ARGS_SOLARIS = 14;
154 	private static final int STATE_VM_ARGS_WIN = 15;
155 	private static final int STATE_CONFIG_INI = 16;
156 	private static final int STATE_CONFIGURATIONS = 17;
157 	private static final int STATE_LICENSE = 18;
158 	private static final int STATE_LICENSE_URL = 19;
159 	private static final int STATE_LICENSE_TEXT = 20;
160 	private static final int STATE_ARCH_X86 = 21;
161 	private static final int STATE_ARCH_X86_64 = 22;
162 	private static final int STATE_ARCH_PPC = 23;
163 	private static final int STATE_ARCH_IA_64 = 24;
164 	private static final int STATE_ARCH_IA_64_32 = 25;
165 	private static final int STATE_ARCH_PA_RISC = 26;
166 	private static final int STATE_ARCH_SPARC = 27;
167 	private static final int STATE_REPOSITORIES = 28;
168 	private static final int STATE_VM = 29;
169 	private static final int STATE_VM_LINUX = 31;
170 	private static final int STATE_VM_MACOS = 32;
171 	private static final int STATE_VM_WINDOWS = 33;
172 
173 	private static final String PI_PDEBUILD = "org.eclipse.pde.build"; //$NON-NLS-1$
174 	private final static int EXCEPTION_PRODUCT_FORMAT = 23;
175 	private final static int EXCEPTION_PRODUCT_FILE = 24;
176 
177 	private int state = STATE_START;
178 	private int outerState = STATE_START;
179 	private String platformKeyPrefix = null;
180 
181 	private SAXParser parser;
182 	private String launcherName = null;
183 	//	private boolean useIco = false;
184 	private final Map<String, Collection<String>> icons = new HashMap<>(6);
185 	private String configPath = null;
186 	private final Map<String, String> platformSpecificConfigPaths = new HashMap<>();
187 	private String configPlatform = null;
188 	private String platformConfigPath = null;
189 	private String id = null;
190 	private String uid = null;
191 	private ProductContentType productContentType = null;
192 	protected List<FeatureEntry> plugins = new ArrayList<>();
193 	protected List<FeatureEntry> fragments = new ArrayList<>();
194 	private final List<FeatureEntry> features = new ArrayList<>();
195 	private final List<FeatureEntry> rootFeatures = new ArrayList<>();
196 	private String splashLocation = null;
197 	private String productName = null;
198 	private String application = null;
199 	private String version = null;
200 	private Properties launcherArgs = new Properties();
201 	private final File location;
202 	private List<BundleInfo> bundleInfos;
203 	private Map<String, String> properties;
204 	private HashMap<String, HashMap<String, String>> filteredProperties;
205 	private boolean includeLaunchers = true;
206 	private String licenseURL;
207 	private String licenseText = null;
208 	private final String currentOS;
209 	private final List<IRepositoryReference> repositories = new ArrayList<>();
210 	private final Map<String, String> vms = new HashMap<>();
211 
normalize(String text)212 	private static String normalize(String text) {
213 		if (text == null || text.trim().length() == 0)
214 			return ""; //$NON-NLS-1$
215 
216 		StringBuilder result = new StringBuilder(text.length());
217 		boolean haveSpace = false;
218 		for (int i = 0; i < text.length(); i++) {
219 			char c = text.charAt(i);
220 			if (Character.isWhitespace(c)) {
221 				if (haveSpace)
222 					continue;
223 				haveSpace = true;
224 				result.append(" "); //$NON-NLS-1$
225 			} else {
226 				haveSpace = false;
227 				result.append(c);
228 			}
229 		}
230 		return result.toString();
231 	}
232 
ProductFile(String location, String os)233 	public ProductFile(String location, String os) throws CoreException {
234 		this.currentOS = os;
235 		this.location = new File(location);
236 		try {
237 			SAXParserFactory parserFactory = SecureXMLUtil.newSecureSAXParserFactory();
238 			parserFactory.setNamespaceAware(true);
239 			parser = parserFactory.newSAXParser();
240 			InputStream in = new BufferedInputStream(new FileInputStream(location));
241 			try {
242 				parser.parse(new InputSource(in), this);
243 			} finally {
244 				try {
245 					in.close();
246 				} catch (IOException e) {
247 					// ignore exception on close (as it was done by Utils.close() before)
248 				}
249 			}
250 		} catch (ParserConfigurationException e) {
251 			throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e));
252 		} catch (SAXException e) {
253 			throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e));
254 		} catch (FileNotFoundException e) {
255 			throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FILE, NLS.bind(Messages.exception_missingElement, location), null));
256 		} catch (IOException e) {
257 			throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e));
258 		}
259 	}
260 
261 	/**
262 	 * Constructs a product file parser.
263 	 */
ProductFile(String location)264 	public ProductFile(String location) throws Exception {
265 		this(location, null);
266 	}
267 
268 	/**
269 	 * Gets the name of the launcher specified in the .product file.
270 	 */
271 	@Override
getLauncherName()272 	public String getLauncherName() {
273 		return launcherName;
274 	}
275 
276 	/**
277 	 * Gets the location of the .product file.
278 	 */
279 	@Override
getLocation()280 	public File getLocation() {
281 		return location;
282 	}
283 
284 	/**
285 	 * Returns the properties found in .product file.  Properties
286 	 * are located in the <configurations> block of the file
287 	 */
288 	@Override
getConfigurationProperties()289 	public Map<String, String> getConfigurationProperties() {
290 		return getConfigurationProperties(null, null);
291 	}
292 
293 	/**
294 	 * Returns the properties found in .product file that are valid
295 	 * for the specified platform os and architecture.  If there is no
296 	 * platform os and/or architecture specified, return only the properties
297 	 * that are not filtered by the unspecified os and/or arch.
298 	 * Properties are located in the <configurations> block of the file
299 	 */
300 	@Override
getConfigurationProperties(String os, String arch)301 	public Map<String, String> getConfigurationProperties(String os, String arch) {
302 		// add all generic properties
303 		Map<String, String> result = properties != null ? properties : new HashMap<>();
304 		// add any properties filtered on os and/or arch
305 		if (filteredProperties != null) {
306 			String[] filteredKeys = new String[3]; // ".arch", "os.", "os.arch"
307 			if (os == null) {
308 				// only arch is specified. Provide properties defined for
309 				// all os and a specific architecture
310 				if (arch != null && arch.length() > 0) {
311 					filteredKeys[0] = "." + arch; //$NON-NLS-1$
312 				}
313 			} else {
314 				if (arch == null) {
315 					// only os is specified. Provide properties defined for
316 					// specific os and all architectures.
317 					filteredKeys[1] = os + "."; //$NON-NLS-1$
318 				} else {
319 					// os and arch specified. Provide properties defined for
320 					// the os, for the arch, and for both
321 					filteredKeys[0] = "." + arch; //$NON-NLS-1$
322 					filteredKeys[1] = os + "."; //$NON-NLS-1$
323 					filteredKeys[2] = os + "." + arch; //$NON-NLS-1$
324 				}
325 			}
326 			for (String filteredKey : filteredKeys) {
327 				if (filteredKey != null) {
328 					// copy all mappings that are filtered for this os and/or arch
329 					HashMap<String, String> innerMap = filteredProperties.get(filteredKey);
330 					if (innerMap != null) {
331 						result.putAll(innerMap);
332 					}
333 				}
334 			}
335 		}
336 		if (application != null && !result.containsKey(PROPERTY_ECLIPSE_APPLICATION))
337 			result.put(PROPERTY_ECLIPSE_APPLICATION, application);
338 		if (id != null && !result.containsKey(PROPERTY_ECLIPSE_PRODUCT))
339 			result.put(PROPERTY_ECLIPSE_PRODUCT, id);
340 
341 		return result;
342 	}
343 
344 	/**
345 	 * Returns a List<VersionedName> for each bundle that makes up this product.
346 	 * @param includeFragments Indicates whether or not fragments should
347 	 * be included in the list
348 	 */
349 	@Override
getBundles(boolean includeFragments)350 	public List<IVersionedId> getBundles(boolean includeFragments) {
351 		List<IVersionedId> result = new LinkedList<>();
352 
353 		for (FeatureEntry plugin : plugins) {
354 			result.add(new VersionedId(plugin.getId(), plugin.getVersion()));
355 		}
356 
357 		if (includeFragments) {
358 			for (FeatureEntry fragment : fragments) {
359 				result.add(new VersionedId(fragment.getId(), fragment.getVersion()));
360 			}
361 		}
362 
363 		return result;
364 	}
365 
366 	@Override
hasBundles(boolean includeFragments)367 	public boolean hasBundles(boolean includeFragments) {
368 		// implement directly; don't call the potentially overridden getBundles
369 		return !plugins.isEmpty() || (includeFragments && !fragments.isEmpty());
370 	}
371 
getBundleEntries(boolean includeFragments)372 	private List<FeatureEntry> getBundleEntries(boolean includeFragments) {
373 		List<FeatureEntry> result = new LinkedList<>();
374 		result.addAll(plugins);
375 		if (includeFragments)
376 			result.addAll(fragments);
377 		return result;
378 	}
379 
380 	/**
381 	 * Returns a List<BundleInfo> for each bundle that has custom configuration data
382 	 * in the product file.
383 	 * @return A List<BundleInfo>
384 	 */
385 	@Override
getBundleInfos()386 	public List<BundleInfo> getBundleInfos() {
387 		return bundleInfos != null ? bundleInfos : Collections.emptyList();
388 	}
389 
390 	/**
391 	 * Returns a list<VersionedName> of fragments that constitute this product.
392 	 */
393 	@Override
getFragments()394 	public List<IVersionedId> getFragments() {
395 		List<IVersionedId> result = new LinkedList<>();
396 
397 		for (FeatureEntry fragment : fragments) {
398 			result.add(new VersionedId(fragment.getId(), fragment.getVersion()));
399 		}
400 
401 		return result;
402 	}
403 
404 	/**
405 	 * Returns a List<VersionedName> of features that constitute this product.
406 	 */
407 	@Override
getFeatures()408 	public List<IVersionedId> getFeatures() {
409 		return getFeatures(INCLUDED_FEATURES);
410 	}
411 
412 	@Override
hasFeatures()413 	public boolean hasFeatures() {
414 		// implement directly; don't call the potentially overridden getFeatures
415 		return !features.isEmpty();
416 	}
417 
418 	@Override
getFeatures(int options)419 	public List<IVersionedId> getFeatures(int options) {
420 		List<IVersionedId> result = new LinkedList<>();
421 
422 		if ((options & INCLUDED_FEATURES) != 0) {
423 			for (FeatureEntry feature : features) {
424 				result.add(new VersionedId(feature.getId(), feature.getVersion()));
425 			}
426 		}
427 		if ((options & ROOT_FEATURES) != 0) {
428 			for (FeatureEntry feature : rootFeatures) {
429 				result.add(new VersionedId(feature.getId(), feature.getVersion()));
430 			}
431 		}
432 
433 		return result;
434 	}
435 
getProductEntries()436 	public List<FeatureEntry> getProductEntries() {
437 		if (useFeatures()) {
438 			return features;
439 		}
440 		return getBundleEntries(true);
441 	}
442 
containsPlugin(String plugin)443 	public boolean containsPlugin(String plugin) {
444 		List<IVersionedId> bundles = getBundles(true);
445 		for (IVersionedId versionedId : bundles) {
446 			if (versionedId.getId().equals(plugin)) {
447 				return true;
448 			}
449 		}
450 		return false;
451 	}
452 
getIcons()453 	public String[] getIcons() {
454 		return getIcons(currentOS);
455 	}
456 
457 	@Override
getIcons(String os)458 	public String[] getIcons(String os) {
459 		Collection<String> result = icons.get(os);
460 		if (result == null)
461 			return new String[0];
462 		return result.toArray(new String[result.size()]);
463 	}
464 
465 	@Override
getConfigIniPath(String os)466 	public String getConfigIniPath(String os) {
467 		String specific = platformSpecificConfigPaths.get(os);
468 		return specific == null ? configPath : specific;
469 	}
470 
getConfigIniPath()471 	public String getConfigIniPath() {
472 		return configPath;
473 	}
474 
haveCustomConfig()475 	public boolean haveCustomConfig() {
476 		return configPath != null || platformSpecificConfigPaths.size() > 0;
477 	}
478 
479 	/**
480 	 * Returns the ID for this product.
481 	 */
482 	@Override
getId()483 	public String getId() {
484 		if (uid != null)
485 			return uid;
486 		return id;
487 	}
488 
489 	@Override
getProductId()490 	public String getProductId() {
491 		return id;
492 	}
493 
494 	/**
495 	 * Returns the location (the bundle) that defines the splash screen
496 	 */
497 	@Override
getSplashLocation()498 	public String getSplashLocation() {
499 		return splashLocation;
500 	}
501 
502 	/**
503 	 * Returns the product name.
504 	 */
505 	@Override
getProductName()506 	public String getProductName() {
507 		return productName;
508 	}
509 
510 	/**
511 	 * Returns the application identifier for this product.
512 	 */
513 	@Override
getApplication()514 	public String getApplication() {
515 		return application;
516 	}
517 
518 	/**
519 	 * Returns true if this product is built using feature,
520 	 * false otherwise.
521 	 */
522 	@Override
useFeatures()523 	public boolean useFeatures() {
524 		return productContentType == ProductContentType.FEATURES;
525 	}
526 
527 	/**
528 	 * Returns the version of the product
529 	 */
530 	@Override
getVersion()531 	public String getVersion() {
532 		return (version == null || version.length() == 0) ? "0.0.0" : version; //$NON-NLS-1$
533 	}
534 
535 	@Override
includeLaunchers()536 	public boolean includeLaunchers() {
537 		return includeLaunchers;
538 	}
539 
getConfigurationInfo()540 	public Map<String, BundleInfo> getConfigurationInfo() {
541 		Map<String, BundleInfo> result = new HashMap<>();
542 		for (BundleInfo info : getBundleInfos()) {
543 			result.put(info.getSymbolicName(), info);
544 		}
545 		return result;
546 	}
547 
getConfigProperties()548 	public Properties getConfigProperties() {
549 		Properties props = new Properties();
550 		for (Entry<String, String> property : getConfigurationProperties().entrySet()) {
551 			props.setProperty(property.getKey(), property.getValue());
552 		}
553 		return props;
554 	}
555 
556 	/**
557 	 * Returns the VM arguments for a specific platform.
558 	 * If the empty string is used for the OS, this returns
559 	 * the default VM arguments
560 	 */
561 	@Override
getVMArguments(String os)562 	public String getVMArguments(String os) {
563 		return getVMArguments(os, null);
564 	}
565 
566 	/**
567 	 * Returns the VM arguments for a specific platform and architecture
568 	 * combination. If the empty string is used for the architecture, this
569 	 * returns the default arguments for the platform.  If the empty string is
570 	 * used for the OS, this returns the default VM arguments.
571 	 */
572 	@Override
getVMArguments(String os, String arch)573 	public String getVMArguments(String os, String arch) {
574 		os = os == null ? "" : os; //$NON-NLS-1$
575 		String key = null;
576 		switch (os) {
577 			case OS_WIN32:
578 				key = VM_ARGS_WIN;
579 				break;
580 			case OS_LINUX:
581 				key = VM_ARGS_LINUX;
582 				break;
583 			case OS_MACOSX:
584 				key = VM_ARGS_MAC;
585 				break;
586 			case OS_SOLARIS:
587 				key = VM_ARGS_SOLARIS;
588 				break;
589 			default:
590 				break;
591 		}
592 
593 		arch = arch == null ? "" : arch; //$NON-NLS-1$
594 		String archKey = null;
595 		switch (arch) {
596 			case ARCH_X86:
597 				archKey = EL_ARCH_X86;
598 				break;
599 			case ARCH_X86_64:
600 				archKey = EL_ARCH_X86_64;
601 				break;
602 			case ARCH_PPC:
603 				archKey = EL_ARCH_PPC;
604 				break;
605 			case ARCH_IA_64:
606 				archKey = EL_ARCH_IA_64;
607 				break;
608 			case ARCH_IA_64_32:
609 				archKey = EL_ARCH_IA_64_32;
610 				break;
611 			case ARCH_PA_RISC:
612 				archKey = EL_ARCH_PA_RISC;
613 				break;
614 			case ARCH_SPARC:
615 				archKey = EL_ARCH_SPARC;
616 				break;
617 			default:
618 				break;
619 		}
620 
621 		String platformArchKey = null;
622 		String defaults = launcherArgs.getProperty(VM_ARGS);
623 		// architecture arguments independent of platform should be part
624 		// of the defaults.
625 		if (archKey != null) {
626 			String archOnAllPlatforms = launcherArgs.getProperty(VM_ARGS + "." + archKey); //$NON-NLS-1$
627 			if (archOnAllPlatforms != null && archOnAllPlatforms.length() > 0) {
628 				defaults = defaults + " " + archOnAllPlatforms; //$NON-NLS-1$
629 			}
630 		}
631 		String platform = null, platformAndArch = null, args = null;
632 		if (key != null) {
633 			// a platform with no arch specified
634 			platform = launcherArgs.getProperty(key);
635 			// platform + arch
636 			if (archKey != null) {
637 				platformArchKey = key + "." + archKey; //$NON-NLS-1$
638 				platformAndArch = launcherArgs.getProperty(platformArchKey);
639 			}
640 		}
641 		if (defaults != null) {
642 			if (platform != null)
643 				args = platformAndArch != null ? defaults + " " + platform + " " + platformAndArch : defaults + " " + platform; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
644 			else
645 				args = defaults;
646 		} else {
647 			if (platform != null)
648 				args = platformAndArch != null ? platform + " " + platformAndArch : platform; //$NON-NLS-1$
649 			else
650 				args = platformAndArch != null ? platformAndArch : ""; //$NON-NLS-1$
651 		}
652 		return normalize(args);
653 	}
654 
655 	/**
656 	 * Returns the program arguments for a specific platform.
657 	 * If the empty string is used for the OS, this returns
658 	 * the default program arguments
659 	 */
660 	@Override
getProgramArguments(String os)661 	public String getProgramArguments(String os) {
662 		return getProgramArguments(os, null);
663 	}
664 
665 	/**
666 	 * Returns the program arguments for a specific platform.
667 	 * If the empty string is used for the OS, this returns
668 	 * the default program arguments
669 	 */
670 	@Override
getProgramArguments(String os, String arch)671 	public String getProgramArguments(String os, String arch) {
672 		os = os == null ? "" : os; //$NON-NLS-1$
673 		String key = null;
674 		switch (os) {
675 			case OS_WIN32:
676 				key = PROGRAM_ARGS_WIN;
677 				break;
678 			case OS_LINUX:
679 				key = PROGRAM_ARGS_LINUX;
680 				break;
681 			case OS_MACOSX:
682 				key = PROGRAM_ARGS_MAC;
683 				break;
684 			case OS_SOLARIS:
685 				key = PROGRAM_ARGS_SOLARIS;
686 				break;
687 			default:
688 				break;
689 		}
690 
691 		arch = arch == null ? "" : arch; //$NON-NLS-1$
692 		String archKey = null;
693 		switch (arch) {
694 			case ARCH_X86:
695 				archKey = EL_ARCH_X86;
696 				break;
697 			case ARCH_X86_64:
698 				archKey = EL_ARCH_X86_64;
699 				break;
700 			case ARCH_PPC:
701 				archKey = EL_ARCH_PPC;
702 				break;
703 			case ARCH_IA_64:
704 				archKey = EL_ARCH_IA_64;
705 				break;
706 			case ARCH_IA_64_32:
707 				archKey = EL_ARCH_IA_64_32;
708 				break;
709 			case ARCH_PA_RISC:
710 				archKey = EL_ARCH_PA_RISC;
711 				break;
712 			case ARCH_SPARC:
713 				archKey = EL_ARCH_SPARC;
714 				break;
715 			default:
716 				break;
717 		}
718 
719 		String platformArchKey = null;
720 		String defaults = launcherArgs.getProperty(PROGRAM_ARGS);
721 		// architecture arguments independent of platform should be part
722 		// of the defaults.
723 		if (archKey != null) {
724 			String archOnAllPlatforms = launcherArgs.getProperty(PROGRAM_ARGS + "." + archKey); //$NON-NLS-1$
725 			if (archOnAllPlatforms != null && archOnAllPlatforms.length() > 0) {
726 				defaults = defaults + " " + archOnAllPlatforms; //$NON-NLS-1$
727 			}
728 		}
729 		String platform = null, platformAndArch = null, args = null;
730 		if (key != null) {
731 			// a platform with no arch specified
732 			platform = launcherArgs.getProperty(key);
733 			// platform + arch
734 			if (archKey != null) {
735 				platformArchKey = key + "." + archKey; //$NON-NLS-1$
736 				platformAndArch = launcherArgs.getProperty(platformArchKey);
737 			}
738 		}
739 		if (defaults != null) {
740 			if (platform != null)
741 				args = platformAndArch != null ? defaults + " " + platform + " " + platformAndArch : defaults + " " + platform; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
742 			else
743 				args = defaults;
744 		} else {
745 			if (platform != null)
746 				args = platformAndArch != null ? platform + " " + platformAndArch : platform; //$NON-NLS-1$
747 			else
748 				args = platformAndArch != null ? platformAndArch : ""; //$NON-NLS-1$
749 		}
750 		return normalize(args);
751 	}
752 
753 	@Override
getLicenseText()754 	public String getLicenseText() {
755 		return licenseText;
756 	}
757 
758 	@Override
getLicenseURL()759 	public String getLicenseURL() {
760 		return licenseURL;
761 	}
762 
763 	@Override
getRepositoryEntries()764 	public List<IRepositoryReference> getRepositoryEntries() {
765 		return repositories;
766 	}
767 
768 	@Override
startElement(String uri, String localName, String qName, Attributes attributes)769 	public void startElement(String uri, String localName, String qName, Attributes attributes) {
770 		switch (state) {
771 			case STATE_START :
772 				if (EL_PRODUCT.equals(localName)) {
773 					processProduct(attributes);
774 					state = STATE_PRODUCT;
775 				}
776 				break;
777 
778 			case STATE_PRODUCT :
779 				if (null != localName) switch (localName) {
780 					case EL_CONFIG_INI:
781 						processConfigIni(attributes);
782 						state = STATE_CONFIG_INI;
783 						break;
784 					case EL_LAUNCHER:
785 						processLauncher(attributes);
786 						state = STATE_LAUNCHER;
787 						break;
788 					case EL_PLUGINS:
789 						state = STATE_PLUGINS;
790 						break;
791 					case EL_FEATURES:
792 						state = STATE_FEATURES;
793 						break;
794 					case EL_LAUNCHER_ARGS:
795 						state = STATE_LAUNCHER_ARGS;
796 						break;
797 					case EL_SPLASH:
798 						splashLocation = attributes.getValue(ATTRIBUTE_LOCATION);
799 						break;
800 					case EL_CONFIGURATIONS:
801 						state = STATE_CONFIGURATIONS;
802 						break;
803 					case EL_LICENSE:
804 						state = STATE_LICENSE;
805 						break;
806 					case EL_REPOSITORIES:
807 						state = STATE_REPOSITORIES;
808 						break;
809 					case VM:
810 						state = STATE_VM;
811 						break;
812 					default:
813 						break;
814 				}
815 				break;
816 
817 
818 			case STATE_CONFIG_INI :
819 				processConfigIniPlatform(localName, true);
820 				break;
821 
822 			case STATE_LAUNCHER :
823 				if (null != localName) switch (localName) {
824 					case OS_SOLARIS:
825 						processSolaris(attributes);
826 						break;
827 					case "win": //$NON-NLS-1$
828 						processWin(attributes);
829 						break;
830 					case OS_LINUX:
831 						processLinux(attributes);
832 						break;
833 					case OS_MACOSX:
834 						processMac(attributes);
835 						break;
836 					default:
837 						break;
838 				}
839 				if ("ico".equals(localName)) { //$NON-NLS-1$
840 					processIco(attributes);
841 				} else if ("bmp".equals(localName)) { //$NON-NLS-1$
842 					processBmp(attributes);
843 				}
844 				break;
845 
846 
847 			case STATE_LAUNCHER_ARGS :
848 				if (null != localName) switch (localName) {
849 					case PROGRAM_ARGS:
850 						state = STATE_PROGRAM_ARGS;
851 						break;
852 					case PROGRAM_ARGS_LINUX:
853 						state = STATE_PROGRAM_ARGS_LINUX;
854 						break;
855 					case PROGRAM_ARGS_MAC:
856 						state = STATE_PROGRAM_ARGS_MAC;
857 						break;
858 					case PROGRAM_ARGS_SOLARIS:
859 						state = STATE_PROGRAM_ARGS_SOLARIS;
860 						break;
861 					case PROGRAM_ARGS_WIN:
862 						state = STATE_PROGRAM_ARGS_WIN;
863 						break;
864 					case VM_ARGS:
865 						state = STATE_VM_ARGS;
866 						break;
867 					case VM_ARGS_LINUX:
868 						state = STATE_VM_ARGS_LINUX;
869 						break;
870 					case VM_ARGS_MAC:
871 						state = STATE_VM_ARGS_MAC;
872 						break;
873 					case VM_ARGS_SOLARIS:
874 						state = STATE_VM_ARGS_SOLARIS;
875 						break;
876 					case VM_ARGS_WIN:
877 						state = STATE_VM_ARGS_WIN;
878 						break;
879 					default:
880 						break;
881 				}
882 				break;
883 
884 
885 			// For all argument states.  Set a platform key prefix representing
886 			// the outer state (platform) of the launcher arguments and then
887 			// set the state of the inner state (architecture).
888 			case STATE_PROGRAM_ARGS :
889 				platformKeyPrefix = PROGRAM_ARGS;
890 				setArchState(localName);
891 				break;
892 
893 			case STATE_PROGRAM_ARGS_LINUX :
894 				platformKeyPrefix = PROGRAM_ARGS_LINUX;
895 				setArchState(localName);
896 				break;
897 
898 			case STATE_PROGRAM_ARGS_MAC :
899 				platformKeyPrefix = PROGRAM_ARGS_MAC;
900 				setArchState(localName);
901 				break;
902 
903 			case STATE_PROGRAM_ARGS_SOLARIS :
904 				platformKeyPrefix = PROGRAM_ARGS_SOLARIS;
905 				setArchState(localName);
906 				break;
907 
908 			case STATE_PROGRAM_ARGS_WIN :
909 				platformKeyPrefix = PROGRAM_ARGS_WIN;
910 				setArchState(localName);
911 				break;
912 
913 			case STATE_VM_ARGS :
914 				platformKeyPrefix = VM_ARGS;
915 				setArchState(localName);
916 				break;
917 
918 			case STATE_VM_ARGS_LINUX :
919 				platformKeyPrefix = VM_ARGS_LINUX;
920 				setArchState(localName);
921 				break;
922 
923 			case STATE_VM_ARGS_MAC :
924 				platformKeyPrefix = VM_ARGS_MAC;
925 				setArchState(localName);
926 				break;
927 
928 			case STATE_VM_ARGS_SOLARIS :
929 				platformKeyPrefix = VM_ARGS_SOLARIS;
930 				setArchState(localName);
931 				break;
932 
933 			case STATE_VM_ARGS_WIN :
934 				platformKeyPrefix = VM_ARGS_WIN;
935 				setArchState(localName);
936 				break;
937 
938 			case STATE_PLUGINS :
939 				if (EL_PLUGIN.equals(localName)) {
940 					processPlugin(attributes);
941 				}
942 				break;
943 
944 			case STATE_REPOSITORIES :
945 				if (EL_REPOSITORY.equals(localName)) {
946 					processRepositoryInformation(attributes);
947 				}
948 				break;
949 
950 			case STATE_LICENSE :
951 				if (EL_URL.equals(localName)) {
952 					state = STATE_LICENSE_URL;
953 				} else if (EL_TEXT.equals(localName)) {
954 					licenseText = ""; //$NON-NLS-1$
955 					state = STATE_LICENSE_TEXT;
956 				}
957 				break;
958 
959 			case STATE_FEATURES :
960 				if (EL_FEATURE.equals(localName)) {
961 					processFeature(attributes);
962 				}
963 				break;
964 			case STATE_CONFIGURATIONS :
965 				if (EL_PLUGIN.equals(localName)) {
966 					processPluginConfiguration(attributes);
967 				} else if (EL_PROPERTY.equals(localName)) {
968 					processPropertyConfiguration(attributes);
969 				}
970 				break;
971 
972 			case STATE_VM :
973 				if (null != localName) switch (localName) {
974 					case OS_LINUX:
975 						state = STATE_VM_LINUX;
976 						break;
977 					case OS_WINDOWS:
978 						state = STATE_VM_WINDOWS;
979 						break;
980 					case OS_MACOS:
981 						state = STATE_VM_MACOS;
982 						break;
983 					default:
984 						break;
985 				}
986 				break;
987 
988 		}
989 	}
990 
setArchState(String archName)991 	private void setArchState(String archName) {
992 		outerState = state;
993 		if (null != archName) switch (archName) {
994 			case EL_ARCH_X86:
995 				state = STATE_ARCH_X86;
996 				break;
997 			case EL_ARCH_X86_64:
998 				state = STATE_ARCH_X86_64;
999 				break;
1000 			case EL_ARCH_PPC:
1001 				state = STATE_ARCH_PPC;
1002 				break;
1003 			case EL_ARCH_IA_64:
1004 				state = STATE_ARCH_IA_64;
1005 				break;
1006 			case EL_ARCH_IA_64_32:
1007 				state = STATE_ARCH_IA_64_32;
1008 				break;
1009 			case EL_ARCH_PA_RISC:
1010 				state = STATE_ARCH_PA_RISC;
1011 				break;
1012 			case EL_ARCH_SPARC:
1013 				state = STATE_ARCH_SPARC;
1014 				break;
1015 			default:
1016 				break;
1017 		}
1018 	}
1019 
1020 	/**
1021 	 * Processes the property tag in the .product file.  These tags contain
1022 	 * a Name and Value pair.  For each tag (with a non-null name), a property
1023 	 * is created.
1024 	 */
processPropertyConfiguration(Attributes attributes)1025 	private void processPropertyConfiguration(Attributes attributes) {
1026 		String name = attributes.getValue(ATTRIBUTE_NAME);
1027 		String value = attributes.getValue(ATTRIBUTE_VALUE);
1028 		String os = attributes.getValue(ATTRIBUTE_OS);
1029 		if (os == null)
1030 			os = ""; //$NON-NLS-1$
1031 		String arch = attributes.getValue(ATTRIBUTE_ARCH);
1032 		if (arch == null)
1033 			arch = ""; //$NON-NLS-1$
1034 		String propOSArchKey = os + "." + arch; //$NON-NLS-1$
1035 		if (name == null)
1036 			return;
1037 		if (value == null)
1038 			value = ""; //$NON-NLS-1$
1039 		if (propOSArchKey.length() <= 1) {
1040 			// this is a generic property for all platforms and arch
1041 			if (properties == null)
1042 				properties = new HashMap<>();
1043 			properties.put(name, value);
1044 		} else {
1045 			// store the property in the filtered map, keyed by "os.arch"
1046 			if (filteredProperties == null)
1047 				filteredProperties = new HashMap<>();
1048 			HashMap<String, String> filteredMap = filteredProperties.get(propOSArchKey);
1049 			if (filteredMap == null) {
1050 				filteredMap = new HashMap<>();
1051 				filteredProperties.put(propOSArchKey, filteredMap);
1052 			}
1053 			filteredMap.put(name, value);
1054 		}
1055 	}
1056 
processPluginConfiguration(Attributes attributes)1057 	private void processPluginConfiguration(Attributes attributes) {
1058 		BundleInfo info = new BundleInfo();
1059 		info.setSymbolicName(attributes.getValue(ATTRIBUTE_ID));
1060 		info.setVersion(attributes.getValue(ATTRIBUTE_VERSION));
1061 		String value = attributes.getValue(ATTRIBUTE_START_LEVEL);
1062 		if (value != null) {
1063 			int startLevel = Integer.parseInt(value);
1064 			if (startLevel > 0)
1065 				info.setStartLevel(startLevel);
1066 		}
1067 		value = attributes.getValue(ATTRIBUTE_AUTO_START);
1068 		if (value != null)
1069 			info.setMarkedAsStarted(Boolean.parseBoolean(value));
1070 		if (bundleInfos == null)
1071 			bundleInfos = new ArrayList<>();
1072 		bundleInfos.add(info);
1073 	}
1074 
processRepositoryInformation(Attributes attributes)1075 	private void processRepositoryInformation(Attributes attributes) {
1076 		try {
1077 			URI uri = URIUtil.fromString(attributes.getValue(ATTRIBUTE_LOCATION));
1078 			boolean enabled = Boolean.parseBoolean(attributes.getValue(ATTRIBUTE_ENABLED));
1079 			// First add a metadata repository
1080 			repositories.add(new RepositoryReference(uri, null, IRepository.TYPE_METADATA, enabled ? IRepository.ENABLED : IRepository.NONE));
1081 			// Now a colocated artifact repository
1082 			repositories.add(new RepositoryReference(uri, null, IRepository.TYPE_ARTIFACT, enabled ? IRepository.ENABLED : IRepository.NONE));
1083 		} catch (URISyntaxException e) {
1084 			// ignore malformed URI's. These should have already been caught by the UI
1085 		}
1086 	}
1087 
1088 	@Override
endElement(String uri, String localName, String qName)1089 	public void endElement(String uri, String localName, String qName) {
1090 		switch (state) {
1091 			case STATE_PLUGINS :
1092 				if (EL_PLUGINS.equals(localName))
1093 					state = STATE_PRODUCT;
1094 				break;
1095 			case STATE_FEATURES :
1096 				if (EL_FEATURES.equals(localName))
1097 					state = STATE_PRODUCT;
1098 				break;
1099 			case STATE_LAUNCHER_ARGS :
1100 				if (EL_LAUNCHER_ARGS.equals(localName))
1101 					state = STATE_PRODUCT;
1102 				break;
1103 			case STATE_LAUNCHER :
1104 				if (EL_LAUNCHER.equals(localName))
1105 					state = STATE_PRODUCT;
1106 				break;
1107 			case STATE_CONFIGURATIONS :
1108 				if (EL_CONFIGURATIONS.equals(localName))
1109 					state = STATE_PRODUCT;
1110 				break;
1111 			case STATE_LICENSE :
1112 				if (EL_LICENSE.equals(localName))
1113 					state = STATE_PRODUCT;
1114 				break;
1115 			case STATE_VM :
1116 				state = STATE_PRODUCT;
1117 				break;
1118 			case STATE_VM_LINUX :
1119 			case STATE_VM_WINDOWS :
1120 			case STATE_VM_MACOS :
1121 				state = STATE_VM;
1122 				break;
1123 
1124 			case STATE_PROGRAM_ARGS :
1125 			case STATE_PROGRAM_ARGS_LINUX :
1126 			case STATE_PROGRAM_ARGS_MAC :
1127 			case STATE_PROGRAM_ARGS_SOLARIS :
1128 			case STATE_PROGRAM_ARGS_WIN :
1129 			case STATE_VM_ARGS :
1130 			case STATE_VM_ARGS_LINUX :
1131 			case STATE_VM_ARGS_MAC :
1132 			case STATE_VM_ARGS_SOLARIS :
1133 			case STATE_VM_ARGS_WIN :
1134 				state = STATE_LAUNCHER_ARGS;
1135 				break;
1136 			case STATE_LICENSE_URL :
1137 			case STATE_LICENSE_TEXT :
1138 				state = STATE_LICENSE;
1139 				break;
1140 
1141 			case STATE_ARCH_X86 :
1142 			case STATE_ARCH_X86_64 :
1143 			case STATE_ARCH_PPC :
1144 			case STATE_ARCH_IA_64 :
1145 			case STATE_ARCH_IA_64_32 :
1146 			case STATE_ARCH_PA_RISC :
1147 			case STATE_ARCH_SPARC :
1148 				state = outerState;
1149 				break;
1150 
1151 			case STATE_CONFIG_INI :
1152 				if (EL_CONFIG_INI.equals(localName))
1153 					state = STATE_PRODUCT;
1154 				else
1155 					processConfigIniPlatform(localName, false);
1156 				break;
1157 
1158 			case STATE_REPOSITORIES :
1159 				if (EL_REPOSITORIES.equals(localName))
1160 					state = STATE_PRODUCT;
1161 				break;
1162 
1163 		}
1164 	}
1165 
1166 	@Override
characters(char[] ch, int start, int length)1167 	public void characters(char[] ch, int start, int length) {
1168 		switch (state) {
1169 			case STATE_PROGRAM_ARGS :
1170 				addLaunchArgumentToMap(PROGRAM_ARGS, String.valueOf(ch, start, length));
1171 				break;
1172 			case STATE_PROGRAM_ARGS_LINUX :
1173 				addLaunchArgumentToMap(PROGRAM_ARGS_LINUX, String.valueOf(ch, start, length));
1174 				break;
1175 			case STATE_PROGRAM_ARGS_MAC :
1176 				addLaunchArgumentToMap(PROGRAM_ARGS_MAC, String.valueOf(ch, start, length));
1177 				break;
1178 			case STATE_PROGRAM_ARGS_SOLARIS :
1179 				addLaunchArgumentToMap(PROGRAM_ARGS_SOLARIS, String.valueOf(ch, start, length));
1180 				break;
1181 			case STATE_PROGRAM_ARGS_WIN :
1182 				addLaunchArgumentToMap(PROGRAM_ARGS_WIN, String.valueOf(ch, start, length));
1183 				break;
1184 			case STATE_VM_ARGS :
1185 				addLaunchArgumentToMap(VM_ARGS, String.valueOf(ch, start, length));
1186 				break;
1187 			case STATE_VM_ARGS_LINUX :
1188 				addLaunchArgumentToMap(VM_ARGS_LINUX, String.valueOf(ch, start, length));
1189 				break;
1190 			case STATE_VM_ARGS_MAC :
1191 				addLaunchArgumentToMap(VM_ARGS_MAC, String.valueOf(ch, start, length));
1192 				break;
1193 			case STATE_VM_ARGS_SOLARIS :
1194 				addLaunchArgumentToMap(VM_ARGS_SOLARIS, String.valueOf(ch, start, length));
1195 				break;
1196 			case STATE_VM_ARGS_WIN :
1197 				addLaunchArgumentToMap(VM_ARGS_WIN, String.valueOf(ch, start, length));
1198 				break;
1199 			case STATE_ARCH_X86 :
1200 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_X86, String.valueOf(ch, start, length)); //$NON-NLS-1$
1201 				break;
1202 			case STATE_ARCH_X86_64 :
1203 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_X86_64, String.valueOf(ch, start, length)); //$NON-NLS-1$
1204 				break;
1205 			case STATE_ARCH_PPC :
1206 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_PPC, String.valueOf(ch, start, length)); //$NON-NLS-1$
1207 				break;
1208 			case STATE_ARCH_IA_64 :
1209 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_IA_64, String.valueOf(ch, start, length)); //$NON-NLS-1$
1210 				break;
1211 			case STATE_ARCH_IA_64_32 :
1212 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_IA_64_32, String.valueOf(ch, start, length)); //$NON-NLS-1$
1213 				break;
1214 			case STATE_ARCH_PA_RISC :
1215 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_PA_RISC, String.valueOf(ch, start, length)); //$NON-NLS-1$
1216 				break;
1217 			case STATE_ARCH_SPARC :
1218 				addLaunchArgumentToMap(platformKeyPrefix + "." + EL_ARCH_SPARC, String.valueOf(ch, start, length)); //$NON-NLS-1$
1219 				break;
1220 			case STATE_CONFIG_INI :
1221 				if (platformConfigPath != null)
1222 					platformConfigPath += String.valueOf(ch, start, length);
1223 				break;
1224 			case STATE_LICENSE_URL :
1225 				licenseURL = String.valueOf(ch, start, length);
1226 				break;
1227 			case STATE_LICENSE_TEXT :
1228 				if (licenseText != null)
1229 					licenseText += String.valueOf(ch, start, length);
1230 				break;
1231 			case STATE_VM_LINUX :
1232 				addVM(OS_LINUX, String.valueOf(ch, start, length));
1233 				break;
1234 			case STATE_VM_WINDOWS :
1235 				addVM(OS_WINDOWS, String.valueOf(ch, start, length));
1236 				break;
1237 			case STATE_VM_MACOS :
1238 				addVM(OS_MACOS, String.valueOf(ch, start, length));
1239 				break;
1240 		}
1241 	}
1242 
addVM(String os, String vm)1243 	private void addVM(String os, String vm) {
1244 		vms.put(os, vm);
1245 	}
1246 
1247 	@Override
getVM(String os)1248 	public String getVM(String os) {
1249 		if (os.equals(OS_MACOSX)) {
1250 			os = OS_MACOS;
1251 		} else if (os.equals(OS_WIN32)) {
1252 			os = OS_WINDOWS;
1253 		}
1254 		return vms.get(os);
1255 	}
1256 
addLaunchArgumentToMap(String key, String value)1257 	private void addLaunchArgumentToMap(String key, String value) {
1258 		if (launcherArgs == null)
1259 			launcherArgs = new Properties();
1260 
1261 		String oldValue = launcherArgs.getProperty(key);
1262 		if (oldValue != null)
1263 			launcherArgs.setProperty(key, oldValue + value);
1264 		else
1265 			launcherArgs.setProperty(key, value);
1266 	}
1267 
processPlugin(Attributes attributes)1268 	protected void processPlugin(Attributes attributes) {
1269 		String fragment = attributes.getValue(ATTRIBUTE_FRAGMENT);
1270 		String pluginId = attributes.getValue(ATTRIBUTE_ID);
1271 		String pluginVersion = attributes.getValue(ATTRIBUTE_VERSION);
1272 
1273 		FeatureEntry entry = new FeatureEntry(pluginId, pluginVersion != null ? pluginVersion : GENERIC_VERSION_NUMBER, true);
1274 		entry.setFragment(Boolean.parseBoolean(fragment));
1275 
1276 		if (fragment != null && Boolean.parseBoolean(fragment)) {
1277 			fragments.add(entry);
1278 		} else {
1279 			plugins.add(entry);
1280 		}
1281 	}
1282 
processFeature(Attributes attributes)1283 	private void processFeature(Attributes attributes) {
1284 		String featureId = attributes.getValue(ATTRIBUTE_ID);
1285 		String featureVersion = attributes.getValue(ATTRIBUTE_VERSION);
1286 		FeatureInstallMode installMode = FeatureInstallMode.parse(attributes.getValue(ATTRIBUTE_FEATURE_INSTALL_MODE));
1287 		FeatureEntry featureEntry = new FeatureEntry(featureId, featureVersion != null ? featureVersion : GENERIC_VERSION_NUMBER, false);
1288 
1289 		switch (installMode) {
1290 			case ROOT :
1291 				rootFeatures.add(featureEntry);
1292 				break;
1293 			default :
1294 				features.add(featureEntry);
1295 		}
1296 	}
1297 
processProduct(Attributes attributes)1298 	private void processProduct(Attributes attributes) {
1299 		id = attributes.getValue(ATTRIBUTE_ID);
1300 		uid = attributes.getValue(ATTRIBUTE_UID);
1301 		productName = attributes.getValue(ATTRIBUTE_NAME);
1302 		application = attributes.getValue(ATTRIBUTE_APPLICATION);
1303 		if (attributes.getIndex(ATTRIBUTE_INCLUDE_LAUNCHERS) >= 0)
1304 			includeLaunchers = Boolean.valueOf(attributes.getValue(ATTRIBUTE_INCLUDE_LAUNCHERS));
1305 		String contentTypeString = attributes.getValue(ATTRIBUTE_CONTENT_TYPE);
1306 		if (contentTypeString != null)
1307 			productContentType = ProductContentType.toProductContentType(contentTypeString);
1308 		if (productContentType == null) { // useFeatures attribute is taken into account only if the contentType attribute is missing
1309 			String use = attributes.getValue("useFeatures"); //$NON-NLS-1$
1310 			// for backward compatibility with the old behavior
1311 			if (use != null && Boolean.parseBoolean(use))
1312 				productContentType = ProductContentType.FEATURES;
1313 			else
1314 				productContentType = ProductContentType.BUNDLES;
1315 		}
1316 
1317 		version = attributes.getValue(ATTRIBUTE_VERSION);
1318 	}
1319 
processConfigIni(Attributes attributes)1320 	private void processConfigIni(Attributes attributes) {
1321 		String path = null;
1322 		if ("custom".equals(attributes.getValue("use"))) { //$NON-NLS-1$//$NON-NLS-2$
1323 			path = attributes.getValue(ATTRIBUTE_PATH);
1324 		}
1325 		String os = attributes.getValue("os"); //$NON-NLS-1$
1326 		if (os != null && os.length() > 0) {
1327 			// TODO should we allow a platform-specific default to over-ride a custom generic path?
1328 			if (path != null)
1329 				platformSpecificConfigPaths.put(os, path);
1330 		} else if (path != null) {
1331 			configPath = path;
1332 		}
1333 	}
1334 
processConfigIniPlatform(String key, boolean begin)1335 	private void processConfigIniPlatform(String key, boolean begin) {
1336 		if (begin) {
1337 			configPlatform = key;
1338 			platformConfigPath = ""; //$NON-NLS-1$
1339 		} else if (configPlatform.equals(key) && platformConfigPath.length() > 0) {
1340 			platformSpecificConfigPaths.put(key, platformConfigPath);
1341 			platformConfigPath = null;
1342 		}
1343 	}
1344 
processLauncher(Attributes attributes)1345 	private void processLauncher(Attributes attributes) {
1346 		launcherName = attributes.getValue(ATTRIBUTE_NAME);
1347 	}
1348 
addIcon(String os, String value)1349 	private void addIcon(String os, String value) {
1350 		if (value == null)
1351 			return;
1352 
1353 		File iconFile = new File(value);
1354 		if (!iconFile.isFile()) {
1355 			//workspace
1356 			Location instanceLocation = ServiceHelper.getService(Activator.getContext(), Location.class, Location.INSTANCE_FILTER);
1357 			if (instanceLocation != null && instanceLocation.getURL() != null) {
1358 				File workspace = URLUtil.toFile(instanceLocation.getURL());
1359 				if (workspace != null)
1360 					iconFile = new File(workspace, value);
1361 			}
1362 		}
1363 		if (!iconFile.isFile())
1364 			iconFile = new File(location.getParentFile(), value);
1365 
1366 		Collection<String> list = icons.get(os);
1367 		if (list == null) {
1368 			list = new ArrayList<>(6);
1369 			icons.put(os, list);
1370 		}
1371 		list.add(iconFile.getAbsolutePath());
1372 	}
1373 
processSolaris(Attributes attributes)1374 	private void processSolaris(Attributes attributes) {
1375 		addIcon(OS_SOLARIS, attributes.getValue(SOLARIS_LARGE));
1376 		addIcon(OS_SOLARIS, attributes.getValue(SOLARIS_MEDIUM));
1377 		addIcon(OS_SOLARIS, attributes.getValue(SOLARIS_SMALL));
1378 		addIcon(OS_SOLARIS, attributes.getValue(SOLARIS_TINY));
1379 	}
1380 
processWin(Attributes attributes)1381 	private void processWin(Attributes attributes) {
1382 		//		useIco = Boolean.parseBoolean(attributes.getValue(P_USE_ICO));
1383 	}
1384 
processIco(Attributes attributes)1385 	private void processIco(Attributes attributes) {
1386 		addIcon(OS_WIN32, attributes.getValue(ATTRIBUTE_PATH));
1387 	}
1388 
processBmp(Attributes attributes)1389 	private void processBmp(Attributes attributes) {
1390 		addIcon(OS_WIN32, attributes.getValue(WIN32_16_HIGH));
1391 		addIcon(OS_WIN32, attributes.getValue(WIN32_16_LOW));
1392 		addIcon(OS_WIN32, attributes.getValue(WIN32_24_LOW));
1393 		addIcon(OS_WIN32, attributes.getValue(WIN32_32_HIGH));
1394 		addIcon(OS_WIN32, attributes.getValue(WIN32_32_LOW));
1395 		addIcon(OS_WIN32, attributes.getValue(WIN32_48_HIGH));
1396 		addIcon(OS_WIN32, attributes.getValue(WIN32_48_LOW));
1397 		addIcon(OS_WIN32, attributes.getValue(WIN32_256_HIGH));
1398 	}
1399 
processLinux(Attributes attributes)1400 	private void processLinux(Attributes attributes) {
1401 		addIcon(OS_LINUX, attributes.getValue(ATTRIBUTE_ICON));
1402 	}
1403 
processMac(Attributes attributes)1404 	private void processMac(Attributes attributes) {
1405 		addIcon(OS_MACOSX, attributes.getValue(ATTRIBUTE_ICON));
1406 	}
1407 
1408 	@Override
getProductContentType()1409 	public ProductContentType getProductContentType() {
1410 		return productContentType;
1411 	}
1412 }
1413