eu.etaxonomy.taxeditor.product, eu.etaxonomy.taxeditor.feature/feature.xml, eu.etaxon...
[taxeditor.git] / eu.etaxonomy.taxeditor.application / src / main / java / eu / etaxonomy / taxeditor / update / P2Util.java
1 package eu.etaxonomy.taxeditor.update;
2
3 import java.net.URI;
4 import java.net.URISyntaxException;
5
6 import org.eclipse.core.runtime.IProgressMonitor;
7 import org.eclipse.core.runtime.IStatus;
8 import org.eclipse.core.runtime.OperationCanceledException;
9 import org.eclipse.core.runtime.Status;
10 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
11 import org.eclipse.core.runtime.jobs.Job;
12 import org.eclipse.core.runtime.jobs.JobChangeAdapter;
13 import org.eclipse.equinox.internal.p2.ui.model.ElementUtils;
14 import org.eclipse.equinox.internal.p2.ui.model.MetadataRepositoryElement;
15 import org.eclipse.equinox.p2.core.IProvisioningAgent;
16 import org.eclipse.equinox.p2.operations.ProvisioningJob;
17 import org.eclipse.equinox.p2.operations.ProvisioningSession;
18 import org.eclipse.equinox.p2.operations.Update;
19 import org.eclipse.equinox.p2.operations.UpdateOperation;
20 import org.eclipse.equinox.p2.ui.ProvisioningUI;
21 import org.eclipse.swt.widgets.Display;
22 import org.eclipse.ui.PlatformUI;
23 import org.osgi.framework.BundleContext;
24 import org.osgi.framework.ServiceReference;
25
26 import eu.etaxonomy.taxeditor.ApplicationUtil;
27 import eu.etaxonomy.taxeditor.TaxonomicEditorPlugin;
28 import eu.etaxonomy.taxeditor.model.MessagingUtils;
29
30 /**
31 * This class is a utility class for updating the editor from a p2 update site,
32 * greatly inspired by the links given below.
33 *
34 *
35 * To Do :
36 * - Allow configurable update sites
37 *
38 * Notes :
39 * - tried to get rid of the popup dialog which warns about unsigned jars using
40 * -Declipse.p2.unsignedPolicy=allow but this does not work due to
41 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=391399, so the only solution
42 * is to sign the jars with an official certificate.
43 *
44 * @see http://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application
45 * @see http://bugs.eclipse.org/281226
46 * @see http://www.vogella.com/tutorials/EclipseP2Update/article.html
47 */
48 public class P2Util {
49
50 //private static String LOCAL_UPDATE_SITE = "file:///path/.../to/Development/EDIT/taxeditor/eu.etaxonomy.taxeditor/target/repository/";
51 private static String EDIT_NIGHTLY_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/nightly/";
52 private static String EDIT_NIGHTLY_UPDATE_SITE_NAME = "Taxonomic Editor Nightly";
53
54 private static String EDIT_SNAPSHOT_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/snapshot/";
55 private static String EDIT_SNAPSHOT_UPDATE_SITE_NAME = "Taxonomic Editor Snapshot";
56
57 private static String EDIT_STABLE_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/stable/";
58 private static String EDIT_STABLE_UPDATE_SITE_NAME = "Taxonomic Editor Stable";
59
60 @SuppressWarnings("restriction")
61 public static void setDefaultUpdateRepositories() {
62 String updateSite = EDIT_NIGHTLY_UPDATE_SITE;
63 String updateSiteName = EDIT_NIGHTLY_UPDATE_SITE_NAME;
64
65 if(ApplicationUtil.isStable()) {
66 updateSite = EDIT_STABLE_UPDATE_SITE;
67 updateSiteName = EDIT_STABLE_UPDATE_SITE_NAME;
68 }
69 try {
70 final MetadataRepositoryElement element = new MetadataRepositoryElement(null, new URI(updateSite), true);
71 element.setNickname(updateSiteName);
72 ElementUtils.updateRepositoryUsingElements(ProvisioningUI.getDefaultUI(),new MetadataRepositoryElement[] {element}, null);
73 } catch (URISyntaxException e) {
74 MessagingUtils.errorDialog("Invalid update site URI",
75 P2Util.class,
76 "The update site URI has an invalid syntax",
77 TaxonomicEditorPlugin.PLUGIN_ID,
78 e,
79 false);
80 }
81 }
82
83 /**
84 *
85 *
86 */
87 public static void checkForUpdates() {
88 // the main job which performs the update
89 Job updateJob = new Job("Update Job") {
90 @Override
91 public IStatus run(IProgressMonitor monitor) {
92 return doCheckForUpdates(monitor);
93 }
94 };
95 updateJob.schedule();
96 }
97
98 /**
99 * @param monitor
100 * @return
101 */
102 private static IStatus doCheckForUpdates(IProgressMonitor monitor) {
103
104 BundleContext bundleContext = TaxonomicEditorPlugin.getContext();
105 ServiceReference reference = bundleContext.getServiceReference(IProvisioningAgent.SERVICE_NAME);
106 if (reference == null) {
107 IStatus errorStatus = new Status(IStatus.ERROR, TaxonomicEditorPlugin.PLUGIN_ID,
108 "No provisioning agent found. This application is not set up for updates.");
109 return errorStatus;
110 }
111
112 final IProvisioningAgent agent = (IProvisioningAgent) bundleContext.getService(reference);
113 IStatus updateStatus;
114 try {
115 updateStatus = P2Util.checkForUpdates(agent, monitor);
116 MessagingUtils.info(updateStatus);
117 } finally {
118 bundleContext.ungetService(reference);
119 }
120 return updateStatus;
121 }
122
123 /**
124 * @param agent
125 * @param monitor
126 * @return
127 * @throws OperationCanceledException
128 */
129 static IStatus checkForUpdates(IProvisioningAgent agent, final IProgressMonitor monitor) {
130 ProvisioningSession session = new ProvisioningSession(agent);
131 // the default update operation looks for updates to the currently
132 // running profile, using the default profile root marker. To change
133 // which installable units are being updated, use the more detailed
134 // constructors.
135 final UpdateOperation operation = new UpdateOperation(session);
136 // try {
137 // setUpdateRepositories(operation);
138 // } catch (URISyntaxException e) {
139 // MessagingUtils.errorDialog("Invalid update site URI",
140 // operation,
141 // "The update site URI has an invalid syntax",
142 // TaxonomicEditorPlugin.PLUGIN_ID,
143 // e,
144 // false);
145 // return null;
146 // }
147
148 final IStatus status = operation.resolveModal(monitor);
149
150 if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
151 return status;
152 }
153
154 if (status.isOK() && status.getSeverity() != IStatus.ERROR) {
155 // We need this block of code to be in async execution
156 // since the confirm dialogs work only on the UI thread
157 Display.getDefault().asyncExec(new Runnable() {
158 @Override
159 public void run() {
160 String updates = "";
161 Update[] possibleUpdates = operation
162 .getPossibleUpdates();
163 for (Update update : possibleUpdates) {
164 updates += update + "\n";
165 }
166
167 boolean doInstall = MessagingUtils.confirmDialog("Updates available", "Do you want to install the available updates ?");
168 // We may need to think whether we still run in async mode once
169 // the user agrees to update. Maybe be reasonable to change to blocking
170 // from this point until the update is complete.
171
172 // More complex status handling might include showing the user what
173 // updates are available if there are multiples, differentiating
174 // patches vs. updates, etc. In this example, we simply update as
175 // suggested by the operation.
176 if(doInstall) {
177 ProvisioningJob provisioningJob = operation.getProvisioningJob(monitor);
178 if (provisioningJob == null) {
179 MessagingUtils.messageDialog("Error in performing update",
180 operation,
181 "ProvisioningJob could not be created." + System.getProperty("line.separator") +
182 "Either this application does not support p2 software installation or this application has been launched from within the Eclipse IDE",
183 null,
184 false);
185
186 } else {
187 // register a job change listener to track
188 // installation progress and notify user upon success
189 provisioningJob
190 .addJobChangeListener(new JobChangeAdapter() {
191 @Override
192 public void done(IJobChangeEvent event) {
193 if (event.getResult().isOK()) {
194 // We need this block of code to be in async execution
195 // since the confirm dialogs work only on the UI thread
196 Display.getDefault().asyncExec(new Runnable() {
197 @Override
198 public void run() {
199 boolean restart = MessagingUtils.confirmDialog(
200 "Updates installed, restart?",
201 "Updates have been installed successfully, do you want to restart?");
202 if (restart) {
203 PlatformUI.getWorkbench().restart();
204 }
205 }
206 });
207 }
208 super.done(event);
209 }
210 });
211 provisioningJob.schedule();
212 }
213 }
214 }
215 });
216 }
217 return status;
218 }
219 }