1 package eu
.etaxonomy
.taxeditor
.update
;
4 import java
.net
.URISyntaxException
;
5 import java
.util
.ArrayList
;
8 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
9 import org
.eclipse
.core
.runtime
.IStatus
;
10 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
11 import org
.eclipse
.core
.runtime
.OperationCanceledException
;
12 import org
.eclipse
.core
.runtime
.Status
;
13 import org
.eclipse
.core
.runtime
.jobs
.IJobChangeEvent
;
14 import org
.eclipse
.core
.runtime
.jobs
.Job
;
15 import org
.eclipse
.core
.runtime
.jobs
.JobChangeAdapter
;
16 import org
.eclipse
.equinox
.internal
.p2
.ui
.ProvUI
;
17 import org
.eclipse
.equinox
.internal
.p2
.ui
.model
.ElementUtils
;
18 import org
.eclipse
.equinox
.internal
.p2
.ui
.model
.MetadataRepositoryElement
;
19 import org
.eclipse
.equinox
.p2
.repository
.IRepository
;
20 import org
.eclipse
.equinox
.p2
.repository
.IRepositoryManager
;
21 import org
.eclipse
.equinox
.p2
.repository
.metadata
.IMetadataRepository
;
22 import org
.eclipse
.equinox
.p2
.repository
.metadata
.IMetadataRepositoryManager
;
23 import org
.eclipse
.equinox
.p2
.core
.IProvisioningAgent
;
24 import org
.eclipse
.equinox
.p2
.core
.ProvisionException
;
25 import org
.eclipse
.equinox
.p2
.operations
.ProvisioningJob
;
26 import org
.eclipse
.equinox
.p2
.operations
.ProvisioningSession
;
27 import org
.eclipse
.equinox
.p2
.operations
.RepositoryTracker
;
28 import org
.eclipse
.equinox
.p2
.operations
.Update
;
29 import org
.eclipse
.equinox
.p2
.operations
.UpdateOperation
;
30 import org
.eclipse
.equinox
.p2
.ui
.ProvisioningUI
;
31 import org
.eclipse
.swt
.widgets
.Display
;
32 import org
.eclipse
.ui
.PlatformUI
;
33 import org
.osgi
.framework
.BundleContext
;
34 import org
.osgi
.framework
.ServiceReference
;
36 import eu
.etaxonomy
.taxeditor
.ApplicationUtil
;
37 import eu
.etaxonomy
.taxeditor
.TaxonomicEditorPlugin
;
38 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
39 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
42 * This class is a utility class for updating the editor from a p2 update site,
43 * greatly inspired by the links given below.
47 * - Allow configurable update sites
52 * @see http://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application
53 * @see http://bugs.eclipse.org/281226
54 * @see http://www.vogella.com/tutorials/EclipseP2Update/article.html
58 //private static String LOCAL_UPDATE_SITE = "file:///path/.../to/Development/EDIT/taxeditor/eu.etaxonomy.taxeditor/target/repository/";
60 private static String EDIT_NIGHTLY_UPDATE_SITE
= "http://cybertaxonomy.eu/download/taxeditor/update/nightly/";
61 private static String EDIT_NIGHTLY_UPDATE_SITE_NAME
= "Taxonomic Editor Nightly";
63 private static String EDIT_SNAPSHOT_UPDATE_SITE
= "http://cybertaxonomy.eu/download/taxeditor/update/snapshot/";
64 private static String EDIT_SNAPSHOT_UPDATE_SITE_NAME
= "Taxonomic Editor Snapshot";
66 private static String EDIT_STABLE_UPDATE_SITE
= "http://cybertaxonomy.eu/download/taxeditor/update/stable/";
67 private static String EDIT_STABLE_UPDATE_SITE_NAME
= "Taxonomic Editor Stable";
70 * Retrieve and load the saved list of repositories from the preference store,
71 * making sure that at least the default repository is always loaded.
73 @SuppressWarnings("restriction")
74 public static void setP2UpdateRepositories() {
75 String updateSite
= EDIT_NIGHTLY_UPDATE_SITE
;
76 String updateSiteName
= EDIT_NIGHTLY_UPDATE_SITE_NAME
;
78 if(ApplicationUtil
.isStable()) {
79 updateSite
= EDIT_STABLE_UPDATE_SITE
;
80 updateSiteName
= EDIT_STABLE_UPDATE_SITE_NAME
;
82 List
<MetadataRepositoryElement
> repoElements
= new ArrayList
<MetadataRepositoryElement
>();
83 List
<MetadataRepositoryElement
> savedRepoElements
= PreferencesUtil
.getP2Repositories();
84 if(savedRepoElements
.isEmpty()) {
85 // we always need an update site, so we add the default one
87 MetadataRepositoryElement element
= new MetadataRepositoryElement(null, new URI(updateSite
), true);
88 element
.setNickname(updateSiteName
);
89 repoElements
.add(element
);
90 } catch (URISyntaxException e
) {
91 MessagingUtils
.errorDialog("Invalid update site URI",
93 "The update site URI has an invalid syntax",
94 TaxonomicEditorPlugin
.PLUGIN_ID
,
99 repoElements
.addAll(savedRepoElements
);
101 ElementUtils
.updateRepositoryUsingElements(ProvisioningUI
.getDefaultUI(),repoElements
102 .toArray(new MetadataRepositoryElement
[]{} ), null);
107 * {@link org.eclipse.equinox.p2.ui.RepositoryManipulationPage} which handles the repsitory site list
108 * in preferences does not create a preference store and hence the changes are not saved. This means
109 * that we need to save it ourselves.
111 * This method saves the list of current repositories in the preference store as a string with
112 * specific delimiters.
115 public static void saveP2RepositoryPreferences() {
117 IMetadataRepositoryManager metaManager
= ProvUI
.getMetadataRepositoryManager(ProvisioningUI
.getDefaultUI().getSession());
119 URI
[] currentlyEnabled
= metaManager
.getKnownRepositories(IRepositoryManager
.REPOSITORIES_ALL
);
120 URI
[] currentlyDisabled
= metaManager
.getKnownRepositories(IRepositoryManager
.REPOSITORIES_DISABLED
);
122 List
<MetadataRepositoryElement
> repoElements
= new ArrayList
<MetadataRepositoryElement
>();
124 for(URI repo
: currentlyEnabled
) {
125 boolean enabled
= true;
126 String nickname
= metaManager
.getRepositoryProperty(repo
, IRepository
.PROP_NICKNAME
);
127 MetadataRepositoryElement element
= new MetadataRepositoryElement(null, repo
, true);
128 element
.setNickname(nickname
);
129 element
.setEnabled(enabled
);
130 repoElements
.add(element
);
133 for(URI repo
: currentlyDisabled
) {
134 boolean enabled
= false;
135 String nickname
= metaManager
.getRepositoryProperty(repo
, IRepository
.PROP_NICKNAME
);
136 MetadataRepositoryElement element
= new MetadataRepositoryElement(null, repo
, true);
137 element
.setNickname(nickname
);
138 element
.setEnabled(enabled
);
139 repoElements
.add(element
);
141 PreferencesUtil
.setP2Repositories(repoElements
);
148 public static void checkForUpdates() {
149 // the main job which performs the update
150 Job updateJob
= new Job("Update Job") {
152 public IStatus
run(IProgressMonitor monitor
) {
153 return doCheckForUpdates(monitor
);
156 updateJob
.schedule();
163 private static IStatus
doCheckForUpdates(IProgressMonitor monitor
) {
165 BundleContext bundleContext
= TaxonomicEditorPlugin
.getContext();
166 ServiceReference reference
= bundleContext
.getServiceReference(IProvisioningAgent
.SERVICE_NAME
);
167 if (reference
== null) {
168 IStatus errorStatus
= new Status(IStatus
.ERROR
, TaxonomicEditorPlugin
.PLUGIN_ID
,
169 "No provisioning agent found. This application is not set up for updates.");
173 final IProvisioningAgent agent
= (IProvisioningAgent
) bundleContext
.getService(reference
);
174 IStatus updateStatus
;
176 updateStatus
= P2Util
.checkForUpdates(agent
, monitor
);
177 MessagingUtils
.info(updateStatus
);
179 bundleContext
.ungetService(reference
);
188 * @throws OperationCanceledException
190 static IStatus
checkForUpdates(IProvisioningAgent agent
, final IProgressMonitor monitor
) {
191 ProvisioningSession session
= new ProvisioningSession(agent
);
192 // the default update operation looks for updates to the currently
193 // running profile, using the default profile root marker. To change
194 // which installable units are being updated, use the more detailed
196 final UpdateOperation operation
= new UpdateOperation(session
);
198 // setUpdateRepositories(operation);
199 // } catch (URISyntaxException e) {
200 // MessagingUtils.errorDialog("Invalid update site URI",
202 // "The update site URI has an invalid syntax",
203 // TaxonomicEditorPlugin.PLUGIN_ID,
209 final IStatus status
= operation
.resolveModal(monitor
);
211 if (status
.getCode() == UpdateOperation
.STATUS_NOTHING_TO_UPDATE
) {
215 if (status
.isOK() && status
.getSeverity() != IStatus
.ERROR
) {
216 // We need this block of code to be in async execution
217 // since the confirm dialogs work only on the UI thread
218 Display
.getDefault().asyncExec(new Runnable() {
222 Update
[] possibleUpdates
= operation
223 .getPossibleUpdates();
224 for (Update update
: possibleUpdates
) {
225 updates
+= update
+ "\n";
228 boolean doInstall
= MessagingUtils
.confirmDialog("Updates available", "Do you want to install the available updates ?");
229 // We may need to think whether we still run in async mode once
230 // the user agrees to update. Maybe be reasonable to change to blocking
231 // from this point until the update is complete.
233 // More complex status handling might include showing the user what
234 // updates are available if there are multiples, differentiating
235 // patches vs. updates, etc. In this example, we simply update as
236 // suggested by the operation.
238 ProvisioningJob provisioningJob
= operation
.getProvisioningJob(monitor
);
239 if (provisioningJob
== null) {
240 MessagingUtils
.messageDialog("Error in performing update",
242 "ProvisioningJob could not be created." + System
.getProperty("line.separator") +
243 "Either this application does not support p2 software installation or this application has been launched from within the Eclipse IDE",
248 // register a job change listener to track
249 // installation progress and notify user upon success
251 .addJobChangeListener(new JobChangeAdapter() {
253 public void done(IJobChangeEvent event
) {
254 if (event
.getResult().isOK()) {
255 // We need this block of code to be in async execution
256 // since the confirm dialogs work only on the UI thread
257 Display
.getDefault().asyncExec(new Runnable() {
260 boolean restart
= MessagingUtils
.confirmDialog(
261 "Updates installed, restart?",
262 "Updates have been installed successfully, do you want to restart?");
264 PlatformUI
.getWorkbench().restart();
272 provisioningJob
.schedule();