blob: 4290af2ad2b3479bf0c5c84fd4f96b8920bf89f5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2014 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.core.sync;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants;
import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery;
import org.eclipse.mylyn.internal.tasks.core.TaskList;
import org.eclipse.mylyn.internal.tasks.core.data.TaskDataManager;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryManager;
import org.eclipse.mylyn.tasks.core.IRepositoryModel;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.sync.SynchronizationJob;
import org.eclipse.osgi.util.NLS;
/**
* Updates the task list.
*
* @author Steffen Pingel
*/
public class SynchronizeRepositoriesJob extends SynchronizationJob {
private static final boolean TRACE_ENABLED = Boolean.valueOf(Platform.getDebugOption("org.eclipse.mylyn.tasks.core/debug/synchronization")); //$NON-NLS-1$
private final TaskList taskList;
private final TaskDataManager taskDataManager;
private final IRepositoryManager repositoryManager;
private Set<TaskRepository> repositories;
private final IRepositoryModel tasksModel;
private final Map<QualifiedName, Object> properties = new ConcurrentHashMap<QualifiedName, Object>();
public SynchronizeRepositoriesJob(TaskList taskList, TaskDataManager taskDataManager, IRepositoryModel tasksModel,
IRepositoryManager repositoryManager) {
super(Messages.SynchronizeRepositoriesJob_Synchronizing_Task_List);
this.taskList = taskList;
this.taskDataManager = taskDataManager;
this.tasksModel = tasksModel;
this.repositoryManager = repositoryManager;
}
public Collection<TaskRepository> getRepositories() {
return Collections.unmodifiableCollection(repositories);
}
public void setRepositories(Collection<TaskRepository> repositories) {
if (repositories != null) {
this.repositories = new HashSet<TaskRepository>(repositories);
} else {
this.repositories = null;
}
}
@Override
public IStatus run(IProgressMonitor jobMonitor) {
try {
monitor.setCanceled(false);
monitor.attach(jobMonitor);
// get the current list of repositories
Set<TaskRepository> repositories = this.repositories;
if (repositories == null) {
repositories = new HashSet<TaskRepository>(repositoryManager.getAllRepositories());
}
try {
monitor.beginTask(Messages.SynchronizeRepositoriesJob_Processing, repositories.size() * 100);
if (TRACE_ENABLED) {
trace("Starting repository synchronization"); //$NON-NLS-1$
}
for (TaskRepository repository : repositories) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
if (repository.isOffline()) {
if (TRACE_ENABLED) {
trace("Skipping synchronization for " + repository.getRepositoryLabel()); //$NON-NLS-1$
}
monitor.worked(100);
continue;
}
monitor.setTaskName(MessageFormat.format(Messages.SynchronizeRepositoriesJob_Processing_,
repository.getRepositoryLabel()));
final AbstractRepositoryConnector connector = repositoryManager.getRepositoryConnector(repository.getConnectorKind());
Set<RepositoryQuery> queries = new HashSet<RepositoryQuery>(
taskList.getRepositoryQueries(repository.getRepositoryUrl()));
// remove queries that are not configured for auto update
if (!isUser()) {
for (Iterator<RepositoryQuery> it = queries.iterator(); it.hasNext();) {
if (!it.next().getAutoUpdate()) {
it.remove();
}
}
}
if (isUser() || queries.isEmpty()) {
monitor.worked(20);
} else {
// occasionally request update of repository configuration attributes as part of background synchronizations
updateRepositoryConfiguration(repository, connector, new SubProgressMonitor(monitor, 20));
}
if (TRACE_ENABLED) {
trace("Synchronizing queries for " + repository.getRepositoryLabel()); //$NON-NLS-1$
}
updateQueries(repository, connector, queries, monitor);
}
if (TRACE_ENABLED) {
trace("Completed repository synchronization"); //$NON-NLS-1$
}
// it's better to remove the job from the progress view instead of having it blocked until all child jobs finish
// if (isUser()) {
// Job.getJobManager().join(family, monitor);
// }
} catch (OperationCanceledException e) {
return Status.CANCEL_STATUS;
} finally {
monitor.done();
}
} finally {
monitor.detach(jobMonitor);
}
return Status.OK_STATUS;
}
private void updateQueries(TaskRepository repository, final AbstractRepositoryConnector connector,
Set<RepositoryQuery> queries, IProgressMonitor monitor) {
if (isUser()) {
for (RepositoryQuery query : queries) {
query.setSynchronizing(true);
}
taskList.notifySynchronizationStateChanged(queries);
}
SynchronizeQueriesJob job = new SynchronizeQueriesJob(taskList, taskDataManager, tasksModel, connector,
repository, queries) {
@Override
public boolean belongsTo(Object family) {
return ITasksCoreConstants.JOB_FAMILY_SYNCHRONIZATION == family;
}
};
job.setFetchSubtasks(getFetchSubtasks());
job.setUser(isUser());
job.setFullSynchronization(true);
job.setPriority(Job.DECORATE);
// propagate all properties from the current job to the newly created job to make sure the job icon, showing progress on the system taskbar, etc. are maintained.
copyPropertiesTo(job);
if (isUser()) {
job.schedule();
} else {
job.run(new SubProgressMonitor(monitor, 80));
}
}
private void copyPropertiesTo(SynchronizeQueriesJob job) {
for (QualifiedName key : properties.keySet()) {
job.setProperty(key, properties.get(key));
}
}
@Override
public void setProperty(QualifiedName key, Object value) {
super.setProperty(key, value);
properties.put(key, value);
}
@Override
public boolean belongsTo(Object family) {
return ITasksCoreConstants.JOB_FAMILY_SYNCHRONIZATION == family;
}
private void updateRepositoryConfiguration(TaskRepository repository, AbstractRepositoryConnector connector,
IProgressMonitor monitor) {
try {
if (!isUser()) {
monitor = Policy.backgroundMonitorFor(monitor);
}
monitor.beginTask(MessageFormat.format(
Messages.SynchronizeRepositoriesJob_Updating_repository_configuration_for_X,
repository.getRepositoryUrl()), 100);
if (connector.isRepositoryConfigurationStale(repository, monitor)) {
if (TRACE_ENABLED) {
trace("Updating configuration for " + repository.getRepositoryLabel()); //$NON-NLS-1$
}
connector.updateRepositoryConfiguration(repository, monitor);
repository.setConfigurationDate(new Date());
}
} catch (OperationCanceledException e) {
throw e;
} catch (Exception e) {
repository.setStatus(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
"Updating of repository configuration failed", e)); //$NON-NLS-1$
} catch (LinkageError e) {
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, NLS.bind(
"Internal error while updating repository configuration for ''{0}''", repository.getUrl()), e)); //$NON-NLS-1$
} finally {
monitor.done();
}
}
private void trace(String message) {
System.err.println("[" + new Date() + "] " + message); //$NON-NLS-1$ //$NON-NLS-2$
}
}