Bug 358842 pausing/resuming a p2 operation.

Introduce new test cases that will download artifacts from Internet, so add vm arguments to make downloading more stable.

Signed-off-by: Mengxin Zhu <kane.zhu@windriver.com>
diff --git a/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
index c2d53fa..af0028f 100644
--- a/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
@@ -60,7 +60,8 @@
    org.eclipse.equinox.p2.ui.sdk,
    org.eclipse.equinox.p2.ui.sdk.scheduler,
    org.eclipse.equinox.p2.updatesite,
-   org.eclipse.equinox.p2.director.app",
+   org.eclipse.equinox.p2.director.app,
+   org.eclipse.equinox.p2.transport.ecf",
  org.eclipse.equinox.p2.core;version="2.0.0",
  org.eclipse.equinox.p2.core.spi;version="2.0.0"
 Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.5.0,4.0.0)"
diff --git a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
index 92d9198..9024921 100644
--- a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
@@ -34,6 +34,7 @@
  org.eclipse.equinox.internal.p2.metadata.index,
  org.eclipse.equinox.internal.p2.metadata.repository.io,
  org.eclipse.equinox.internal.p2.persistence,
+ org.eclipse.equinox.internal.p2.repository,
  org.eclipse.equinox.internal.provisional.p2.core.eventbus,
  org.eclipse.equinox.internal.provisional.p2.repository,
  org.eclipse.equinox.p2.core;version="[2.0.0,3.0.0)",
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Messages.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Messages.java
index 9c9710c..0b8d794 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Messages.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Messages.java
@@ -70,6 +70,8 @@
 	public static String Phase_Install_Task;
 	public static String Phase_Sizing_Error;
 	public static String Phase_Sizing_Warning;
+
+	public static String phase_thread_interrupted_error;
 	public static String Phase_Unconfigure_Error;
 	public static String Phase_Uninstall_Error;
 
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java
index f57a482..bcf9129 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java
@@ -44,6 +44,7 @@
 	private Map<Touchpoint, Map<String, Object>> touchpointToTouchpointPhaseParameters = new HashMap<Touchpoint, Map<String, Object>>();
 	private Map<Touchpoint, Map<String, Object>> touchpointToTouchpointOperandParameters = new HashMap<Touchpoint, Map<String, Object>>();
 	ActionManager actionManager; // injected from phaseset
+	protected boolean isPaused = false;
 
 	protected Phase(String phaseId, int weight, boolean forced) {
 		if (phaseId == null || phaseId.length() == 0)
@@ -121,6 +122,16 @@
 			subMonitor.setWorkRemaining(operands.length - i);
 			if (subMonitor.isCanceled())
 				throw new OperationCanceledException();
+			while (isPaused) {
+				try {
+					Thread.sleep(1000);
+				} catch (InterruptedException e) {
+					mergeStatus(status, new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_thread_interrupted_error, phaseId), e));
+					return;
+				}
+				if (subMonitor.isCanceled())
+					throw new OperationCanceledException();
+			}
 			Operand operand = operands[i];
 			if (!isApplicable(operand))
 				continue;
@@ -336,4 +347,8 @@
 	protected String getProblemMessage() {
 		return NLS.bind(Messages.phase_error, getClass().getName());
 	}
+
+	protected void setPaused(boolean isPaused) {
+		this.isPaused = isPaused;
+	}
 }
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/PhaseSet.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/PhaseSet.java
index d4d1c6c..6e03eda 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/PhaseSet.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/PhaseSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2007, 2010 IBM Corporation and others.
+ *  Copyright (c) 2007, 2012 IBM Corporation and others.
  *  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
@@ -19,6 +19,8 @@
 public class PhaseSet implements IPhaseSet {
 
 	private final Phase[] phases;
+	private boolean isRunning = false;
+	private boolean isPaused = false;
 
 	public PhaseSet(Phase[] phases) {
 		if (phases == null)
@@ -33,6 +35,7 @@
 		int totalWork = getTotalWork(weights);
 		SubMonitor pm = SubMonitor.convert(monitor, totalWork);
 		try {
+			isRunning = true;
 			for (int i = 0; i < phases.length; i++) {
 				if (pm.isCanceled()) {
 					status.add(Status.CANCEL_STATUS);
@@ -68,10 +71,33 @@
 			}
 		} finally {
 			pm.done();
+			isRunning = false;
 		}
 		return status;
 	}
 
+	public synchronized boolean pause() {
+		if (isRunning && !isPaused) {
+			isPaused = true;
+			for (Phase phase : phases) {
+				phase.setPaused(isPaused);
+			}
+			return true;
+		}
+		return false;
+	}
+
+	public synchronized boolean resume() {
+		if (isRunning && isPaused) {
+			isPaused = false;
+			for (Phase phase : phases) {
+				phase.setPaused(isPaused);
+			}
+			return true;
+		}
+		return false;
+	}
+
 	public final IStatus validate(ActionManager actionManager, IProfile profile, Operand[] operands, ProvisioningContext context, IProgressMonitor monitor) {
 		Set<MissingAction> missingActions = new HashSet<MissingAction>();
 		for (int i = 0; i < phases.length; i++) {
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/messages.properties b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/messages.properties
index 597ef54..f5af6f2 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/messages.properties
@@ -105,5 +105,6 @@
 Phase_Install_Task=Installing {0}
 Phase_Sizing_Error=Error computing the size.  Some of the items to be installed could not be found.
 Phase_Sizing_Warning=The size may not be accurate.  Some of the items did not report a size.
+phase_thread_interrupted_error=Phase({0}) is interrupted.
 Phase_Unconfigure_Error=An error occurred while unconfiguring the items to uninstall
 Phase_Uninstall_Error=An error occurred while uninstalling
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/Collect.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/Collect.java
index df2435e..640bf08 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/Collect.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/Collect.java
@@ -12,9 +12,9 @@
 package org.eclipse.equinox.internal.p2.engine.phases;
 
 import java.util.*;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.*;
 import org.eclipse.equinox.internal.p2.engine.*;
+import org.eclipse.equinox.internal.p2.repository.DownloadPauseResumeEvent;
 import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
 import org.eclipse.equinox.p2.core.IProvisioningAgent;
 import org.eclipse.equinox.p2.engine.*;
@@ -22,6 +22,7 @@
 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
 import org.eclipse.equinox.p2.metadata.ITouchpointType;
 import org.eclipse.equinox.p2.repository.artifact.IArtifactRequest;
+import org.eclipse.osgi.util.NLS;
 
 /**
  * The goal of the collect phase is to ask the touchpoints if the artifacts associated with an IU need to be downloaded.
@@ -29,6 +30,7 @@
 public class Collect extends InstallableUnitPhase {
 	public static final String PARM_ARTIFACT_REQUESTS = "artifactRequests"; //$NON-NLS-1$
 	public static final String NO_ARTIFACT_REPOSITORIES_AVAILABLE = "noArtifactRepositoriesAvailable"; //$NON-NLS-1$
+	private IProvisioningAgent agent = null;
 
 	public Collect(int weight) {
 		super(PhaseSetFactory.PHASE_COLLECT, weight);
@@ -67,8 +69,23 @@
 	protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) {
 		@SuppressWarnings("unchecked")
 		List<IArtifactRequest[]> artifactRequests = (List<IArtifactRequest[]>) parameters.get(PARM_ARTIFACT_REQUESTS);
+		// it happens when rollbacking
+		if (artifactRequests.size() == 0)
+			return Status.OK_STATUS;
 		ProvisioningContext context = (ProvisioningContext) parameters.get(PARM_CONTEXT);
-		IProvisioningAgent agent = (IProvisioningAgent) parameters.get(PARM_AGENT);
+		synchronized (this) {
+			agent = (IProvisioningAgent) parameters.get(PARM_AGENT);
+		}
+
+		if (isPaused) {
+			try {
+				Thread.sleep(1000);
+			} catch (InterruptedException e) {
+				return new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_thread_interrupted_error, phaseId), e);
+			}
+			if (monitor.isCanceled())
+				return Status.CANCEL_STATUS;
+		}
 
 		List<IArtifactRequest> totalArtifactRequests = new ArrayList<IArtifactRequest>(artifactRequests.size());
 		DownloadManager dm = new DownloadManager(context, agent);
@@ -87,6 +104,9 @@
 		} finally {
 			if (downloadStatus.isOK() && bus != null)
 				bus.publishEvent(new CollectEvent(CollectEvent.TYPE_OVERALL_END, null, context, totalArtifactRequests.toArray(new IArtifactRequest[totalArtifactRequests.size()])));
+			synchronized (this) {
+				agent = null;
+			}
 		}
 	}
 
@@ -95,6 +115,22 @@
 		return null;
 	}
 
+	@Override
+	protected void setPaused(boolean isPaused) {
+		super.setPaused(isPaused);
+		firePauseEventToDownloadJobs();
+	}
+
+	private void firePauseEventToDownloadJobs() {
+		synchronized (this) {
+			if (agent != null) {
+				IProvisioningEventBus bus = (IProvisioningEventBus) agent.getService(IProvisioningEventBus.SERVICE_NAME);
+				if (bus != null)
+					bus.publishEvent(new DownloadPauseResumeEvent(isPaused ? DownloadPauseResumeEvent.TYPE_PAUSE : DownloadPauseResumeEvent.TYPE_RESUME));
+			}
+		}
+	}
+
 	protected IStatus initializeOperand(IProfile profile, InstallableUnitOperand operand, Map<String, Object> parameters, IProgressMonitor monitor) {
 		IStatus status = super.initializeOperand(profile, operand, parameters, monitor);
 		// defer setting the IU until after the super method to avoid triggering touchpoint initialization
diff --git a/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF
index d681c08..10912e0 100644
--- a/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF
@@ -17,7 +17,8 @@
    org.eclipse.equinox.p2.metadata.repository,
    org.eclipse.equinox.p2.updatesite,
    org.eclipse.equinox.p2.repository.tools,
-   org.eclipse.equinox.p2.transport.ecf",
+   org.eclipse.equinox.p2.transport.ecf,
+   org.eclipse.equinox.p2.engine",
  org.eclipse.equinox.internal.p2.repository.helpers;
   x-friends:="org.eclipse.equinox.p2.artifact.repository,
    org.eclipse.equinox.p2.exemplarysetup,
diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/repository/DownloadPauseResumeEvent.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/repository/DownloadPauseResumeEvent.java
new file mode 100644
index 0000000..679d016
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/repository/DownloadPauseResumeEvent.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Wind River and others.
+ * 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:
+ *     Wind River - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.repository;
+
+import java.util.EventObject;
+
+public class DownloadPauseResumeEvent extends EventObject {
+
+	private static final long serialVersionUID = 5782796765127875200L;
+	/**
+	 * It means downloading job should be paused.
+	 */
+	public static final int TYPE_PAUSE = 1;
+	/**
+	 * It means downloading job should be resumed.
+	 */
+	public static final int TYPE_RESUME = 2;
+
+	private int type;
+
+	public DownloadPauseResumeEvent(int type) {
+		super(type);
+		this.type = type;
+	}
+
+	public int getType() {
+		return type;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.tests/All p2 Tests.launch b/bundles/org.eclipse.equinox.p2.tests/All p2 Tests.launch
index e28d160..5c5c201 100644
--- a/bundles/org.eclipse.equinox.p2.tests/All p2 Tests.launch
+++ b/bundles/org.eclipse.equinox.p2.tests/All p2 Tests.launch
@@ -57,7 +57,7 @@
 <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consolelog -console"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.equinox.p2.tests"/>
 <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.eclipse.equinox.p2.reconciler.tests.platform.archive=c:/dev/platform/zips/eclipse-platform-3.6M6-win32.zip&#13;&#10;-Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=c:/dev/platform/zips/eclipse-platform-3.5-win32.zip&#13;&#10;-Dorg.eclipse.equinox.p2.repository&#13;&#10;-Dorg.eclipse.equinox.p2.tests.current.build.repo=http://eclipsebuildserv/3.6-I-builds/&#13;&#13;&#10;-Xmx512m&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.browse.connectTimeout=10000&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout=10000&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout=10000"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.eclipse.equinox.p2.reconciler.tests.platform.archive=c:/dev/platform/zips/eclipse-platform-3.6M6-win32.zip&#13;&#10;-Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=c:/dev/platform/zips/eclipse-platform-3.5-win32.zip&#13;&#10;-Dorg.eclipse.equinox.p2.repository&#13;&#10;-Dorg.eclipse.equinox.p2.tests.current.build.repo=http://eclipsebuildserv/3.6-I-builds/&#13;&#13;&#10;-Xmx512m&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.browse.connectTimeout=10000&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout=10000&#10;-Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout=10000&#10;-Dorg.eclipse.equinox.p2.transport.ecf.retry=5"/>
 <stringAttribute key="pde.version" value="3.3"/>
 <stringAttribute key="product" value="org.eclipse.sdk.ide"/>
 <booleanAttribute key="run_in_ui_thread" value="true"/>
diff --git a/bundles/org.eclipse.equinox.p2.tests/pom.xml b/bundles/org.eclipse.equinox.p2.tests/pom.xml
index a4bba0e..1e44b9c 100644
--- a/bundles/org.eclipse.equinox.p2.tests/pom.xml
+++ b/bundles/org.eclipse.equinox.p2.tests/pom.xml
@@ -53,7 +53,7 @@
 				<configuration>
 					<testSuite>org.eclipse.equinox.p2.tests</testSuite>
 					<testClass>org.eclipse.equinox.p2.tests.AutomatedTests</testClass>
-					<argLine>-Xmx512m -Dorg.eclipse.equinox.p2.reconciler.tests.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.reconciler.tests.lastrelease.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.repository</argLine>
+					<argLine>-Xmx512m -Dorg.eclipse.equinox.p2.reconciler.tests.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.reconciler.tests.lastrelease.platform.archive=${platform.archive.name} -Dorg.eclipse.equinox.p2.repository -Dorg.eclipse.equinox.p2.transport.ecf.retry=5</argLine>
 					<appArgLine>-consoleLog</appArgLine>
 					<bundleStartLevel>
 						<bundle>
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
index aca6ba7..7255475 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2007, 2010 IBM Corporation and others.
+ *  Copyright (c) 2007, 2012 IBM Corporation and others.
  *  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
@@ -10,16 +10,32 @@
  *******************************************************************************/
 package org.eclipse.equinox.p2.tests.engine;
 
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
+import java.io.File;
+import java.net.URI;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
 import org.eclipse.equinox.internal.p2.engine.*;
+import org.eclipse.equinox.internal.p2.touchpoint.natives.Util;
+import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
+import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent;
+import org.eclipse.equinox.p2.core.ProvisionException;
 import org.eclipse.equinox.p2.engine.*;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
+import org.eclipse.equinox.p2.query.*;
 import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
+import org.eclipse.equinox.p2.tests.TestActivator;
+import org.junit.Test;
 
 /**
  * Simple test of the engine API.
  */
 public class PhaseSetTest extends AbstractProvisioningTest {
+	PauseJob pause = null;
+
 	public PhaseSetTest(String name) {
 		super(name);
 	}
@@ -57,4 +73,219 @@
 		IStatus result = phaseSet.perform(new EngineSession(null, profile, context), operands, new NullProgressMonitor());
 		assertTrue(result.isOK());
 	}
+
+	@Test
+	public void testPauseNotRunningPhaseSet() {
+		PhaseSet set = (PhaseSet) PhaseSetFactory.createDefaultPhaseSet();
+		assertFalse("Can pause not running phaseset.", set.pause());
+	}
+
+	@Test
+	public void testResumeNotPausedPhaseSet() {
+		PhaseSet set = (PhaseSet) PhaseSetFactory.createDefaultPhaseSet();
+		assertFalse("Can resume not phaused phaseset.", set.resume());
+	}
+
+	abstract class PauseJob extends Job {
+		public PauseJob(String name) {
+			super(name);
+		}
+
+		private boolean isPaused = false;
+		Job resume = null;
+
+		public boolean isPaused() {
+			return isPaused;
+		}
+
+		public void setPause(boolean paused) {
+			isPaused = paused;
+		}
+	}
+
+	@Test
+	public void testPauseAndResume() throws ProvisionException, OperationCanceledException, InterruptedException {
+		URI repoLoc = getTestData("Load test data.", "/testData/pausefeature").toURI();
+		final PhaseSet phaseSet = (PhaseSet) PhaseSetFactory.createDefaultPhaseSet();
+		pause = new PauseJob("pause") {
+			protected IStatus run(IProgressMonitor monitor) {
+				if (!phaseSet.pause())
+					return new Status(IStatus.ERROR, TestActivator.PI_PROV_TESTS, "pause() failed.");
+				try {
+					Thread.sleep(5000);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				}
+				System.out.println(new Date() + " -- paused provisioning.");
+				setPause(true);
+				resume = new Job("resume") {
+					@Override
+					protected IStatus run(IProgressMonitor monitor1) {
+						pause.setPause(false);
+						System.out.println(new Date() + " -- will resume provisioning.");
+						if (!phaseSet.resume())
+							return new Status(IStatus.ERROR, TestActivator.PI_PROV_TESTS, "resume() failed.");
+						return Status.OK_STATUS;
+					}
+				};
+				resume.schedule(10000);
+				return Status.OK_STATUS;
+			}
+		};
+		basicTest(repoLoc, phaseSet, pause, QueryUtil.createIUQuery("org.eclipse.equinox.launcher"), 500, IStatus.OK, null);
+		assertTrue("Pause job is failed.", pause.getResult().isOK());
+		pause.resume.join();
+		assertTrue("Resume job is failed.", pause.resume.getResult().isOK());
+	}
+
+	private void basicTest(URI repoURI, PhaseSet phaseSet, final PauseJob pauseJob, IQuery<IInstallableUnit> query, final long delay, int expectedCode, IProgressMonitor monitor) throws ProvisionException, InterruptedException {
+		class ProvTestListener implements ProvisioningListener {
+			boolean hasProvisioningEventAfterPaused = false;
+			CountDownLatch latch = new CountDownLatch(1);
+
+			public void notify(EventObject o) {
+				if (o instanceof BeginOperationEvent) {
+					pauseJob.schedule(delay);
+					System.out.println(new Date() + " -- scheduled pause job.");
+					return;
+				}
+				if (o instanceof RepositoryEvent || o instanceof ProfileEvent)
+					return;
+				System.out.println(new Date() + " -- recive event " + o.getClass().getName());
+				if (o instanceof CommitOperationEvent || o instanceof RollbackOperationEvent) {
+					latch.countDown();
+					pauseJob.cancel();
+					return;
+				}
+				if (pauseJob.isPaused() && !(o instanceof PhaseEvent)) {
+					hasProvisioningEventAfterPaused = true;
+				}
+			}
+		}
+
+		ProvTestListener listener = new ProvTestListener();
+		getEventBus().addListener(listener);
+		try {
+			getMetadataRepositoryManager().loadRepository(repoURI, null);
+			getArtifactRepositoryManager().loadRepository(repoURI, null);
+			doProvisioning(repoURI, phaseSet, query, expectedCode, monitor);
+			// make sure the listener handles all event already that are dispatched asynchronously
+			listener.latch.await(10, TimeUnit.SECONDS);
+			assertFalse("Engine still do provisioning after pausing.", listener.hasProvisioningEventAfterPaused);
+			pauseJob.join();
+		} finally {
+			getEventBus().removeListener(listener);
+		}
+	}
+
+	private void doProvisioning(URI repoLoc, final PhaseSet phaseSet, IQuery<IInstallableUnit> query, int expectedResult, IProgressMonitor monitor) throws ProvisionException {
+		File testFolder = new File(System.getProperty("java.io.tmpdir"), "testProvisioning");
+		delete(testFolder);
+		testFolder.mkdir();
+		final String profileId = "test";
+		try {
+			ProvisioningContext context = new ProvisioningContext(getAgent());
+			context.setArtifactRepositories(new URI[] {repoLoc});
+			context.setMetadataRepositories(new URI[] {repoLoc});
+			IEngine engine = getEngine();
+			// restrict the installation to 'linux & gtk & x86' to match the test repo
+			Map props = new HashMap<String, String>();
+			props.put(IProfile.PROP_ENVIRONMENTS, "osgi.ws=gtk,osgi.arch=x86,osgi.os=linux");
+			props.put(IProfile.PROP_INSTALL_FOLDER, testFolder.getAbsolutePath());
+			IProfile profile = createProfile(profileId, props);
+			ProfileChangeRequest request = ProfileChangeRequest.createByProfileId(getAgent(), profile.getProfileId());
+			IQueryResult<IInstallableUnit> toBeInstalledIUs = getMetadataRepositoryManager().loadRepository(repoLoc, null).query(query, null);
+			assertFalse("Test case has problem to find IU to be installed.", toBeInstalledIUs.isEmpty());
+			request.addAll(toBeInstalledIUs.toSet());
+			IProvisioningPlan plan = getPlanner(getAgent()).getProvisioningPlan(request, context, null);
+			assertTrue("Provisioning plan can't be resolved.", plan.getStatus().isOK());
+			IStatus status = engine.perform(plan, phaseSet, monitor);
+			assertEquals("The reture code of provisioning is not expected.", expectedResult, status.getSeverity());
+		} finally {
+			delete(testFolder);
+			getProfileRegistry().removeProfile(profileId);
+			Util.getDownloadCacheRepo(getAgent()).removeAll(new NullProgressMonitor());
+		}
+	}
+
+	@Test
+	public void testPauseAndResumeMoreThanOnce() throws ProvisionException, InterruptedException {
+		//		URI repoLoc = URI.create("http://download.eclipse.org/releases/indigo");
+		URI repoLoc = getTestData("Load test data.", "/testData/pausefeature").toURI();
+		final PhaseSet phaseSet = (PhaseSet) PhaseSetFactory.createDefaultPhaseSet();
+		final int threhold = 3;
+		class ResumeJob extends Job {
+
+			private PauseJob pauseJob;
+			private int count = 0;
+
+			public ResumeJob(String name, PauseJob pauseJob) {
+				super(name);
+				this.pauseJob = pauseJob;
+			}
+
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				pauseJob.setPause(false);
+				System.out.println(new Date() + " -- resume provisioning.");
+				if (!phaseSet.resume())
+					return new Status(IStatus.INFO, TestActivator.PI_PROV_TESTS, "resume() failed.");
+				if (count++ < threhold)
+					pauseJob.schedule(10000);
+				return Status.OK_STATUS;
+			}
+		}
+		pause = new PauseJob("pause") {
+			protected IStatus run(IProgressMonitor monitor) {
+				if (!phaseSet.pause())
+					return new Status(IStatus.INFO, TestActivator.PI_PROV_TESTS, "pause() failed.");
+				try {
+					Thread.sleep(5000);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				}
+				System.out.println(new Date() + " -- paused provisioning.");
+				setPause(true);
+				if (resume == null)
+					resume = new ResumeJob("resume", this);
+				resume.schedule(10000);
+				return Status.OK_STATUS;
+			}
+		};
+
+		basicTest(repoLoc, phaseSet, pause, QueryUtil.createLatestQuery(QueryUtil.createIUQuery("org.eclipse.equinox.executable.feature.group")), 3000, IStatus.OK, null);
+	}
+
+	@Test
+	public void testCancelPausedProvisioing() throws ProvisionException, InterruptedException {
+		URI repoLoc = getTestData("Load test data.", "/testData/pausefeature").toURI();
+		final PhaseSet phaseSet = (PhaseSet) PhaseSetFactory.createDefaultPhaseSet();
+		pause = new PauseJob("pause") {
+			protected IStatus run(IProgressMonitor monitor) {
+				if (!phaseSet.pause())
+					return new Status(IStatus.ERROR, TestActivator.PI_PROV_TESTS, "pause() failed.");
+				try {
+					Thread.sleep(5000);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				}
+				System.out.println(new Date() + " -- paused provisioning.");
+				// wait seconds
+				try {
+					Thread.sleep(2000);
+				} catch (InterruptedException e) {
+					// 
+				}
+				setPause(true);
+				return Status.OK_STATUS;
+			}
+		};
+
+		basicTest(repoLoc, phaseSet, pause, QueryUtil.createLatestQuery(QueryUtil.createIUQuery("org.eclipse.equinox.executable.feature.group")), 3000, IStatus.CANCEL, new NullProgressMonitor() {
+			@Override
+			public boolean isCanceled() {
+				return pause.isPaused();
+			}
+		});
+	}
 }
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/AllTests.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/AllTests.java
index e67cb15..509799d 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/AllTests.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/AllTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009 Cloudsmith Inc and others.
+ * Copyright (c) 2009, 2012 Cloudsmith Inc and others.
  * 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
@@ -20,6 +20,7 @@
 	public static Test suite() {
 		TestSuite suite = new TestSuite(AllTests.class.getName());
 		suite.addTestSuite(RepositoryHelperTest.class);
+		suite.addTestSuite(FileReaderTest2.class);
 		return suite;
 	}
 }
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/FileReaderTest2.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/FileReaderTest2.java
new file mode 100644
index 0000000..214523f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/FileReaderTest2.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Wind River and others.
+ * 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:
+ *     Wind River - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.tests.repository;
+
+import java.io.*;
+import java.net.URI;
+import java.util.Date;
+import java.util.EventObject;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.*;
+import org.eclipse.equinox.internal.p2.repository.DownloadProgressEvent;
+import org.eclipse.equinox.internal.p2.transport.ecf.FileReader;
+import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
+import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
+import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
+import org.junit.Test;
+
+public class FileReaderTest2 extends AbstractProvisioningTest {
+
+	abstract class PauseJob extends Job {
+
+		private FileReader reader;
+
+		public PauseJob(String name, FileReader reader) {
+			super(name);
+			this.reader = reader;
+		}
+
+		public FileReader getReader() {
+			return reader;
+		}
+	}
+
+	@Test
+	public void testPauseAndResume() throws IOException, CoreException {
+		IProvisioningEventBus eventBus = getEventBus();
+		class PauseResumeProvisioningListener implements ProvisioningListener {
+			boolean downloadIsOngoing = false;
+			boolean isPaused = false;
+			float downloadProgressEventAfterPaused = 0;
+
+			public void notify(EventObject event) {
+				if (event instanceof DownloadProgressEvent) {
+					downloadIsOngoing = true;
+					if (isPaused) {
+						downloadProgressEventAfterPaused++;
+					}
+				}
+			}
+		}
+		final PauseResumeProvisioningListener listener = new PauseResumeProvisioningListener();
+		eventBus.addListener(listener);
+		try {
+			final org.eclipse.equinox.internal.p2.transport.ecf.FileReader reader = new org.eclipse.equinox.internal.p2.transport.ecf.FileReader(getAgent(), null);
+			final Job resumeJob = new Job("resume") {
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					listener.isPaused = false;
+					System.out.println("Download job is resumed at " + new Date());
+					reader.resume();
+					return Status.OK_STATUS;
+				}
+			};
+			PauseJob pauseJob = new PauseJob("pause", reader) {
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					reader.pause();
+					// wait for actual downloading thread is paused.
+					try {
+						Thread.sleep(2000);
+					} catch (InterruptedException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+					listener.isPaused = true;
+					System.out.println("Download job is paused at " + new Date());
+					resumeJob.schedule(10000);
+					return Status.OK_STATUS;
+				}
+			};
+			doFileReaderTest(pauseJob, null);
+			assertTrue("No download progress event is fired!", listener.downloadIsOngoing);
+			assertEquals("Download is not paused!", 0, listener.downloadProgressEventAfterPaused, 1);
+		} finally {
+			eventBus.removeListener(listener);
+		}
+	}
+
+	@Test
+	public void testPauseAndResumeMoreThanOnce() throws IOException, CoreException {
+		final org.eclipse.equinox.internal.p2.transport.ecf.FileReader reader = new org.eclipse.equinox.internal.p2.transport.ecf.FileReader(getAgent(), null);
+		abstract class ResumeJob extends Job {
+			PauseJob pausejob;
+
+			public ResumeJob(String name, PauseJob pauseJob) {
+				super(name);
+				this.pausejob = pauseJob;
+			}
+		}
+
+		final PauseJob pauseJob = new PauseJob("pause", reader) {
+			int count = 0;
+			final int threhold = 3;
+
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				reader.pause();
+				// wait for actual downloading thread is paused.
+				try {
+					Thread.sleep(2000);
+				} catch (InterruptedException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				System.out.println("Download job is paused at " + new Date());
+				final ResumeJob resumeJob = new ResumeJob("resume", this) {
+
+					@Override
+					protected IStatus run(IProgressMonitor monitor1) {
+						System.out.println("Download job is resumed at " + new Date());
+						reader.resume();
+						if (count++ < threhold)
+							this.pausejob.schedule(5000);
+						return Status.OK_STATUS;
+					}
+				};
+				resumeJob.schedule(10000);
+				return Status.OK_STATUS;
+			}
+		};
+		doFileReaderTest(pauseJob, null);
+	}
+
+	@Test
+	public void testCancelPausedDownload() throws IOException, CoreException {
+		final org.eclipse.equinox.internal.p2.transport.ecf.FileReader reader = new org.eclipse.equinox.internal.p2.transport.ecf.FileReader(getAgent(), null);
+		PauseJob pauseJob = new PauseJob("pause", reader) {
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				reader.pause();
+				// wait for actual downloading thread is paused.
+				try {
+					Thread.sleep(2000);
+				} catch (InterruptedException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				System.out.println("Download job is paused at " + new Date());
+				return Status.OK_STATUS;
+			}
+		};
+		try {
+			class CancelDownloadListener extends JobChangeAdapter {
+				boolean cancelDownload = false;
+
+				@Override
+				public void done(IJobChangeEvent event) {
+					try {
+						Thread.sleep(3000);
+					} catch (InterruptedException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+					cancelDownload = true;
+				}
+			}
+			final CancelDownloadListener pauseJobListener = new CancelDownloadListener();
+			pauseJob.addJobChangeListener(pauseJobListener);
+			doFileReaderTest(pauseJob, new NullProgressMonitor() {
+				@Override
+				public boolean isCanceled() {
+					return pauseJobListener.cancelDownload;
+				}
+			});
+			fail("Don't throw operation cancel exception.");
+		} catch (OperationCanceledException e) {
+			// expected
+		}
+	}
+
+	private void doFileReaderTest(PauseJob pauseJob, IProgressMonitor monitor) throws IOException, CoreException {
+		final String testRemoteFileURL = "http://ftp.osuosl.org/pub/eclipse/rt/ecf/3.5.4/site.p2/plugins/org.eclipse.ecf.doc_1.3.0.v20111230-0120.jar";
+		OutputStream out = null;
+		OutputStream out1 = null;
+		File tmpFolder = getTempFolder();
+		File tmpFile = new File(tmpFolder, "testDownloadPauseResume.zip");
+		File tmpFile1 = new File(tmpFolder, "testDownloadWithoutPause.zip");
+		try {
+			tmpFile1.createNewFile();
+			out1 = new FileOutputStream(tmpFile1);
+			FileReader readerWithoutPausing = new FileReader(null, null);
+			readerWithoutPausing.readInto(URI.create(testRemoteFileURL), out1, null);
+			assertNotNull(readerWithoutPausing.getResult());
+			assertTrue(readerWithoutPausing.getResult().isOK());
+			tmpFile.createNewFile();
+			out = new FileOutputStream(tmpFile);
+			FileReader reader = pauseJob.getReader();
+			pauseJob.schedule(5000);
+			reader.readInto(URI.create(testRemoteFileURL), out, monitor);
+			assertNotNull(reader.getResult());
+			assertTrue(reader.getResult().isOK());
+			assertEquals("File with pausing/resuming is not identical with file without pausing.", tmpFile1.length(), tmpFile.length());
+		} finally {
+			if (out1 != null)
+				out1.close();
+			tmpFile1.delete();
+			if (out != null)
+				out.close();
+			tmpFile.delete();
+			delete(tmpFolder);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.equinox.p2.tests/test.xml b/bundles/org.eclipse.equinox.p2.tests/test.xml
index 93c8214..1263e95 100644
--- a/bundles/org.eclipse.equinox.p2.tests/test.xml
+++ b/bundles/org.eclipse.equinox.p2.tests/test.xml
@@ -46,7 +46,7 @@
 			<property name="data-dir" value="${p2_location}" />
 			<property name="plugin-name" value="org.eclipse.equinox.p2.tests" />
 			<property name="classname" value="org.eclipse.equinox.p2.tests.AutomatedTests" />
-		    <property name="extraVMargs" value="-XX:MaxPermSize=256m" />
+		    <property name="extraVMargs" value="-XX:MaxPermSize=256m -Dorg.eclipse.equinox.p2.transport.ecf.retry=5" />
 		</ant>
 	</target>
 
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/artifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/artifacts.xml
new file mode 100644
index 0000000..baf533c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/artifacts.xml
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?artifactRepository version='1.1.0'?>
+<repository name='&quot;Eclipse Project Test Site&quot;'
+	type='org.eclipse.equinox.p2.artifact.repository.simpleRepository'
+	version='1.0.0'>
+	<properties size='4'>
+		<property name='publishPackFilesAsSiblings' value='true' />
+		<property name='p2.mirrorsURL'
+			value='http://www.eclipse.org/downloads/download.php?file=/eclipse/updates/3.7/R-3.7.2-201202080800&amp;format=xml&amp;protocol=http' />
+		<property name='p2.timestamp' value='1328722968200' />
+		<property name='p2.compressed' value='false' />
+	</properties>
+	<mappings size='5'>
+		<rule filter='(&amp; (classifier=osgi.bundle) (format=packed))'
+			output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/plugins/${id}_${version}.jar.pack.gz' />
+		<rule filter='(&amp; (classifier=osgi.bundle))' output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/plugins/${id}_${version}.jar' />
+		<rule filter='(&amp; (classifier=binary))' output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/binary/${id}_${version}' />
+		<rule
+			filter='(&amp; (classifier=org.eclipse.update.feature) (format=packed))'
+			output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/features/${id}_${version}.jar.pack.gz' />
+		<rule filter='(&amp; (classifier=org.eclipse.update.feature))'
+			output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/features/${id}_${version}.jar' />
+	</mappings>
+	<artifacts size='13433'>
+		<artifact classifier='binary'
+			id='org.eclipse.equinox.executable_root.gtk.linux.x86' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ'>
+			<properties size='3'>
+				<property name='download.size' value='161367' />
+				<property name='artifact.size' value='161367' />
+				<property name='download.md5' value='2211bc75c31415de3b6b1d85df031ad2' />
+			</properties>
+		</artifact>
+		<artifact classifier='osgi.bundle'
+			id='org.eclipse.equinox.launcher.gtk.linux.x86' version='1.1.100.v20110505'>
+			<properties size='3'>
+				<property name='artifact.size' value='73673' />
+				<property name='download.size' value='73673' />
+				<property name='download.md5' value='b2dd3eb2753f67aca3a16d4aca4b4236' />
+			</properties>
+		</artifact>
+		<artifact classifier='osgi.bundle' id='org.eclipse.equinox.launcher'
+			version='1.2.0.v20110502'>
+			<properties size='3'>
+				<property name='artifact.size' value='47262' />
+				<property name='download.size' value='47262' />
+				<property name='download.md5' value='8f64108bbd31ae9cdc4d7c2dd1e06deb' />
+			</properties>
+		</artifact>
+	</artifacts>
+</repository>    
+  
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/content.xml b/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/content.xml
new file mode 100644
index 0000000..2fe6510
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/content.xml
@@ -0,0 +1,138 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?metadataRepository version='1.1.0'?>
+<repository name='Indigo' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1'>
+  <properties size='2'>
+    <property name='p2.compressed' value='false'/>
+    <property name='p2.timestamp' value='1329418105201'/>
+  </properties>
+ <units size='6371'>
+      <unit id='org.eclipse.equinox.executable.feature.group' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ' singleton='false'>
+      <update id='org.eclipse.equinox.executable.feature.group' range='[0.0.0,3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ)' severity='0'/>
+      <properties size='6'>
+        <property name='org.eclipse.equinox.p2.name' value='%featureName'/>
+        <property name='org.eclipse.equinox.p2.description' value='%description'/>
+        <property name='org.eclipse.equinox.p2.type.group' value='true'/>
+        <property name='df_LT.featureName' value='Eclipse Platform Launchers'/>
+        <property name='df_LT.description' value='Platform specific launchers.'/>
+        <property name='df_LT.license' value='Eclipse Foundation Software User Agreement&#xA;February 1, 2011&#xA;&#xA;Usage Of Content&#xA;&#xA;THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR&#xA;OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY &quot;CONTENT&quot;).&#xA;USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS&#xA;AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR&#xA;NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU&#xA;AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT&#xA;AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS&#xA;OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE&#xA;TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS&#xA;OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED&#xA;BELOW, THEN YOU MAY NOT USE THE CONTENT.&#xA;&#xA;Applicable Licenses&#xA;&#xA;Unless otherwise indicated, all Content made available by the&#xA;Eclipse Foundation is provided to you under the terms and conditions of&#xA;the Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is&#xA;provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.&#xA;For purposes of the EPL, &quot;Program&quot; will mean the Content.&#xA;&#xA;Content includes, but is not limited to, source code, object code,&#xA;documentation and other files maintained in the Eclipse Foundation source code&#xA;repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available&#xA;as downloadable archives (&quot;Downloads&quot;).&#xA;&#xA;- Content may be structured and packaged into modules to facilitate delivering,&#xA;extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;),&#xA;plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).&#xA;- Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)&#xA;in a directory named &quot;plugins&quot;.&#xA;- A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.&#xA;Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.&#xA;Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version&#xA;numbers of the Plug-ins and/or Fragments associated with that Feature.&#xA;- Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files&#xA;named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.&#xA;&#xA;The terms and conditions governing Plug-ins and Fragments should be&#xA;contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and&#xA;conditions governing Features and Included Features should be contained&#xA;in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature&#xA;Licenses may be located in any directory of a Download or Module&#xA;including, but not limited to the following locations:&#xA;&#xA;- The top-level (root) directory&#xA;- Plug-in and Fragment directories&#xA;- Inside Plug-ins and Fragments packaged as JARs&#xA;- Sub-directories of the directory named &quot;src&quot; of certain Plug-ins&#xA;- Feature directories&#xA;&#xA;Note: if a Feature made available by the Eclipse Foundation is installed using the&#xA;Provisioning Technology (as defined below), you must agree to a license (&quot;Feature &#xA;Update License&quot;) during the installation process. If the Feature contains&#xA;Included Features, the Feature Update License should either provide you&#xA;with the terms and conditions governing the Included Features or inform&#xA;you where you can locate them. Feature Update Licenses may be found in&#xA;the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.&#xA;Such Abouts, Feature Licenses, and Feature Update Licenses contain the&#xA;terms and conditions (or references to such terms and conditions) that&#xA;govern your use of the associated Content in that directory.&#xA;&#xA;THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER&#xA;TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.&#xA;SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):&#xA;&#xA;- Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)&#xA;- Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)&#xA;- Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)&#xA;- Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)&#xA;- Metro Link Public License 1.00 (available at http://www.opengroup.org/openmotif/supporters/metrolink/license.html)&#xA;- Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)&#xA;&#xA;IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR&#xA;TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License&#xA;is provided, please contact the Eclipse Foundation to determine what terms and conditions&#xA;govern that particular Content.&#xA;&#xA;&#xA;Use of Provisioning Technology&#xA;&#xA;The Eclipse Foundation makes available provisioning software, examples of which include,&#xA;but are not limited to, p2 and the Eclipse Update Manager (&quot;Provisioning Technology&quot;) for&#xA;the purpose of allowing users to install software, documentation, information and/or&#xA;other materials (collectively &quot;Installable Software&quot;). This capability is provided with&#xA;the intent of allowing such users to install, extend and update Eclipse-based products.&#xA;Information about packaging Installable Software is available at&#xA;http://eclipse.org/equinox/p2/repository_packaging.html (&quot;Specification&quot;).&#xA;&#xA;You may use Provisioning Technology to allow other parties to install Installable Software.&#xA;You shall be responsible for enabling the applicable license agreements relating to the&#xA;Installable Software to be presented to, and accepted by, the users of the Provisioning Technology&#xA;in accordance with the Specification. By using Provisioning Technology in such a manner and&#xA;making it available in accordance with the Specification, you further acknowledge your&#xA;agreement to, and the acquisition of all necessary rights to permit the following:&#xA;&#xA;1. A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute&#xA;the Provisioning Technology on a machine (&quot;Target Machine&quot;) with the intent of installing,&#xA;extending or updating the functionality of an Eclipse-based product.&#xA;2. During the Provisioning Process, the Provisioning Technology may cause third party&#xA;Installable Software or a portion thereof to be accessed and copied to the Target Machine.&#xA;3. Pursuant to the Specification, you will provide to the user the terms and conditions that&#xA;govern the use of the Installable Software (&quot;Installable Software Agreement&quot;) and such&#xA;Installable Software Agreement shall be accessed from the Target Machine in accordance&#xA;with the Specification. Such Installable Software Agreement must inform the user of the&#xA;terms and conditions that govern the Installable Software and must solicit acceptance by&#xA;the end user in the manner prescribed in such Installable Software Agreement. Upon such&#xA;indication of agreement by the user, the provisioning Technology will complete installation&#xA;of the Installable Software.&#xA;&#xA;Cryptography&#xA;&#xA;Content may contain encryption software. The country in which you are&#xA;currently may have restrictions on the import, possession, and use,&#xA;and/or re-export to another country, of encryption software. BEFORE&#xA;using any encryption software, please check the country&apos;s laws,&#xA;regulations and policies concerning the import, possession, or use, and&#xA;re-export of encryption software, to see if this is permitted.&#xA;&#xA;Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.'/>
+      </properties>
+      <provides size='2'>
+        <provided namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.executable.feature.group' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ'/>
+        <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+      </provides>
+      <requires size='49'>
+        <required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.launcher' range='[1.2.0.v20110502,1.2.0.v20110502]'/>
+        <required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.launcher.gtk.linux.x86' range='[1.1.100.v20110505,1.1.100.v20110505]'>
+          <filter>
+            (&amp;(osgi.arch=x86)(osgi.os=linux)(osgi.ws=gtk))
+          </filter>
+        </required>
+        <required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.executable_root.gtk.linux.x86' range='[3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ,3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ]'>
+          <filter>
+            (&amp;(osgi.arch=x86)(osgi.os=linux)(osgi.ws=gtk))
+          </filter>
+        </required>
+      </requires>
+      <touchpoint id='null' version='0.0.0'/>
+      <licenses size='1'>
+        <license uri='%25licenseURL' url='%25licenseURL'>
+          %license
+        </license>
+      </licenses>
+    </unit>
+    <unit id='org.eclipse.equinox.launcher' version='1.2.0.v20110502'>
+      <update id='org.eclipse.equinox.launcher' range='[0.0.0,1.2.0.v20110502)' severity='0'/>
+      <properties size='5'>
+        <property name='df_LT.providerName' value='Eclipse.org - Equinox'/>
+        <property name='df_LT.pluginName' value='Equinox Launcher'/>
+        <property name='org.eclipse.equinox.p2.name' value='%pluginName'/>
+        <property name='org.eclipse.equinox.p2.provider' value='%providerName'/>
+        <property name='org.eclipse.equinox.p2.bundle.localization' value='launcher'/>
+      </properties>
+      <provides size='7'>
+        <provided namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.launcher' version='1.2.0.v20110502'/>
+        <provided namespace='osgi.bundle' name='org.eclipse.equinox.launcher' version='1.2.0.v20110502'/>
+        <provided namespace='java.package' name='org.eclipse.core.launcher' version='0.0.0'/>
+        <provided namespace='java.package' name='org.eclipse.equinox.internal.launcher' version='0.0.0'/>
+        <provided namespace='java.package' name='org.eclipse.equinox.launcher' version='0.0.0'/>
+        <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+        <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+      </provides>
+      <artifacts size='1'>
+        <artifact classifier='osgi.bundle' id='org.eclipse.equinox.launcher' version='1.2.0.v20110502'/>
+      </artifacts>
+      <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+      <touchpointData size='1'>
+        <instructions size='1'>
+          <instruction key='manifest'>
+            Bundle-SymbolicName: org.eclipse.equinox.launcher;singleton:=true&#xA;Bundle-Version: 1.2.0.v20110502
+          </instruction>
+        </instructions>
+      </touchpointData>
+    </unit>
+    <unit id='org.eclipse.equinox.launcher.gtk.linux.x86' version='1.1.100.v20110505'>
+      <update id='org.eclipse.equinox.launcher.gtk.linux.x86' range='[0.0.0,1.1.100.v20110505)' severity='0'/>
+      <properties size='5'>
+        <property name='df_LT.providerName' value='Eclipse.org - Equinox'/>
+        <property name='df_LT.pluginName' value='Equinox Launcher Linux X86 Fragment'/>
+        <property name='org.eclipse.equinox.p2.name' value='%pluginName'/>
+        <property name='org.eclipse.equinox.p2.provider' value='%providerName'/>
+        <property name='org.eclipse.equinox.p2.bundle.localization' value='launcher.gtk.linux.x86'/>
+      </properties>
+      <provides size='5'>
+        <provided namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.launcher.gtk.linux.x86' version='1.1.100.v20110505'/>
+        <provided namespace='osgi.bundle' name='org.eclipse.equinox.launcher.gtk.linux.x86' version='1.1.100.v20110505'/>
+        <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+        <provided namespace='osgi.fragment' name='org.eclipse.equinox.launcher' version='1.1.100.v20110505'/>
+        <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+      </provides>
+      <requires size='1'>
+        <required namespace='osgi.bundle' name='org.eclipse.equinox.launcher' range='[1.0.0,1.3.0)'/>
+      </requires>
+      <filter>
+        (&amp;(osgi.arch=x86)(osgi.os=linux)(osgi.ws=gtk))
+      </filter>
+      <artifacts size='1'>
+        <artifact classifier='osgi.bundle' id='org.eclipse.equinox.launcher.gtk.linux.x86' version='1.1.100.v20110505'/>
+      </artifacts>
+      <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+      <touchpointData size='1'>
+        <instructions size='2'>
+          <instruction key='manifest'>
+            Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.x86;singleton:=true&#xA;Bundle-Version: 1.1.100.v20110505&#xA;Fragment-Host: org.eclipse.equinox.launcher;bundle-version=&quot;[1.0.0,1.3.0)&quot;
+          </instruction>
+          <instruction key='zipped'>
+            true
+          </instruction>
+        </instructions>
+      </touchpointData>
+    </unit>
+      <unit id='org.eclipse.equinox.executable_root.gtk.linux.x86' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ'>
+      <provides size='1'>
+        <provided namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.executable_root.gtk.linux.x86' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ'/>
+      </provides>
+      <filter>
+        (&amp;(osgi.arch=x86)(osgi.os=linux)(osgi.ws=gtk))
+      </filter>
+      <artifacts size='1'>
+        <artifact classifier='binary' id='org.eclipse.equinox.executable_root.gtk.linux.x86' version='3.5.1.v20111216-1653-7P7NFUIFIbaUcU77s0KQWHw5HZTZ'/>
+      </artifacts>
+      <touchpoint id='org.eclipse.equinox.p2.native' version='1.0.0'/>
+      <touchpointData size='2'>
+        <instructions size='2'>
+          <instruction key='uninstall'>
+            cleanupzip(source:@artifact, target:${installFolder});
+          </instruction>
+          <instruction key='install'>
+            unzip(source:@artifact, target:${installFolder});
+          </instruction>
+        </instructions>
+        <instructions size='1'>
+          <instruction key='install'>
+            chmod(targetDir:${installFolder}, targetFile:libcairo-swt.so, permissions:755);
+          </instruction>
+        </instructions>
+      </touchpointData>
+    </unit>    
+ </units>
+ </repository>
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java b/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java
index a4a5237..3ca9e04 100644
--- a/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java
+++ b/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java
@@ -34,6 +34,7 @@
 import org.eclipse.ecf.filetransfer.FileTransferJob;
 import org.eclipse.ecf.filetransfer.IFileRangeSpecification;
 import org.eclipse.ecf.filetransfer.IFileTransferListener;
+import org.eclipse.ecf.filetransfer.IFileTransferPausable;
 import org.eclipse.ecf.filetransfer.IIncomingFileTransfer;
 import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter;
 import org.eclipse.ecf.filetransfer.IncomingFileTransferException;
@@ -43,6 +44,8 @@
 import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferEvent;
 import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDataEvent;
 import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDoneEvent;
+import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceivePausedEvent;
+import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveResumedEvent;
 import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent;
 import org.eclipse.ecf.filetransfer.identity.FileCreateException;
 import org.eclipse.ecf.filetransfer.identity.FileIDFactory;
@@ -99,6 +102,10 @@
 	private Job cancelJob;
 	private boolean monitorStarted;
 	private IProvisioningAgent agent;
+	private boolean isPause = false;
+	private boolean hasPaused = false;
+	private IFileTransferPausable pasuable = null;
+
 
 	/**
 	 * Create a new FileReader that will retry failed connection attempts and sleep some amount of time between each
@@ -217,14 +224,39 @@
 					}
 				}
 			}
+			pauseIfPossible(source);
 			onData(source);
 		} else if (event instanceof IIncomingFileTransferReceiveDoneEvent) {
+			// stop paused Reader if resuming failed
+			this.hasPaused = false;
 			if (closeStreamWhenFinished)
 				hardClose(theOutputStream);
 
 			if (exception == null)
 				exception = ((IIncomingFileTransferReceiveDoneEvent) event).getException();
 			onDone(((IIncomingFileTransferReceiveDoneEvent) event).getSource());
+		} else if (event instanceof IIncomingFileTransferReceivePausedEvent) {
+			this.hasPaused  = true;
+		} else if (event instanceof IIncomingFileTransferReceiveResumedEvent) {
+			//we no longer need the cancel handler because we are about to resume the transfer job
+			if (cancelJob != null)
+				cancelJob.cancel();
+			try {
+				((IIncomingFileTransferReceiveResumedEvent) event).receive(theOutputStream, this);
+			} catch (IOException e) {
+				exception = e;
+			} finally {
+				this.hasPaused = false;
+			}
+		}
+	}
+
+	private synchronized void pauseIfPossible(IIncomingFileTransfer source) {
+		if (isPaused() && !hasPaused) {
+			pasuable  = (IFileTransferPausable) source
+					.getAdapter(IFileTransferPausable.class);
+			if (pasuable != null)
+				pasuable.pause();
 		}
 	}
 
@@ -320,8 +352,9 @@
 		if (monitor == null)
 			monitor = new NullProgressMonitor();
 		try {
-			sendRetrieveRequest(uri, anOutputStream, (startPos != -1 ? new DownloadRange(startPos) : null), false, monitor);
+			sendRetrieveRequest(uri, anOutputStream, (startPos != -1 ? new DownloadRange(startPos) : null), false, monitor);			
 			Job.getJobManager().join(this, new SuppressBlockedMonitor(monitor, 0));
+			waitPaused(uri, anOutputStream, startPos, monitor);
 			if (monitor.isCanceled() && connectEvent != null)
 				connectEvent.cancel();
 			// check and throw exception if received in callback
@@ -342,6 +375,18 @@
 			monitor.done();
 		}
 	}
+	
+	protected void waitPaused(URI uri, OutputStream anOutputStream, long startPos, IProgressMonitor monitor) throws AuthenticationFailedException, JREHttpClientRequiredException, FileNotFoundException, CoreException, OperationCanceledException, InterruptedException {
+		if (hasPaused) {
+			while (hasPaused) {
+				Thread.sleep(1000);
+				if (monitor.isCanceled())
+					throw new OperationCanceledException();
+			}	
+			Job.getJobManager().join(this, new SuppressBlockedMonitor(monitor, 0));
+			waitPaused(uri, anOutputStream, startPos, monitor);
+		}
+	}
 
 	protected void sendRetrieveRequest(URI uri, OutputStream outputStream, DownloadRange range, boolean closeStreamOnFinish, //
 			IProgressMonitor monitor) throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException {
@@ -350,8 +395,8 @@
 		if (factory == null) {
 			throw RepositoryStatusHelper.fromMessage(Messages.ecf_configuration_error);
 		}
+				
 		IRetrieveFileTransferContainerAdapter adapter = factory.newInstance();
-
 		adapter.setConnectContextForAuthentication(connectContext);
 
 		this.exception = null;
@@ -387,6 +432,23 @@
 				break;
 		}
 	}
+	
+	public synchronized boolean pause() {
+		this.isPause  = true;
+		return true;
+	}
+	
+	public boolean isPaused() {		
+		return this.isPause;
+	}
+	
+	public synchronized boolean resume() {
+		this.isPause = false;
+		if (this.pasuable != null) {
+			return this.pasuable.resume();
+		}
+		return false;
+	}
 
 	/**
 	 * Utility method to check exception condition and determine if retry should be done.
diff --git a/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java b/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java
index 4be3aa9..5444642 100644
--- a/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java
+++ b/bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java
@@ -20,6 +20,7 @@
 import java.net.SocketTimeoutException;
 import java.net.URI;
 import java.net.UnknownHostException;
+import java.util.EventObject;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -37,12 +38,15 @@
 import org.eclipse.equinox.internal.p2.repository.AuthenticationFailedException;
 import org.eclipse.equinox.internal.p2.repository.Credentials;
 import org.eclipse.equinox.internal.p2.repository.Credentials.LoginCanceledException;
+import org.eclipse.equinox.internal.p2.repository.DownloadPauseResumeEvent;
 import org.eclipse.equinox.internal.p2.repository.DownloadStatus;
 import org.eclipse.equinox.internal.p2.repository.FileInfo;
 import org.eclipse.equinox.internal.p2.repository.JREHttpClientRequiredException;
 import org.eclipse.equinox.internal.p2.repository.Messages;
 import org.eclipse.equinox.internal.p2.repository.RepositoryPreferences;
 import org.eclipse.equinox.internal.p2.repository.Transport;
+import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
+import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
 import org.eclipse.equinox.internal.provisional.p2.repository.IStateful;
 import org.eclipse.equinox.p2.core.IProvisioningAgent;
 import org.eclipse.equinox.p2.core.ProvisionException;
@@ -96,7 +100,33 @@
 
 				// perform the download
 				reader = new FileReader(agent, context);
-				reader.readInto(toDownload, target, startPos, monitor);
+				ProvisioningListener listener = null;
+				IProvisioningEventBus eventBus = null;
+				try {
+					final FileReader fileReader = reader;
+					if (agent != null) {
+						eventBus = (IProvisioningEventBus) agent.getService(IProvisioningEventBus.SERVICE_NAME);
+						if (eventBus != null) {
+							listener = new ProvisioningListener() {							
+								@Override
+								public void notify(EventObject event) {
+									if (event instanceof DownloadPauseResumeEvent) {
+										if (((DownloadPauseResumeEvent) event).getType() == DownloadPauseResumeEvent.TYPE_PAUSE)
+											fileReader.pause();
+										else if (((DownloadPauseResumeEvent) event).getType() == DownloadPauseResumeEvent.TYPE_RESUME)
+											fileReader.resume();
+									}
+								}
+							};
+							eventBus.addListener(listener);
+						}
+					}
+					reader.readInto(toDownload, target, startPos, monitor);
+				} finally {
+					if (eventBus != null) {
+						eventBus.removeListener(listener);
+					}
+				}
 
 				// check that job ended ok - throw exceptions otherwise
 				IStatus result = reader.getResult();