Project

General

Profile

Download (12.5 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.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;
35

    
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;
40

    
41
/**
42
 * This class is a utility class for updating the editor from a p2 update site,
43
 * greatly inspired by the links given below.
44
 *
45
 *
46
 * To Do :
47
 * - Allow configurable update sites
48
 *
49
 * Notes :
50
 *
51
 *
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
55
 */
56
public class P2Util {
57

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

    
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";
62

    
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";
65

    
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";
68

    
69
    /**
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.
72
     */
73
    @SuppressWarnings("restriction")
74
    public static void setP2UpdateRepositories() {
75
        String updateSite = EDIT_NIGHTLY_UPDATE_SITE;
76
        String updateSiteName = EDIT_NIGHTLY_UPDATE_SITE_NAME;
77

    
78
        if(ApplicationUtil.isStable()) {
79
            updateSite = EDIT_STABLE_UPDATE_SITE;
80
            updateSiteName = EDIT_STABLE_UPDATE_SITE_NAME;
81
        }
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
86
            try {
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",
92
                        P2Util.class,
93
                        "The update site URI has an invalid syntax",
94
                        TaxonomicEditorPlugin.PLUGIN_ID,
95
                        e,
96
                        false);
97
            }
98
        }
99
        repoElements.addAll(savedRepoElements);
100

    
101
        ElementUtils.updateRepositoryUsingElements(ProvisioningUI.getDefaultUI(),repoElements
102
                .toArray(new MetadataRepositoryElement[]{} ), null);
103

    
104
    }
105

    
106
    /**
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.
110
     *
111
     * This method saves the list of current repositories in the preference store as a string with
112
     * specific delimiters.
113
     */
114

    
115
    public static void saveP2RepositoryPreferences() {
116

    
117
        IMetadataRepositoryManager metaManager = ProvUI.getMetadataRepositoryManager(ProvisioningUI.getDefaultUI().getSession());
118

    
119
        URI[] currentlyEnabled = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);
120
        URI[] currentlyDisabled = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_DISABLED);
121

    
122
        List<MetadataRepositoryElement> repoElements = new ArrayList<MetadataRepositoryElement>();
123

    
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);
131
        }
132

    
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);
140
        }
141
        PreferencesUtil.setP2Repositories(repoElements);
142
    }
143

    
144
    /**
145
     *
146
     *
147
     */
148
    public static void checkForUpdates() {
149
        // the main job which performs the update
150
        Job updateJob = new Job("Update Job") {
151
            @Override
152
            public IStatus run(IProgressMonitor monitor) {
153
                return doCheckForUpdates(monitor);
154
            }
155
        };
156
        updateJob.schedule();
157
    }
158

    
159
    /**
160
     * @param monitor
161
     * @return
162
     */
163
    private static IStatus doCheckForUpdates(IProgressMonitor monitor) {
164

    
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.");
170
            return errorStatus;
171
        }
172

    
173
        final IProvisioningAgent agent = (IProvisioningAgent) bundleContext.getService(reference);
174
        IStatus updateStatus;
175
        try {
176
            updateStatus = P2Util.checkForUpdates(agent, monitor);
177
            MessagingUtils.info(updateStatus);
178
        } finally {
179
            bundleContext.ungetService(reference);
180
        }
181
        return updateStatus;
182
    }
183

    
184
    /**
185
     * @param agent
186
     * @param monitor
187
     * @return
188
     * @throws OperationCanceledException
189
     */
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
195
        // constructors.
196
        final UpdateOperation operation = new UpdateOperation(session);
197
//        try {
198
//            setUpdateRepositories(operation);
199
//        } catch (URISyntaxException e) {
200
//            MessagingUtils.errorDialog("Invalid update site URI",
201
//                    operation,
202
//                    "The update site URI has an invalid syntax",
203
//                    TaxonomicEditorPlugin.PLUGIN_ID,
204
//                    e,
205
//                    false);
206
//            return null;
207
//        }
208

    
209
        final IStatus status = operation.resolveModal(monitor);
210

    
211
        if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
212
            return status;
213
        }
214

    
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() {
219
                @Override
220
                public void run() {
221
                    String updates = "";
222
                    Update[] possibleUpdates = operation
223
                            .getPossibleUpdates();
224
                    for (Update update : possibleUpdates) {
225
                        updates += update + "\n";
226
                    }
227

    
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.
232

    
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.
237
                    if(doInstall) {
238
                        ProvisioningJob provisioningJob = operation.getProvisioningJob(monitor);
239
                        if (provisioningJob == null) {
240
                            MessagingUtils.messageDialog("Error in performing update",
241
                                    operation,
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",
244
                                    null,
245
                                    false);
246

    
247
                        } else {
248
                            // register a job change listener to track
249
                            // installation progress and notify user upon success
250
                            provisioningJob
251
                            .addJobChangeListener(new JobChangeAdapter() {
252
                                @Override
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() {
258
                                            @Override
259
                                            public void run() {
260
                                                boolean restart = MessagingUtils.confirmDialog(
261
                                                        "Updates installed, restart?",
262
                                                        "Updates have been installed successfully, do you want to restart?");
263
                                                if (restart) {
264
                                                    PlatformUI.getWorkbench().restart();
265
                                                }
266
                                            }
267
                                        });
268
                                    }
269
                                    super.done(event);
270
                                }
271
                            });
272
                            provisioningJob.schedule();
273
                        }
274
                    }
275
                }
276
            });
277
        }
278
        return status;
279
    }
280
}
(2-2/4)