Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/synchronize/RefreshSubscriberJob.java')
-rw-r--r--bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/synchronize/RefreshSubscriberJob.java354
1 files changed, 354 insertions, 0 deletions
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/synchronize/RefreshSubscriberJob.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/synchronize/RefreshSubscriberJob.java
new file mode 100644
index 000000000..69a4b2129
--- /dev/null
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/synchronize/RefreshSubscriberJob.java
@@ -0,0 +1,354 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.internal.ui.synchronize;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.*;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.subscribers.Subscriber;
+import org.eclipse.team.core.synchronize.*;
+import org.eclipse.team.internal.core.Assert;
+import org.eclipse.team.internal.core.TeamPlugin;
+import org.eclipse.team.internal.core.subscribers.SubscriberSyncInfoCollector;
+import org.eclipse.team.internal.ui.Policy;
+import org.eclipse.team.internal.ui.TeamUIPlugin;
+import org.eclipse.team.ui.synchronize.ISynchronizeManager;
+import org.eclipse.ui.internal.progress.ProgressManager;
+
+/**
+ * Job to refresh a {@link Subscriber} in the background. The job can be configured
+ * to be re-scheduled and run at a specified interval.
+ *
+ * @since 3.0
+ */
+public final class RefreshSubscriberJob extends WorkspaceJob {
+
+ /**
+ * Uniquely identifies this type of job. This is used for cancellation.
+ */
+ private final static Object FAMILY_ID = new Object();
+
+ /**
+ * If true this job will be restarted when it completes
+ */
+ private boolean reschedule = false;
+
+ /**
+ * If true a rescheduled refresh job should be retarted when cancelled
+ */
+ private boolean restartOnCancel = true;
+
+ /**
+ * The schedule delay used when rescheduling a completed job
+ */
+ private static long scheduleDelay;
+
+ /**
+ * The subscribers and resources to refresh.
+ */
+ private IResource[] resources;
+ private Subscriber subscriber;
+
+ /**
+ * Refresh started/completed listener for every refresh
+ */
+ private static List listeners = new ArrayList(1);
+ private static final int STARTED = 1;
+ private static final int DONE = 2;
+
+ private SubscriberSyncInfoCollector collector;
+
+ /**
+ * Notification for safely notifying listeners of refresh lifecycle.
+ */
+ private abstract class Notification implements ISafeRunnable {
+ private IRefreshSubscriberListener listener;
+ public void handleException(Throwable exception) {
+ // don't log the exception....it is already being logged in Platform#run
+ }
+ public void run(IRefreshSubscriberListener listener) {
+ this.listener = listener;
+ Platform.run(this);
+ }
+ public void run() throws Exception {
+ notify(listener);
+ }
+ /**
+ * Subsclasses overide this method to send an event safely to a lsistener
+ * @param listener
+ */
+ protected abstract void notify(IRefreshSubscriberListener listener);
+ }
+
+ /**
+ * Create a job to refresh the specified resources with the subscriber.
+ * @param name
+ * @param resources
+ * @param subscriber
+ */
+ public RefreshSubscriberJob(String name, IResource[] resources, Subscriber subscriber) {
+ super(name);
+ Assert.isNotNull(resources);
+ Assert.isNotNull(subscriber);
+ this.resources = resources;
+ this.subscriber = subscriber;
+ setPriority(Job.DECORATE);
+ setRefreshInterval(3600 /* 1 hour */);
+
+ // Handle restarting of job if it is configured as a scheduled refresh job.
+ addJobChangeListener(new JobChangeAdapter() {
+ public void done(IJobChangeEvent event) {
+ if(shouldReschedule()) {
+ if(event.getResult().getSeverity() == IStatus.CANCEL && ! restartOnCancel) {
+ return;
+ }
+ RefreshSubscriberJob.this.schedule(scheduleDelay);
+ restartOnCancel = true;
+ }
+ }
+ });
+ }
+
+ public void setSubscriberCollector(SubscriberSyncInfoCollector collector) {
+ this.collector = collector;
+ }
+
+ /**
+ * If a collector is available then run the refresh and the background event processing
+ * within the same progess group.
+ */
+ public boolean shouldRun() {
+ // Ensure that any progress shown as a result of this refresh occurs hidden in a progress group.
+ return getSubscriber() != null;
+ }
+
+ public boolean belongsTo(Object family) {
+ return family == getFamily() || family == ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION;
+ }
+
+ public static Object getFamily() {
+ return FAMILY_ID;
+ }
+
+ /**
+ * This is run by the job scheduler. A list of subscribers will be refreshed, errors will not stop the job
+ * and it will continue to refresh the other subscribers.
+ */
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ // Only allow one refresh job at a time
+ // NOTE: It would be cleaner if this was done by a scheduling
+ // rule but at the time of writting, it is not possible due to
+ // the scheduling rule containment rules.
+ // Synchronized to ensure only one refresh job is running at a particular time
+ synchronized (getFamily()) {
+ Subscriber subscriber = getSubscriber();
+ IResource[] roots = getResources();
+ MultiStatus status = new MultiStatus(TeamPlugin.ID, TeamException.UNABLE, subscriber.getName(), null); //$NON-NLS-1$
+
+ // if there are no resources to refresh, just return
+ if(subscriber == null || roots == null) {
+ return Status.OK_STATUS;
+ }
+
+ monitor.beginTask(null, 100);
+ RefreshEvent event = new RefreshEvent(reschedule ? IRefreshEvent.SCHEDULED_REFRESH : IRefreshEvent.USER_REFRESH, roots, collector.getSubscriber());
+ RefreshChangeListener changeListener = new RefreshChangeListener(collector);
+ try {
+ event.setStartTime(System.currentTimeMillis());
+ if(monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ try {
+ // Set-up change listener so that we can determine the changes found
+ // during this refresh.
+ subscriber.addListener(changeListener);
+ // Pre-Notify
+ notifyListeners(STARTED, event);
+ // Perform the refresh
+ subscriber.refresh(roots, IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, 100));
+ } catch(TeamException e) {
+ status.merge(e.getStatus());
+ }
+ } catch(OperationCanceledException e2) {
+ subscriber.removeListener(changeListener);
+ event.setStatus(Status.CANCEL_STATUS);
+ event.setStopTime(System.currentTimeMillis());
+ notifyListeners(DONE, event);
+ return Status.CANCEL_STATUS;
+ } finally {
+ monitor.done();
+ }
+
+ Boolean modelProperty = (Boolean)getProperty(ProgressManager.PROPERTY_IN_DIALOG);
+ boolean isModal = modelProperty == null ? true : false;
+ setProperty(new QualifiedName("org.eclipse.ui.workbench.progress", "keep"), Boolean.valueOf(! isModal));
+
+ // Post-Notify
+ event.setChanges(changeListener.getChanges());
+ event.setStopTime(System.currentTimeMillis());
+ event.setStatus(status.isOK() ? calculateStatus(event) : (IStatus) status);
+ notifyListeners(DONE, event);
+ changeListener.clear();
+ return event.getStatus();
+ }
+ }
+
+ private IStatus calculateStatus(IRefreshEvent event) {
+ StringBuffer text = new StringBuffer();
+ int code = IStatus.OK;
+ SyncInfo[] changes = event.getChanges();
+ IResource[] resources = event.getResources();
+ if (collector != null) {
+ SyncInfoSet set = collector.getSyncInfoSet();
+ if (refreshedResourcesContainChanges(event)) {
+ code = IRefreshEvent.STATUS_CHANGES;
+ String outgoing = Long.toString(set.countFor(SyncInfo.OUTGOING, SyncInfo.DIRECTION_MASK));
+ String incoming = Long.toString(set.countFor(SyncInfo.INCOMING, SyncInfo.DIRECTION_MASK));
+ String conflicting = Long.toString(set.countFor(SyncInfo.CONFLICTING, SyncInfo.DIRECTION_MASK));
+ if (changes.length > 0) {
+ // New changes found
+ String numNewChanges = Integer.toString(event.getChanges().length);
+ text.append(Policy.bind("RefreshCompleteDialog.5a", new Object[]{numNewChanges, subscriber.getName(), outgoing, incoming, conflicting})); //$NON-NLS-1$
+ } else {
+ // Refreshed resources contain changes
+ text.append(Policy.bind("RefreshCompleteDialog.5", new Object[]{subscriber.getName(), outgoing, incoming, conflicting})); //$NON-NLS-1$
+ }
+ } else {
+ // No changes found
+ code = IRefreshEvent.STATUS_NO_CHANGES;
+ text.append(Policy.bind("RefreshCompleteDialog.6")); //$NON-NLS-1$
+ }
+ return new Status(IStatus.INFO, TeamUIPlugin.ID, code, text.toString(), null);
+ }
+ return Status.OK_STATUS;
+ }
+
+ private boolean refreshedResourcesContainChanges(IRefreshEvent event) {
+ if (collector != null) {
+ SyncInfoTree set = collector.getSyncInfoSet();
+ IResource[] resources = event.getResources();
+ for (int i = 0; i < resources.length; i++) {
+ IResource resource = resources[i];
+ SyncInfo[] infos = set.getSyncInfos(resource, IResource.DEPTH_INFINITE);
+ if(infos != null && infos.length > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ protected IResource[] getResources() {
+ return resources;
+ }
+
+ protected Subscriber getSubscriber() {
+ return subscriber;
+ }
+
+ protected SubscriberSyncInfoCollector getCollector() {
+ return collector;
+ }
+
+ public long getScheduleDelay() {
+ return scheduleDelay;
+ }
+
+ protected void start() {
+ if(getState() == Job.NONE) {
+ if(shouldReschedule()) {
+ setUser(collector != null);
+ schedule(getScheduleDelay());
+ }
+ }
+ }
+
+ /**
+ * Specify the interval in seconds at which this job is scheduled.
+ * @param seconds delay specified in seconds
+ */
+ public void setRefreshInterval(long seconds) {
+ boolean restart = false;
+ if(getState() == Job.SLEEPING) {
+ restart = true;
+ cancel();
+ }
+ scheduleDelay = seconds * 1000;
+ if(restart) {
+ start();
+ }
+ }
+
+ /**
+ * Returns the interval of this job in seconds.
+ * @return
+ */
+ public long getRefreshInterval() {
+ return scheduleDelay / 1000;
+ }
+
+ public void setRestartOnCancel(boolean restartOnCancel) {
+ this.restartOnCancel = restartOnCancel;
+ }
+
+ public void setReschedule(boolean reschedule) {
+ this.reschedule = reschedule;
+ }
+
+ public boolean shouldReschedule() {
+ return reschedule;
+ }
+
+ public static void addRefreshListener(IRefreshSubscriberListener listener) {
+ synchronized(listeners) {
+ if(! listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+ }
+
+ public static void removeRefreshListener(IRefreshSubscriberListener listener) {
+ synchronized(listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+ protected void notifyListeners(final int state, final IRefreshEvent event) {
+ // Get a snapshot of the listeners so the list doesn't change while we're firing
+ IRefreshSubscriberListener[] listenerArray;
+ synchronized (listeners) {
+ listenerArray = (IRefreshSubscriberListener[]) listeners.toArray(new IRefreshSubscriberListener[listeners.size()]);
+ }
+ // Notify each listener in a safe manner (i.e. so their exceptions don't kill us)
+ for (int i = 0; i < listenerArray.length; i++) {
+ IRefreshSubscriberListener listener = listenerArray[i];
+ Notification notification = new Notification() {
+ protected void notify(IRefreshSubscriberListener listener) {
+ switch (state) {
+ case STARTED:
+ listener.refreshStarted(event);
+ break;
+ case DONE:
+ listener.refreshDone(event);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+ notification.run(listener);
+ }
+ }
+} \ No newline at end of file

Back to the top