package goko;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.lang3.StringUtils;
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.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.operations.ProvisioningJob;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.operations.UpdateOperation;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.goko.core.config.GokoPreference;
import org.goko.core.log.GkLog;
import org.goko.core.log.LogUtils;
public class GokoUpdateCheckRunnable {
private static final GkLog LOG = GkLog.getLogger(GokoUpdateCheckRunnable.class);
private boolean cancelled;
/** Nothing to update status */
public static final IStatus NOTHING_TO_UPDATE = new Status(Status.OK, "Goko", 10000, "", null);
/** Update available status */
public static final IStatus UPDATE_AVAILABLE = new Status(Status.OK, "Goko", 10001, "", null);
/** Default update site location */
private static final String UPDATE_SITE_URL = "http://update.goko.fr/";
/** Developer mode update site location */
private static final String DEV_UPDATE_SITE_URL = "http://update.goko.fr/dev/";
/** The update operation */
private UpdateOperation operation;
public IStatus update(final IProvisioningAgent agent, final IProgressMonitor monitor, final UISynchronize sync, final IWorkbench workbench, boolean silent){
if(GokoPreference.getInstance().isDevEnvironment()){
// Don't perform update check in development environment
LOG.info("Update check disabled in dev environment");
return NOTHING_TO_UPDATE;
}
ProvisioningSession session = new ProvisioningSession(agent);
// update the whole running profile, otherwise specify IUs
operation = new UpdateOperation(session);
final SubMonitor sub = SubMonitor.convert(monitor, "Checking for application updates...", 200);
IMetadataRepositoryManager metadataManager = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
if(GokoPreference.getInstance().isDeveloperMode()){
LOG.info("********** DEV MODE UPDATE **********");
removeDistantRepositories(metadataManager, artifactManager);
addGokoDeveloperRepositories(metadataManager, artifactManager);
}else{
addGokoDefaultRepositories(metadataManager, artifactManager);
}
refreshUsedRepositories(metadataManager, artifactManager, monitor);
traceUsedRepositories(metadataManager, artifactManager);
//check if updates are available
IStatus status = operation.resolveModal(sub.newChild(100));
IStatus finalStatus = status;
if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
LOG.info("Nothing to update");
finalStatus = NOTHING_TO_UPDATE;
}
else {
finalStatus = UPDATE_AVAILABLE;
}
if(GokoPreference.getInstance().isDeveloperMode()){
removeGokoDeveloperRepositories(metadataManager, artifactManager);
}
if (cancelled) {
// reset cancelled flag
cancelled = false;
finalStatus = Status.CANCEL_STATUS;
}
return finalStatus;
}
/**
* Retrieve the provisioning job for update
* @param monitor progress monitor
* @param sync ui sync
* @return ProvisioningJob
*/
protected ProvisioningJob getProvisioningJob(final IProgressMonitor monitor, final UISynchronize sync){
final SubMonitor sub = SubMonitor.convert(monitor, "Retrieving provisioning job...", 10);
final ProvisioningJob provisioningJob = operation.getProvisioningJob(sub);
if (provisioningJob == null) {
if (operation.hasResolved()) {
showError(sync, "Couldn't get provisioning job: " + operation.getResolutionResult());
LOG.error( LogUtils.getMessage(operation.getResolutionResult()) );
} else {
showError(sync, "Couldn't resolve provisioning job");
}
cancelled = true;
}
return provisioningJob;
}
public IStatus performUpdate(final IProgressMonitor monitor, final UISynchronize sync, final IWorkbench workbench) {
final ProvisioningJob provisioningJob = getProvisioningJob(monitor, sync);
sync.syncExec(new Runnable() {
@Override
public void run() {
provisioningJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
if (event.getResult().isOK()) {
sync.asyncExec(new Runnable() {
@Override
public void run() {
GokoPreference.getInstance().setSystemClearPersistedState(true);
boolean restart = MessageDialog.open(MessageDialog.QUESTION, null,
"Updates installed, restart?",
"Updates have been installed successfully, do you want to restart?", SWT.MODELESS);
if (restart) {
workbench.restart();
}
}
});
}else {
LOG.info( LogUtils.getMessage(event.getResult()));
showError(sync, event.getResult().getMessage());
cancelled = true;
}
}
});
// since we switched to the UI thread for interacting with the user
// we need to schedule the provisioning thread, otherwise it would
// be executed also in the UI thread and not in a background thread
provisioningJob.setUser(true);
provisioningJob.schedule();
}
});
if (cancelled) {
// reset cancelled flag
cancelled = false;
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
private void showError(UISynchronize sync, final String message) {
// as the provision needs to be executed in a background thread
// we need to ensure that the message dialog is executed in
// the UI thread
sync.syncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openError(null, "Error", message);
}
});
}
/**
* Traces the list of known repositories
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void traceUsedRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager){
URI[] lstMetadataRepositories = metadataManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
URI[] lstArtifactRepositories = artifactManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
// Logging known metadata repositories
if(lstMetadataRepositories != null && lstMetadataRepositories.length > 0){
LOG.info("Checking updates from the following metadata repositories :");
for (URI uri : lstMetadataRepositories) {
LOG.info(" - "+uri.toString());
}
}
// Logging known artifact repositories
if(lstArtifactRepositories != null && lstArtifactRepositories.length > 0){
LOG.info("Checking updates from the following artifact repositories :");
for (URI uri : lstArtifactRepositories) {
LOG.info(" - "+uri.toString());
}
}
}
/**
* Traces the list of known repositories
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void refreshUsedRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager, IProgressMonitor monitor){
URI[] lstMetadataRepositories = metadataManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
URI[] lstArtifactRepositories = artifactManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
// Logging known metadata repositories
if(lstMetadataRepositories != null && lstMetadataRepositories.length > 0){
LOG.info("Refreshing metadata repositories : ");
for (URI uri : lstMetadataRepositories) {
LOG.info(" - "+uri.toString());
try {
metadataManager.loadRepository(uri, monitor);
metadataManager.refreshRepository(uri, monitor);
} catch (ProvisionException | OperationCanceledException e) {
LOG.error(e);
}
}
}
// Logging known artifact repositories
if(lstArtifactRepositories != null && lstArtifactRepositories.length > 0){
LOG.info("Refreshing artifact repositories : ");
for (URI uri : lstArtifactRepositories) {
LOG.info(" - "+uri.toString());
try {
metadataManager.loadRepository(uri, monitor);
artifactManager.refreshRepository(uri, monitor);
} catch (ProvisionException | OperationCanceledException e) {
LOG.error(e);
}
}
}
}
/**
* Adds Goko default repository if not found in the known repositories list
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void addGokoDefaultRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager){
URI[] lstMetadataRepositories = metadataManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
URI[] lstArtifactRepositories = artifactManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_ALL);
boolean metadataRepositoryFound = false;
boolean artifactRepositoryFound = false;
// Looking through known metadata repositories
if(lstMetadataRepositories != null && lstMetadataRepositories.length > 0){
for (URI uri : lstMetadataRepositories) {
if(StringUtils.contains(uri.toString(), UPDATE_SITE_URL)){
metadataRepositoryFound = true;
break;
}
}
}
// Looking through known artifact repositories
if(lstArtifactRepositories != null && lstArtifactRepositories.length > 0){
for (URI uri : lstArtifactRepositories) {
if(StringUtils.contains(uri.toString(), UPDATE_SITE_URL)){
artifactRepositoryFound = true;
break;
}
}
}
if(!metadataRepositoryFound){
LOG.info("Adding Goko default repository ("+UPDATE_SITE_URL+") to metadata repositories.");
try {
metadataManager.addRepository(new URI(UPDATE_SITE_URL));
} catch (URISyntaxException e) {
LOG.error(e);
}
}
if(!artifactRepositoryFound){
LOG.info("Adding Goko default repository ("+UPDATE_SITE_URL+") to artifact repositories.");
try {
artifactManager.addRepository(new URI(UPDATE_SITE_URL));
} catch (URISyntaxException e) {
LOG.error(e);
}
}
}
/**
* Adds Goko developer's mode repository
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void addGokoDeveloperRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager){
try {
metadataManager.addRepository(new URI(DEV_UPDATE_SITE_URL));
LOG.info("Adding Goko dev repository ("+DEV_UPDATE_SITE_URL+") to metadata repositories.");
artifactManager.addRepository(new URI(DEV_UPDATE_SITE_URL));
LOG.info("Adding Goko dev repository ("+DEV_UPDATE_SITE_URL+") to artifact repositories.");
} catch (URISyntaxException e) {
LOG.error(e);
}
}
/**
* Removes any update site that is not "dev"
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void removeDistantRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager){
URI[] lstMetadataRepositories = metadataManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_NON_LOCAL);
URI[] lstArtifactRepositories = artifactManager.getKnownRepositories(IMetadataRepositoryManager.REPOSITORIES_NON_LOCAL);
// Logging known metadata repositories
if(lstMetadataRepositories != null && lstMetadataRepositories.length > 0){
LOG.info("Removing distant updates site from the following metadata repositories :");
for (URI uri : lstMetadataRepositories) {
metadataManager.removeRepository(uri);
LOG.info(" - Removing "+uri.toString());
}
}
// Logging known artifact repositories
if(lstArtifactRepositories != null && lstArtifactRepositories.length > 0){
LOG.info("Removing distant updates site from the following artifact repositories :");
for (URI uri : lstArtifactRepositories) {
artifactManager.removeRepository(uri);
LOG.info(" - Removing "+uri.toString());
}
}
}
/**
* Removes Goko developer's mode repository
* @param metadataManager the used IMetadataRepositoryManager
* @param artifactManager the used IArtifactRepositoryManager
*/
private void removeGokoDeveloperRepositories(IMetadataRepositoryManager metadataManager, IArtifactRepositoryManager artifactManager){
try {
metadataManager.removeRepository(new URI(DEV_UPDATE_SITE_URL));
artifactManager.removeRepository(new URI(DEV_UPDATE_SITE_URL));
} catch (URISyntaxException e) {
LOG.error(e);
}
}
}