--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 IBM Corporation and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * IBM Corporation - initial API and implementation\r
+ * Code 9 - ongoing development\r
+ * Sonatype, Inc. - ongoing development\r
+ *******************************************************************************/\r
+package org.simantics.project.management.install;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.StringTokenizer;\r
+\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Path;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.eclipse.core.runtime.URIUtil;\r
+import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils;\r
+import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;\r
+import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;\r
+import org.eclipse.equinox.internal.p2.repository.Transport;\r
+import org.eclipse.equinox.internal.provisional.p2.installer.InstallDescription;\r
+import org.eclipse.equinox.p2.core.IProvisioningAgent;\r
+import org.eclipse.equinox.p2.metadata.IVersionedId;\r
+import org.eclipse.equinox.p2.metadata.VersionedId;\r
+import org.simantics.project.internal.Activator;\r
+\r
+/**\r
+ * This class is responsible for loading install descriptions from a stream.\r
+ */\r
+@SuppressWarnings("restriction")\r
+public class InstallDescriptionParser {\r
+ private static final String PROP_AGENT_LOCATION = "eclipse.p2.agentLocation"; //$NON-NLS-1$\r
+ private static final String PROP_ARTIFACT_REPOSITORY = "eclipse.p2.artifacts";//$NON-NLS-1$\r
+ private static final String PROP_BUNDLE_LOCATION = "eclipse.p2.bundleLocation";//$NON-NLS-1$\r
+ private static final String PROP_INSTALL_LOCATION = "eclipse.p2.installLocation";//$NON-NLS-1$\r
+ private static final String PROP_IS_AUTO_START = "eclipse.p2.autoStart";//$NON-NLS-1$\r
+ private static final String PROP_LAUNCHER_NAME = "eclipse.p2.launcherName";//$NON-NLS-1$\r
+ private static final String PROP_METADATA_REPOSITORY = "eclipse.p2.metadata";//$NON-NLS-1$\r
+ private static final String PROP_PROFILE_NAME = "eclipse.p2.profileName";//$NON-NLS-1$\r
+ private static final String PROP_ROOT_ID = "eclipse.p2.rootId";//$NON-NLS-1$\r
+ private static final String PROP_ROOT_VERSION = "eclipse.p2.rootVersion";//$NON-NLS-1$\r
+ private static final String PROP_ROOTS = "eclipse.p2.roots";//$NON-NLS-1$\r
+\r
+ /**\r
+ * Loads and returns an install description that is stored in a properties file.\r
+ * @param site The URL of the install properties file.\r
+ */\r
+ public static InstallDescription createDescription(String site, SubMonitor monitor) throws Exception {\r
+ // if no description URL was given from the outside, look for an "install.properties" file \r
+ // in relative to where the installer is running. This allows the installer to be self-contained\r
+ if (site == null)\r
+ site = "installer.properties"; //$NON-NLS-1$\r
+\r
+ URI propsURI = URIUtil.fromString(site);\r
+ InputStream in = null;\r
+ if (!propsURI.isAbsolute()) {\r
+ String installerInstallArea = System.getProperty("osgi.install.area");\r
+ if (installerInstallArea == null)\r
+ throw new IllegalStateException("Install area is not specified.");\r
+\r
+ propsURI = URIUtil.append(URIUtil.fromString(installerInstallArea), site);\r
+ File installerDescription = URIUtil.toFile(propsURI);\r
+ if (!installerDescription.exists()) {\r
+ throw new IllegalStateException("Can't find install description file: " + installerDescription);\r
+ }\r
+ }\r
+ Map<String, String> properties;\r
+ try {\r
+ in = getTransport().stream(propsURI, monitor);\r
+ properties = CollectionUtils.loadProperties(in);\r
+ } finally {\r
+ safeClose(in);\r
+ }\r
+\r
+ URI base = getBase(propsURI);\r
+ InstallDescription result = new InstallDescription();\r
+ result = initialize(result, properties, base);\r
+ initializeProfileProperties(result, properties);\r
+\r
+ // now override the properties from anything interesting in system properties\r
+ result = initialize(result, CollectionUtils.toMap(System.getProperties()), base);\r
+ return result;\r
+ }\r
+\r
+ private static IProvisioningAgent getAgent() {\r
+ return (IProvisioningAgent) ServiceHelper.getService(Activator.getDefault().getContext(), IProvisioningAgent.SERVICE_NAME);\r
+ }\r
+\r
+ private static Transport getTransport() {\r
+ return (Transport) getAgent().getService(Transport.SERVICE_NAME);\r
+ }\r
+\r
+ private static URI getBase(URI uri) {\r
+ if (uri == null)\r
+ return null;\r
+\r
+ String uriString = uri.toString();\r
+ int slashIndex = uriString.lastIndexOf('/');\r
+ if (slashIndex == -1 || slashIndex == (uriString.length() - 1))\r
+ return uri;\r
+\r
+ return URI.create(uriString.substring(0, slashIndex + 1));\r
+ }\r
+\r
+ private static InstallDescription initialize(InstallDescription description, Map<String, String> properties, URI base) {\r
+ String property = properties.get(PROP_ARTIFACT_REPOSITORY);\r
+ if (property != null)\r
+ description.setArtifactRepositories(getURIs(property, base));\r
+\r
+ property = properties.get(PROP_METADATA_REPOSITORY);\r
+ if (property != null)\r
+ description.setMetadataRepositories(getURIs(property, base));\r
+\r
+ property = properties.get(PROP_IS_AUTO_START);\r
+ if (property != null)\r
+ description.setAutoStart(Boolean.TRUE.toString().equalsIgnoreCase(property));\r
+\r
+ property = properties.get(PROP_LAUNCHER_NAME);\r
+ if (property != null)\r
+ description.setLauncherName(property);\r
+\r
+ property = properties.get(PROP_INSTALL_LOCATION);\r
+ if (property != null)\r
+ description.setInstallLocation(new Path(property));\r
+\r
+ property = properties.get(PROP_AGENT_LOCATION);\r
+ if (property != null)\r
+ description.setAgentLocation(new Path(property));\r
+\r
+ property = properties.get(PROP_BUNDLE_LOCATION);\r
+ if (property != null)\r
+ description.setBundleLocation(new Path(property));\r
+\r
+ property = properties.get(PROP_PROFILE_NAME);\r
+ if (property != null)\r
+ description.setProductName(property);\r
+\r
+ // Process the retro root id and rootVersion properties\r
+ String id = properties.get(PROP_ROOT_ID);\r
+ if (id != null) {\r
+ String version = properties.get(PROP_ROOT_VERSION);\r
+ try {\r
+ description.setRoots(new IVersionedId[] {new VersionedId(id, version)});\r
+ } catch (IllegalArgumentException e) {\r
+ LogHelper.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Invalid version in install description: " + version, e)); //$NON-NLS-1$\r
+ }\r
+ }\r
+\r
+ String rootSpec = properties.get(PROP_ROOTS);\r
+ if (rootSpec != null) {\r
+ String[] rootList = getArrayFromString(rootSpec, ","); //$NON-NLS-1$\r
+ ArrayList<IVersionedId> roots = new ArrayList<IVersionedId>(rootList.length);\r
+ for (int i = 0; i < rootList.length; i++) {\r
+ try {\r
+ roots.add(VersionedId.parse(rootList[i]));\r
+ } catch (IllegalArgumentException e) {\r
+ LogHelper.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Invalid version in install description: " + rootList[i], e)); //$NON-NLS-1$\r
+ }\r
+ }\r
+ if (!roots.isEmpty())\r
+ description.setRoots(roots.toArray(new IVersionedId[roots.size()]));\r
+ }\r
+ return description;\r
+ }\r
+\r
+ /**\r
+ * Add all of the given properties to profile properties of the given description \r
+ * after removing the keys known to be for the installer. This allows install descriptions \r
+ * to also set random profile properties.\r
+ * @param description\r
+ * @param properties\r
+ */\r
+ private static void initializeProfileProperties(InstallDescription description, Map<String, String> properties) {\r
+ //any remaining properties are profile properties\r
+ Map<String, String> profileProperties = new HashMap<String, String>(properties);\r
+ profileProperties.remove(PROP_PROFILE_NAME);\r
+ profileProperties.remove(PROP_ARTIFACT_REPOSITORY);\r
+ profileProperties.remove(PROP_METADATA_REPOSITORY);\r
+ profileProperties.remove(PROP_IS_AUTO_START);\r
+ profileProperties.remove(PROP_LAUNCHER_NAME);\r
+ profileProperties.remove(PROP_AGENT_LOCATION);\r
+ profileProperties.remove(PROP_BUNDLE_LOCATION);\r
+ profileProperties.remove(PROP_ROOT_ID);\r
+ profileProperties.remove(PROP_ROOT_VERSION);\r
+ profileProperties.remove(PROP_ROOTS);\r
+ description.setProfileProperties(profileProperties);\r
+ }\r
+\r
+ /**\r
+ * Returns an array of URIs from the given comma-separated list\r
+ * of URLs. Returns null if the given spec does not contain any URLs.\r
+ * @param base \r
+ * @return An array of URIs in the given spec, or <code>null</code>\r
+ */\r
+ private static URI[] getURIs(String spec, URI base) {\r
+ String[] urlSpecs = getArrayFromString(spec, ","); //$NON-NLS-1$\r
+ ArrayList<URI> result = new ArrayList<URI>(urlSpecs.length);\r
+ for (int i = 0; i < urlSpecs.length; i++) {\r
+ try {\r
+ URI uri = URIUtil.fromString(urlSpecs[i]);\r
+ uri = URIUtil.makeAbsolute(uri, base);\r
+ result.add(uri);\r
+ } catch (URISyntaxException e) {\r
+ LogHelper.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Invalid URL in install description: " + urlSpecs[i], e)); //$NON-NLS-1$\r
+ }\r
+ }\r
+ if (result.isEmpty())\r
+ return null;\r
+ return result.toArray(new URI[result.size()]);\r
+ }\r
+\r
+ private static void safeClose(InputStream in) {\r
+ try {\r
+ if (in != null)\r
+ in.close();\r
+ } catch (IOException e) {\r
+ //ignore secondary failure during close\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Convert a list of tokens into an array. The list separator has to be\r
+ * specified.\r
+ */\r
+ public static String[] getArrayFromString(String list, String separator) {\r
+ if (list == null || list.trim().equals("")) //$NON-NLS-1$\r
+ return new String[0];\r
+ List<String> result = new ArrayList<String>();\r
+ for (StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();) {\r
+ String token = tokens.nextToken().trim();\r
+ if (!token.equals("")) //$NON-NLS-1$\r
+ result.add(token);\r
+ }\r
+ return result.toArray(new String[result.size()]);\r
+ }\r
+\r
+}\r