| /******************************************************************************* |
| * Copyright (c) 2007, 2009 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.internal.p2.engine; |
| |
| import java.io.File; |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.p2.core.IProvisioningAgent; |
| import org.eclipse.equinox.p2.engine.*; |
| import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; |
| import org.eclipse.equinox.p2.engine.spi.Touchpoint; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * TODO: not API |
| */ |
| public class EngineSession { |
| private static final String ENGINE_SESSION = "enginesession"; //$NON-NLS-1$ |
| |
| private static final String EMPTY_STRING = ""; //$NON-NLS-1$ |
| |
| private static class ActionsRecord { |
| Operand operand; |
| List<ProvisioningAction> actions = new ArrayList<ProvisioningAction>(); |
| |
| ActionsRecord(Operand operand) { |
| this.operand = operand; |
| } |
| } |
| |
| private List<Object[]> phaseActionRecordsPairs = new ArrayList<Object[]>(); |
| |
| private Phase currentPhase; |
| boolean currentPhaseActive; |
| |
| private List<ActionsRecord> currentActionRecords; |
| private ActionsRecord currentRecord; |
| |
| private IProfile profile; |
| |
| private ProvisioningContext context; |
| |
| private final HashMap<String, Object> sessionServices = new HashMap<String, Object>(); |
| |
| private Set<Touchpoint> touchpoints = new HashSet<Touchpoint>(); |
| |
| private final IProvisioningAgent agent; |
| |
| public EngineSession(IProvisioningAgent agent, IProfile profile, ProvisioningContext context) { |
| super(); |
| this.agent = agent; |
| this.profile = profile; |
| this.context = context; |
| } |
| |
| public IProfile getProfile() { |
| return profile; |
| } |
| |
| public IProvisioningAgent getAgent() { |
| return agent; |
| } |
| |
| public ProvisioningContext getProvisioningContext() { |
| return context; |
| } |
| |
| public File getProfileDataDirectory() { |
| SimpleProfileRegistry profileRegistry = (SimpleProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME); |
| return profileRegistry.getProfileDataDirectory(profile.getProfileId()); |
| } |
| |
| /** |
| * This is the interface through which parts of the engine obtain the services they need |
| * @param serviceName The name of the service to obtain |
| * @return The service instance, or <code>null</code> if no such service is available |
| */ |
| public Object getxService(String serviceName) { |
| Object result = sessionServices.get(serviceName); |
| if (result != null) |
| return result; |
| return agent.getService(serviceName); |
| } |
| |
| IStatus prepare(IProgressMonitor monitor) { |
| monitor.subTask(Messages.preparing); |
| MultiStatus status = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); |
| for (Touchpoint touchpoint : touchpoints) { |
| try { |
| status.add(touchpoint.prepare(profile)); |
| } catch (RuntimeException e) { |
| // "touchpoint.prepare" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_prepare_error, touchpoint.getClass().getName()), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_prepare_error, touchpoint.getClass().getName()), e)); |
| } |
| } |
| |
| if (status.matches(IStatus.ERROR)) { |
| MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.ERROR, NLS.bind(Messages.session_prepare_error, profile.getProfileId()), null); |
| result.merge(status); |
| return result; |
| } |
| return status; |
| } |
| |
| IStatus commit(IProgressMonitor monitor) { |
| monitor.subTask(Messages.committing); |
| MultiStatus status = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); |
| phaseActionRecordsPairs.clear(); |
| for (Touchpoint touchpoint : touchpoints) { |
| try { |
| IStatus result = touchpoint.commit(profile); |
| if (!result.isOK()) |
| status.add(result); |
| } catch (RuntimeException e) { |
| // "touchpoint.commit" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_commit_error, touchpoint.getClass().getName()), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_commit_error, touchpoint.getClass().getName()), e)); |
| } |
| } |
| |
| if (status.matches(IStatus.ERROR)) { |
| MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.ERROR, NLS.bind(Messages.session_commit_error, profile.getProfileId()), null); |
| result.merge(status); |
| return result; |
| } |
| return status; |
| } |
| |
| IStatus rollback(IProgressMonitor monitor, int severity) { |
| if (severity == IStatus.CANCEL) |
| monitor.subTask(Messages.rollingback_cancel); |
| |
| if (severity == IStatus.ERROR) |
| monitor.subTask(Messages.rollingback_error); |
| |
| MultiStatus status = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); |
| |
| if (currentPhaseActive) { |
| try { |
| IStatus result = rollBackPhase(currentPhase, currentActionRecords); |
| if (!result.isOK()) |
| status.add(result); |
| } catch (RuntimeException e) { |
| // "phase.prePerform and phase.postPerform" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_error, currentPhase.getClass().getName()), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_error, currentPhase.getClass().getName()), e)); |
| } |
| currentPhaseActive = false; |
| currentActionRecords = null; |
| currentRecord = null; |
| } |
| currentPhase = null; |
| |
| for (ListIterator<Object[]> it = phaseActionRecordsPairs.listIterator(phaseActionRecordsPairs.size()); it.hasPrevious();) { |
| Object[] pair = it.previous(); |
| Phase phase = (Phase) pair[0]; |
| @SuppressWarnings("unchecked") |
| List<ActionsRecord> actionRecords = (List<ActionsRecord>) pair[1]; |
| try { |
| final IStatus result = rollBackPhase(phase, actionRecords); |
| if (!result.isOK()) |
| status.add(result); |
| } catch (RuntimeException e) { |
| // "phase.prePerform and phase.postPerform" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_error, phase.getClass().getName()), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_error, phase.getClass().getName()), e)); |
| } |
| } |
| |
| phaseActionRecordsPairs.clear(); |
| for (Touchpoint touchpoint : touchpoints) { |
| try { |
| IStatus result = touchpoint.rollback(profile); |
| if (!result.isOK()) |
| status.add(result); |
| } catch (RuntimeException e) { |
| // "touchpoint.rollback" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_rollback_error, touchpoint.getClass().getName()), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| status.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.touchpoint_rollback_error, touchpoint.getClass().getName()), e)); |
| } |
| } |
| |
| if (status.matches(IStatus.ERROR)) { |
| MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.ERROR, NLS.bind(Messages.session_commit_error, profile.getProfileId()), null); |
| result.merge(status); |
| return result; |
| } |
| return status; |
| } |
| |
| private IStatus rollBackPhase(Phase phase, List<ActionsRecord> actionRecords) { |
| MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); |
| try { |
| phase.actionManager = (ActionManager) agent.getService(ActionManager.SERVICE_NAME); |
| |
| if (!currentPhaseActive) |
| phase.prePerform(result, this, new NullProgressMonitor()); |
| |
| for (ListIterator<ActionsRecord> it = actionRecords.listIterator(actionRecords.size()); it.hasPrevious();) { |
| ActionsRecord record = it.previous(); |
| ProvisioningAction[] actions = record.actions.toArray(new ProvisioningAction[record.actions.size()]); |
| try { |
| phase.undo(result, this, profile, record.operand, actions, context); |
| } catch (RuntimeException e) { |
| // "phase.undo" calls user code and might throw an unchecked exception |
| // we catch the error here to gather information on where the problem occurred. |
| result.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_operand_error, phase.getClass().getName(), record.operand), e)); |
| } catch (LinkageError e) { |
| // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) |
| result.add(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.phase_undo_operand_error, phase.getClass().getName(), record.operand), e)); |
| } |
| } |
| phase.postPerform(result, this, new NullProgressMonitor()); |
| } finally { |
| phase.actionManager = null; |
| } |
| return result; |
| } |
| |
| void recordPhaseEnter(Phase phase) { |
| if (phase == null) |
| throw new IllegalArgumentException(Messages.null_phase); |
| |
| if (currentPhase != null) |
| throw new IllegalStateException(Messages.phase_started); |
| |
| currentPhase = phase; |
| |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugPhaseEnter(phase); |
| } |
| |
| void recordPhaseStart(Phase phase) { |
| if (phase == null) |
| throw new IllegalArgumentException(Messages.null_phase); |
| |
| if (currentPhase != phase) |
| throw new IllegalArgumentException(Messages.not_current_phase); |
| |
| currentPhaseActive = true; |
| currentActionRecords = new ArrayList<ActionsRecord>(); |
| } |
| |
| void recordPhaseEnd(Phase phase) { |
| if (currentPhase == null) |
| throw new IllegalStateException(Messages.phase_not_started); |
| |
| if (currentPhase != phase) |
| throw new IllegalArgumentException(Messages.not_current_phase); |
| |
| phaseActionRecordsPairs.add(new Object[] {currentPhase, currentActionRecords}); |
| currentActionRecords = null; |
| currentPhaseActive = false; |
| } |
| |
| void recordPhaseExit(Phase phase) { |
| if (currentPhase == null) |
| throw new IllegalStateException(Messages.phase_not_started); |
| |
| if (currentPhase != phase) |
| throw new IllegalArgumentException(Messages.not_current_phase); |
| |
| currentPhase = null; |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugPhaseExit(phase); |
| } |
| |
| void recordOperandStart(Operand operand) { |
| if (operand == null) |
| throw new IllegalArgumentException(Messages.null_operand); |
| |
| if (currentRecord != null) |
| throw new IllegalStateException(Messages.operand_started); |
| |
| currentRecord = new ActionsRecord(operand); |
| currentActionRecords.add(currentRecord); |
| |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugOperandStart(operand); |
| } |
| |
| void recordOperandEnd(Operand operand) { |
| if (currentRecord == null) |
| throw new IllegalStateException(Messages.operand_not_started); |
| |
| if (currentRecord.operand != operand) |
| throw new IllegalArgumentException(Messages.not_current_operand); |
| |
| currentRecord = null; |
| |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugOperandEnd(operand); |
| } |
| |
| void recordActionExecute(ProvisioningAction action, Map<String, Object> parameters) { |
| if (action == null) |
| throw new IllegalArgumentException(Messages.null_action); |
| |
| currentRecord.actions.add(action); |
| |
| Touchpoint touchpoint = action.getTouchpoint(); |
| if (touchpoint != null) |
| touchpoints.add(touchpoint); |
| |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugActionExecute(action, parameters); |
| } |
| |
| public void recordActionUndo(ProvisioningAction action, Map<String, Object> parameters) { |
| if (DebugHelper.DEBUG_ENGINE_SESSION) |
| debugActionUndo(action, parameters); |
| } |
| |
| public String getContextString(Phase phase, Operand operand, ProvisioningAction action) { |
| if (action instanceof ParameterizedProvisioningAction) { |
| ParameterizedProvisioningAction parameterizedAction = (ParameterizedProvisioningAction) action; |
| action = parameterizedAction.getAction(); |
| } |
| String message = NLS.bind(Messages.session_context, new Object[] {profile.getProfileId(), phase.getClass().getName(), operand.toString(), getCurrentActionId()}); |
| return message; |
| } |
| |
| public String getContextString() { |
| String message = NLS.bind(Messages.session_context, new Object[] {profile.getProfileId(), getCurrentPhaseId(), getCurrentOperandId(), getCurrentActionId()}); |
| return message; |
| } |
| |
| private Object getCurrentActionId() { |
| if (currentRecord == null || currentRecord.actions.isEmpty()) |
| return EMPTY_STRING; |
| |
| Object currentAction = currentRecord.actions.get(currentRecord.actions.size() - 1); |
| if (currentAction instanceof ParameterizedProvisioningAction) { |
| ParameterizedProvisioningAction parameterizedAction = (ParameterizedProvisioningAction) currentAction; |
| currentAction = parameterizedAction.getAction(); |
| } |
| return currentAction.getClass().getName(); |
| } |
| |
| private String getCurrentPhaseId() { |
| if (currentPhase == null) |
| return EMPTY_STRING; |
| return currentPhase.getClass().getName(); |
| } |
| |
| private String getCurrentOperandId() { |
| if (currentRecord == null) |
| return EMPTY_STRING; |
| return currentRecord.operand.toString(); |
| } |
| |
| private static void debugPhaseEnter(Phase phase) { |
| DebugHelper.debug(ENGINE_SESSION, "Entering phase: " + phase.getClass().getName()); //$NON-NLS-1$ |
| } |
| |
| private static void debugPhaseExit(Phase phase) { |
| DebugHelper.debug(ENGINE_SESSION, "Exiting phase: " + phase.getClass().getName()); //$NON-NLS-1$ |
| } |
| |
| private static void debugOperandStart(Operand operand) { |
| DebugHelper.debug(ENGINE_SESSION, "Starting processing of operand: " + operand.toString()); //$NON-NLS-1$ |
| } |
| |
| private static void debugOperandEnd(Operand operand) { |
| DebugHelper.debug(ENGINE_SESSION, "Ending processing of operand: " + operand.toString()); //$NON-NLS-1$ |
| } |
| |
| private static void debugActionExecute(ProvisioningAction action, Map<String, Object> parameters) { |
| DebugHelper.debug(ENGINE_SESSION, "Executing action: " + DebugHelper.formatAction(action, parameters)); //$NON-NLS-1$ |
| } |
| |
| private static void debugActionUndo(ProvisioningAction action, Map<String, Object> parameters) { |
| DebugHelper.debug(ENGINE_SESSION, "Undoing action: " + DebugHelper.formatAction(action, parameters)); //$NON-NLS-1$ |
| } |
| } |