Project

General

Profile

Download (13.1 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.taxeditor.update;
2

    
3
import java.net.URI;
4
import java.net.URISyntaxException;
5
import java.util.ArrayList;
6
import java.util.List;
7

    
8
import org.eclipse.core.runtime.IProgressMonitor;
9
import org.eclipse.core.runtime.IStatus;
10
import org.eclipse.core.runtime.OperationCanceledException;
11
import org.eclipse.core.runtime.Status;
12
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
13
import org.eclipse.core.runtime.jobs.Job;
14
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
15
import org.eclipse.equinox.internal.p2.ui.ProvUI;
16
import org.eclipse.equinox.internal.p2.ui.model.ElementUtils;
17
import org.eclipse.equinox.internal.p2.ui.model.MetadataRepositoryElement;
18
import org.eclipse.equinox.p2.core.IProvisioningAgent;
19
import org.eclipse.equinox.p2.core.ProvisionException;
20
import org.eclipse.equinox.p2.operations.ProvisioningJob;
21
import org.eclipse.equinox.p2.operations.ProvisioningSession;
22
import org.eclipse.equinox.p2.operations.Update;
23
import org.eclipse.equinox.p2.operations.UpdateOperation;
24
import org.eclipse.equinox.p2.repository.IRepository;
25
import org.eclipse.equinox.p2.repository.IRepositoryManager;
26
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
27
import org.eclipse.equinox.p2.ui.ProvisioningUI;
28
import org.eclipse.swt.widgets.Display;
29
import org.eclipse.ui.PlatformUI;
30
import org.osgi.framework.BundleContext;
31
import org.osgi.framework.ServiceReference;
32

    
33
import eu.etaxonomy.taxeditor.ApplicationUtil;
34
import eu.etaxonomy.taxeditor.TaxonomicEditorPlugin;
35
import eu.etaxonomy.taxeditor.model.MessagingUtils;
36
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
37

    
38
/**
39
 * This class is a utility class for updating the editor from a p2 update site,
40
 * greatly inspired by the links given below.
41
 *
42
 *
43
 * To Do :
44
 * - Allow configurable update sites
45
 *
46
 * Notes :
47
 *
48
 *
49
 * @see http://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application
50
 * @see http://bugs.eclipse.org/281226
51
 * @see http://www.vogella.com/tutorials/EclipseP2Update/article.html
52
 */
53
public class P2Util {
54

    
55
    //private static String LOCAL_UPDATE_SITE = "file:///path/.../to/Development/EDIT/taxeditor/eu.etaxonomy.taxeditor/target/repository/";
56

    
57
    private static String EDIT_NIGHTLY_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/nightly/";
58
    private static String EDIT_NIGHTLY_UPDATE_SITE_NAME = "Taxonomic Editor Nightly";
59

    
60
    private static String EDIT_SNAPSHOT_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/snapshot/";
61
    private static String EDIT_SNAPSHOT_UPDATE_SITE_NAME = "Taxonomic Editor Snapshot";
62

    
63
    private static String EDIT_STABLE_UPDATE_SITE = "http://cybertaxonomy.eu/download/taxeditor/update/stable/";
64
    private static String EDIT_STABLE_UPDATE_SITE_NAME = "Taxonomic Editor Stable";
65

    
66
    /**
67
     * Retrieve and load the saved list of repositories from the preference store,
68
     * making sure that at least the default repository is always loaded.
69
     */
70
    @SuppressWarnings("restriction")
71
    public static void setP2UpdateRepositories() {
72
        String updateSite = EDIT_NIGHTLY_UPDATE_SITE;
73
        String updateSiteName = EDIT_NIGHTLY_UPDATE_SITE_NAME;
74

    
75
        if(ApplicationUtil.isStable()) {
76
            updateSite = EDIT_STABLE_UPDATE_SITE;
77
            updateSiteName = EDIT_STABLE_UPDATE_SITE_NAME;
78
        }
79
        List<MetadataRepositoryElement> repoElements = new ArrayList<MetadataRepositoryElement>();
80
        List<MetadataRepositoryElement> savedRepoElements = PreferencesUtil.getP2Repositories();
81
        if(savedRepoElements.isEmpty()) {
82
            // we always need an update site, so we add the default one
83
            try {
84
                MetadataRepositoryElement element = new MetadataRepositoryElement(null, new URI(updateSite), true);
85
                element.setNickname(updateSiteName);
86
                repoElements.add(element);
87
            } catch (URISyntaxException e) {
88
                MessagingUtils.errorDialog("Invalid update site URI",
89
                        P2Util.class,
90
                        "The update site URI has an invalid syntax",
91
                        TaxonomicEditorPlugin.PLUGIN_ID,
92
                        e,
93
                        false);
94
            }
95
        }
96
        repoElements.addAll(savedRepoElements);
97

    
98
        ElementUtils.updateRepositoryUsingElements(ProvisioningUI.getDefaultUI(),repoElements
99
                .toArray(new MetadataRepositoryElement[]{} ), null);
100

    
101
    }
102

    
103
    /**
104
     * {@link org.eclipse.equinox.p2.ui.RepositoryManipulationPage} which handles the repsitory site list
105
     * in preferences does not create a preference store and hence the changes are not saved. This means
106
     * that we need to save it ourselves.
107
     *
108
     * This method saves the list of current repositories in the preference store as a string with
109
     * specific delimiters.
110
     */
111

    
112
    public static void saveP2RepositoryPreferences() {
113

    
114
        IMetadataRepositoryManager metaManager = ProvUI.getMetadataRepositoryManager(ProvisioningUI.getDefaultUI().getSession());
115

    
116
        URI[] currentlyEnabled = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);
117
        URI[] currentlyDisabled = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_DISABLED);
118

    
119
        List<MetadataRepositoryElement> repoElements = new ArrayList<MetadataRepositoryElement>();
120

    
121
        for(URI repo : currentlyEnabled) {
122
            boolean enabled = true;
123
            String nickname = metaManager.getRepositoryProperty(repo, IRepository.PROP_NICKNAME);
124
            MetadataRepositoryElement element = new MetadataRepositoryElement(null, repo, true);
125
            element.setNickname(nickname);
126
            element.setEnabled(enabled);
127
            repoElements.add(element);
128
        }
129

    
130
        for(URI repo : currentlyDisabled) {
131
            boolean enabled = false;
132
            String nickname = metaManager.getRepositoryProperty(repo, IRepository.PROP_NICKNAME);
133
            MetadataRepositoryElement element = new MetadataRepositoryElement(null, repo, true);
134
            element.setNickname(nickname);
135
            element.setEnabled(enabled);
136
            repoElements.add(element);
137
        }
138
        PreferencesUtil.setP2Repositories(repoElements);
139
    }
140

    
141
    /**
142
     *
143
     *
144
     */
145
    public static void checkForUpdates() {
146

    
147
        Job updateJob = new Job("Update Job") {
148
            @Override
149
            public IStatus run(IProgressMonitor monitor) {
150
                return doCheckForUpdates(monitor);
151
            }
152
        };
153
        updateJob.schedule();
154
    }
155

    
156
    /**
157
     * @param monitor
158
     * @return
159
     */
160
    private static IStatus doCheckForUpdates(IProgressMonitor monitor) {
161

    
162
     // force refresh all the caches before
163
        IMetadataRepositoryManager metaManager = ProvUI.getMetadataRepositoryManager(ProvisioningUI.getDefaultUI().getSession());
164
        URI[] repos = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);
165
        for(URI repo : repos) {
166
            try {
167
                metaManager.refreshRepository(repo, monitor);
168
            } catch (ProvisionException pe) {
169
                IStatus errorStatus = new Status(IStatus.ERROR, TaxonomicEditorPlugin.PLUGIN_ID,
170
                        "Error occured while reloading cache.", pe);
171

    
172
            } catch (OperationCanceledException oce) {
173
                IStatus errorStatus = new Status(IStatus.ERROR, TaxonomicEditorPlugin.PLUGIN_ID,
174
                        "Error occured while reloading cache.", oce);
175
            }
176
        }
177
        BundleContext bundleContext = TaxonomicEditorPlugin.getContext();
178
        ServiceReference reference = bundleContext.getServiceReference(IProvisioningAgent.SERVICE_NAME);
179
        if (reference == null) {
180
            IStatus errorStatus = new Status(IStatus.ERROR, TaxonomicEditorPlugin.PLUGIN_ID,
181
                    "No provisioning agent found.  This application is not set up for updates.");
182
            return errorStatus;
183
        }
184

    
185
        final IProvisioningAgent agent = (IProvisioningAgent) bundleContext.getService(reference);
186
        IStatus updateStatus;
187
        try {
188
            updateStatus = P2Util.checkForUpdates(agent, monitor);
189
            MessagingUtils.info(updateStatus);
190
        } finally {
191
            bundleContext.ungetService(reference);
192
        }
193
        return updateStatus;
194
    }
195

    
196
    /**
197
     * @param agent
198
     * @param monitor
199
     * @return
200
     * @throws OperationCanceledException
201
     */
202
    static IStatus checkForUpdates(IProvisioningAgent agent, final IProgressMonitor monitor) {
203
        ProvisioningSession session = new ProvisioningSession(agent);
204
        // the default update operation looks for updates to the currently
205
        // running profile, using the default profile root marker. To change
206
        // which installable units are being updated, use the more detailed
207
        // constructors.
208
        final UpdateOperation operation = new UpdateOperation(session);
209
//        try {
210
//            setUpdateRepositories(operation);
211
//        } catch (URISyntaxException e) {
212
//            MessagingUtils.errorDialog("Invalid update site URI",
213
//                    operation,
214
//                    "The update site URI has an invalid syntax",
215
//                    TaxonomicEditorPlugin.PLUGIN_ID,
216
//                    e,
217
//                    false);
218
//            return null;
219
//        }
220

    
221
        final IStatus status = operation.resolveModal(monitor);
222

    
223
        if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
224
            return status;
225
        }
226

    
227
        if (status.isOK() && status.getSeverity() != IStatus.ERROR) {
228
            // We need this block of code to be in async execution
229
            // since the confirm dialogs work only on the UI thread
230
            Display.getDefault().asyncExec(new Runnable() {
231
                @Override
232
                public void run() {
233
                    String updates = "";
234
                    Update[] possibleUpdates = operation
235
                            .getPossibleUpdates();
236
                    for (Update update : possibleUpdates) {
237
                        updates += update + "\n";
238
                    }
239

    
240
                    boolean doInstall = MessagingUtils.confirmDialog("Updates available", "Do you want to install the available updates ?");
241
                    // We may need to think whether we still run in async mode once
242
                    // the user agrees to update. Maybe be reasonable to change to blocking
243
                    // from this point until the update is complete.
244

    
245
                    // More complex status handling might include showing the user what
246
                    // updates are available if there are multiples, differentiating
247
                    // patches vs. updates, etc. In this example, we simply update as
248
                    // suggested by the operation.
249
                    if(doInstall) {
250
                        ProvisioningJob provisioningJob = operation.getProvisioningJob(monitor);
251
                        if (provisioningJob == null) {
252
                            MessagingUtils.messageDialog("Error in performing update",
253
                                    operation,
254
                                    "ProvisioningJob could not be created." + System.getProperty("line.separator") +
255
                                    "Either this application does not support p2 software installation or this application has been launched from within the Eclipse IDE",
256
                                    null,
257
                                    false);
258

    
259
                        } else {
260
                            // register a job change listener to track
261
                            // installation progress and notify user upon success
262
                            provisioningJob
263
                            .addJobChangeListener(new JobChangeAdapter() {
264
                                @Override
265
                                public void done(IJobChangeEvent event) {
266
                                    if (event.getResult().isOK()) {
267
                                        // We need this block of code to be in async execution
268
                                        // since the confirm dialogs work only on the UI thread
269
                                        Display.getDefault().asyncExec(new Runnable() {
270
                                            @Override
271
                                            public void run() {
272
                                                boolean restart = MessagingUtils.confirmDialog(
273
                                                        "Updates installed, restart?",
274
                                                        "Updates have been installed successfully, do you want to restart?");
275
                                                if (restart) {
276
                                                    PlatformUI.getWorkbench().restart();
277
                                                }
278
                                            }
279
                                        });
280
                                    }
281
                                    super.done(event);
282
                                }
283
                            });
284
                            provisioningJob.schedule();
285
                        }
286
                    }
287
                }
288
            });
289
        }
290
        return status;
291
    }
292
}
(2-2/4)