summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMengxin Zhu2012-02-27 03:47:36 (EST)
committerMengxin Zhu2012-03-01 02:11:36 (EST)
commita927f26f8308300acb803be667733da7795c3fe1 (patch)
treebb563d2860ad1692d067315fea9bdaa7dc57e0db
parentdac2766583d7f0d27dd1c8692af7c9346cbac92c (diff)
downloadrt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.zip
rt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.tar.gz
rt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.tar.bz2
Bug 358842 pausing/resuming a p2 operation.v20120301-1523v20120301-0711
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>
-rw-r--r--bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF1
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Messages.java2
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java15
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/PhaseSet.java28
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/messages.properties1
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/Collect.java42
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/repository/DownloadPauseResumeEvent.java38
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/All p2 Tests.launch2
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/pom.xml2
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java237
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/AllTests.java3
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/repository/FileReaderTest2.java221
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/test.xml2
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/artifacts.xml51
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/pausefeature/content.xml138
-rw-r--r--bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java66
-rw-r--r--bundles/org.eclipse.equinox.p2.transport.ecf/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java32
19 files changed, 871 insertions, 16 deletions
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 @@ Export-Package: org.eclipse.equinox.internal.p2.core;x-friends:="org.eclipse.equ
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 @@ Import-Package: javax.xml.parsers,
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 class Messages extends NLS {
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 @@ public abstract class Phase {
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 @@ public abstract class Phase {
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 @@ public abstract class Phase {
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 @@ import org.eclipse.osgi.util.NLS;
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 @@ public class PhaseSet implements IPhaseSet {
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 @@ public class PhaseSet implements IPhaseSet {
}
} 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_Error=An error occurred while installing the items
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.engine.spi.ProvisioningAction;
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 @@ import org.eclipse.equinox.p2.repository.artifact.IArtifactRequest;
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 @@ public class Collect extends InstallableUnitPhase {
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 @@ public class Collect extends InstallableUnitPhase {
} 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 @@ public class Collect extends InstallableUnitPhase {
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 @@ Export-Package: org.eclipse.equinox.internal.p2.persistence;
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 @@ public class PhaseSetTest extends AbstractProvisioningTest {
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 class AllTests extends TestCase {
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.core.security.IConnectContext;
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.IFileTransferEvent;
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 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
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 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
}
}
}
+ 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 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
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 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
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 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
if (factory == null) {
throw RepositoryStatusHelper.fromMessage(Messages.ecf_configuration_error);
}
+
IRetrieveFileTransferContainerAdapter adapter = factory.newInstance();
-
adapter.setConnectContextForAuthentication(connectContext);
this.exception = null;
@@ -387,6 +432,23 @@ public final class FileReader extends FileTransferJob implements IFileTransferLi
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.SocketException;
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.ecf.filetransfer.UserCancelledException;
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 @@ public class RepositoryTransport extends Transport {
// 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();