/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marcel Bruch - initial API and implementation. */ package org.eclipse.recommenders.internal.models.rcp; import static java.text.MessageFormat.format; import static org.eclipse.core.runtime.Status.OK_STATUS; import static org.eclipse.recommenders.internal.models.rcp.l10n.LogMessages.ERROR_SAVE_PREFERENCES_FAILED; import static org.eclipse.recommenders.models.IModelIndex.INDEX; import static org.eclipse.recommenders.utils.Logs.log; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.Objects; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.recommenders.internal.models.rcp.l10n.Messages; import org.eclipse.recommenders.models.IModelRepository; import org.eclipse.recommenders.models.ModelCoordinate; import org.eclipse.recommenders.models.rcp.ModelEvents.ModelArchiveDownloadedEvent; import org.eclipse.recommenders.utils.rcp.Browsers; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.eclipse.ui.statushandlers.StatusManager; import com.google.common.eventbus.EventBus; public class DownloadModelArchiveJob extends Job { private static final int MAXIMUM_NUMBER_OF_DOWNLOADS_PER_JOB = 2; private static final int TOTAL_WORK_UNITS = 100000; private final IModelRepository repository; private final ModelCoordinate mc; private final boolean forceDownload; private final EventBus bus; public DownloadModelArchiveJob(IModelRepository repository, ModelCoordinate mc, boolean forceDownload, EventBus bus) { super(MessageFormat.format(Messages.JOB_NAME_RESOLVING_MODEL, mc)); this.repository = repository; this.mc = mc; this.forceDownload = forceDownload; this.bus = bus; } @Override protected IStatus run(final IProgressMonitor monitor) { try { String message = MessageFormat.format(Messages.MONITOR_NAME_RESOLVING_MODEL, mc); MultipleDownloadCallback downloadCallback = new MultipleDownloadCallback(monitor, message, TOTAL_WORK_UNITS, MAXIMUM_NUMBER_OF_DOWNLOADS_PER_JOB); File result = repository.resolve(mc, forceDownload, downloadCallback).orNull(); boolean isDownloadSuccessful = downloadCallback.isDownloadSucceeded(); if (isDownloadSuccessful) { bus.post(new ModelArchiveDownloadedEvent(mc)); } downloadCallback.finish(); // Returns null if the model coordinate could not be resolved. This may because we are requesting an mc that // does not exist in the repository or because of the network being down. // Moreover, we can get *cached* null answers, i.e., the same negative result over and over again. if (result == null) { if (isIndex(mc)) { // Failure to download the index is serious; display an error message. final Display display = PlatformUI.getWorkbench().getDisplay(); display.asyncExec(new Runnable() { @Override public void run() { IndexDownloadFailureDialog dialog = new IndexDownloadFailureDialog( display.getActiveShell()); if (!dialog.isIgnored()) { dialog.open(); } } }); } // Log that as informational but do not open a (extra, in case of index downloads) popup. IStatus err = new Status(IStatus.INFO, Constants.BUNDLE_ID, format(Messages.LOG_INFO_NO_MODEL_RESOLVED, mc)); StatusManager.getManager().handle(err, StatusManager.LOG); return Status.CANCEL_STATUS; } } catch (Exception e) { return new Status(IStatus.ERROR, Constants.BUNDLE_ID, format(Messages.LOG_ERROR_MODEL_RESOLUTION_FAILURE, mc), e); } finally { monitor.done(); } return OK_STATUS; } private boolean isIndex(ModelCoordinate mc) { return Objects.equals(INDEX.getGroupId(), mc.getGroupId()) && Objects.equals(INDEX.getArtifactId(), mc.getArtifactId()) && Objects.equals(INDEX.getClassifier(), mc.getClassifier()) && Objects.equals(INDEX.getExtension(), mc.getExtension()); } private static final class IndexDownloadFailureDialog extends MessageDialogWithToggle { private IndexDownloadFailureDialog(Shell parentShell) { super(parentShell, Messages.DIALOG_TITLE_INDEX_DOWNLOAD_FAILURE, null, Messages.DIALOG_MESSAGE_INDEX_DOWNLOAD_FAILURE, MessageDialog.ERROR, new String[] { IDialogConstants.OK_LABEL }, 0, Messages.DIALOG_TOGGLE_IGNORE_DOWNLOAD_FAILURES, false); setPrefStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, Constants.BUNDLE_ID)); setPrefKey(Constants.PREF_IGNORE_DOWNLOAD_FAILURES); } @Override protected Control createCustomArea(Composite parent) { Link link = new Link(parent, SWT.BEGINNING); link.setText(MessageFormat.format(Messages.DIALOG_MESSAGE_INDEX_DOWNLOAD_FAILURE_SUGGESTIONS, "https://eclipse.org/recommenders/faq/", //$NON-NLS-1$ "https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Recommenders")); //$NON-NLS-1$ link.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { Browsers.tryOpenInExternalBrowser(event.text); } }); return link; } @Override protected void buttonPressed(int buttonId) { super.buttonPressed(buttonId); try { ((ScopedPreferenceStore) getPrefStore()).save(); } catch (IOException e) { log(ERROR_SAVE_PREFERENCES_FAILED, e); } } public boolean isIgnored() { return getPrefStore().getString(getPrefKey()).equals(MessageDialogWithToggle.ALWAYS); } } }