diff options
author | Tobias Schwarz | 2013-04-09 11:34:28 +0000 |
---|---|---|
committer | Tobias Schwarz | 2013-04-09 11:35:13 +0000 |
commit | c4d1ff0c3cf8d73fcdf57e7a3c269c0a4bf34553 (patch) | |
tree | 81f7c107c32884fd117f4bae5ea391c91a6c57dd /target_explorer | |
parent | 1ea76786fb48d778e7b7dd3fc4b6417875225899 (diff) | |
download | org.eclipse.tcf-c4d1ff0c3cf8d73fcdf57e7a3c269c0a4bf34553.tar.gz org.eclipse.tcf-c4d1ff0c3cf8d73fcdf57e7a3c269c0a4bf34553.tar.xz org.eclipse.tcf-c4d1ff0c3cf8d73fcdf57e7a3c269c0a4bf34553.zip |
Target Explorer: add watchdog when stepper is canceled and on rollback
Diffstat (limited to 'target_explorer')
13 files changed, 1334 insertions, 1327 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.launch.core/src/org/eclipse/tcf/te/launch/core/delegates/LaunchConfigurationDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.launch.core/src/org/eclipse/tcf/te/launch/core/delegates/LaunchConfigurationDelegate.java index 5612da668..7eab7db2f 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.launch.core/src/org/eclipse/tcf/te/launch/core/delegates/LaunchConfigurationDelegate.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.launch.core/src/org/eclipse/tcf/te/launch/core/delegates/LaunchConfigurationDelegate.java @@ -41,7 +41,6 @@ import org.eclipse.tcf.te.launch.core.lm.interfaces.ICommonLaunchAttributes; import org.eclipse.tcf.te.launch.core.lm.interfaces.ILaunchManagerDelegate; import org.eclipse.tcf.te.launch.core.nls.Messages; import org.eclipse.tcf.te.launch.core.persistence.projects.ReferencedProjectsPersistenceDelegate; -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.stepper.interfaces.IStepContext; @@ -144,8 +143,6 @@ public class LaunchConfigurationDelegate extends org.eclipse.debug.core.model.La // Execute stepper.execute(); - // Wait for the stepper to be finished - ExecutorsUtil.waitAndExecute(0, new IStepper.ExecutionFinishedConditionTester(stepper)); } catch (CoreException e) { // We have to catch the CoreException here as we do want to open the // launch configurations dialog on ERROR only. diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepExecutor.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepExecutor.java index 590c56e73..f9cfb6d4d 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepExecutor.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepExecutor.java @@ -25,7 +25,6 @@ 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.stepper.activator.CoreBundleActivator;
-import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedStep;
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.IStepContext;
@@ -64,10 +63,10 @@ public class StepExecutor implements IStepExecutor { * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepExecutor#execute(org.eclipse.tcf.te.runtime.stepper.interfaces.IStep, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
- public final void execute(IStep step, IFullQualifiedId id, final IStepContext context, final IPropertiesContainer data, IProgressMonitor progress) throws CoreException {
+ public final void execute(final IStep step, IFullQualifiedId id, final IStepContext context, final IPropertiesContainer data, IProgressMonitor progress) throws CoreException {
Assert.isNotNull(step);
Assert.isNotNull(id);
- // Assert.isNotNull(context);
+ Assert.isNotNull(context);
Assert.isNotNull(data);
Assert.isNotNull(progress);
@@ -79,7 +78,7 @@ public class StepExecutor implements IStepExecutor { + " ***", //$NON-NLS-1$
0, ITraceIds.PROFILE_STEPPING, IStatus.WARNING, this);
- int ticksToUse = (step instanceof IExtendedStep) ? ((IExtendedStep)step).getTotalWork(context, data) : IProgressMonitor.UNKNOWN;
+ int ticksToUse = step.getTotalWork(context, data);
progress = ProgressHelper.getProgressMonitor(progress, ticksToUse);
ProgressHelper.beginTask(progress, step.getLabel(), ticksToUse);
@@ -89,23 +88,13 @@ public class StepExecutor implements IStepExecutor { // Catch any exception that might occur during execution.
// Errors are passed through by definition.
try {
- // Execute the step. Spawn to the dispatch thread if necessary.
- if (step instanceof IExtendedStep) {
- IExtendedStep extendedStep = (IExtendedStep)step;
-
- // IExtendedStep provides protocol for initialization and validation.
- extendedStep.initializeFrom(context, data, id, progress);
-
- // step is initialized -> now validate for execution.
- // If the step if not valid for execution, validateExecute is throwing an exception.
- extendedStep.validateExecute(context, data, id, progress);
- }
-
+ step.initializeFrom(context, data, id, progress);
+ step.validateExecute(context, data, id, progress);
step.execute(context, data, id, progress, callback);
// Wait till the step finished, an execution occurred or the
// user hit cancel on the progress monitor.
- ExecutorsUtil.waitAndExecute(0, callback.getDoneConditionTester(null));
+ ExecutorsUtil.waitAndExecute(0, callback.getDoneConditionTester(progress, step.getCancelTimeout()));
// Check the status of the step
normalizeStatus(step, id, context, data, callback.getStatus());
@@ -136,9 +125,7 @@ public class StepExecutor implements IStepExecutor { }
// Give the step a chance for cleanup
- if (step instanceof IExtendedStep) {
- ((IExtendedStep)step).cleanup(context, data, id, progress);
- }
+ step.cleanup(context, data, id, progress);
long endTime = System.currentTimeMillis();
CoreBundleActivator.getTraceHandler().trace("StepExecutor#execute: *** DONE (" + step.getLabel() + ")", //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepGroup.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepGroup.java index a753f2604..d00ba8a68 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepGroup.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/StepGroup.java @@ -32,7 +32,6 @@ import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy; import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; import org.eclipse.tcf.te.runtime.stepper.StepperManager; import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator; -import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedStep; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStep; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext; import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup; @@ -398,8 +397,7 @@ public class StepGroup extends ExecutableExtension implements IStepGroup { // If either the groupable, the reference or the extension is // marked singleton, than this is an failure. checkFailed = step.isSingleton() || reference.isSingleton() - || (step.getExtension() instanceof IExtendedStep - && ((IExtendedStep)step.getExtension()).isSingleton()); + || (step.getExtension() instanceof IStep && ((IStep)step.getExtension()).isSingleton()); if (checkFailed) { break; } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedStep.java deleted file mode 100644 index 962541ea5..000000000 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedStep.java +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011, 2012 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.interfaces; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; - -/** - * Extended single step providing additional life cycle methods. - */ -public interface IExtendedStep extends IStep { - - /** - * Returns if or if not this step can have multiple references within step groups. If - * <code>true</code> is returned, the step can occur exactly once per step group. This method - * effects all defined step groups and overwrite individual step settings. - * <p> - * The default implementation returns <code>false</code>. - * - * @return <code>True</code> if the step can be referenced only ones per step group, - * <code>false</code> otherwise. - */ - public boolean isSingleton(); - - /** - * Initialize the step from the given data. - * - * @param context The context. Must not be <code>null</code>. - * @param data The data. Must not be <code>null</code>. - * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>. - * @param monitor The progress monitor. Must not be <code>null</code>. - */ - public void initializeFrom(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor); - - /** - * Validate execution conditions. - * <p> - * This method is called from - * {@link #execute(IAdaptable, IPropertiesContainer, IFullQualifiedId, IProgressMonitor, ICallback)} - * after the step initialization. If any execution condition is not fulfilled, the method should - * throw an {@link CoreException} to signal the failure. - * - * @param context The context. Must not be <code>null</code>. - * @param data The data. Must not be <code>null</code>. - * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>. - * @param monitor The progress monitor. Must not be <code>null</code>. - * - * @throws CoreException if the execution cannot be continue. The associated status should - * describe the failure cause. - */ - public void validateExecute(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws CoreException; - - /** - * Cleanup intermediate data of the step. - * <p> - * This method will be called at the end of each step execution. - * - * @param context The context. Must not be <code>null</code>. - * @param data The data. Must not be <code>null</code>. - * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>. - * @param monitor The progress monitor. Must not be <code>null</code>. - */ - public void cleanup(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor); - - /** - * Called from the stepper engine once an error occurred during the stepping. Gives each step, - * completed previously to the error, the possibility to rollback whatever the step did. - * <p> - * <b>Note:</b> It is not guaranteed that the shared step data hasn't been overwritten in the - * meanwhile by multiple invocation of the same step. If a step supports multiple invocations, - * the implementer of the step is required to identify all the step data to rollback by himself. - * - * @param context The context. Must not be <code>null</code>. - * @param data The data. Must not be <code>null</code>. - * @param status The status of the last step executed and that caused the rollback. - * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>. - * @param monitor The progress monitor. Must not be <code>null</code>. - * @param callback The callback to invoke if finished. Must not be <code>null</code>. - */ - public void rollback(IStepContext context, IPropertiesContainer data, IStatus status, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback); -} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStep.java index 1f91fe001..872268c2d 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStep.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStep.java @@ -1,80 +1,161 @@ -/******************************************************************************* - * Copyright (c) 2011, 2012 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.interfaces; - -import java.util.Map; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; -import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; - -/** - * A single step. - * <p> - * Steps are assumed to be asynchronous. If the step execution finished, the passed in <b>callback - * must be invoked</b>. The parent stepper suspend the step sequence execution till the callback is - * invoked. - * <p> - * Steps signals the execution state to the parent stepper via the <code>IStatus</code> object - * passed to the callback as first argument. The status object is mandatory and cannot be - * <code>null</code>. If the step execution succeeds, an status with severity {@link IStatus#OK} is - * expected. - */ -public interface IStep extends IExecutableExtension { - - /** - * Additional data property for ICallback. - */ - public static final String CALLBACK_PROPERTY_DATA = "data"; //$NON-NLS-1$ - - /** - * Executes the context step logic. - * - * @param context The context. Must not be <code>null</code>. - * @param data The data giving object. Must not be <code>null</code>. - * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>. - * @param monitor The progress monitor. Must not be <code>null</code>. - * @param callback The callback to invoke if finished. Must not be <code>null</code>. - */ - public void execute(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback); - - /** - * Returns the number of total work the step is consuming. - * - * @return The number of total work or {@link IProgressMonitor#UNKNOWN}. - */ - public int getTotalWork(IStepContext context, IPropertiesContainer data); - - /** - * Returns the list of required context step or context step group id's. The execution of a - * context step fails if not all of the required steps are available or have not been executed - * before. - * <p> - * If the listed required steps have dependencies on their own, these dependencies are - * implicitly inherited. - * - * @return The list of required context step or context step group id's or an empty list. - */ - public String[] getDependencies(); - - /** - * Set additional parameters for this step - * @param parameters - */ - public void setParameters(Map<String,String> parameters); - - /** - * Returns a map of additional parameters given through the parameters section in the Reference section of a StepGroups. - * @return The parameters of an empty Map. - */ - public Map<String,String> getParameters(); -} +/*******************************************************************************
+ * Copyright (c) 2011, 2012 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.interfaces;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback;
+import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension;
+import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer;
+
+/**
+ * A single step.
+ * <p>
+ * Steps are assumed to be asynchronous. If the step execution finished, the passed in <b>callback
+ * must be invoked</b>. The parent stepper suspend the step sequence execution till the callback is
+ * invoked.
+ * <p>
+ * Steps signals the execution state to the parent stepper via the <code>IStatus</code> object
+ * passed to the callback as first argument. The status object is mandatory and cannot be
+ * <code>null</code>. If the step execution succeeds, an status with severity {@link IStatus#OK} is
+ * expected.
+ */
+public interface IStep extends IExecutableExtension {
+
+ /**
+ * Additional data property for ICallback.
+ */
+ public static final String CALLBACK_PROPERTY_DATA = "data"; //$NON-NLS-1$
+
+ /**
+ * Executes the context step logic.
+ *
+ * @param context The context. Must not be <code>null</code>.
+ * @param data The data giving object. Must not be <code>null</code>.
+ * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>.
+ * @param monitor The progress monitor. Must not be <code>null</code>.
+ * @param callback The callback to invoke if finished. Must not be <code>null</code>.
+ */
+ public void execute(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback);
+
+ /**
+ * Returns if or if not this step can have multiple references within step groups. If
+ * <code>true</code> is returned, the step can occur exactly once per step group. This method
+ * effects all defined step groups and overwrite individual step settings.
+ * <p>
+ * The default implementation returns <code>false</code>.
+ *
+ * @return <code>True</code> if the step can be referenced only ones per step group,
+ * <code>false</code> otherwise.
+ */
+ public boolean isSingleton();
+
+ /**
+ * Initialize the step from the given data.
+ *
+ * @param context The context. Must not be <code>null</code>.
+ * @param data The data. Must not be <code>null</code>.
+ * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>.
+ * @param monitor The progress monitor. Must not be <code>null</code>.
+ */
+ public void initializeFrom(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor);
+
+ /**
+ * Validate execution conditions.
+ * <p>
+ * This method is called from
+ * {@link #execute(IAdaptable, IPropertiesContainer, IFullQualifiedId, IProgressMonitor, ICallback)}
+ * after the step initialization. If any execution condition is not fulfilled, the method should
+ * throw an {@link CoreException} to signal the failure.
+ *
+ * @param context The context. Must not be <code>null</code>.
+ * @param data The data. Must not be <code>null</code>.
+ * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>.
+ * @param monitor The progress monitor. Must not be <code>null</code>.
+ *
+ * @throws CoreException if the execution cannot be continue. The associated status should
+ * describe the failure cause.
+ */
+ public void validateExecute(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Cleanup intermediate data of the step.
+ * <p>
+ * This method will be called at the end of each step execution.
+ *
+ * @param context The context. Must not be <code>null</code>.
+ * @param data The data. Must not be <code>null</code>.
+ * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>.
+ * @param monitor The progress monitor. Must not be <code>null</code>.
+ */
+ public void cleanup(IStepContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor);
+
+ /**
+ * Called from the stepper engine once an error occurred during the stepping. Gives each step,
+ * completed previously to the error, the possibility to rollback whatever the step did.
+ * <p>
+ * <b>Note:</b> It is not guaranteed that the shared step data hasn't been overwritten in the
+ * meanwhile by multiple invocation of the same step. If a step supports multiple invocations,
+ * the implementer of the step is required to identify all the step data to rollback by himself.
+ * <p>
+ * IProgressMonitor.worked(int) should not be used for the given progress monitor. Setting sub task labels is ok.
+ *
+ * @param context The context. Must not be <code>null</code>.
+ * @param data The data. Must not be <code>null</code>.
+ * @param status The status of the last step executed and that caused the rollback.
+ * @param fullQualifiedId The full qualified id for this step. Must not be <code>null</code>.
+ * @param monitor The progress monitor. Must not be <code>null</code>.
+ * @param callback The callback to invoke if finished. Must not be <code>null</code>.
+ */
+ public void rollback(IStepContext context, IPropertiesContainer data, IStatus status, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback);
+
+ /**
+ * Get the timeout in milliseconds to wait for finish
+ * when the progress monitor was canceled.
+ * If a step should not have a timeout and handles the cancel itself return -1.
+ * @return Timeout in milliseconds.
+ */
+ public int getCancelTimeout();
+
+ /**
+ * Returns the number of total work the step is consuming.
+ *
+ * @return The number of total work or {@link IProgressMonitor#UNKNOWN}.
+ */
+ public int getTotalWork(IStepContext context, IPropertiesContainer data);
+
+ /**
+ * Returns the list of required context step or context step group id's. The execution of a
+ * context step fails if not all of the required steps are available or have not been executed
+ * before.
+ * <p>
+ * If the listed required steps have dependencies on their own, these dependencies are
+ * implicitly inherited.
+ *
+ * @return The list of required context step or context step group id's or an empty list.
+ */
+ public String[] getDependencies();
+
+ /**
+ * Set additional parameters for this step
+ * @param parameters
+ */
+ public void setParameters(Map<String,String> parameters);
+
+ /**
+ * Returns a map of additional parameters given through the parameters section in the Reference section of a StepGroups.
+ * @return The parameters of an empty Map.
+ */
+ public Map<String,String> getParameters();
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.java index b80750d0f..3a78f8ae7 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.java @@ -64,4 +64,6 @@ public class Messages extends NLS { public static String StepExecutor_warning_stepFailed;
public static String StepExecutor_error_stepFailed;
public static String StepExecutor_stepFailed_debugInfo;
+ public static String StepExecutor_warning_rollbackTimeout;
+
}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.properties index b8040ba9b..3c4f7ff66 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.properties @@ -49,3 +49,4 @@ StepExecutor_error_stepFailed=Step finished with this error: {0}\n\n\ Context: {1}\n\{2}\n\
Step: {3}
StepExecutor_stepFailed_debugInfo=Debug info:\n{0}
+StepExecutor_warning_rollbackTimeout=Step rollback was aborted due to timeout.
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/stepper/Stepper.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/stepper/Stepper.java index e8a91e33a..57d307918 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/stepper/Stepper.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/stepper/Stepper.java @@ -1,759 +1,738 @@ -/******************************************************************************* - * Copyright (c) 2011, 2012 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.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.IExtendedStep; -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.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; - -/** - * An abstract 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(); - } - - /* (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; - - // 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 - if (getMonitor() != null) { - getMonitor().done(); - } - - // 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>(); - - // 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 - getMonitor().beginTask(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() && getMonitor().isCanceled()) { - rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); - throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); - } - - CoreBundleActivator - .getTraceHandler() - .trace("Stepper#executeStepGroup: step group: '" + stepGroup.getLabel() + "'", //$NON-NLS-1$ //$NON-NLS-2$ - 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() && 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("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); - } - 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()); - } - 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 and the step must be of type {@link IExtendedStep} 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 IExtendedStep) { - IExtendedStep step = (IExtendedStep) executedStep.step; - step.rollback(getContext(), 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 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()) { - 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.Stepper_multiStatus_finishedWithErrors, getLabel()), null); - for (IStatus stat : statusContainer) { - multiStatus.merge(stat); - } - // Re-throw via a new CoreException - coreException = new CoreException(multiStatus); - } - } - - return coreException; - } -} +/*******************************************************************************
+ * Copyright (c) 2011, 2012 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.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.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.StatusHelper;
+
+/**
+ * An abstract 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();
+ }
+
+ /* (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;
+
+ // 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
+ if (getMonitor() != null) {
+ getMonitor().done();
+ }
+
+ // 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>();
+
+ // 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
+ getMonitor().beginTask(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() && getMonitor().isCanceled()) {
+ rollback(executedSteps, Status.CANCEL_STATUS, getMonitor());
+ throw new CoreException(StatusHelper.getStatus(new OperationCanceledException()));
+ }
+
+ CoreBundleActivator
+ .getTraceHandler()
+ .trace("Stepper#executeStepGroup: step group: '" + stepGroup.getLabel() + "'", //$NON-NLS-1$ //$NON-NLS-2$
+ 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() && 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("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);
+ }
+ 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());
+ }
+ 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()) {
+ 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.Stepper_multiStatus_finishedWithErrors, getLabel()), null);
+ for (IStatus stat : statusContainer) {
+ multiStatus.merge(stat);
+ }
+ // Re-throw via a new CoreException
+ coreException = new CoreException(multiStatus);
+ }
+ }
+
+ return coreException;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/steps/AbstractStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/steps/AbstractStep.java index d1b7316a4..371505a75 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/steps/AbstractStep.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/steps/AbstractStep.java @@ -27,7 +27,6 @@ import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer;
import org.eclipse.tcf.te.runtime.stepper.StepperAttributeUtil;
import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator;
-import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedStep;
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;
@@ -37,7 +36,7 @@ import org.eclipse.tcf.te.runtime.stepper.nls.Messages; /**
* An abstract step implementation.
*/
-public abstract class AbstractStep extends ExecutableExtension implements IExtendedStep {
+public abstract class AbstractStep extends ExecutableExtension implements IStep {
// List of string id's of the step dependencies.
private final List<String> dependencies = new ArrayList<String>();
@@ -178,4 +177,13 @@ public abstract class AbstractStep extends ExecutableExtension implements IExten return activeContext;
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedStep#getCancelTimeout()
+ */
+ @Override
+ public int getCancelTimeout() {
+ // default timeout is 1 minute
+ return 60000;
+ }
}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/callback/Callback.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/callback/Callback.java index edeb6fd49..be9ed0348 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/callback/Callback.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/callback/Callback.java @@ -1,320 +1,360 @@ -/******************************************************************************* - * Copyright (c) 2011, 2012 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.callback; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Status; -import org.eclipse.tcf.te.runtime.activator.CoreBundleActivator; -import org.eclipse.tcf.te.runtime.interfaces.IConditionTester; -import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tcf.te.runtime.properties.PropertiesContainer; -import org.eclipse.tcf.te.runtime.utils.ProgressHelper; - -/** - * Default implementation of the <code>ICallback</code> interface. - */ -public class Callback extends PropertiesContainer implements ICallback { - - protected static final String PROPERTY_PARENT_CALLBACK = "parentCallback"; //$NON-NLS-1$ - protected static final String PROPERTY_PROGRESS_MONITOR = "progressMonitor"; //$NON-NLS-1$ - protected static final String PROPERTY_PROGRESS_TICKS = "progressTicks"; //$NON-NLS-1$ - protected static final String PROPERTY_IS_DONE = "isDone"; //$NON-NLS-1$ - protected static final String PROPERTY_STATUS = "status"; //$NON-NLS-1$ - - /** - * Property: Asynchronous operations can store a result to the callback - * object they invoke once the operation has been finished. - */ - protected static final String PROPERTY_RESULT = "result"; //$NON-NLS-1$ - - - private static final String[] PROPERTY_KEYS_NOT_TO_COPY = { - PROPERTY_PARENT_CALLBACK, PROPERTY_PROGRESS_MONITOR, - PROPERTY_PROGRESS_TICKS, PROPERTY_IS_DONE, PROPERTY_STATUS - }; - private static final List<String> PROPERTY_KEYS_NOT_TO_COPY_LIST = Arrays.asList(PROPERTY_KEYS_NOT_TO_COPY); - - /** - * Condition tester for ExecutorsUtil to check whether the callback is done - * or the {@link IProgressMonitor} is canceled. - */ - private class CallbackDoneConditionTester implements IConditionTester { - final ICallback callback; - final IProgressMonitor monitor; - - /** - * Constructor. - * - * @param callback - * The callback to check. Must not be <code>null</code>. - * @param monitor - * The progress monitor to check. - */ - public CallbackDoneConditionTester(ICallback callback, IProgressMonitor monitor) { - Assert.isNotNull(callback); - this.callback = callback; - this.monitor = monitor; - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#isConditionFulfilled() - */ - @Override - public boolean isConditionFulfilled() { - if (monitor == null) { - return callback.isDone(); - } - return monitor.isCanceled() || callback.isDone(); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#cleanup() - */ - @Override - public void cleanup() { - } - } - - /** - * Constructor. - */ - public Callback() { - this(null); - } - - /** - * Constructor to wrap a parent callback. - * - * @param parentCallback - * The parent callback. - */ - public Callback(ICallback parentCallback) { - this(null, -1, parentCallback); - } - - /** - * Constructor to handle a progress monitor. - * - * @param monitor - * The progress monitor. - * @param ticksToUse - * The ticks to add when done. - */ - public Callback(IProgressMonitor monitor, int ticksToUse) { - this(monitor, ticksToUse, null); - } - - /** - * Constructor to handle a progress monitor and wrap a parent callback. - * - * @param monitor - * The progress monitor. - * @param ticksToUse - * The ticks to add when done. - * @param parentCallback - * The parent callback. - */ - public Callback(IProgressMonitor monitor, int ticksToUse, ICallback parentCallback) { - super(); - setProperty(PROPERTY_PARENT_CALLBACK, parentCallback); - setProperty(PROPERTY_PROGRESS_MONITOR, monitor); - setProperty(PROPERTY_PROGRESS_TICKS, ticksToUse); - } - - /** - * Get a condition tester for this callback. - * - * @param monitor - * The progress monitor or <code>null</code>. - * @return The condition tester. - */ - public final IConditionTester getDoneConditionTester(IProgressMonitor monitor) { - return new CallbackDoneConditionTester(this, monitor); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#done(java.lang.Object, org.eclipse.core.runtime.IStatus) - */ - @Override - public final void done(Object caller, IStatus status) { - Assert.isNotNull(status); - - if (isDone()) { - CoreBundleActivator.getTraceHandler().trace("WARNING: callback called twice!!", 1, this); //$NON-NLS-1$ - return; - } - - setProperty(PROPERTY_IS_DONE, null); - setProperty(PROPERTY_STATUS, checkStatusIntegrity(status)); - - internalDone(caller, status); - - if (getProperty(PROPERTY_IS_DONE) == null) { - setProperty(PROPERTY_IS_DONE, true); - } - - if (isDone()) { - if (getProperty(PROPERTY_PROGRESS_MONITOR) instanceof IProgressMonitor) { - IProgressMonitor progress = ((IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR)); - if (!progress.isCanceled() && getStatus().getSeverity() != IStatus.CANCEL) { - int ticks = getIntProperty(PROPERTY_PROGRESS_TICKS); - if (ticks > 0) { - progress.worked(ticks); - } else if (ticks == ProgressHelper.PROGRESS_DONE) { - progress.done(); - } - } - } - - ICallback parentCallback = (ICallback) getProperty(PROPERTY_PARENT_CALLBACK); - if (parentCallback != null) { - if (parentCallback.isDone()) { - CoreBundleActivator.getTraceHandler().trace("WARNING: parent callback called twice!!", 1, this); //$NON-NLS-1$ - } - else { - copyProperties(this, parentCallback); - if (!ProgressHelper.isCancelOrError(this, - getStatus(), - (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR), - parentCallback)) { - parentCallback.done(caller, getStatus()); - } - } - } - } - } - - /** - * Copy the properties from the given source callback to the given - * destination callback. - * - * @param source - * The source callback. Must not be <code>null</code>. - * @param destination - * The destination callback. Must not be <code>null</code> and - * not yet done. - */ - public static final void copyProperties(ICallback source, ICallback destination) { - Assert.isNotNull(source); - Assert.isNotNull(destination); - Assert.isTrue(!destination.isDone()); - - for (String key : source.getProperties().keySet()) { - if (!PROPERTY_KEYS_NOT_TO_COPY_LIST.contains(key)) { - destination.setProperty(key, source.getProperty(key)); - } - } - Assert.isTrue(!destination.isDone()); - } - - /** - * Checks the status integrity. - * - * @param status - * The status or <code>null</code>. - * @return The checked status. - */ - private IStatus checkStatusIntegrity(IStatus status) { - if (status == null) status = Status.OK_STATUS; - - if (status.getSeverity() == IStatus.CANCEL && status.getException() == null) { - status = new Status(IStatus.CANCEL, status.getPlugin(), - status.getMessage(), new OperationCanceledException(status.getMessage())); - } - - if (status.getSeverity() == IStatus.WARNING && status.getException() == null) { - status = new Status(IStatus.WARNING, status.getPlugin(), - status.getMessage(), new Exception(status.getMessage())); - } - - if (status.getSeverity() == IStatus.ERROR && status.getException() == null) { - status = new Status(IStatus.ERROR, status.getPlugin(), - status.getMessage(), new Exception(status.getMessage())); - } - - return status; - } - - /** - * Return the progress monitor or <code>null</code>. - */ - protected final IProgressMonitor getProgressMonitor() { - return (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR); - } - - /** - * Internal callback done. - * - * @param caller - * The caller. - * @param status - * The status. - */ - protected void internalDone(Object caller, IStatus status) { - } - - /** - * Return the result on done. - */ - public final IStatus getStatus() { - IStatus status = (IStatus) getProperty(PROPERTY_STATUS); - if (status == null && getProperty(PROPERTY_PROGRESS_MONITOR) instanceof IProgressMonitor) { - IProgressMonitor monitor = (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR); - if (monitor.isCanceled()) { - return checkStatusIntegrity(Status.CANCEL_STATUS); - } - } - - return checkStatusIntegrity(status); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#isDone() - */ - @Override - public final boolean isDone() { - return getBooleanProperty(PROPERTY_IS_DONE); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#addParentCallback(org.eclipse.tcf.te.runtime.interfaces.callback.ICallback) - */ - @Override - public void addParentCallback(ICallback callback) { - if (getProperty(PROPERTY_PARENT_CALLBACK) instanceof ICallback) { - ICallback parentCallback = (ICallback) getProperty(PROPERTY_PARENT_CALLBACK); - parentCallback.addParentCallback(callback); - } else { - setProperty(PROPERTY_PARENT_CALLBACK, callback); - } - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#setResult(java.lang.Object) - */ - @Override - public void setResult(Object result) { - setProperty(PROPERTY_RESULT, result); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#getResult() - */ - @Override - public Object getResult() { - return getProperty(PROPERTY_RESULT); - } -} +/*******************************************************************************
+ * Copyright (c) 2011, 2012 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.callback;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.tcf.te.runtime.activator.CoreBundleActivator;
+import org.eclipse.tcf.te.runtime.interfaces.IConditionTester;
+import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback;
+import org.eclipse.tcf.te.runtime.nls.Messages;
+import org.eclipse.tcf.te.runtime.properties.PropertiesContainer;
+import org.eclipse.tcf.te.runtime.utils.ProgressHelper;
+import org.eclipse.tcf.te.runtime.utils.StatusHelper;
+
+/**
+ * Default implementation of the <code>ICallback</code> interface.
+ */
+public class Callback extends PropertiesContainer implements ICallback {
+
+ protected static final String PROPERTY_PARENT_CALLBACK = "parentCallback"; //$NON-NLS-1$
+ protected static final String PROPERTY_PROGRESS_MONITOR = "progressMonitor"; //$NON-NLS-1$
+ protected static final String PROPERTY_PROGRESS_TICKS = "progressTicks"; //$NON-NLS-1$
+ protected static final String PROPERTY_IS_DONE = "isDone"; //$NON-NLS-1$
+ protected static final String PROPERTY_STATUS = "status"; //$NON-NLS-1$
+
+ /**
+ * Property: Asynchronous operations can store a result to the callback
+ * object they invoke once the operation has been finished.
+ */
+ protected static final String PROPERTY_RESULT = "result"; //$NON-NLS-1$
+
+
+ private static final String[] PROPERTY_KEYS_NOT_TO_COPY = {
+ PROPERTY_PARENT_CALLBACK, PROPERTY_PROGRESS_MONITOR,
+ PROPERTY_PROGRESS_TICKS, PROPERTY_IS_DONE, PROPERTY_STATUS
+ };
+ private static final List<String> PROPERTY_KEYS_NOT_TO_COPY_LIST = Arrays.asList(PROPERTY_KEYS_NOT_TO_COPY);
+
+ /**
+ * Condition tester for ExecutorsUtil to check whether the callback is done
+ * or the {@link IProgressMonitor} is canceled.
+ */
+ private class CallbackDoneConditionTester implements IConditionTester {
+ final ICallback callback;
+ final IProgressMonitor monitor;
+ int cancelTimeout = -1;
+ long cancelTime = -1;
+
+ /**
+ * Constructor.
+ *
+ * @param callback The callback to check. Must not be <code>null</code>.
+ * @param monitor The progress monitor to check or <code>null</code>.
+ */
+ public CallbackDoneConditionTester(ICallback callback, IProgressMonitor monitor) {
+ this(callback, monitor, -1);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param callback The callback to check. Must not be <code>null</code>.
+ * @param monitor The progress monitor to check or <code>null</code>.
+ * @param cancelTimeout Timeout in milliseconds to wait for callback.isDone() when progress monitor was canceled.
+ */
+ public CallbackDoneConditionTester(ICallback callback, IProgressMonitor monitor, int cancelTimeout) {
+ Assert.isNotNull(callback);
+ this.callback = callback;
+ this.monitor = monitor;
+ this.cancelTimeout = cancelTimeout;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#isConditionFulfilled()
+ */
+ @Override
+ public boolean isConditionFulfilled() {
+ if (monitor == null)
+ return callback.isDone();
+
+ // handle cancel timeout
+ if (cancelTimeout > 0 && !callback.isDone() && monitor.isCanceled()) {
+ if (cancelTime == -1) {
+ cancelTime = System.currentTimeMillis();
+ monitor.subTask("Cancelling..."); //$NON-NLS-1$
+ }
+ else {
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - cancelTime) >= cancelTimeout) {
+ callback.done(this, StatusHelper.getStatus(new OperationCanceledException(Messages.Callback_warning_cancelTimeout)));
+ return true;
+ }
+ }
+ }
+
+ return callback.isDone();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#cleanup()
+ */
+ @Override
+ public void cleanup() {
+ }
+ }
+
+ /**
+ * Constructor.
+ */
+ public Callback() {
+ this(null);
+ }
+
+ /**
+ * Constructor to wrap a parent callback.
+ *
+ * @param parentCallback
+ * The parent callback.
+ */
+ public Callback(ICallback parentCallback) {
+ this(null, -1, parentCallback);
+ }
+
+ /**
+ * Constructor to handle a progress monitor.
+ *
+ * @param monitor
+ * The progress monitor.
+ * @param ticksToUse
+ * The ticks to add when done.
+ */
+ public Callback(IProgressMonitor monitor, int ticksToUse) {
+ this(monitor, ticksToUse, null);
+ }
+
+ /**
+ * Constructor to handle a progress monitor and wrap a parent callback.
+ *
+ * @param monitor
+ * The progress monitor.
+ * @param ticksToUse
+ * The ticks to add when done.
+ * @param parentCallback
+ * The parent callback.
+ */
+ public Callback(IProgressMonitor monitor, int ticksToUse, ICallback parentCallback) {
+ super();
+ setProperty(PROPERTY_PARENT_CALLBACK, parentCallback);
+ setProperty(PROPERTY_PROGRESS_MONITOR, monitor);
+ setProperty(PROPERTY_PROGRESS_TICKS, ticksToUse);
+ }
+
+ /**
+ * Get a condition tester for this callback.
+ *
+ * @param monitor The progress monitor to check or <code>null</code>.
+ * @return The condition tester.
+ */
+ public final IConditionTester getDoneConditionTester(IProgressMonitor monitor) {
+ return new CallbackDoneConditionTester(this, monitor);
+ }
+
+ /**
+ * Get a condition tester for this callback.
+ *
+ * @param monitor The progress monitor to check or <code>null</code>.
+ * @param cancelTimeout Timeout in milliseconds to wait for callback.isDone() when progress monitor was canceled.
+ * @return The condition tester.
+ */
+ public final IConditionTester getDoneConditionTester(IProgressMonitor monitor, int cancelTimeout) {
+ return new CallbackDoneConditionTester(this, monitor, cancelTimeout);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#done(java.lang.Object, org.eclipse.core.runtime.IStatus)
+ */
+ @Override
+ public final void done(Object caller, IStatus status) {
+ Assert.isNotNull(status);
+
+ if (isDone()) {
+ if (getStatus() != null && getStatus().getSeverity() != IStatus.CANCEL)
+ CoreBundleActivator.getTraceHandler().trace("WARNING: callback called twice!!", 1, this); //$NON-NLS-1$
+ return;
+ }
+
+ setProperty(PROPERTY_IS_DONE, null);
+ setProperty(PROPERTY_STATUS, checkStatusIntegrity(status));
+
+ internalDone(caller, status);
+
+ if (getProperty(PROPERTY_IS_DONE) == null) {
+ setProperty(PROPERTY_IS_DONE, true);
+ }
+
+ if (isDone()) {
+ if (getProperty(PROPERTY_PROGRESS_MONITOR) instanceof IProgressMonitor) {
+ IProgressMonitor progress = ((IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR));
+ if (!progress.isCanceled() && getStatus().getSeverity() != IStatus.CANCEL) {
+ int ticks = getIntProperty(PROPERTY_PROGRESS_TICKS);
+ if (ticks > 0) {
+ progress.worked(ticks);
+ } else if (ticks == ProgressHelper.PROGRESS_DONE) {
+ progress.done();
+ }
+ }
+ }
+
+ ICallback parentCallback = (ICallback) getProperty(PROPERTY_PARENT_CALLBACK);
+ if (parentCallback != null) {
+ if (parentCallback.isDone()) {
+ CoreBundleActivator.getTraceHandler().trace("WARNING: parent callback called twice!!", 1, this); //$NON-NLS-1$
+ }
+ else {
+ copyProperties(this, parentCallback);
+ if (!ProgressHelper.isCancelOrError(this,
+ getStatus(),
+ (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR),
+ parentCallback)) {
+ parentCallback.done(caller, getStatus());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Copy the properties from the given source callback to the given
+ * destination callback.
+ *
+ * @param source
+ * The source callback. Must not be <code>null</code>.
+ * @param destination
+ * The destination callback. Must not be <code>null</code> and
+ * not yet done.
+ */
+ public static final void copyProperties(ICallback source, ICallback destination) {
+ Assert.isNotNull(source);
+ Assert.isNotNull(destination);
+ Assert.isTrue(!destination.isDone());
+
+ for (String key : source.getProperties().keySet()) {
+ if (!PROPERTY_KEYS_NOT_TO_COPY_LIST.contains(key)) {
+ destination.setProperty(key, source.getProperty(key));
+ }
+ }
+ Assert.isTrue(!destination.isDone());
+ }
+
+ /**
+ * Checks the status integrity.
+ *
+ * @param status
+ * The status or <code>null</code>.
+ * @return The checked status.
+ */
+ private IStatus checkStatusIntegrity(IStatus status) {
+ if (status == null) status = Status.OK_STATUS;
+
+ if (status.getSeverity() == IStatus.CANCEL && status.getException() == null) {
+ status = new Status(IStatus.CANCEL, status.getPlugin(),
+ status.getMessage(), new OperationCanceledException(status.getMessage()));
+ }
+
+ if (status.getSeverity() == IStatus.WARNING && status.getException() == null) {
+ status = new Status(IStatus.WARNING, status.getPlugin(),
+ status.getMessage(), new Exception(status.getMessage()));
+ }
+
+ if (status.getSeverity() == IStatus.ERROR && status.getException() == null) {
+ status = new Status(IStatus.ERROR, status.getPlugin(),
+ status.getMessage(), new Exception(status.getMessage()));
+ }
+
+ return status;
+ }
+
+ /**
+ * Return the progress monitor or <code>null</code>.
+ */
+ protected final IProgressMonitor getProgressMonitor() {
+ return (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR);
+ }
+
+ /**
+ * Internal callback done.
+ *
+ * @param caller
+ * The caller.
+ * @param status
+ * The status.
+ */
+ protected void internalDone(Object caller, IStatus status) {
+ }
+
+ /**
+ * Return the result on done.
+ */
+ public final IStatus getStatus() {
+ IStatus status = (IStatus) getProperty(PROPERTY_STATUS);
+ if (status == null && getProperty(PROPERTY_PROGRESS_MONITOR) instanceof IProgressMonitor) {
+ IProgressMonitor monitor = (IProgressMonitor) getProperty(PROPERTY_PROGRESS_MONITOR);
+ if (monitor.isCanceled()) {
+ return checkStatusIntegrity(Status.CANCEL_STATUS);
+ }
+ }
+
+ return checkStatusIntegrity(status);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#isDone()
+ */
+ @Override
+ public final boolean isDone() {
+ return getBooleanProperty(PROPERTY_IS_DONE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#addParentCallback(org.eclipse.tcf.te.runtime.interfaces.callback.ICallback)
+ */
+ @Override
+ public void addParentCallback(ICallback callback) {
+ if (getProperty(PROPERTY_PARENT_CALLBACK) instanceof ICallback) {
+ ICallback parentCallback = (ICallback) getProperty(PROPERTY_PARENT_CALLBACK);
+ parentCallback.addParentCallback(callback);
+ } else {
+ setProperty(PROPERTY_PARENT_CALLBACK, callback);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#setResult(java.lang.Object)
+ */
+ @Override
+ public void setResult(Object result) {
+ setProperty(PROPERTY_RESULT, result);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.interfaces.callback.ICallback#getResult()
+ */
+ @Override
+ public Object getResult() {
+ return getProperty(PROPERTY_RESULT);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.java index bd95b364f..92e82cfd7 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.java @@ -1,35 +1,37 @@ -/******************************************************************************* - * 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.tcf.te.runtime.nls; - -import org.eclipse.osgi.util.NLS; - -/** - * Target Explorer Runtime plugin externalized strings management. - */ -public class Messages extends NLS { - - // The plug-in resource bundle name - private static final String BUNDLE_NAME = "org.eclipse.tcf.te.runtime.nls.Messages"; //$NON-NLS-1$ - - /** - * Static constructor. - */ - static { - // Load message values from bundle file - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - // **** Declare externalized string id's down here ***** - - public static String Extension_error_missingRequiredAttribute; - public static String Extension_error_duplicateExtension; - public static String Extension_error_invalidExtensionPoint; -} +/*******************************************************************************
+ * 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.tcf.te.runtime.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Target Explorer Runtime plugin externalized strings management.
+ */
+public class Messages extends NLS {
+
+ // The plug-in resource bundle name
+ private static final String BUNDLE_NAME = "org.eclipse.tcf.te.runtime.nls.Messages"; //$NON-NLS-1$
+
+ /**
+ * Static constructor.
+ */
+ static {
+ // Load message values from bundle file
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ // **** Declare externalized string id's down here *****
+
+ public static String Extension_error_missingRequiredAttribute;
+ public static String Extension_error_duplicateExtension;
+ public static String Extension_error_invalidExtensionPoint;
+
+ public static String Callback_warning_cancelTimeout;
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.properties index 31e029738..30dd6118f 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime/src/org/eclipse/tcf/te/runtime/nls/Messages.properties @@ -1,13 +1,15 @@ -############################################################################### -# Copyright (c) 2012 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 -############################################################################### - -Extension_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"! -Extension_error_duplicateExtension=Duplicate extension with id ''{0}''. Ignoring duplicated contribution from contributor ''{1}''! -Extension_error_invalidExtensionPoint=Failed to instantiate the executable extension from extension point ''{0}''. +###############################################################################
+# Copyright (c) 2012 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
+###############################################################################
+
+Extension_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"!
+Extension_error_duplicateExtension=Duplicate extension with id ''{0}''. Ignoring duplicated contribution from contributor ''{1}''!
+Extension_error_invalidExtensionPoint=Failed to instantiate the executable extension from extension point ''{0}''.
+
+Callback_warning_cancelTimeout=Step cancellation was aborted due to timeout.
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/steps/OpenChannelStep.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/steps/OpenChannelStep.java index 5d902c2cc..bfa638548 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/steps/OpenChannelStep.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/steps/OpenChannelStep.java @@ -18,6 +18,7 @@ import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; import org.eclipse.tcf.te.runtime.stepper.StepperAttributeUtil;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext;
+import org.eclipse.tcf.te.runtime.utils.ProgressHelper;
import org.eclipse.tcf.te.runtime.utils.StatusHelper;
import org.eclipse.tcf.te.tcf.core.Tcf;
import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager;
@@ -62,6 +63,7 @@ public class OpenChannelStep extends AbstractPeerStep { public void rollback(IStepContext context, IPropertiesContainer data, IStatus status, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback) {
IChannel channel = (IChannel)StepperAttributeUtil.getProperty(ITcfStepAttributes.ATTR_CHANNEL, fullQualifiedId, data);
if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ ProgressHelper.setSubTaskName(monitor, "Closing TCF channel"); //$NON-NLS-1$
Tcf.getChannelManager().closeChannel(channel);
}
super.rollback(context, data, status, fullQualifiedId, monitor, callback);
|