diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine')
27 files changed, 1483 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/AbstractProvisioningTransaction.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/AbstractProvisioningTransaction.java new file mode 100644 index 000000000..2f48238a2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/AbstractProvisioningTransaction.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2007 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 http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.ArrayList; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.prov.engine.EngineActivator; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; +import org.eclipse.equinox.prov.core.helpers.MultiStatusUtil; +import org.eclipse.osgi.util.NLS; + +/** + * An abstract provisioning transaction specifies a simple mechanism + * for atomicity of a sequence of actions, based on the ability to + * revert the consequences of those actions. + * + * TODO: Implementation(s) of transactions should be registered via + * an extension point by classes that extended this class. + * This class should really be abstract. + */ +public abstract class AbstractProvisioningTransaction { + + private ArrayList actions = new ArrayList(); + + private String description; + + private boolean isUndoable; + + private MultiStatus result; + + private IProgressMonitor progressMonitor; + + public AbstractProvisioningTransaction(String description, boolean isUndoable, MultiStatus result, IProgressMonitor monitor) { + this.description = description; + this.isUndoable = isUndoable; + this.result = (result != null ? result : new MultiStatus()); + this.progressMonitor = monitor; + } + + public IStatus performActions(IProvisioningAction[] ops, int[] weights, IProgressMonitor monitor) { + SubMonitor pm = SubMonitor.convert(monitor, weights.length); + IStatus status = Status.OK_STATUS; + try { + for (int i = 0; i < ops.length; i += 1) { + IProvisioningAction action = ops[i]; + IProgressMonitor sub = (i < weights.length ? (IProgressMonitor) pm.newChild(weights[i]) : new NullProgressMonitor()); + status = performAction(action, sub); + if (MultiStatusUtil.isErrorOrCancel(status)) { + break; + } + } + } finally { + pm.done(); + } + return status; + } + + protected IStatus performAction(IProvisioningAction action, IProgressMonitor monitor) { + actions.add(action); + IStatus opStatus = action.perform(this, monitor); + IStatus status = opStatus; + + if (!isUndoable) { + result.add(opStatus); + status = Status.OK_STATUS; + } else if (MultiStatusUtil.isErrorOrCancel(opStatus)) { + int length = actions.size(); + IProvisioningAction lastAction = (IProvisioningAction) actions.get(length - 1); + if (!lastAction.shouldRevertOnError()) { + actions.remove(length - 1); + } + } else if (monitor.isCanceled()) { + // first time we noticed cancellation + opStatus = new Status(IStatus.CANCEL, EngineActivator.ID, 0, ""/*Messages.Engine_Operation_Canceled_By_User*/, null); + } + + if (opStatus.matches(IStatus.ERROR) && result.getMessage().length() == 0) { + result.setMessage(NLS.bind("Errors occurred during the transaction {0}", //$NON-NLS-1$ + description)); + } else if (opStatus.matches(IStatus.CANCEL) && result.getMessage().length() == 0) { + result.setMessage(NLS.bind("The transaction {0} was canceled", //$NON-NLS-1$ + description)); + } + + monitor.done(); + return status; + } + + public void rollback(IProgressMonitor monitor) { + if (!isUndoable) + return; + isUndoable = false; + + // TODO: is it necessary to allow support rollback that does NOT reverse the order + // of the actions? Consider phases. + + SubMonitor pm = SubMonitor.convert(monitor, actions.size()); + for (int i = actions.size() - 1; i >= 0; i--) { + IProvisioningAction action = (IProvisioningAction) actions.get(i); + try { + IStatus status = action.revert(this, pm.newChild(10)); + // log.statusNotOK(status); + } catch (Exception e) { + // log.exception + } + } + } + + public IProgressMonitor getProgressMonitor() { + return progressMonitor; + } + + public boolean isUndoable() { + return isUndoable; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Transaction: "); //$NON-NLS-1$ + sb.append(description); + sb.append(", ").append(actions.size()).append( //$NON-NLS-1$ + " actions performed"); //$NON-NLS-1$ + if (!isUndoable) { + sb.append(", isUndoable=").append(isUndoable); //$NON-NLS-1$ + } + return sb.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/BeginOperationEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/BeginOperationEvent.java new file mode 100644 index 000000000..9acffd2cf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/BeginOperationEvent.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +public class BeginOperationEvent extends TransactionEvent { + + private static final long serialVersionUID = 6389318375739324865L; + + public BeginOperationEvent(Profile profile, PhaseSet phaseSet, Operand[] deltas, Engine engine) { + super(profile, phaseSet, deltas, engine); + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/CommitOperationEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/CommitOperationEvent.java new file mode 100644 index 000000000..e3bdd998a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/CommitOperationEvent.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +public class CommitOperationEvent extends TransactionEvent { + private static final long serialVersionUID = -523967775426133720L; + + public CommitOperationEvent(Profile profile, PhaseSet phaseSet, Operand[] deltas, Engine engine) { + super(profile, phaseSet, deltas, engine); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/DefaultPhaseSet.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/DefaultPhaseSet.java new file mode 100644 index 000000000..ec52bb252 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/DefaultPhaseSet.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.equinox.prov.engine.phases.*; + +public class DefaultPhaseSet extends PhaseSet { + + public DefaultPhaseSet() { + super(new Phase[] {new Collect(10), new Uninstall(10), new Install(10)}); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Engine.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Engine.java new file mode 100644 index 000000000..4a81eb640 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Engine.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.prov.core.eventbus.ProvisioningEventBus; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; + +public class Engine { + + private final ProvisioningEventBus eventBus; + private List lockedProfiles = new ArrayList(); + + public Engine(ProvisioningEventBus eventBus) { + this.eventBus = eventBus; + } + + public MultiStatus perform(Profile profile, PhaseSet phaseSet, Operand[] operands, IProgressMonitor monitor) { + + // TODO -- Messages + if (profile == null) + throw new IllegalArgumentException("Profile must not be null."); + + if (phaseSet == null) + throw new IllegalArgumentException("PhaseSet must not be null."); + + if (operands == null) + throw new IllegalArgumentException("Operands must not be null."); + + if (monitor == null) + monitor = new NullProgressMonitor(); + + if (operands.length == 0) + return new MultiStatus(IStatus.OK, null); + + lockProfile(profile); + try { + eventBus.publishEvent(new BeginOperationEvent(profile, phaseSet, operands, this)); + + EngineSession session = new EngineSession(); + MultiStatus result = phaseSet.perform(session, profile, operands, monitor); + if (result.isOK()) { + eventBus.publishEvent(new CommitOperationEvent(profile, phaseSet, operands, this)); + session.commit(); + } + + if (result.isErrorOrCancel()) { + eventBus.publishEvent(new RollbackOperationEvent(profile, phaseSet, operands, this, result)); + session.rollback(); + } + return result; + } finally { + unlockProfile(profile); + } + } + + private synchronized void unlockProfile(Profile profile) { + lockedProfiles.remove(profile); + notify(); + } + + private synchronized void lockProfile(Profile profile) { + while (lockedProfiles.contains(profile)) { + try { + wait(); + } catch (InterruptedException e) { + // TODO We should think about how we want to handle blocked engine requests + Thread.currentThread().interrupt(); + } + } + lockedProfiles.add(profile); + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/EngineSession.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/EngineSession.java new file mode 100644 index 000000000..893e40ec0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/EngineSession.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.*; + +public class EngineSession { + List actions = new ArrayList(); + + public void record(ITouchpointAction action) { + actions.add(action); + } + + public void commit() { + actions.clear(); + } + + public void rollback() { + for (ListIterator it = actions.listIterator(actions.size()); it.hasPrevious();) { + ITouchpointAction action = (ITouchpointAction) it.previous(); + action.undo(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProfileRegistry.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProfileRegistry.java new file mode 100644 index 000000000..504ae8651 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProfileRegistry.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +/** + * This encapsulates the access to the profile registry. + * It deals with persistence in a transparent way. + */ +public interface IProfileRegistry { + public static final String SELF = "_SELF_"; //$NON-NLS-1$ + + /** + * Return the profile in the registry that has the given id. If it does not exist, + * then return <code>null</code>. + * + * @param id the profile identifier + * @return the profile or <code>null</code> + */ + Profile getProfile(String id); + + /** + * Return an array of profiles known to this registry. If there are none, then + * return an empty array. + * + * @return the array of profiles + */ + Profile[] getProfiles(); + + /** + * Add the given profile to this profile registry. + * + * @param toAdd the profile to add + * @throws IllegalArgumentException if a profile + * with the same id is already present in the registry. + */ + void addProfile(Profile toAdd) throws IllegalArgumentException; + + /** + * Remove the given profile from this profile registry. + * + * @param toRemove the profile to remove + */ + void removeProfile(Profile toRemove); + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProvisioningAction.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProvisioningAction.java new file mode 100644 index 000000000..7b976aa69 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IProvisioningAction.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007 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 http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ + +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; + +/** + * The provisioning action interface represents a unit of work + * that can be performed during a provisioning activity. + * The granularity of the action can vary from a simple, + * indivisible unit of work to a complex, organized collection + * of steps. + * <p> + * The results of an provisioning activity must be revert-able + * an error or if a cancellation occurs. A provisioning action + * that will return an error or cancel status may choose to revert + * any work performed before returning or may indicate that + * the caller must explicitly revert. + */ +public interface IProvisioningAction { + + public IStatus perform(AbstractProvisioningTransaction transaction, IProgressMonitor monitor); + + public IStatus revert(AbstractProvisioningTransaction transaction, IProgressMonitor monitor); + + public boolean shouldRevertOnError(); + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpoint.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpoint.java new file mode 100644 index 000000000..838d2a3de --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpoint.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.equinox.prov.metadata.TouchpointType; + +/** + * A touchpoint is responsible for executing a given phase for a given + * targeted system (eclipse, native). The order of phases is defined in the {@link PhaseSet}. + */ +public interface ITouchpoint { + + public TouchpointType getTouchpointType(); + + public boolean supports(String phaseId); + + public ITouchpointAction[] getActions(String phaseId, Profile profile, Operand operand); +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpointAction.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpointAction.java new file mode 100644 index 000000000..c7a9a78e7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ITouchpointAction.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +public interface ITouchpointAction { + + Object execute(); + + Object undo(); +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IUPhase.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IUPhase.java new file mode 100644 index 000000000..4ac09ee3c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/IUPhase.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; + +// An operation that is applied to a set of IUs. +public abstract class IUPhase extends Phase { + protected int PRE_PERFORM_WORK = 1000; + protected int PERFORM_WORK = 10000; + protected int POST_PERFORM_WORK = 1000; + + protected IUPhase(String phaseId, int weight, String phaseName) { + super(phaseId, weight, phaseName); + } + + protected void perform(MultiStatus status, EngineSession session, Profile profile, Operand[] operands, IProgressMonitor monitor) { //TODO Maybe should we do some kind of adaptable + SubMonitor subMonitor = SubMonitor.convert(monitor, PRE_PERFORM_WORK + PERFORM_WORK + POST_PERFORM_WORK); + prePerform(status, profile, operands, subMonitor.newChild(PRE_PERFORM_WORK)); + if (status.isErrorOrCancel()) + return; + + subMonitor.setWorkRemaining(PERFORM_WORK + POST_PERFORM_WORK); + mainPerform(status, session, profile, operands, subMonitor.newChild(PERFORM_WORK)); + if (status.isErrorOrCancel()) + return; + + subMonitor.setWorkRemaining(POST_PERFORM_WORK); + postPerform(status, profile, operands, subMonitor.newChild(POST_PERFORM_WORK)); + if (status.isErrorOrCancel()) + return; + + subMonitor.done(); + } + + protected void mainPerform(MultiStatus status, EngineSession session, Profile profile, Operand[] operands, SubMonitor subMonitor) { + int operandWork = PERFORM_WORK / operands.length; + for (int i = 0; i < operands.length; ++i) { + if (subMonitor.isCanceled()) + throw new OperationCanceledException(); + Operand currentOperand = operands[i]; + if (!isApplicable(currentOperand)) + continue; + IStatus result = performOperand(session, profile, currentOperand, subMonitor.newChild(operandWork)); + status.add(result); + if (status.isErrorOrCancel()) + return; + } + } + + protected abstract boolean isApplicable(Operand op); + + // ITouchpoint touchpoint = TouchpointManager.getInstance().getTouchpoint(currentOperand.getTouchpointType()); + // if (touchpoint == null) { //TODO Should we throw an exception instead? + // status.add(new Status(IStatus.ERROR, "org.eclipse.equinox.prov.engine", "The touchpoint " + currentOperand.getTouchpointType() + " is not available.")); + // return; + // } + // if (touchpoint.supports(phaseId)) { + // status.add(performIU(touchpoint, currentOperand, subMonitor.newChild(operandWork))); + // } + // if (status.isErrorOrCancel() || sub.isCanceled()) { + // undoPerform(status, ius, i, context); + // return; + // } + + // Error or cancel: undo IUs that were done. + // private void undoPerform(MultiStatus status, InstallableUnitPair[] ius, int currentIU, InstallContext context) { + // if (!status.isErrorOrCancel()) { + // status.setCanceled(); // first time we noticed cancelation + // currentIU += 1; // currentIU was completed so it must be undone + // } + // InstallableUnitPair[] undoIUs = new InstallableUnitPair[currentIU]; + // for (int i = 0; i < currentIU; i += 1) { + // log.debug("Undo {0} phase for {1}", super.phaseName, ius[i]); //$NON-NLS-1$ + // undoIUs[i] = ius[currentIU - (i + 1)].reverse(); + // } + // // 1 unit to undo this phase, 10 for preceding phases + // SplitProgressMonitor pm = new SplitProgressMonitor(getUndoProgressMonitor(), new int[] {1, 10}); + // doPerform(status, /*undoable*/false, undoIUs, context, pm.next()); + // setUndoProgressMonitor(pm.next()); + // } + protected abstract IStatus performOperand(EngineSession session, Profile profile, Operand operand, IProgressMonitor monitor); + + protected void prePerform(MultiStatus status, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + //Nothing to do. + } + + protected void postPerform(MultiStatus status, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + //Nothing to do. + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/InstallableUnitEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/InstallableUnitEvent.java new file mode 100644 index 000000000..6ba45dc09 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/InstallableUnitEvent.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.EventObject; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +public class InstallableUnitEvent extends EventObject { + private static final long serialVersionUID = 3318712818811459886L; + + private String phaseId; + private boolean prePhase; + + private Profile profile; + private Operand operand; + private ITouchpoint touchpoint; + private IStatus result; + + public InstallableUnitEvent(String phaseId, boolean prePhase, Profile profile, Operand operand, ITouchpoint touchpoint) { + this(phaseId, prePhase, profile, operand, touchpoint, null); + } + + public InstallableUnitEvent(String phaseId, boolean prePhase, Profile profile, Operand operand, ITouchpoint touchpoint, IStatus result) { + super(touchpoint); //TODO not sure if the touchpoint should be the source + this.phaseId = phaseId; + this.prePhase = prePhase; + this.profile = profile; + this.operand = operand; + this.result = result; + } + + public ITouchpoint getTouchpoint() { + return touchpoint; + } + + public Profile getProfile() { + return profile; + } + + public Operand getOperand() { + return operand; + } + + public String getPhase() { + return phaseId; + } + + public boolean isPre() { + return prePhase; + } + + public boolean isPost() { + return !prePhase; + } + + public IStatus getResult() { + return (result != null ? result : Status.OK_STATUS); + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Operand.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Operand.java new file mode 100644 index 000000000..5a4ac821e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Operand.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.equinox.prov.metadata.IResolvedInstallableUnit; + +public class Operand { + private final IResolvedInstallableUnit first; + private final IResolvedInstallableUnit second; + + public Operand(IResolvedInstallableUnit first, IResolvedInstallableUnit second) { + this.first = first; + this.second = second; + } + + public IResolvedInstallableUnit first() { + return first; + } + + public IResolvedInstallableUnit second() { + return second; + } + + public String toString() { + return first + " --> " + second; //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Phase.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Phase.java new file mode 100644 index 000000000..19729096f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Phase.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.equinox.internal.prov.engine.Messages; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; +import org.eclipse.osgi.util.NLS; + +public abstract class Phase { + protected final String phaseId; + protected final int weight; + protected final String phaseName; + + protected Phase(String phaseId, int weight, String phaseName) { + if (phaseId == null || phaseId.length() == 0) { + throw new IllegalArgumentException("Phase id must be set."); + } + + if (weight <= 0) { + throw new IllegalArgumentException("Phase weight must be positive."); + } + + if (phaseName == null || phaseName.length() == 0) { + throw new IllegalArgumentException("Phase name must be set."); + } + + this.weight = weight; + this.phaseName = phaseName; + this.phaseId = phaseId; + } + + public String toString() { + return "Phase: " + this.phaseName + " - " + this.weight; //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected MultiStatus perform(EngineSession session, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + MultiStatus status = new MultiStatus(); + // log.start(log.info(Messages2.Engine_Performing_Phase, this.phaseName)); + perform(status, session, profile, deltas, monitor); + // log.stop(); + if (status.matches(IStatus.CANCEL)) { + status.setMessage(Messages.Engine_Operation_Canceled_By_User); + } else if (status.matches(IStatus.ERROR)) { + status.setMessage(NLS.bind(Messages.Engine_Error_During_Phase, this.phaseName)); + } + return status; + } + + protected abstract void perform(MultiStatus status, EngineSession session, Profile profile, Operand[] deltas, IProgressMonitor monitor); + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/PhaseSet.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/PhaseSet.java new file mode 100644 index 000000000..f5d85a2b4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/PhaseSet.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; + +public abstract class PhaseSet { + private final Phase[] phases; + + public PhaseSet(Phase[] phases) { + if (phases == null) + throw new IllegalArgumentException("Phases must not be null"); + + this.phases = phases; + } + + public MultiStatus perform(EngineSession session, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + MultiStatus result = new MultiStatus(); + int[] weights = getProgressWeights(); + int totalWork = getTotalWork(weights); + SubMonitor pm = SubMonitor.convert(monitor, totalWork); + try { + for (int i = 0; i < phases.length; i++) { + if (pm.isCanceled()) { + result.setCanceled(); + return result; + } + Phase phase = phases[i]; + result.add(phase.perform(session, profile, deltas, pm.newChild(weights[i]))); + if (result.isErrorOrCancel())// || sub.isCanceled()) { + //TODO Need to perform the undo if we don't we use transactions + return result; + } + } finally { + pm.done(); + } + return result; + } + + private int getTotalWork(int[] weights) { + int sum = 0; + for (int i = 0; i < weights.length; i++) + sum += weights[i]; + return sum; + } + + private int[] getProgressWeights() { + int[] weights = new int[phases.length]; + for (int i = 0; i < phases.length; i += 1) { + weights[i] = phases[i].weight; + } + return weights; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Profile.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Profile.java new file mode 100644 index 000000000..1894f375d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Profile.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2007 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 http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.*; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.equinox.internal.prov.engine.EngineActivator; +import org.eclipse.equinox.prov.core.helpers.ServiceHelper; +import org.eclipse.equinox.prov.installregistry.IInstallRegistry; +import org.eclipse.equinox.prov.installregistry.IProfileInstallRegistry; +import org.eclipse.equinox.prov.metadata.IInstallableUnit; +import org.eclipse.equinox.prov.metadata.RequiredCapability; +import org.eclipse.equinox.prov.query.IQueryable; +import org.eclipse.equinox.prov.query.QueryableArray; +import org.eclipse.osgi.service.resolver.VersionRange; + +public class Profile implements IQueryable { + + /** + * Profile property constant indicating the flavor for the profile. + */ + public static String PROP_FLAVOR = "eclipse.prov.flavor"; //$NON-NLS-1$ + + /** + * Profile property constant indicating the install folder for the profile. + */ + public static final String PROP_INSTALL_FOLDER = "eclipse.prov.installFolder"; //$NON-NLS-1$ + + /** + * Profile property constant indicating the installed language(s) for the profile. + */ + public static final String PROP_NL = "eclipse.prov.nl"; //$NON-NLS-1$ + + /** + * Profile property constant for a string property indicating a user visible short + * textual description of this profile. May be empty or <code>null</code>, and + * generally will be for non-top level install contexts. + */ + public static final String PROP_DESCRIPTION = "eclipse.prov.description"; //$NON-NLS-1$ + + /** + * Profile property constant for a string property indicating a user visible name of this profile. + * May be empty or <code>null</code>, and generally will be for non-top level + * install contexts. + */ + public static final String PROP_NAME = "eclipse.prov.name"; //$NON-NLS-1$ + + /** + * Profile property constant indicating the list of environments + * (e.g., OS, WS, ...) in which a profile can operate. The value of the property + * is a comma-delimited string of key/value pairs. + */ + public static final String PROP_ENVIRONMENTS = "eclipse.prov.environments"; //$NON-NLS-1$ + + /** + * Profile property constant for a boolean property indicating if the profiling + * is roaming. A roaming profile is one whose physical install location varies + * and is updated whenever it runs. + */ + public static final String PROP_ROAMING = "eclipse.prov.roaming"; //$NON-NLS-1$ + + /** + * Profile property constant indicating the bundle pool cache location. + */ + public static final String PROP_CACHE = "eclipse.prov.cache"; //$NON-NLS-1$ + + //Internal id of the profile + private String profileId; + + private Profile parentProfile; + + /** + * This storage is to be used by the touchpoints to store data. The data must be serializable + */ + private Properties storage = new Properties(); + + public Profile(String profileId) { + if (profileId == null || profileId.length() == 0) { + throw new IllegalArgumentException("Profile id must be set."); + } + this.profileId = profileId; + } + + public String getProfileId() { + return profileId; + } + + public Profile getParentProfile() { + return parentProfile; + } + + public String getValue(String key) { + return storage.getProperty(key); + } + + public void setValue(String key, String value) { + storage.setProperty(key, value); + } + + public Dictionary getSelectionContext() { + Properties result = new Properties(storage); + String environments = storage.getProperty(PROP_ENVIRONMENTS); + if (environments == null) + return result; + for (StringTokenizer tokenizer = new StringTokenizer(environments, ","); tokenizer.hasMoreElements();) { + String entry = tokenizer.nextToken(); + int i = entry.indexOf('='); + String key = entry.substring(0, i).trim(); + String value = entry.substring(i + 1).trim(); + result.put(key, value); + } + return result; + } + + private IInstallableUnit[] getAllInstallableUnits() { + IInstallRegistry registry = (IInstallRegistry) ServiceHelper.getService(EngineActivator.getContext(), IInstallRegistry.class.getName()); + if (registry == null) + return null; + IProfileInstallRegistry profile = registry.getProfileInstallRegistry(new Profile(profileId)); + if (profile == null) + return null; + return profile.getInstallableUnits(); + } + + public Iterator getIterator(String id, VersionRange range, RequiredCapability[] requirements, boolean and) { + return new QueryableArray(getAllInstallableUnits()).getIterator(id, range, requirements, and); + } + + public IInstallableUnit[] query(String id, VersionRange range, RequiredCapability[] requirements, boolean and, IProgressMonitor progress) { + return new QueryableArray(getAllInstallableUnits()).query(id, range, requirements, and, progress); + } + + public Iterator getInstallableUnits() { + return Arrays.asList(getAllInstallableUnits()).iterator(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProfileEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProfileEvent.java new file mode 100644 index 000000000..cbb120e67 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProfileEvent.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.EventObject; + +public class ProfileEvent extends EventObject { + private static final long serialVersionUID = 3082402920617281765L; + + public static byte ADDED = 0; + public static byte REMOVED = 1; + + private byte reason; + + public ProfileEvent(Profile source, byte reason) { + super(source); + this.reason = reason; + } + + public byte getReason() { + return reason; + } + + public Profile getProfile() { + return (Profile) getSource(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProvisioningConfigurationException.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProvisioningConfigurationException.java new file mode 100644 index 000000000..4c2496080 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/ProvisioningConfigurationException.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +public class ProvisioningConfigurationException extends RuntimeException { + + private static final long serialVersionUID = -712627437440533809L; + + public ProvisioningConfigurationException(String name) { + super(name); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/RollbackOperationEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/RollbackOperationEvent.java new file mode 100644 index 000000000..9de0d51c1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/RollbackOperationEvent.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.IStatus; + +public class RollbackOperationEvent extends TransactionEvent { + + private static final long serialVersionUID = -2076492953949691215L; + private IStatus cause; + + public RollbackOperationEvent(Profile profile, PhaseSet phaseSet, Operand[] deltas, Engine engine, IStatus cause) { + super(profile, phaseSet, deltas, engine); + this.cause = cause; + } + + public IStatus getStatus() { + return cause; + } +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/SimpleProfileRegistry.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/SimpleProfileRegistry.java new file mode 100644 index 000000000..ae4c4c622 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/SimpleProfileRegistry.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2007 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 http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import com.thoughtworks.xstream.XStream; +import java.io.*; +import java.net.URL; +import java.util.LinkedHashMap; +import java.util.Properties; +import org.eclipse.equinox.internal.prov.engine.EngineActivator; +import org.eclipse.equinox.internal.prov.engine.Messages; +import org.eclipse.equinox.prov.core.eventbus.ProvisioningEventBus; +import org.eclipse.equinox.prov.core.helpers.ServiceHelper; +import org.eclipse.equinox.prov.core.location.AgentLocation; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.util.NLS; + +public class SimpleProfileRegistry implements IProfileRegistry { + private static String STORAGE = "profileRegistry.xml"; //$NON-NLS-1$ + + /** + * Map of String(Profile id)->Profile. + */ + private LinkedHashMap profiles = new LinkedHashMap(8); + + private Properties properties = new Properties(); + + private String self; + + public SimpleProfileRegistry() { + self = EngineActivator.getContext().getProperty("eclipse.prov.profile"); //$NON-NLS-1$ + restore(); + updateRoamingProfile(); + } + + /** + * If the current profile for self is marked as a roaming profile, we need + * to update its install and bundle pool locations. + */ + private void updateRoamingProfile() { + Profile selfProfile = getProfile(SELF); + if (selfProfile == null) + return; + //only update if self is a roaming profile + if (!Boolean.valueOf(selfProfile.getValue(Profile.PROP_ROAMING)).booleanValue()) + return; + Location installLocation = (Location) ServiceHelper.getService(EngineActivator.getContext(), Location.class.getName(), Location.INSTALL_FILTER); + String locationString = installLocation.getURL().getPath(); + boolean changed = false; + if (!locationString.equals(selfProfile.getValue(Profile.PROP_INSTALL_FOLDER))) { + selfProfile.setValue(Profile.PROP_INSTALL_FOLDER, locationString); + changed = true; + } + if (!locationString.equals(selfProfile.getValue(Profile.PROP_CACHE))) { + selfProfile.setValue(Profile.PROP_CACHE, locationString); + changed = true; + } + if (changed) + persist(); + } + + public String toString() { + return this.profiles.toString(); + } + + public Profile getProfile(String id) { + if (SELF.equals(id)) + id = self; + return (Profile) profiles.get(id); + } + + public Profile[] getProfiles() { + return (Profile[]) profiles.values().toArray(new Profile[profiles.size()]); + } + + public void addProfile(Profile toAdd) throws IllegalArgumentException { + if (isNamedSelf(toAdd)) + throw new IllegalArgumentException(NLS.bind(Messages.Profile_Not_Named_Self, toAdd.getProfileId())); + String id = toAdd.getProfileId(); + if (getProfile(id) == null) { + profiles.put(id, toAdd); + } else + throw new IllegalArgumentException(NLS.bind(Messages.Profile_Duplicate_Profile_Id, id)); + broadcastChangeEvent(toAdd, ProfileEvent.ADDED); + persist(); //TODO This is not enough to keep track of the changes that are being done in a profile. This will likely have to be based on some event like commit + } + + private void broadcastChangeEvent(Profile profile, byte reason) { + ((ProvisioningEventBus) ServiceHelper.getService(EngineActivator.getContext(), ProvisioningEventBus.class.getName())).publishEvent(new ProfileEvent(profile, reason)); + } + + private void restore() { + try { + BufferedInputStream bif = null; + try { + Location agent = (Location) ServiceHelper.getService(EngineActivator.getContext(), AgentLocation.class.getName()); + if (agent == null) + // TODO should likely do something here since we failed to restore. + return; + bif = new BufferedInputStream(new URL(agent.getURL(), STORAGE).openStream()); + XStream xml = new XStream(); + Object[] read = (Object[]) xml.fromXML(bif); + properties = (Properties) read[0]; + profiles = (LinkedHashMap) read[1]; + } finally { + if (bif != null) + bif.close(); + } + } catch (FileNotFoundException e) { + //This is ok. + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void persist() { + OutputStream os; + try { + Location agent = (Location) ServiceHelper.getService(EngineActivator.getContext(), AgentLocation.class.getName()); + if (agent == null) + // TODO should likely do something here since we failed to persist. + return; + if (!agent.getURL().getProtocol().equals("file")) + throw new IOException("can't write at the given location"); + + File outputFile = new File(agent.getURL().getFile(), STORAGE); + if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) + throw new RuntimeException("can't persist profile registry at: " + outputFile); + os = new BufferedOutputStream(new FileOutputStream(outputFile)); + try { + XStream xstream = new XStream(); + xstream.toXML(new Object[] {properties, profiles}, os); + } finally { + os.close(); + } + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public void removeProfile(Profile toRemove) { + if (isNamedSelf(toRemove)) + throw new IllegalArgumentException(NLS.bind(Messages.Profile_Not_Named_Self, toRemove.getProfileId())); + if (profiles.remove(toRemove.getProfileId()) == null) + return; + broadcastChangeEvent(toRemove, ProfileEvent.REMOVED); + persist(); + } + + private boolean isNamedSelf(Profile p) { + if (SELF.equals(p.getParentProfile())) + return true; + return false; + } + + public Properties getProperties() { + return properties; + } + + public String getProperty(String key) { + return properties.getProperty(key); + } + + public void setProperty(String key, String value) { + properties.setProperty(key, value); + } + + public void removeProperty(String key) { + properties.remove(key); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/TransactionEvent.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/TransactionEvent.java new file mode 100644 index 000000000..9249735a1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/TransactionEvent.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import java.util.EventObject; + +public abstract class TransactionEvent extends EventObject { + protected Profile profile; + protected PhaseSet phaseSet; + protected Operand[] deltas; + + public TransactionEvent(Profile profile, PhaseSet phaseSet, Operand[] deltas, Engine engine) { + super(engine); + this.profile = profile; + this.phaseSet = phaseSet; + this.deltas = deltas; + } + + public Profile getProfile() { + return profile; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Utils.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Utils.java new file mode 100644 index 000000000..949119d6b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/Utils.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine; + +import org.eclipse.core.runtime.IAdaptable; + +public class Utils { + + //This method will return the adapter, or will throw an exception + public static Object getAdapter(IAdaptable toAdapt, Class toAdaptType) throws ProvisioningConfigurationException { + Object result = toAdapt.getAdapter(toAdaptType); + if (result == null) + throw new ProvisioningConfigurationException("Adaptation failure. Can't adapt :" + toAdapt.getClass().getName() + " into a" + toAdaptType.getName()); + return result; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Collect.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Collect.java new file mode 100644 index 000000000..e0cff6d83 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Collect.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2007 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 http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.equinox.prov.engine.phases; + +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.prov.engine.TouchpointManager; +import org.eclipse.equinox.prov.artifact.repository.IArtifactRequest; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; +import org.eclipse.equinox.prov.download.DownloadManager; +import org.eclipse.equinox.prov.engine.*; +import org.eclipse.equinox.prov.metadata.IInstallableUnit; +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. + */ +public class Collect extends IUPhase { + private static final String PHASE_ID = "collect"; //$NON-NLS-1$ + private DownloadManager dm = null; + + public Collect(int weight) { + super(PHASE_ID, weight, Messages.Engine_Collect_Phase); + //re-balance work since postPerform will do almost all the time-consuming work + PRE_PERFORM_WORK = 0; + PERFORM_WORK = 100; + POST_PERFORM_WORK = 1000; + } + + protected IStatus performOperand(EngineSession session, Profile profile, Operand operand, IProgressMonitor monitor) { + IInstallableUnit unit = operand.second(); + + if (unit != null) { + monitor.subTask(NLS.bind(Messages.Engine_Collecting_For_IU, unit.getId())); + + // TODO: Need do progress reporting + + // Ask all the touchpoints if they need to download an artifact + ITouchpoint touchpoint = TouchpointManager.getInstance().getTouchpoint(unit.getTouchpointType()); + if (touchpoint.supports(PHASE_ID)) { + ITouchpointAction[] actions = touchpoint.getActions(PHASE_ID, profile, operand); + for (int i = 0; i < actions.length; i++) { + Object result = actions[i].execute(); + if (result != null) + dm.add((IArtifactRequest[]) result); + session.record(actions[i]); + } + } + + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + } + + return Status.OK_STATUS; + } + + protected void postPerform(MultiStatus status, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + // Start the download + status.add(dm.start(monitor)); + } + + protected void prePerform(MultiStatus status, Profile profile, Operand[] deltas, IProgressMonitor monitor) { + dm = new DownloadManager(); + } + + protected boolean isApplicable(Operand op) { + if (op.second() != null) + return true; + return false; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Install.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Install.java new file mode 100644 index 000000000..660d2f74e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Install.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine.phases; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.equinox.internal.prov.engine.EngineActivator; +import org.eclipse.equinox.internal.prov.engine.TouchpointManager; +import org.eclipse.equinox.prov.core.eventbus.ProvisioningEventBus; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; +import org.eclipse.equinox.prov.core.helpers.ServiceHelper; +import org.eclipse.equinox.prov.engine.*; +import org.eclipse.equinox.prov.metadata.IInstallableUnit; +import org.eclipse.osgi.util.NLS; + +public class Install extends IUPhase { + + private static final String PHASE_ID = "install"; //$NON-NLS-1$ + + public Install(int weight) { + super(PHASE_ID, weight, Messages.Engine_Install_Phase); + } + + protected IStatus performOperand(EngineSession session, Profile profile, Operand operand, IProgressMonitor monitor) { + IInstallableUnit unit = operand.second(); + + monitor.subTask(NLS.bind(Messages.Engine_Installing_IU, unit.getId())); + + ITouchpoint touchpoint = TouchpointManager.getInstance().getTouchpoint(unit.getTouchpointType()); + if (!touchpoint.supports(PHASE_ID)) + ((ProvisioningEventBus) ServiceHelper.getService(EngineActivator.getContext(), ProvisioningEventBus.class.getName())).publishEvent(new InstallableUnitEvent(PHASE_ID, true, profile, operand, touchpoint)); + + ITouchpointAction[] actions = touchpoint.getActions(PHASE_ID, profile, operand); + MultiStatus result = new MultiStatus(); + for (int i = 0; i < actions.length; i++) { + IStatus actionStatus = (IStatus) actions[i].execute(); + result.add(actionStatus); + if (!actionStatus.isOK()) + return result; + + session.record(actions[i]); + } + ((ProvisioningEventBus) ServiceHelper.getService(EngineActivator.getContext(), ProvisioningEventBus.class.getName())).publishEvent(new InstallableUnitEvent(PHASE_ID, false, profile, operand, touchpoint, result)); + return result; + } + + protected boolean isApplicable(Operand op) { + if (op.second() != null) + return true; + return false; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Messages.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Messages.java new file mode 100644 index 000000000..f35b810e0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Messages.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine.phases; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.equinox.prov.engine.phases.messages"; //$NON-NLS-1$ + + static { + // initialize resource bundles + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // Do not instantiate + } + + public static String Engine_Collect_Phase; + public static String Engine_Collecting_For_IU; + public static String Engine_Install_Phase; + public static String Engine_Installing_IU; + public static String Engine_Uninstall_Phase; + public static String Engine_Uninstalling_IU; +} diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Uninstall.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Uninstall.java new file mode 100644 index 000000000..0732680e1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/Uninstall.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.prov.engine.phases; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.equinox.internal.prov.engine.EngineActivator; +import org.eclipse.equinox.internal.prov.engine.TouchpointManager; +import org.eclipse.equinox.prov.core.eventbus.ProvisioningEventBus; +import org.eclipse.equinox.prov.core.helpers.MultiStatus; +import org.eclipse.equinox.prov.core.helpers.ServiceHelper; +import org.eclipse.equinox.prov.engine.*; +import org.eclipse.equinox.prov.metadata.IInstallableUnit; +import org.eclipse.osgi.util.NLS; + +public class Uninstall extends IUPhase { + + private static final String PHASE_ID = "uninstall"; //$NON-NLS-1$ + + public Uninstall(int weight) { + super(PHASE_ID, weight, Messages.Engine_Uninstall_Phase); + } + + protected IStatus performOperand(EngineSession session, Profile profile, Operand operand, IProgressMonitor monitor) { + IInstallableUnit unit = operand.first(); + + monitor.subTask(NLS.bind(Messages.Engine_Uninstalling_IU, unit.getId())); + + ITouchpoint touchpoint = TouchpointManager.getInstance().getTouchpoint(unit.getTouchpointType()); + if (touchpoint.supports(PHASE_ID)) + ((ProvisioningEventBus) ServiceHelper.getService(EngineActivator.getContext(), ProvisioningEventBus.class.getName())).publishEvent(new InstallableUnitEvent(PHASE_ID, true, profile, operand, touchpoint)); + + //TODO need to protect the actual operation on a try / catch to ensure the delivery of event. + ITouchpointAction[] actions = touchpoint.getActions(PHASE_ID, profile, operand); + MultiStatus result = new MultiStatus(); + for (int i = 0; i < actions.length; i++) { + result.add((IStatus) actions[i].execute()); + session.record(actions[i]); + } + + ((ProvisioningEventBus) ServiceHelper.getService(EngineActivator.getContext(), ProvisioningEventBus.class.getName())).publishEvent(new InstallableUnitEvent(PHASE_ID, false, profile, operand, touchpoint, result)); + return result; + } + + protected boolean isApplicable(Operand op) { + if (op.first() != null) + return true; + return false; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/messages.properties b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/messages.properties new file mode 100644 index 000000000..9e644e32f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/prov/engine/phases/messages.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright (c) 2007 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 +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +Engine_Collect_Phase=collect +Engine_Install_Phase=install +Engine_Uninstall_Phase=uninstall +Engine_Collecting_For_IU=Collecting for {0} +Engine_Installing_IU=Installing {0} +Engine_Uninstalling_IU=Uninstalling {0}
\ No newline at end of file |