/******************************************************************************* * Copyright (c) 2011, 2014 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.tcf.te.runtime.stepper.stepper; 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.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.osgi.util.NLS; import org.eclipse.tcf.te.runtime.callback.Callback; import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil; import org.eclipse.tcf.te.runtime.interfaces.ISharedConstants; import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; import org.eclipse.tcf.te.runtime.persistence.history.HistoryManager; import org.eclipse.tcf.te.runtime.persistence.utils.DataHelper; import org.eclipse.tcf.te.runtime.stepper.FullQualifiedId; import org.eclipse.tcf.te.runtime.stepper.StepperManager; import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator; import org.eclipse.tcf.te.runtime.stepper.extensions.StepExecutor; import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStep; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepAttributes; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepExecutor; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroupIterator; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroupable; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper; import org.eclipse.tcf.te.runtime.stepper.interfaces.tracing.ITraceIds; import org.eclipse.tcf.te.runtime.stepper.nls.Messages; import org.eclipse.tcf.te.runtime.utils.ProgressHelper; import org.eclipse.tcf.te.runtime.utils.StatusHelper; /** * Stepper implementation. */ public class Stepper implements IStepper { private boolean initialized = false; private boolean finished = false; private IPropertiesContainer data = null; private IFullQualifiedId fullQualifiedId = null; private IProgressMonitor monitor = null; private IStepContext context = null; private boolean cancelable = true; private String stepGroupId = null; private String name = null; /** * Internal helper describing a fully executed step. */ protected final class ExecutedContextStep { final IFullQualifiedId id; final IStep step; public ExecutedContextStep(IFullQualifiedId id, IStep step) { this.id = id; this.step = step; } } /** * Constructor. */ public Stepper() { super(); } /** * Constructor. * * @param name The name of this stepper. */ public Stepper(String name) { super(); this.name = name; } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#getId() */ @Override public String getId() { return getClass().getName(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#getLabel() */ @Override public String getLabel() { return name != null && name.trim().length() > 0 ? name.trim() : getId(); } /** * Returns the id of the step group to execute by the stepper. * * @return The step group id. */ protected String getStepGroupId() { return stepGroupId; } /** * Returns the step group for the given step group id. * * @param The step group id. Must not be <code>null</code>: * @return The step group or <code>null</code>. */ protected IStepGroup getStepGroup(String id) { Assert.isNotNull(id); CoreBundleActivator.getTraceHandler().trace("SingleContextStepper#getStepGroup:" //$NON-NLS-1$ + " id = '" + id + "'", //$NON-NLS-1$ //$NON-NLS-2$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); return StepperManager.getInstance().getStepGroupExtManager().getStepGroup(id, false); } /** * Creates a new instance of the step executor to use for executing a step. * * @param step The step. Must not be <code>null</code>. * @param secondaryId The secondary id or <code>null</code>. * @param fullQualifiedStepId The fully qualified step id. Must not be <code>null</code>. * * @return The step executor instance. */ protected IStepExecutor doCreateStepExecutor(IStep step, String secondaryId, IFullQualifiedId fullQualifiedStepId) { Assert.isNotNull(step); Assert.isNotNull(fullQualifiedStepId); return new StepExecutor(this); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#initialize(org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext, java.lang.String, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor) */ @Override public final void initialize(IStepContext context, String stepGroupId, IPropertiesContainer data, IProgressMonitor monitor) throws IllegalStateException { Assert.isNotNull(context); Assert.isNotNull(stepGroupId); Assert.isNotNull(data); // Assert stepper is not in use if (isInitialized()) { throw new IllegalStateException("Stepper instance already initialized!"); //$NON-NLS-1$ } // set the initial stepper attributes this.context = context; this.stepGroupId = stepGroupId; this.data = data; this.monitor = monitor != null ? monitor : new NullProgressMonitor(); this.fullQualifiedId = new FullQualifiedId(IStepper.ID_TYPE_STEP_CONTEXT_ID, context.getId(), context.getSecondaryId()); // but not finished yet this.finished = false; boolean skipLastRunHistory = data.getBooleanProperty(IStepAttributes.PROP_SKIP_LAST_RUN_HISTORY); if (!skipLastRunHistory && !data.isEmpty()) { if (!data.containsKey(IStepAttributes.ATTR_HISTORY_DATA)) { data.setProperty(IStepAttributes.ATTR_STEP_GROUP_ID, stepGroupId); data.setProperty(IStepAttributes.PROP_SKIP_LAST_RUN_HISTORY, null); data.setProperty(IStepAttributes.ATTR_HISTORY_DATA, DataHelper.encodePropertiesContainer(data)); data.setProperty(IStepAttributes.PROP_SKIP_LAST_RUN_HISTORY, skipLastRunHistory); } else { IPropertiesContainer histData = DataHelper.decodePropertiesContainer(data.getStringProperty(IStepAttributes.ATTR_HISTORY_DATA)); histData.setProperty(IStepAttributes.ATTR_STEP_GROUP_ID, stepGroupId); data.setProperty(IStepAttributes.ATTR_HISTORY_DATA, DataHelper.encodePropertiesContainer(histData)); } } // call the hook for the subclasses to initialize themselves onInitialize(this.data, fullQualifiedId, this.monitor); setInitialized(); CoreBundleActivator.getTraceHandler().trace("Stepper#initialize:" //$NON-NLS-1$ + " data = " + data, //$NON-NLS-1$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); } /** * Hook for subclasses to overwrite if subclasses wants to initialize their own state. * * @param data The data. Must not be <code>null</code>. * @param fullQualifiedId The full qualified id of this stepper. * @param monitor The progress monitor. Must not be <code>null</code>. */ protected void onInitialize(IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) { Assert.isNotNull(data); Assert.isNotNull(monitor); } /** * Marks the stepper to be fully initialized. */ protected final void setInitialized() { initialized = true; } /* (non-Javadoc) * @see org.eclipse.tcf.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; } /** * Get the active context. * * @return The active context or <code>null</code>. */ protected IStepContext getContext() { return context; } /** * Get the context id. * * @return The context id or <code>null</code>. */ protected String getContextId() { return context != null ? context.getId() : null; } /** * 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; } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#isFinished() */ @Override public final boolean isFinished() { return finished; } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#cleanup() */ @Override public void cleanup() { // Set the progress monitor done here in any case ProgressHelper.done(getMonitor()); // Reset the initial stepper attributes context = null; data = null; monitor = null; fullQualifiedId = null; finished = false; initialized = false; } /* (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.tcf.te.runtime.stepper.interfaces.IStepper#execute() */ @Override public final void execute() throws CoreException { long startTime = System.currentTimeMillis(); CoreBundleActivator.getTraceHandler().trace("Stepper#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.Stepper_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>(); // save execution to history boolean skipLastRunHistory = data.getBooleanProperty(IStepAttributes.PROP_SKIP_LAST_RUN_HISTORY); String historyData = data.getStringProperty(IStepAttributes.ATTR_HISTORY_DATA); if (!skipLastRunHistory && historyData != null) { // this is the history for each step group used by action dialogs to prefill the values if no usable selection is available HistoryManager.getInstance().add(stepGroupId + "@" + context.getId(), historyData, 1); //$NON-NLS-1$ if (!data.getBooleanProperty(IStepAttributes.PROP_SKIP_LAST_RUN_HISTORY)) { // this is the history used for the list of history actions and the history dialog HistoryManager.getInstance().add(IStepAttributes.PROP_LAST_RUN_HISTORY_ID + "@" + context.getId(), historyData, 50); //$NON-NLS-1$ } } // 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.Stepper_multiStatus_finishedWithWarnings, getLabel()), 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("Stepper#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 step group id String stepGroupId = getStepGroupId(); // If no step group id is available, throw an exception if (stepGroupId == null) { throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), NLS.bind(Messages.Stepper_error_missingStepGroupId, getLabel()))); } // Get the step group IStepGroup stepGroup = getStepGroup(stepGroupId); // If no step group could be found, throw an exception if (stepGroup == null) { throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), NLS.bind(Messages.Stepper_error_missingStepGroup, stepGroupId))); } // Initialize the progress monitor ProgressHelper.beginTask(getMonitor(), stepGroup.getLabel(), calculateTotalWork(stepGroup)); IFullQualifiedId fullQualifiedId = getFullQualifiedId().createChildId(ID_TYPE_STEPPER_ID, getId(), 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 stepGroupId The step group. Must not be <code>null</code>. * @param statusContainer A list holding the warnings occurred during the execution. Must not be * <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must not be * <code>null</code>. * @param fullQualifiedGroupId The hierarchy of all parent step group id's separated by "::". * Must not be <code>null</code>. * * @throws CoreException If the execution fails. */ private void executeStepGroup(IStepGroup 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() && ProgressHelper.isCanceled(getMonitor())) { rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); } CoreBundleActivator.getTraceHandler().trace("Stepper#executeStepGroup: step group: '" //$NON-NLS-1$ + (stepGroup.getLabel() != null && !"".equals(stepGroup.getLabel().trim()) ? stepGroup.getLabel() : stepGroup.getId()) //$NON-NLS-1$ + "'", //$NON-NLS-1$ 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); // Resolve the steps to execute IStepGroupable[] groupables = stepGroup.getSteps(getContext()); IStepGroupIterator iterator = stepGroup.getStepGroupIterator(); IFullQualifiedId fullQualifiedIterationId = fullQualifiedGroupId; int iteration = 0; if (iterator != null) { iterator.initialize(getContext(), getData(), fullQualifiedGroupId, getMonitor()); } boolean next = iterator == null || iterator.hasNext(getContext(), getData(), fullQualifiedGroupId, getMonitor()); while (next) { if (iterator != null) { fullQualifiedIterationId = fullQualifiedGroupId.getParentId().createChildId(ID_TYPE_STEP_GROUP_ID, stepGroup.getId(), "" + iteration); //$NON-NLS-1$ iterator.next(getContext(), getData(), fullQualifiedIterationId, getMonitor()); } // Execute the steps or step groups. for (IStepGroupable groupable : groupables) { executeGroupable(groupable, statusContainer, executedSteps, fullQualifiedIterationId); } iteration++; next = iterator != null && iterator.hasNext(getContext(), getData(), fullQualifiedGroupId, getMonitor()); } } /** * Executes a step groupable. The groupable might encapsulate a step or a step group. * * @param step The step groupable. Must not be <code>null</code>. * @param statusContainer A list holding the warnings occurred during the execution. Must not be * <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must not be * <code>null</code>. * @param fullQualifiedParentId The hierarchy of all parent step group id's separated by "::". * Must not be <code>null</code>. * * @throws CoreException If the execution failed. */ private void executeGroupable(IStepGroupable 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() && ProgressHelper.isCanceled(getMonitor())) { 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("Stepper#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 IStepGroup) { 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((IStepGroup) groupable.getExtension(), statusContainer, executedSteps, id); if (groupable.isSavePoint()) { ExecutedContextStep last = executedSteps.isEmpty() ? null : executedSteps.get(executedSteps.size()-1); while (last != null && last.id.toString().startsWith(id.toString())) { executedSteps.remove(executedSteps.size()-1); last = executedSteps.isEmpty() ? null : executedSteps.get(executedSteps.size()-1); } } } else if (groupable.getExtension() instanceof IStep) { // 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. IStep step = (IStep) groupable.getExtension(); IFullQualifiedId id = fullQualifiedParentId.createChildId(ID_TYPE_STEP_ID, step.getId(), groupable.getSecondaryId()); // Create the step executor now IStepExecutor executor = doCreateStepExecutor(step, groupable.getSecondaryId(), id); Assert.isNotNull(executor); try { executedSteps.add(new ExecutedContextStep(id, step)); // Invoke the executor now executor.execute(step, id, getContext(), getData(), getMonitor()); if (groupable.isSavePoint()) { executedSteps.remove(executedSteps.size()-1); } } 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 not be <code>null</code>. * @param executedSteps A list holding the id's of the steps executed before. Must not be * <code>null</code>. * * @throws CoreException If a dependency has not been executed before. */ protected void checkForDependenciesExecuted(IStepGroupable 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 IStep) { dependencies.addAll(Arrays.asList(((IStep) 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.Stepper_error_requiredStepNotExecuted, NLS.bind(groupable.getExtension() instanceof IStep ? Messages.Stepper_error_step : Messages.Stepper_error_stepGroup, groupable.getExtension().getId()), NLS.bind(Messages.Stepper_error_requiredStepOrGroup, dependency), ""))); //$NON-NLS-1$ } // 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. * * @param executedSteps The list of executed steps. * @param progress The progress monitor. */ protected final void rollback(final List<ExecutedContextStep> executedSteps, final IStatus rollBackStatus, IProgressMonitor progress) { Assert.isNotNull(executedSteps); while (!executedSteps.isEmpty()) { ExecutedContextStep executedStep = executedSteps.remove(executedSteps.size() - 1); Callback callback = new Callback(); progress.setTaskName("Rollback " + executedStep.step.getLabel()); //$NON-NLS-1$ executedStep.step.rollback(getContext(), getData(), rollBackStatus, executedStep.id, progress, callback); ExecutorsUtil.waitAndExecute(60000, callback.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 stepGroupId The step group. Must not be <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(IStepGroup stepGroup) throws CoreException { Assert.isNotNull(stepGroup); int totalWork = 0; // Loop the group steps and summarize the returned total work IStepGroupable[] groupables = stepGroup.getSteps(getContext()); for (IStepGroupable groupable : groupables) { int work = groupable.getExtension() instanceof IStep ? ((IStep) groupable .getExtension()).getTotalWork(getContext(), getData()) : groupable .getExtension() instanceof IStepGroup ? calculateTotalWork((IStepGroup) 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 not be <code>null</code>. * @param statusContainer The list of non-severe status objects. Must not be <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()) { ProgressHelper.cancel(getMonitor()); } } 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.Stepper_multiStatus_finishedWithErrors, getLabel()), null); // for (IStatus stat : statusContainer) { // multiStatus.merge(stat); // } // // Re-throw via a new CoreException // coreException = new CoreException(multiStatus); // } } return coreException; } }