diff options
author | Mengxin Zhu | 2012-02-27 08:47:36 +0000 |
---|---|---|
committer | Mengxin Zhu | 2012-03-01 07:11:36 +0000 |
commit | a927f26f8308300acb803be667733da7795c3fe1 (patch) | |
tree | bb563d2860ad1692d067315fea9bdaa7dc57e0db | |
parent | dac2766583d7f0d27dd1c8692af7c9346cbac92c (diff) | |
download | rt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.tar.gz rt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.tar.xz rt.equinox.p2-a927f26f8308300acb803be667733da7795c3fe1.zip |
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>
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 c2d53fae2..af0028fa4 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 92d919815..902492177 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 9c9710c4a..0b8d79429 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 f57a4829a..bcf912978 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 d4d1c6cf3..6e03edabf 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 597ef540d..f5af6f295 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 df2435eda..640bf0807 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 d681c08be..10912e08c 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 000000000..679d01601 --- /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 e28d16008..5c5c20194 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 -Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=c:/dev/platform/zips/eclipse-platform-3.5-win32.zip -Dorg.eclipse.equinox.p2.repository -Dorg.eclipse.equinox.p2.tests.current.build.repo=http://eclipsebuildserv/3.6-I-builds/ -Xmx512m -Dorg.eclipse.ecf.provider.filetransfer.httpclient.browse.connectTimeout=10000 -Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout=10000 -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 -Dorg.eclipse.equinox.p2.reconciler.tests.35.platform.archive=c:/dev/platform/zips/eclipse-platform-3.5-win32.zip -Dorg.eclipse.equinox.p2.repository -Dorg.eclipse.equinox.p2.tests.current.build.repo=http://eclipsebuildserv/3.6-I-builds/ -Xmx512m -Dorg.eclipse.ecf.provider.filetransfer.httpclient.browse.connectTimeout=10000 -Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout=10000 -Dorg.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout=10000 -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 a4bba0ed2..1e44b9c4b 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 aca6ba759..7255475e3 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 e67cb15dc..509799d8e 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 000000000..214523f61 --- /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 93c8214d9..1263e9561 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 000000000..baf533cae --- /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='"Eclipse Project Test Site"' + 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&format=xml&protocol=http' /> + <property name='p2.timestamp' value='1328722968200' /> + <property name='p2.compressed' value='false' /> + </properties> + <mappings size='5'> + <rule filter='(& (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='(& (classifier=osgi.bundle))' output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/plugins/${id}_${version}.jar' /> + <rule filter='(& (classifier=binary))' output='http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/binary/${id}_${version}' /> + <rule + filter='(& (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='(& (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 000000000..2fe6510b4 --- /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
February 1, 2011

Usage Of Content

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR
OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").
USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS
AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR
NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU
AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT
AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS
OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE
TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS
OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
BELOW, THEN YOU MAY NOT USE THE CONTENT.

Applicable Licenses

Unless otherwise indicated, all Content made available by the
Eclipse Foundation is provided to you under the terms and conditions of
the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is
provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
For purposes of the EPL, "Program" will mean the Content.

Content includes, but is not limited to, source code, object code,
documentation and other files maintained in the Eclipse Foundation source code
repository ("Repository") in software modules ("Modules") and made available
as downloadable archives ("Downloads").

- Content may be structured and packaged into modules to facilitate delivering,
extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),
plug-in fragments ("Fragments"), and features ("Features").
- Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)
in a directory named "plugins".
- A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.
Each Feature may be packaged as a sub-directory in a directory named "features".
Within a Feature, files named "feature.xml" may contain a list of the names and version
numbers of the Plug-ins and/or Fragments associated with that Feature.
- Features may also include other Features ("Included Features"). Within a Feature, files
named "feature.xml" may contain a list of the names and version numbers of Included Features.

The terms and conditions governing Plug-ins and Fragments should be
contained in files named "about.html" ("Abouts"). The terms and
conditions governing Features and Included Features should be contained
in files named "license.html" ("Feature Licenses"). Abouts and Feature
Licenses may be located in any directory of a Download or Module
including, but not limited to the following locations:

- The top-level (root) directory
- Plug-in and Fragment directories
- Inside Plug-ins and Fragments packaged as JARs
- Sub-directories of the directory named "src" of certain Plug-ins
- Feature directories

Note: if a Feature made available by the Eclipse Foundation is installed using the
Provisioning Technology (as defined below), you must agree to a license ("Feature 
Update License") during the installation process. If the Feature contains
Included Features, the Feature Update License should either provide you
with the terms and conditions governing the Included Features or inform
you where you can locate them. Feature Update Licenses may be found in
the "license" property of files named "feature.properties" found within a Feature.
Such Abouts, Feature Licenses, and Feature Update Licenses contain the
terms and conditions (or references to such terms and conditions) that
govern your use of the associated Content in that directory.

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER
TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.
SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

- Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)
- Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)
- Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)
- Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)
- Metro Link Public License 1.00 (available at http://www.opengroup.org/openmotif/supporters/metrolink/license.html)
- Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR
TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License
is provided, please contact the Eclipse Foundation to determine what terms and conditions
govern that particular Content.


Use of Provisioning Technology

The Eclipse Foundation makes available provisioning software, examples of which include,
but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for
the purpose of allowing users to install software, documentation, information and/or
other materials (collectively "Installable Software"). This capability is provided with
the intent of allowing such users to install, extend and update Eclipse-based products.
Information about packaging Installable Software is available at
http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").

You may use Provisioning Technology to allow other parties to install Installable Software.
You shall be responsible for enabling the applicable license agreements relating to the
Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
in accordance with the Specification. By using Provisioning Technology in such a manner and
making it available in accordance with the Specification, you further acknowledge your
agreement to, and the acquisition of all necessary rights to permit the following:

1. A series of actions may occur ("Provisioning Process") in which a user may execute
the Provisioning Technology on a machine ("Target Machine") with the intent of installing,
extending or updating the functionality of an Eclipse-based product.
2. During the Provisioning Process, the Provisioning Technology may cause third party
Installable Software or a portion thereof to be accessed and copied to the Target Machine.
3. Pursuant to the Specification, you will provide to the user the terms and conditions that
govern the use of the Installable Software ("Installable Software Agreement") and such
Installable Software Agreement shall be accessed from the Target Machine in accordance
with the Specification. Such Installable Software Agreement must inform the user of the
terms and conditions that govern the Installable Software and must solicit acceptance by
the end user in the manner prescribed in such Installable Software Agreement. Upon such
indication of agreement by the user, the provisioning Technology will complete installation
of the Installable Software.

Cryptography

Content may contain encryption software. The country in which you are
currently may have restrictions on the import, possession, and use,
and/or re-export to another country, of encryption software. BEFORE
using any encryption software, please check the country's laws,
regulations and policies concerning the import, possession, or use, and
re-export of encryption software, to see if this is permitted.

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> + (&(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> + (&(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
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> + (&(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
Bundle-Version: 1.1.100.v20110505
Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.3.0)" + </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> + (&(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 a4a5237c0..3ca9e042b 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 4be3aa92b..5444642f1 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(); |