]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.project/src/org/simantics/project/management/install/InstallUpdateProductOperation.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.project / src / org / simantics / project / management / install / InstallUpdateProductOperation.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 IBM Corporation and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     IBM Corporation - initial API and implementation\r
10  *     Code 9 - ongoing development\r
11  *     Sonatype, Inc. - ongoing development\r
12  *******************************************************************************/\r
13 package org.simantics.project.management.install;\r
14 \r
15 import java.net.URI;\r
16 import java.util.ArrayList;\r
17 import java.util.Collection;\r
18 import java.util.HashMap;\r
19 import java.util.Iterator;\r
20 import java.util.Map;\r
21 \r
22 import org.eclipse.core.runtime.CoreException;\r
23 import org.eclipse.core.runtime.IPath;\r
24 import org.eclipse.core.runtime.IProgressMonitor;\r
25 import org.eclipse.core.runtime.IStatus;\r
26 import org.eclipse.core.runtime.Status;\r
27 import org.eclipse.core.runtime.SubMonitor;\r
28 import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;\r
29 import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;\r
30 import org.eclipse.equinox.internal.provisional.p2.director.IDirector;\r
31 import org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation;\r
32 import org.eclipse.equinox.internal.provisional.p2.installer.InstallDescription;\r
33 import org.eclipse.equinox.p2.core.IProvisioningAgent;\r
34 import org.eclipse.equinox.p2.core.ProvisionException;\r
35 import org.eclipse.equinox.p2.engine.IProfile;\r
36 import org.eclipse.equinox.p2.engine.IProfileRegistry;\r
37 import org.eclipse.equinox.p2.metadata.IInstallableUnit;\r
38 import org.eclipse.equinox.p2.metadata.IVersionedId;\r
39 import org.eclipse.equinox.p2.metadata.Version;\r
40 import org.eclipse.equinox.p2.metadata.VersionRange;\r
41 import org.eclipse.equinox.p2.query.IQuery;\r
42 import org.eclipse.equinox.p2.query.IQueryResult;\r
43 import org.eclipse.equinox.p2.query.QueryUtil;\r
44 import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;\r
45 import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;\r
46 import org.eclipse.osgi.service.environment.EnvironmentInfo;\r
47 import org.eclipse.osgi.util.NLS;\r
48 import org.simantics.project.internal.Activator;\r
49 \r
50 /**\r
51  * This operation performs installation or update of an Eclipse-based product.\r
52  */\r
53 @SuppressWarnings("restriction")\r
54 public class InstallUpdateProductOperation implements IInstallOperation {\r
55 \r
56         private IArtifactRepositoryManager artifactRepoMan;\r
57         private IProvisioningAgent agent;\r
58         private IDirector director;\r
59         private final InstallDescription installDescription;\r
60         private boolean isInstall = true;\r
61         private IMetadataRepositoryManager metadataRepoMan;\r
62         private IProfileRegistry profileRegistry;\r
63         private IStatus result;\r
64 \r
65         public InstallUpdateProductOperation(IProvisioningAgent agent, InstallDescription description) {\r
66                 this.agent = agent;\r
67                 this.installDescription = description;\r
68         }\r
69 \r
70         /**\r
71          * Determine what top level installable units should be installed by the director\r
72          */\r
73         private Collection<IInstallableUnit> computeUnitsToInstall() throws CoreException {\r
74                 ArrayList<IInstallableUnit> units = new ArrayList<IInstallableUnit>();\r
75                 IVersionedId roots[] = installDescription.getRoots();\r
76                 for (int i = 0; i < roots.length; i++) {\r
77                         IVersionedId root = roots[i];\r
78                         IInstallableUnit iu = findUnit(root);\r
79                         if (iu != null)\r
80                                 units.add(iu);\r
81                 }\r
82                 return units;\r
83         }\r
84 \r
85         /**\r
86          * This profile is being updated; return the units to uninstall from the profile.\r
87          */\r
88         private IQueryResult<IInstallableUnit> computeUnitsToUninstall(IProfile p) {\r
89                 return p.query(QueryUtil.createIUAnyQuery(), null);\r
90         }\r
91 \r
92         /**\r
93          * Create and return the profile into which units will be installed.\r
94          */\r
95         private IProfile createProfile() throws ProvisionException {\r
96                 IProfile profile = getProfile();\r
97                 if (profile == null) {\r
98                         Map<String, String> properties = new HashMap<String, String>();\r
99                         properties.put(IProfile.PROP_INSTALL_FOLDER, installDescription.getInstallLocation().toString());\r
100                         EnvironmentInfo info = (EnvironmentInfo) ServiceHelper.getService(Activator.getDefault().getBundle().getBundleContext(), EnvironmentInfo.class.getName());\r
101                         String env = "osgi.os=" + info.getOS() + ",osgi.ws=" + info.getWS() + ",osgi.arch=" + info.getOSArch(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$\r
102                         properties.put(IProfile.PROP_ENVIRONMENTS, env);\r
103                         properties.put(IProfile.PROP_NAME, installDescription.getProductName());\r
104                         properties.putAll(installDescription.getProfileProperties());\r
105                         IPath location = installDescription.getBundleLocation();\r
106                         if (location != null)\r
107                                 properties.put(IProfile.PROP_CACHE, location.toOSString());\r
108                         profile = profileRegistry.addProfile(getProfileId(), properties);\r
109                 }\r
110                 return profile;\r
111         }\r
112 \r
113         /**\r
114          * Performs the actual product install or update.\r
115          */\r
116         private void doInstall(SubMonitor monitor) throws CoreException {\r
117                 prepareMetadataRepositories();\r
118                 prepareArtifactRepositories();\r
119                 IProfile p = createProfile();\r
120                 Collection<IInstallableUnit> toInstall = computeUnitsToInstall();\r
121                 monitor.worked(5);\r
122 \r
123                 IStatus s;\r
124                 ProfileChangeRequest request = new ProfileChangeRequest(p);\r
125                 if (isInstall) {\r
126                         monitor.setTaskName(NLS.bind("Installing", installDescription.getProductName()));\r
127                         request.addAll(toInstall);\r
128                         s = director.provision(request, null, monitor.newChild(90));\r
129                 } else {\r
130                         monitor.setTaskName(NLS.bind("Updating", installDescription.getProductName()));\r
131                         IQueryResult<IInstallableUnit> toUninstall = computeUnitsToUninstall(p);\r
132                         request.removeAll(toUninstall.toUnmodifiableSet());\r
133                         request.addAll(toInstall);\r
134                         s = director.provision(request, null, monitor.newChild(90));\r
135                 }\r
136                 if (!s.isOK())\r
137                         throw new CoreException(s);\r
138         }\r
139 \r
140         /**\r
141          * Returns an exception of severity error with the given error message.\r
142          */\r
143         private CoreException fail(String message) {\r
144                 return fail(message, null);\r
145         }\r
146 \r
147         /**\r
148          * Returns an exception of severity error with the given error message.\r
149          */\r
150         private CoreException fail(String message, Throwable throwable) {\r
151                 return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, throwable));\r
152         }\r
153 \r
154         /**\r
155          * Finds and returns the installable unit with the given id, and optionally the\r
156          * given version.\r
157          */\r
158         private IInstallableUnit findUnit(IVersionedId spec) throws CoreException {\r
159                 String id = spec.getId();\r
160                 if (id == null)\r
161                         throw fail("No id");\r
162                 Version version = spec.getVersion();\r
163                 VersionRange range = VersionRange.emptyRange;\r
164                 if (version != null && !version.equals(Version.emptyVersion))\r
165                         range = new VersionRange(version, true, version, true);\r
166                 IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(id, range);\r
167                 Iterator<IInstallableUnit> matches = metadataRepoMan.query(query, null).iterator();\r
168                 // pick the newest match\r
169                 IInstallableUnit newest = null;\r
170                 while (matches.hasNext()) {\r
171                         IInstallableUnit candidate = matches.next();\r
172                         if (newest == null || (newest.getVersion().compareTo(candidate.getVersion()) < 0))\r
173                                 newest = candidate;\r
174                 }\r
175                 if (newest == null)\r
176                         throw fail("IU not found " + id);\r
177                 return newest;\r
178         }\r
179 \r
180         /**\r
181          * Returns the profile being installed into.\r
182          */\r
183         private IProfile getProfile() {\r
184                 return profileRegistry.getProfile(getProfileId());\r
185         }\r
186 \r
187         /**\r
188          * Returns the id of the profile to use for install/update based on this operation's install description.\r
189          */\r
190         private String getProfileId() {\r
191                 IPath location = installDescription.getInstallLocation();\r
192                 if (location != null)\r
193                         return location.toString();\r
194                 return installDescription.getProductName();\r
195         }\r
196 \r
197         /**\r
198          * Returns the result of the install operation, or <code>null</code> if\r
199          * no install operation has been run.\r
200          */\r
201         public IStatus getResult() {\r
202                 return result;\r
203         }\r
204 \r
205         private Object getService(String name) throws CoreException {\r
206                 Object service = agent.getService(name);\r
207                 if (service == null)\r
208                         throw fail("No service "  + name);\r
209                 return service;\r
210         }\r
211 \r
212         /* (non-Javadoc)\r
213          * @see org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation#install(org.eclipse.core.runtime.IProgressMonitor)\r
214          */\r
215         public IStatus install(IProgressMonitor pm) {\r
216                 SubMonitor monitor = SubMonitor.convert(pm, "Preparing", 100);\r
217                 try {\r
218                         try {\r
219                                 preInstall();\r
220                                 isInstall = getProfile() == null;\r
221                                 doInstall(monitor);\r
222                                 result = new Status(IStatus.OK, Activator.PLUGIN_ID, isInstall ? "Install Complete" : "Update Complete", null);\r
223                                 monitor.setTaskName("Cleanup");\r
224                         } finally {\r
225                                 postInstall();\r
226                         }\r
227                 } catch (CoreException e) {\r
228                         result = e.getStatus();\r
229                 } finally {\r
230                         monitor.done();\r
231                 }\r
232                 return result;\r
233         }\r
234 \r
235         /**\r
236          * Returns whether this operation represents the product being installed\r
237          * for the first time, in a new profile.\r
238          */\r
239         public boolean isFirstInstall() {\r
240                 return isInstall;\r
241         }\r
242 \r
243         private void postInstall() {\r
244                 //nothing to do\r
245         }\r
246 \r
247         private void preInstall() throws CoreException {\r
248                 //obtain required services\r
249                 director = (IDirector) getService(IDirector.SERVICE_NAME);\r
250                 metadataRepoMan = (IMetadataRepositoryManager) getService(IMetadataRepositoryManager.SERVICE_NAME);\r
251                 artifactRepoMan = (IArtifactRepositoryManager) getService(IArtifactRepositoryManager.SERVICE_NAME);\r
252                 profileRegistry = (IProfileRegistry) getService(IProfileRegistry.SERVICE_NAME);\r
253         }\r
254 \r
255         private void prepareArtifactRepositories() throws ProvisionException {\r
256                 URI[] repos = installDescription.getArtifactRepositories();\r
257                 if (repos == null)\r
258                         return;\r
259 \r
260                 // Repositories must be registered before they are loaded\r
261                 // This is to avoid them being possibly overridden with the configuration as a referenced repository\r
262                 for (int i = 0; i < repos.length; i++) {\r
263                         artifactRepoMan.addRepository(repos[i]);\r
264                         artifactRepoMan.loadRepository(repos[i], null);\r
265                 }\r
266         }\r
267 \r
268         private void prepareMetadataRepositories() throws ProvisionException {\r
269                 URI[] repos = installDescription.getMetadataRepositories();\r
270                 if (repos == null)\r
271                         return;\r
272 \r
273                 // Repositories must be registered before they are loaded\r
274                 // This is to avoid them being possibly overridden with the configuration as a referenced repository\r
275                 for (int i = 0; i < repos.length; i++) {\r
276                         metadataRepoMan.addRepository(repos[i]);\r
277                         metadataRepoMan.loadRepository(repos[i], null);\r
278                 }\r
279         }\r
280 }\r