package name.abuchen.portfolio.ui.update;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.Locale;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.operations.ProvisioningJob;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.operations.Update;
import org.eclipse.equinox.p2.operations.UpdateOperation;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.PortfolioPlugin;
import name.abuchen.portfolio.ui.UIConstants;
public class UpdateHelper
{
private static final String VERSION_HISTORY = "version.history"; //$NON-NLS-1$
private final IWorkbench workbench;
private final EPartService partService;
private final IProvisioningAgent agent;
private UpdateOperation operation;
public UpdateHelper(IWorkbench workbench, EPartService partService) throws CoreException
{
this.workbench = workbench;
this.partService = partService;
this.agent = getService(IProvisioningAgent.class, IProvisioningAgent.SERVICE_NAME);
IProfileRegistry profileRegistry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);
IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF);
if (profile == null)
{
IStatus status = new Status(IStatus.ERROR, PortfolioPlugin.PLUGIN_ID, Messages.MsgNoProfileFound);
throw new CoreException(status);
}
}
public void runUpdate(IProgressMonitor monitor, boolean silent) throws OperationCanceledException, CoreException
{
SubMonitor sub = SubMonitor.convert(monitor, Messages.JobMsgCheckingForUpdates, 200);
final NewVersion newVersion = checkForUpdates(sub.newChild(100));
if (newVersion != null)
{
final boolean[] doUpdate = new boolean[1];
Display.getDefault().syncExec(() -> {
Dialog dialog = new UpdateMessageDialog(Display.getDefault().getActiveShell(),
Messages.LabelUpdatesAvailable, //
MessageFormat.format(Messages.MsgConfirmInstall, newVersion.getVersion()), //
newVersion);
doUpdate[0] = dialog.open() == 0;
});
if (doUpdate[0])
{
runUpdateOperation(sub.newChild(100));
promptForRestart();
}
}
else
{
if (!silent)
{
Display.getDefault()
.asyncExec(() -> MessageDialog.openInformation(Display.getDefault().getActiveShell(),
Messages.LabelInfo, Messages.MsgNoUpdatesAvailable));
}
}
}
private void promptForRestart()
{
Display.getDefault().asyncExec(() -> {
MessageDialog dialog = new MessageDialog(Display.getDefault().getActiveShell(), Messages.LabelInfo, null,
Messages.MsgRestartRequired, MessageDialog.INFORMATION, //
new String[] { Messages.BtnLabelRestartNow, Messages.BtnLabelRestartLater }, 0);
int returnCode = dialog.open();
if (returnCode == 0)
{
try
{
boolean successful = partService.saveAll(true);
if (successful)
workbench.restart();
}
catch (IllegalStateException e)
{
PortfolioPlugin.log(e);
MessageDialog.openError(Display.getDefault().getActiveShell(), Messages.LabelError,
Messages.MsgCannotRestartBecauseOfOpenDialog);
}
}
});
}
private NewVersion checkForUpdates(IProgressMonitor monitor) throws OperationCanceledException, CoreException
{
ProvisioningSession session = new ProvisioningSession(agent);
operation = new UpdateOperation(session);
configureUpdateOperation(operation);
IStatus status = operation.resolveModal(monitor);
if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE)
return null;
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
if (status.getSeverity() == IStatus.ERROR)
throw new CoreException(status);
Update[] possibleUpdates = operation.getPossibleUpdates();
Update update = possibleUpdates.length > 0 ? possibleUpdates[0] : null;
if (update == null)
{
return new NewVersion(Messages.LabelUnknownVersion);
}
else
{
NewVersion v = new NewVersion(update.replacement.getVersion().toString());
v.setMinimumJavaVersionRequired(
update.replacement.getProperty("latest.changes.minimumJavaVersionRequired", null)); //$NON-NLS-1$
// try for locale first
String history = update.replacement.getProperty( //
VERSION_HISTORY + "_" + Locale.getDefault().getLanguage(), null); //$NON-NLS-1$
if (history == null)
history = update.replacement.getProperty(VERSION_HISTORY, null);
if (history != null)
v.setVersionHistory(history);
return v;
}
}
private void configureUpdateOperation(UpdateOperation operation)
{
try
{
String updateSite = PortfolioPlugin.getDefault().getPreferenceStore()
.getString(UIConstants.Preferences.UPDATE_SITE);
URI uri = new URI(updateSite);
operation.getProvisioningContext().setArtifactRepositories(new URI[] { uri });
operation.getProvisioningContext().setMetadataRepositories(new URI[] { uri });
}
catch (final URISyntaxException e)
{
PortfolioPlugin.log(e);
}
}
private void runUpdateOperation(IProgressMonitor monitor) throws OperationCanceledException, CoreException
{
if (operation == null)
checkForUpdates(monitor);
ProvisioningJob job = operation.getProvisioningJob(null);
IStatus status = job.runModal(monitor);
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
}
private <T> T getService(Class<T> type, String name)
{
BundleContext context = PortfolioPlugin.getDefault().getBundle().getBundleContext();
ServiceReference<?> reference = context.getServiceReference(name);
if (reference == null)
return null;
Object result = context.getService(reference);
context.ungetService(reference);
return type.cast(result);
}
}