/******************************************************************************* * Copyright (c) 2011 Wind River Systems, 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 http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tm.te.runtime.stepper.extensions; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.osgi.util.NLS; import org.eclipse.tm.te.runtime.callback.Callback; import org.eclipse.tm.te.runtime.concurrent.util.ExecutorsUtil; import org.eclipse.tm.te.runtime.extensions.ExecutableExtension; import org.eclipse.tm.te.runtime.interfaces.ISharedConstants; import org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer; import org.eclipse.tm.te.runtime.stepper.StepperAttributeUtil; import org.eclipse.tm.te.runtime.stepper.activator.CoreBundleActivator; import org.eclipse.tm.te.runtime.stepper.interfaces.IContext; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextManipulator; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextStep; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextStepExecutor; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextStepGroup; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextStepGroupIterator; import org.eclipse.tm.te.runtime.stepper.interfaces.IContextStepGroupable; import org.eclipse.tm.te.runtime.stepper.interfaces.IExtendedContextStep; import org.eclipse.tm.te.runtime.stepper.interfaces.IFullQualifiedId; import org.eclipse.tm.te.runtime.stepper.interfaces.IStepper; import org.eclipse.tm.te.runtime.stepper.interfaces.IVariantDelegate; import org.eclipse.tm.te.runtime.stepper.interfaces.tracing.ITraceIds; import org.eclipse.tm.te.runtime.stepper.nls.Messages; import org.eclipse.tm.te.runtime.utils.ProgressHelper; import org.eclipse.tm.te.runtime.utils.StatusHelper; /** * An abstract stepper implementation. */ public abstract class AbstractContextStepper extends ExecutableExtension implements IStepper, IContextManipulator { private boolean initialized = false; private boolean finished = false; private IPropertiesContainer data = null; private IFullQualifiedId fullQualifiedId = null; private IProgressMonitor monitor = null; private String activeContextId = null; private IContext activeContext = null; private boolean cancelable = true; protected class ExecutedContextStep { final IFullQualifiedId id; final IContextStep step; public ExecutedContextStep(IFullQualifiedId id, IContextStep step) { this.id = id; this.step = step; } } /** * Constructor. */ public AbstractContextStepper() { super(); } /** * Returns the name of what is executed by the stepper. */ protected abstract String getName(); /** * Returns the type if what is executed by the stepper. */ protected abstract String getType(); /** * Returns the sub type if what is executed by the stepper. */ protected abstract String getSubType(); /** * Returns the contexts the stepper is working with. */ protected abstract IContext[] getContexts(); /** * Returns the variant delegate to use or <code>null</code>. */ protected abstract IVariantDelegate getVariantDelegate() throws CoreException; /** * Creates a new instance of the step executor to use for executing a step. */ protected abstract IContextStepExecutor doCreateStepExecutor(IContextStep step, String secondaryId, IFullQualifiedId fullQualifiedStepId); /** * Returns the step group for the given arguments. */ protected abstract IContextStepGroup getStepGroup(String type, String subType, String variant); /* (non-Javadoc) * @see org.eclipse.tm.te.runtime.stepper.interfaces.IStepper#initialize(org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tm.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor) */ @Override public void initialize(IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws IllegalStateException { Assert.isNotNull(data); Assert.isNotNull(fullQualifiedId); Assert.isNotNull(monitor); // Assert stepper is not in use if (isInitialized()) { throw new IllegalStateException("Stepper instance already initialized!"); //$NON-NLS-1$ } // set the initial stepper attributes this.data = data; this.monitor = monitor; this.fullQualifiedId = fullQualifiedId; // but not finished yet this.finished = false; // set the initial stepper attributes this.activeContext = null; this.activeContextId = null; setInitialized(); CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#initialize:" //$NON-NLS-1$ + " type='" + getType() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + ", mode='" + getSubType() + "'", //$NON-NLS-1$ //$NON-NLS-2$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); } /** * Marks the stepper to be fully initialized. */ protected final void setInitialized() { initialized = true; } /* (non-Javadoc) * @see org.eclipse.tm.te.runtime.stepper.interfaces.IStepper#isInitialized() */ @Override public final boolean isInitialized() { return initialized; } /** * Sets the cancelable state of the stepper. * * @param cancelable <code>True</code> if the stepper shall be cancelable, <code>false</code> if not. */ protected final void setCancelable(boolean cancelable) { this.cancelable = cancelable; } /** * Returns the cancelable state of the stepper. * * @return <code>True</code> if the stepper is cancelable, <code>false</code> if not. */ protected final boolean isCancelable() { return cancelable; } /** * Sets the active context. * * @param context The active context or <code>null</code>. */ protected final void setActiveContext(IContext context) { // do not use equals() here!!! if (activeContext != context) { if (activeContext instanceof IPropertiesContainer) { ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), null); //$NON-NLS-1$ } activeContext = context; if (activeContext instanceof IPropertiesContainer) { ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), true); //$NON-NLS-1$ } } } /** * Get the active context. * * @return The active context or <code>null</code>. */ protected IContext getActiveContext() { if (isInitialized() && activeContext == null) { IContext newContext = (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, getFullQualifiedId(), getData()); if (newContext != null) { setActiveContext(newContext); } if (activeContext == null) { IContext[] contexts = getContexts(); if (contexts != null && contexts.length > 0) { for (IContext context : contexts) { setActiveContext(context); StepperAttributeUtil.setProperty(IContextManipulator.CONTEXT, getFullQualifiedId(), getData(), activeContext); break; } } } } return activeContext; } /** * Sets the active context id. * * @param contextId The active context id or <code>null</code>. */ protected final void setActiveContextId(String contextId) { activeContextId = contextId; } /** * Get the active context id. * * @return The active context id or <code>null</code>. */ protected String getActiveContextId() { if (isInitialized() && activeContextId == null) { String newContextId = (String)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT_ID, getFullQualifiedId(), getData()); if (newContextId != null && newContextId.trim().length() > 0) { activeContextId = newContextId.trim(); } if (activeContextId == null) { IContext context = getActiveContext(); if (context != null) { activeContextId = context.getContextId(); StepperAttributeUtil.setProperty(IContextManipulator.CONTEXT_ID, getFullQualifiedId(), getData(), activeContextId); } } } return activeContextId; } /** * Returns the currently associated data. The method returns * <code>null</code> if the stepper is not in initialized state. * * @return The data or <code>null</code> */ protected final IPropertiesContainer getData() { return isInitialized() ? data : null; } /** * Returns the full qualified id for this stepper. * * @return The full qualified stepper id. */ protected final IFullQualifiedId getFullQualifiedId() { return fullQualifiedId; } /** * Returns the currently associated progress monitor. The method returns * <code>null</code> if the stepper is not in initialized state. * * @return The progress monitor or <code>null</code> */ protected final IProgressMonitor getMonitor() { return isInitialized() ? monitor : null; } /** * Marks the stepper to be finished. */ protected final void setFinished() { finished = true; if (activeContext instanceof IPropertiesContainer) { ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), null); //$NON-NLS-1$ } } /* (non-Javadoc) * @see org.eclipse.tm.te.runtime.stepper.interfaces.IStepper#isFinished() */ @Override public final boolean isFinished() { return finished; } /* (non-Javadoc) * @see org.eclipse.tm.te.runtime.stepper.interfaces.IStepper#cleanup() */ @Override public void cleanup() { // Set the progress monitor done here in any case if (getMonitor() != null) getMonitor().done(); // Reset the initial stepper attributes data = null; monitor = null; fullQualifiedId = null; finished = false; initialized = false; // Reset the initial stepper attributes setActiveContext(null); setActiveContextId(null); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); buffer.append(" (" + getLabel() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ buffer.append(": "); //$NON-NLS-1$ buffer.append("id = " + getId()); //$NON-NLS-1$ return buffer.toString(); } /* (non-Javadoc) * @see org.eclipse.tm.te.runtime.stepper.interfaces.IStepper#execute() */ @Override public final void execute() throws CoreException { long startTime = System.currentTimeMillis(); CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: *** ENTERED", //$NON-NLS-1$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); CoreBundleActivator.getTraceHandler().trace(" [" + ISharedConstants.TIME_FORMAT.format(new Date(startTime)) + "]" //$NON-NLS-1$ //$NON-NLS-2$ + " ***", //$NON-NLS-1$ 0, ITraceIds.PROFILE_STEPPING, IStatus.WARNING, this); try { // stepper must be initialized before executing if (!isInitialized()) { throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), Messages.AbstractContextStepper_error_initializeNotCalled)); } // Create a container for collecting the non-severe status objects // during the step execution. Non-severe status objects will // be hold back till the execution completed or stopped with an error. // Severe status objects are errors or cancellation. List<IStatus> statusContainer = new ArrayList<IStatus>(); // start execution internalExecute(statusContainer); // If the warnings container is not empty, create a new status and // throw a core exception if (!statusContainer.isEmpty()) { IStatus status = null; // Check if we need a multi status if (statusContainer.size() > 1) { MultiStatus multiStatus = new MultiStatus(CoreBundleActivator.getUniqueIdentifier(), 0, NLS.bind(Messages.AbstractContextStepper_multiStatus_finishedWithWarnings, getName()), null); for (IStatus subStatus : statusContainer) { multiStatus.merge(subStatus); } status = multiStatus; } else { status = statusContainer.get(0); } throw new CoreException(status); } } finally { // Mark the stepper finished setFinished(); long endTime = System.currentTimeMillis(); CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: *** DONE", //$NON-NLS-1$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); CoreBundleActivator.getTraceHandler().trace(" [" + ISharedConstants.TIME_FORMAT.format(new Date(endTime)) //$NON-NLS-1$ + " , delay = " + (endTime - startTime) + " ms]" //$NON-NLS-1$ //$NON-NLS-2$ + " ***", //$NON-NLS-1$ 0, ITraceIds.PROFILE_STEPPING, IStatus.WARNING, this); } } /** * Executes a step or step group. * * @param statusContainer The status container. Must not be <code>null</code>. * @throws CoreException If the execution fails. */ protected void internalExecute(List<IStatus> statusContainer) throws CoreException { Assert.isNotNull(statusContainer); // Get the variant delegate IVariantDelegate variantDelegate = getVariantDelegate(); String[] variants = null; if (variantDelegate != null) { // Determine the valid variants variants = variantDelegate.getValidVariants(getActiveContext(), getData()); } // Get the step group IContextStepGroup stepGroup = null; if (variants != null) { for (String variant : variants) { stepGroup = getStepGroup(getType(), getSubType(), variant); if (stepGroup != null) { break; } } } if (stepGroup == null) { stepGroup = getStepGroup(getType(), getSubType(), null); } // If no step group could be found for any of the valid variants, throw an exception if (stepGroup == null) { throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), NLS.bind(Messages.AbstractContextStepper_error_missingStepGroup, getName()))); } // Initialize the progress monitor getMonitor().beginTask(stepGroup.getLabel(), calculateTotalWork(stepGroup)); IFullQualifiedId fullQualifiedId = getFullQualifiedId().createChildId(ID_TYPE_CONTEXT_ID, getActiveContextId(), null); fullQualifiedId = fullQualifiedId.createChildId(ID_TYPE_STEP_GROUP_ID, stepGroup.getId(), null); // Execute the step group executeStepGroup(stepGroup, statusContainer, new ArrayList<ExecutedContextStep>(), fullQualifiedId); } /** * Executes a step group. * * @param stepGroup The step group. Must be not <code>null</code>. * @param statusContainer A list holding the warnings occurred during the execution. Must be not <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. * @param fullQualifiedGroupId The hierarchy of all parent step group id's separated by "::". Must be not <code>null</code>. * * @throws CoreException If the execution fails. */ private void executeStepGroup(IContextStepGroup stepGroup, List<IStatus> statusContainer, List<ExecutedContextStep> executedSteps, IFullQualifiedId fullQualifiedGroupId) throws CoreException { Assert.isNotNull(stepGroup); Assert.isNotNull(statusContainer); Assert.isNotNull(executedSteps); Assert.isNotNull(fullQualifiedGroupId); // Return immediately if the user canceled the monitor in the meanwhile if (isCancelable() && getMonitor().isCanceled()) { rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); } CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: step group: '" + stepGroup.getLabel() + "'", //$NON-NLS-1$ //$NON-NLS-2$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); IContextStepGroupIterator iterator = stepGroup.getStepGroupIterator(); IFullQualifiedId fullQualifiedIterationId = fullQualifiedGroupId; int iteration = 0; if (iterator != null) { iterator.initialize(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); } boolean next = iterator == null || iterator.hasNext(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); while (next) { if (iterator != null) { fullQualifiedIterationId = fullQualifiedGroupId.createChildId(ID_TYPE_STEP_GROUP_ITERATION_ID, iterator.getId(), ""+iteration); //$NON-NLS-1$ iterator.next(getActiveContext(), getData(), fullQualifiedIterationId, getMonitor()); // set the active context if the step has manipulated it if (iterator instanceof IContextManipulator) { IContext newContext = (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, fullQualifiedIterationId, getData()); String newContextId = StepperAttributeUtil.getStringProperty(IContextManipulator.CONTEXT_ID, fullQualifiedIterationId, getData()); if (newContext != null) { setActiveContext(newContext); } if (newContextId != null && newContextId.trim().length() > 0) { setActiveContextId(newContextId.trim()); } } } // Get the list of steps or step groups to execute. IContextStepGroupable[] groupables = stepGroup.getSteps(getType(), getSubType()); for (IContextStepGroupable groupable : groupables) { executeGroupable(groupable, statusContainer, executedSteps, fullQualifiedIterationId); } iteration++; next = iterator != null && iterator.hasNext(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); } } /** * Executes a step groupable. The groupable might encapsulate a * step or a step group. * * @param step The step groupable. Must be not <code>null</code>. * @param statusContainer A list holding the warnings occurred during the execution. Must be not <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. * @param fullQualifiedParentId The hierarchy of all parent step group id's separated by "::". Must be not <code>null</code>. * * @throws CoreException If the execution failed. */ private void executeGroupable(IContextStepGroupable groupable, List<IStatus> statusContainer, List<ExecutedContextStep> executedSteps, IFullQualifiedId fullQualifiedParentId) throws CoreException { Assert.isNotNull(groupable); Assert.isNotNull(statusContainer); Assert.isNotNull(executedSteps); Assert.isNotNull(fullQualifiedParentId); // Return immediately if the user canceled the monitor in the meanwhile if (isCancelable() && getMonitor() != null && getMonitor().isCanceled()) { rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); } // If the passed in groupable is disabled -> we are done immediately if (groupable.isDisabled()) { CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#executeGroupable: DROPPED DISABLED groupable: id = '" + groupable.getExtension().getId() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + ", secondaryId = '" + groupable.getSecondaryId() + "'", //$NON-NLS-1$ //$NON-NLS-2$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); return; } // Check if all dependencies of the groupable have been executed before checkForDependenciesExecuted(groupable, executedSteps); if (groupable.getExtension() instanceof IContextStepGroup) { IFullQualifiedId id = fullQualifiedParentId.createChildId(ID_TYPE_STEP_GROUP_ID, groupable.getExtension().getId(), groupable.getSecondaryId()); // If the passed in groupable is associated with a step group // -> get the groupable from that group and execute them executeStepGroup((IContextStepGroup)groupable.getExtension(), statusContainer, executedSteps, id); } else if (groupable.getExtension() instanceof IContextStep) { // If the passed in groupable is associated with a step // -> check if the required steps have been executed before, // create a step executor and invoke the executor. IContextStep step = (IContextStep)groupable.getExtension(); IFullQualifiedId id = fullQualifiedParentId.createChildId(ID_TYPE_STEP_ID, step.getId(), groupable.getSecondaryId()); // Create the step executor now IContextStepExecutor executor = doCreateStepExecutor(step, groupable.getSecondaryId(), id); Assert.isNotNull(executor); try { executedSteps.add(new ExecutedContextStep(id, step)); // Invoke the executor now executor.execute(step, id, getActiveContext(), getData(), getMonitor()); // set the active context if the step has manipulated it if (step instanceof IContextManipulator) { IContext newContext = (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, id, getData()); String newContextId = StepperAttributeUtil.getStringProperty(IContextManipulator.CONTEXT_ID, id, getData()); if (newContext != null) { setActiveContext(newContext); } if (newContextId != null && newContextId.trim().length() > 0) { setActiveContextId(newContextId.trim()); } } } catch (Exception e) { // Catch the CoreException first hand as we need to continue the // stepping if the step returned with warnings or information only. CoreException coreException = normalizeStatus(e, statusContainer); // If the exception has been not eaten, rollback previously executed // steps and re-throw the exception. if (coreException != null) { // Rollback everything, if the step(s) are supporting this and // the cleanup hasn't been done already. if (isInitialized()) { rollback(executedSteps, coreException.getStatus(), getMonitor()); } // Re-throw the exception throw coreException; } } } } /** * Checks if all required dependencies have been executed before. If not, the method * will throw an error status. * * @param groupable The groupable. Must be not <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. * * @throws CoreException If a dependency has not been executed before. */ protected void checkForDependenciesExecuted(IContextStepGroupable groupable, List<ExecutedContextStep> executedSteps) throws CoreException { Assert.isNotNull(groupable); Assert.isNotNull(executedSteps); // Build up the complete list of dependencies. List<String> dependencies = new ArrayList<String>(Arrays.asList(groupable.getDependencies())); // If the groupable wraps a step, the step can have additional dependencies to check if (groupable.getExtension() instanceof IContextStep) { dependencies.addAll(Arrays.asList(((IContextStep)groupable.getExtension()).getDependencies())); } // Check each dependency now. for (String dependency : dependencies) { // The dependencies might be fully qualified. Split out the primary id. String[] splitted = dependency.split("##", 2); //$NON-NLS-1$ String primaryId = splitted.length == 2 ? splitted[0] : dependency; // Check if the id is in the list of executed steps. As the list contains // the fully qualified id's, we cannot just check for contained boolean requiredStepExecuted = false; for (ExecutedContextStep step : executedSteps) { if (step.step.getId().equals(primaryId)) { requiredStepExecuted = true; break; } } if (!requiredStepExecuted) { throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), MessageFormat.format(Messages.AbstractContextStepper_error_requiredStepNotExecuted, NLS.bind((groupable.getExtension() instanceof IContextStep ? Messages.AbstractContextStepper_error_step : Messages.AbstractContextStepper_error_requiredStepOrGroup), dependency), NLS.bind(Messages.AbstractContextStepper_error_typeAndSubtype, getType(), getSubType())))); } // Recursive checking is not necessary here as the step or step group // id's would have made it the executed steps list of they missed required // steps or step groups. } } /** * Rollback the steps previously executed to the failed step. The rollback * is executed in reverse order and the step must be of type {@link IWRExtendedTargetContextStep} * to participate in the rollback. * * @param executedSteps * @param progress */ protected final void rollback(final List<ExecutedContextStep> executedSteps, final IStatus rollBackStatus, IProgressMonitor progress) { Assert.isNotNull(executedSteps); final IProgressMonitor rollbackProgress = ProgressHelper.getProgressMonitor(progress, 1); ProgressHelper.beginTask(rollbackProgress, "Cancel", executedSteps.size()); //$NON-NLS-1$ final Callback finalCallback = new Callback(); final Callback rollbackCallback = new Callback() { @Override protected void internalDone(Object caller, IStatus status) { if (!executedSteps.isEmpty()) { setProperty(PROPERTY_IS_DONE, false); ExecutedContextStep executedStep = executedSteps.remove(executedSteps.size()-1); if (executedStep.step instanceof IExtendedContextStep) { IExtendedContextStep step = (IExtendedContextStep)executedStep.step; step.rollback(getActiveContext(), getData(), rollBackStatus, executedStep.id, rollbackProgress, this); } else { this.done(this, status); } } else { finalCallback.done(this, Status.OK_STATUS); } } }; rollbackCallback.done(this, rollBackStatus); ExecutorsUtil.waitAndExecute(0, finalCallback.getDoneConditionTester(null)); } /** * Calculates the total work required for the step group. The total * work is the sum of the total work of each sub step. If one of the * steps returns {@link IProgressMonitor#UNKNOWN}, the total work will * be unknown for the whole step group. * * @param stepGroup The step group. Must be not <code>null</code>. * @return The total work required or {@link IProgressMonitor#UNKNOWN}. * * @throws CoreException If the total work of the step group cannot be determined. */ protected int calculateTotalWork(IContextStepGroup stepGroup) throws CoreException { Assert.isNotNull(stepGroup); int totalWork = 0; // Loop the group steps and summarize the returned total work IContextStepGroupable[] groupables = stepGroup.getSteps(getType(), getSubType()); for (IContextStepGroupable groupable : groupables) { int work = groupable.getExtension() instanceof IContextStep ? ((IContextStep)groupable.getExtension()).getTotalWork(getActiveContext(), getData()) : groupable.getExtension() instanceof IContextStepGroup ? calculateTotalWork((IContextStepGroup)groupable.getExtension()) : IProgressMonitor.UNKNOWN; if (work == IProgressMonitor.UNKNOWN) { totalWork = IProgressMonitor.UNKNOWN; break; } totalWork += work; } return totalWork; } /** * Normalize the associated status object of the given {@link CoreException}. * <p> * If the associated status contains only WARNING or INFORMATION status objects, * the objects are added to the passed in status container. The passed in exception * is dropped and the method will return <code>null</code>. * <p> * If the associated status contains only OK status objects, the passed in * exception and the associated status are dropped and the method will return * <code>null</code>. * <p> * If the associated status contain ERROR status objects, the passed in exception * and the associated status objects are returned if the passed in status container * is empty. If the status container is not empty, a new exception and multi status * object is created and returned. The multi status object will contain all status * objects from the status container and all objects of the originally associated * status. * <p> * If the associated status contains a CANCEL status object, the passed in * exception and the associated status objects are returned unmodified. * * @param e The core exception. Must be not <code>null</code>. * @param statusContainer The list of non-severe status objects. Must be not <code>null</code>. * @return The exception to re-throw or <code>null</code>. */ private CoreException normalizeStatus(Exception e, List<IStatus> statusContainer) { Assert.isNotNull(statusContainer); CoreException coreException = null; IStatus status = Status.OK_STATUS; // Get the associated status from the exception if (e instanceof CoreException) { status = ((CoreException)e).getStatus(); coreException = (CoreException)e; } else if (e instanceof OperationCanceledException) { status = new Status(IStatus.CANCEL, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); coreException = new CoreException(status); } else if (e != null) { status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); coreException = new CoreException(status); } // Check the severity // PS: MultiStatus.getSeverity() returns always the highest severity. if (status.getSeverity() == IStatus.OK) { // OK -> drop completely and return null coreException = null; } else if (status.getSeverity() == IStatus.CANCEL) { // CANCEL -> Check monitor to be canceled. if (isCancelable()) { if (getMonitor() != null && !getMonitor().isCanceled()) { getMonitor().setCanceled(true); } } } else if (status.getSeverity() == IStatus.WARNING || status.getSeverity() == IStatus.INFO) { // WARNING or INFORMATION -> add to the list and return null statusContainer.add(status); coreException = null; } else if (status.getSeverity() == IStatus.ERROR) { // Error -> If the warnings container not empty, create // a new MultiStatus. if (!statusContainer.isEmpty()) { MultiStatus multiStatus = new MultiStatus(status.getPlugin(), status.getCode(), NLS.bind(Messages.AbstractContextStepper_multiStatus_finishedWithErrors, getName()), null); for (IStatus stat : statusContainer) { multiStatus.merge(stat); } // Re-throw via a new CoreException coreException = new CoreException(multiStatus); } } return coreException; } }