diff options
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te')
28 files changed, 3999 insertions, 0 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/FullQualifiedId.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/FullQualifiedId.java new file mode 100644 index 000000000..fb7fb052c --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/FullQualifiedId.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * 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.stepper; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; + +/** + * Full qualified id implementation. + */ +public class FullQualifiedId implements IFullQualifiedId { + // The list of id's + private final List<IdData> ids = new ArrayList<IdData>(); + + // Inner class describing the data of an id. + private class IdData { + public String type = null; + public String id = null; + public String secondaryId = null; + + /** + * Constructor. + * + * @param type The id type. + * @param id The id. Must not be <code>null</code>. + * @param secondaryId The secondary id. + */ + public IdData(String type, String id, String secondaryId) { + Assert.isNotNull(id); + + this.type = type; + this.id = id; + this.secondaryId = secondaryId; + } + + /** + * Creates a string representation of the id and the given children. + */ + public String toString(String children) { + String typeStr = type != null && type.trim().length() > 0 ? type.trim() : "ID"; //$NON-NLS-1$ + + StringBuilder toString = new StringBuilder(); + toString.append('<'); + toString.append(typeStr); + toString.append(" id=\""); //$NON-NLS-1$ + toString.append(id.trim()); + toString.append('"'); + if (secondaryId != null && secondaryId.trim().length() > 0) { + toString.append(" secondaryId=\""); //$NON-NLS-1$ + toString.append(secondaryId.trim()); + toString.append('"'); + } + if (children != null && children.trim().length() > 0) { + toString.append('>'); + toString.append(children); + toString.append("</"); //$NON-NLS-1$ + toString.append(type); + toString.append('>'); + } + else { + toString.append("/>"); //$NON-NLS-1$ + } + return toString.toString(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return toString(null); + } + } + + /** + * Constructor. + */ + public FullQualifiedId(String type, String id, String secondaryId) { + ids.add(new IdData(type, id, secondaryId)); + } + + /* + * Private constructor for child and parent creation. + * To create the parent, id has to be null! + */ + private FullQualifiedId(IdData[] parentData, String type, String id, String secondaryId) { + for (IdData parent : parentData) { + ids.add(new IdData(parent.type, parent.id, parent.secondaryId)); + } + if (id != null) { + ids.add(new IdData(type, id, secondaryId)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId#createChildId(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public IFullQualifiedId createChildId(String type, String id, String secondaryId) { + return new FullQualifiedId(ids.toArray(new IdData[ids.size()]), type, id, secondaryId); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId#getType() + */ + @Override + public String getType() { + return getIdData().type; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId#getId() + */ + @Override + public String getId() { + return getIdData().id; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId#getSecondaryId() + */ + @Override + public String getSecondaryId() { + return getIdData().secondaryId; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId#getParentId() + */ + @Override + public IFullQualifiedId getParentId() { + if (ids.size() > 1) { + return new FullQualifiedId(ids.subList(0, ids.size() - 1) + .toArray(new IdData[ids.size() - 1]), null, null, null); + } + return null; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + Assert.isTrue(!ids.isEmpty()); + + String toString = getIdData().toString(); + if (ids.size() > 1) { + for (int i = ids.size() - 1; i > 0; i--) { + toString = ids.get(i - 1).toString(toString); + } + } + return toString; + } + + private IdData getIdData() { + Assert.isTrue(!ids.isEmpty()); + return ids.get(ids.size() - 1); + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperAttributeUtil.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperAttributeUtil.java new file mode 100644 index 000000000..85515ea93 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperAttributeUtil.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * 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.stepper; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * A stepper attributes utility provides a set of static methods + * to access the attributes of a step. + */ +public class StepperAttributeUtil { + /** + * Get the full qualified key to get or set data in the data. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return The full qualified key. + */ + protected final static String getFullQualifiedKey(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + return (fullQualifiedId != null ? fullQualifiedId.toString() : "") + key; //$NON-NLS-1$ + } + + /** + * Returns the properties container for the given data object. + * + * @param data The data object or <code>null</code>. + * @return The properties container or <code>null</code> if the container cannot be determined. + */ + private static IPropertiesContainer getPropertiesContainer(Object data) { + if (data instanceof IPropertiesContainer) { + return (IPropertiesContainer) data; + } + if (data instanceof IAdaptable) { + return (IPropertiesContainer)((IAdaptable)data).getAdapter(IPropertiesContainer.class); + } + return null; + } + + /** + * Get a property from the data. If the value is not stored within the full qualified id, the + * value stored within the parent id will be returned. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return The property value or <code>null</code> if either the data has no property container + * or the property is not set. + */ + public final static Object getProperty(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return null; + } + if (fullQualifiedId == null || container + .getProperty(getFullQualifiedKey(key, fullQualifiedId, data)) != null) { + return container.getProperty(getFullQualifiedKey(key, fullQualifiedId, data)); + } + return container.getProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data)); + } + + /** + * Get a string property from the data. If the value is not stored within the full qualified id, + * the value stored within the parent id will be returned. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return The string property value or <code>null</code> if either the data has no property + * container or the property is not set. + */ + public final static String getStringProperty(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return null; + } + if (fullQualifiedId == null || container.getProperty(getFullQualifiedKey(key, fullQualifiedId, data)) != null) { + return container.getStringProperty(getFullQualifiedKey(key, fullQualifiedId, data)); + } + return container.getStringProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data)); + } + + /** + * Get a boolean property from the data. If the value is not stored within the full qualified + * id, the value stored within the parent id will be returned. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return The boolean property value or <code>false</code> if either the data has no property + * container or the property is not set. + */ + public final static boolean getBooleanProperty(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return false; + } + if (fullQualifiedId == null || container.getProperty(getFullQualifiedKey(key, fullQualifiedId, data)) != null) { + return container.getBooleanProperty(getFullQualifiedKey(key, fullQualifiedId, data)); + } + return container.getBooleanProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data)); + } + + /** + * Get a int property from the data. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return The int property value or <code>-1</code> if either the data has no property + * container or the property is not set. + */ + public final static int getIntProperty(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return -1; + } + if (fullQualifiedId == null || container.getProperty(getFullQualifiedKey(key, fullQualifiedId, data)) != null) { + return container.getIntProperty(getFullQualifiedKey(key, fullQualifiedId, data)); + } + return container.getIntProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data)); + } + + /** + * Check if a property is set. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @return <code>true</code> if a property value is set. + */ + public final static boolean isPropertySet(String key, IFullQualifiedId fullQualifiedId, Object data) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return false; + } + return container.getProperty(getFullQualifiedKey(key, fullQualifiedId, data)) != null; + } + + /** + * Set a property value to the data. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new value. + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, Object value) { + return setProperty(key, fullQualifiedId, data, value, false); + } + + /** + * Set a property value to the data and optional share it through the parent full qualified id. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new value. + * @param share When <code>true</code>, the value is also stored within the parent full + * qualified id to share the value with other steps within the same parent (group). + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, Object value, boolean share) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return false; + } + if (share && fullQualifiedId != null) { + container.setProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data), value); + } + return container.setProperty(getFullQualifiedKey(key, fullQualifiedId, data), value); + } + + /** + * Set a boolean property value to the data. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new boolean value. + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, boolean value) { + return setProperty(key, fullQualifiedId, data, value, false); + } + + /** + * Set a boolean property value to the data and optional share it through the parent full + * qualified id. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new boolean value. + * @param share When <code>true</code>, the value is also stored within the parent full + * qualified id to share the value with other steps within the same parent (group). + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, boolean value, boolean share) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return false; + } + if (share && fullQualifiedId != null) { + container.setProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data), value); + } + return container.setProperty(getFullQualifiedKey(key, fullQualifiedId, data), value); + } + + /** + * Set a int property value to the data. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new int value. + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, int value) { + return setProperty(key, fullQualifiedId, data, value, false); + } + + /** + * Set an int property value to the data and optional share it through the parent full qualified + * id. + * + * @param key The key for the value. + * @param fullQualifiedId The full qualified id for this step. + * @param data The data. + * @param value The new int value. + * @param share When <code>true</code>, the value is also stored within the parent full + * qualified id to share the value with other steps within the same parent (group). + * @return <code>true</code> if the value was set. + */ + public final static boolean setProperty(String key, IFullQualifiedId fullQualifiedId, Object data, int value, boolean share) { + Assert.isNotNull(key); + Assert.isNotNull(data); + + IPropertiesContainer container = getPropertiesContainer(data); + if (container == null) { + return false; + } + if (share && fullQualifiedId != null) { + container.setProperty(getFullQualifiedKey(key, fullQualifiedId.getParentId(), data), value); + } + return container.setProperty(getFullQualifiedKey(key, fullQualifiedId, data), value); + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperManager.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperManager.java new file mode 100644 index 000000000..c84d3da7a --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/StepperManager.java @@ -0,0 +1,73 @@ +/*******************************************************************************
+ * 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.stepper;
+
+import org.eclipse.tcf.te.runtime.stepper.internal.extensions.StepExtensionPointManager;
+import org.eclipse.tcf.te.runtime.stepper.internal.extensions.StepGroupExtensionPointManager;
+import org.eclipse.tcf.te.runtime.stepper.internal.extensions.StepperExtensionPointManager;
+
+/**
+ * Central manager providing access to the stepper, steps and step groups
+ * contributed via extension points.
+ */
+public final class StepperManager {
+ // References to the extension point managers
+ private final StepExtensionPointManager stepExtManager = new StepExtensionPointManager();
+ private final StepperExtensionPointManager stepperExtManager = new StepperExtensionPointManager();
+ private final StepGroupExtensionPointManager stepGroupExtManager = new StepGroupExtensionPointManager();
+
+ /*
+ * Thread save singleton instance creation.
+ */
+ private static class LazyInstance {
+ public static StepperManager instance = new StepperManager();
+ }
+
+ /**
+ * Constructor.
+ */
+ StepperManager() {
+ super();
+ }
+
+ /**
+ * Returns the singleton instance of the manager.
+ */
+ public static StepperManager getInstance() {
+ return LazyInstance.instance;
+ }
+
+ /**
+ * Returns the step extension point manager instance.
+ *
+ * @return The step extension point manager instance.
+ */
+ public StepExtensionPointManager getStepExtManager() {
+ return stepExtManager;
+ }
+
+ /**
+ * Returns the stepper extension point manager instance.
+ *
+ * @return The stepper extension point manager instance.
+ */
+ public StepperExtensionPointManager getStepperExtManager() {
+ return stepperExtManager;
+ }
+
+ /**
+ * Returns the step group extension point manager instance.
+ *
+ * @return The step group extension point manager instance.
+ */
+ public StepGroupExtensionPointManager getStepGroupExtManager() {
+ return stepGroupExtManager;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/activator/CoreBundleActivator.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/activator/CoreBundleActivator.java new file mode 100644 index 000000000..6744469e0 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/activator/CoreBundleActivator.java @@ -0,0 +1,72 @@ +/*******************************************************************************
+ * 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.stepper.activator;
+
+import org.eclipse.tcf.te.runtime.tracing.TraceHandler;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class CoreBundleActivator implements BundleActivator {
+ // The bundle context
+ private static BundleContext context;
+ // The trace handler instance
+ private static TraceHandler traceHandler;
+
+ /**
+ * Returns the bundle context
+ *
+ * @return the bundle context
+ */
+ public static BundleContext getContext() {
+ return context;
+ }
+
+ /**
+ * Convenience method which returns the unique identifier of this plugin.
+ */
+ public static String getUniqueIdentifier() {
+ if (getContext() != null && getContext().getBundle() != null) {
+ return getContext().getBundle().getSymbolicName();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the bundles trace handler.
+ *
+ * @return The bundles trace handler.
+ */
+ public static TraceHandler getTraceHandler() {
+ if (traceHandler == null) {
+ traceHandler = new TraceHandler(getUniqueIdentifier());
+ }
+ return traceHandler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext bundleContext) throws Exception {
+ CoreBundleActivator.context = bundleContext;
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext bundleContext) throws Exception {
+ CoreBundleActivator.context = null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStep.java new file mode 100644 index 000000000..bee21a04e --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStep.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +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.IContext; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; +import org.eclipse.tcf.te.runtime.stepper.nls.Messages; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtension; +import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * An abstract step implementation. + */ +public abstract class AbstractContextStep extends ExecutableExtension implements IExtendedContextStep { + // List of string id's of the step dependencies. + private final List<String> dependencies = new ArrayList<String>(); + + /** + * The suffix to append to the full qualified step id to + * get the delayed status object. + */ + public final static String SUFFIX_DELAYED_STATUS = "delayedStatus"; //$NON-NLS-1$ + + /** + * The suffix to append to the full qualified step id to + * get the step target event listener. + */ + public final static String SUFFIX_EVENT_LISTENER = "eventListener"; //$NON-NLS-1$ + + /** + * The suffix to append to the full qualified step id to + * get the operational flag. + */ + public final static String SUFFIX_OPERATIONAL = "operational"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep#isSingleton() + */ + @Override + public boolean isSingleton() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.ExecutableExtension#doSetInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void doSetInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + super.doSetInitializationData(config, propertyName, data); + + // Read in the list of required step or step id's if specified. + dependencies.clear(); + IConfigurationElement[] requires = config.getChildren("requires"); //$NON-NLS-1$ + for (IConfigurationElement require : requires) { + String value = require.getAttribute("id"); //$NON-NLS-1$ + if (value == null || value.trim().length() == 0) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + 0, + NLS.bind(Messages.AbstractContextStep_error_missingRequiredAttribute, "dependency id (requires)", getLabel()), //$NON-NLS-1$ + null)); + } + if (!dependencies.contains(value.trim())) { + dependencies.add(value.trim()); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep#initializeFrom(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void initializeFrom(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) { + Assert.isNotNull(context); + Assert.isNotNull(data); + Assert.isNotNull(fullQualifiedId); + Assert.isNotNull(monitor); + + StepperAttributeUtil.setProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, data, false); + StepperAttributeUtil.setProperty(SUFFIX_OPERATIONAL, fullQualifiedId, data, true); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep#cleanup(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void cleanup(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) { + StepperAttributeUtil.setProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, data, false); + StepperAttributeUtil.setProperty(SUFFIX_OPERATIONAL, fullQualifiedId, data, false); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep#rollback(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.core.runtime.IStatus, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor, org.eclipse.tcf.te.runtime.interfaces.callback.ICallback) + */ + @Override + public void rollback(IContext context, IPropertiesContainer data, IStatus status, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor, ICallback callback) { + if (callback != null) callback.done(this, Status.OK_STATUS); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep#getTotalWork(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer) + */ + @Override + public int getTotalWork(IContext context, IPropertiesContainer data) { + return 10; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep#getDependencies() + */ + @Override + public String[] getDependencies() { + return dependencies.toArray(new String[dependencies.size()]); + } + + /** + * Invoke the specified callback and pass on the status and user defined data object. + * + * @param stepData + * @param fullQualifiedId + * @param callback + * @param status + * @param data + */ + public final void callback(IPropertiesContainer stepData, IFullQualifiedId fullQualifiedId, ICallback callback, IStatus status, Object data) { + Assert.isNotNull(stepData); + Assert.isNotNull(fullQualifiedId); + Assert.isNotNull(callback); + Assert.isNotNull(status); + + // Check if there have been states delayed + IStatus delayedStatus = (IStatus)StepperAttributeUtil.getProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, stepData); + if (status.getSeverity() != IStatus.ERROR && status.getSeverity() != IStatus.CANCEL && delayedStatus != null) { + if (status.getSeverity() == IStatus.OK) { + // replace the whole status with the delayed one + status = delayedStatus; + } else { + // Merge the passed in status and the delayed stati together + IStatus[] delayedStati = delayedStatus instanceof MultiStatus ? ((MultiStatus)delayedStatus).getChildren() : new IStatus[] { delayedStatus }; + if (delayedStati.length > 0) { + if (!(status instanceof MultiStatus)) { + status = new MultiStatus(CoreBundleActivator.getUniqueIdentifier(), 0, + NLS.bind(Messages.AbstractContextStep_warning_stepFinishedWithWarnings, getLabel()), + null); + + } + // At this point the status must be a MultiStatus + Assert.isTrue(status instanceof MultiStatus); + for (IStatus delayed : delayedStati) { + ((MultiStatus)status).merge(delayed); + } + } + + } + } + + // Finally invoke the callback + callback.setProperty(IContextStep.CALLBACK_PROPERTY_DATA, data); + callback.done(this, status); + } + + /** + * Delay the reporting of the given status till the associated launch callback is invoked. If + * delayed states are available and the callback is invoked not with an error status, the + * delayed states will be reported instead. + * + * @param status The status to delay. Must be not <code>null</code> and either a warning or info status. + */ + protected void delayStatus(IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IStatus status) { + Assert.isNotNull(status); + Assert.isTrue(status.getSeverity() == IStatus.WARNING || status.getSeverity() == IStatus.INFO); + + IStatus delayedStatus = (IStatus)StepperAttributeUtil.getProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, data); + if (delayedStatus == null) { + StepperAttributeUtil.setProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, data, status); + } else if (delayedStatus instanceof MultiStatus) { + ((MultiStatus)delayedStatus).merge(status); + } else { + MultiStatus multiStatus = new MultiStatus(CoreBundleActivator.getUniqueIdentifier(), 0, + new IStatus[] { delayedStatus, status }, + "", //$NON-NLS-1$ + null); + StepperAttributeUtil.setProperty(SUFFIX_DELAYED_STATUS, fullQualifiedId, data, multiStatus); + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepExecutor.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepExecutor.java new file mode 100644 index 000000000..1c02471dd --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepExecutor.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import java.util.Date; + +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.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContext; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepExecutor; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; +import org.eclipse.tcf.te.runtime.stepper.interfaces.tracing.ITraceIds; +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.utils.ProgressHelper; +import org.eclipse.tcf.te.runtime.utils.StatusHelper; + +/** + * Step executor implementation. + * <p> + * The step executor is responsible for initiating the execution of a single step. The executor + * creates and associated the step callback and blocks the execution till the executed step invoked + * the callback. + * <p> + * The step executor is passing any status thrown by the executed step to the parent stepper + * instance for handling. + * <p> + * If the step to execute is of type {@link IExtendedContextStep}, the step executor is calling + * {@link IExtendedContextStep#initializeFrom(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, Object, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, IProgressMonitor)} and + * {@link IExtendedContextStep#validateExecute(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, Object, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, IProgressMonitor)} before calling + * {@link IContextStep#execute(org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, Object, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, IProgressMonitor, org.eclipse.tcf.te.runtime.interfaces.callback.ICallback)}. + * <p> + * The methods will be called within the current step executor thread. + * <p> + * The stepper implementation can be traced and profiled by setting the debug options: + * <ul> + * <li><i>org.eclipse.tcf.te.runtime.stepper/trace/stepping</i></li> + * <li><i>org.eclipse.tcf.te.runtime.stepper/profile/stepping</i></li> + * </ul> + */ +public abstract class AbstractContextStepExecutor implements IContextStepExecutor { + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepExecutor#execute(org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.tcf.te.runtime.stepper.interfaces.IContext, org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public final void execute(IContextStep step, IFullQualifiedId id, final IContext context, final IPropertiesContainer data, IProgressMonitor progress) throws CoreException { + Assert.isNotNull(step); + Assert.isNotNull(id); + Assert.isNotNull(context); + Assert.isNotNull(data); + Assert.isNotNull(progress); + + long startTime = System.currentTimeMillis(); + + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepExecutor#execute: *** START (" + step.getLabel() + ")", //$NON-NLS-1$ //$NON-NLS-2$ + 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); + + int ticksToUse = (step instanceof IExtendedContextStep) ? ((IExtendedContextStep)step).getTotalWork(context, data) : IProgressMonitor.UNKNOWN; + progress = ProgressHelper.getProgressMonitor(progress, ticksToUse); + ProgressHelper.beginTask(progress, step.getLabel(), ticksToUse); + + // Create the handler (and the callback) for the current step + final Callback callback = new Callback(); + + // 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 IExtendedContextStep) { + IExtendedContextStep extendedStep = (IExtendedContextStep)step; + + // IExtendedContextStep 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.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)); + + // Check the status of the step + normalizeStatus(step, id, context, data, callback.getStatus()); + } + catch (Exception e) { + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepExecutor#execute: Exception catched: class ='" + e.getClass().getName() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + + ", message = '" + e.getLocalizedMessage() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + + ", cause = " //$NON-NLS-1$ + + (e instanceof CoreException ? ((CoreException)e).getStatus().getException() : e.getCause()), + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + + // If the exception is a CoreException by itself, just re-throw + if (e instanceof CoreException) { + // Check if the message does need normalization + if (isExceptionMessageFormatted(e.getLocalizedMessage())) { + throw (CoreException)e; + } + // We have to normalize the status message first + normalizeStatus(step, id, context, data, ((CoreException)e).getStatus()); + } else { + // all other exceptions are repackaged within a CoreException + normalizeStatus(step, id, context, data, StatusHelper.getStatus(e)); + } + } + finally { + if (!progress.isCanceled()) { + progress.done(); + } + + // Give the step a chance for cleanup + if (step instanceof IExtendedContextStep) { + ((IExtendedContextStep)step).cleanup(context, data, id, progress); + } + + long endTime = System.currentTimeMillis(); + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepExecutor#execute: *** DONE (" + step.getLabel() + ")", //$NON-NLS-1$ //$NON-NLS-2$ + 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); + } + } + + private void normalizeStatus(IContextStep step, IFullQualifiedId id, IContext context , IPropertiesContainer data, IStatus status) throws CoreException { + Assert.isNotNull(context); + Assert.isNotNull(data); + Assert.isNotNull(id); + Assert.isNotNull(step); + + if (status == null || status.isOK()) { + return; + } + + switch (status.getSeverity()) { + case IStatus.CANCEL: + throw new OperationCanceledException(status.getMessage()); + default: + String message = formatMessage(status.getMessage(), status.getSeverity(), step, id, context, data); + status = new Status(status.getSeverity(), status.getPlugin(), status.getCode(), message != null ? message : status.getMessage(), status.getException()); + throw new CoreException(status); + } + } + + /** + * Checks if the given message is already formatted to get displayed to the user. + * + * @param message The message. Must not be <code>null</code>. + * @return <code>True</code> if the message is already formatted to get displayed to the user, <code>false</code> otherwise. + */ + protected abstract boolean isExceptionMessageFormatted(String message); + + /** + * Format the message depending on the severity. + * + * @param message The message to format. + * @param severity The message severity. + * @param step The step. + * @param id The full qualified step id. + * @param context The target context. + * @param data The step data. + * @return Formatted message. + */ + protected abstract String formatMessage(String message, int severity, IContextStep step, IFullQualifiedId id, IContext context, IPropertiesContainer data); + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepGroup.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepGroup.java new file mode 100644 index 000000000..04ca6c7be --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepGroup.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupIterator; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtension; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy; + +/** + * Abstract context step group implementation. + */ +public abstract class AbstractContextStepGroup extends ExecutableExtension implements IContextStepGroup { + + private ExecutableExtensionProxy<IContextStepGroupIterator> iteratorProxy = null; + + /** + * Constant to be returned in case the step group contains no steps. + */ + protected final static IContextStepGroupable[] NO_STEPS = new IContextStepGroupable[0]; + + /** + * Constructor. + */ + public AbstractContextStepGroup() { + super(); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup#isLocked() + */ + @Override + public boolean isLocked() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.ExecutableExtension#doSetInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void doSetInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + super.doSetInitializationData(config, propertyName, data); + + if (iteratorProxy == null) { + iteratorProxy = new ExecutableExtensionProxy<IContextStepGroupIterator>(config) { + @Override + protected String getExecutableExtensionAttributeName() { + return "iterator"; //$NON-NLS-1$ + } + }; + } + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup#getStepGroupIterator() + */ + @Override + public IContextStepGroupIterator getStepGroupIterator() { + return iteratorProxy != null ? iteratorProxy.newInstance() : null; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepper.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepper.java new file mode 100644 index 000000000..8f4d50906 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/AbstractContextStepper.java @@ -0,0 +1,804 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tcf.te.runtime.stepper.StepperAttributeUtil; +import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContext; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextManipulator; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepExecutor; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupIterator; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IVariantDelegate; +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.callback.Callback; +import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtension; +import org.eclipse.tcf.te.runtime.interfaces.ISharedConstants; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; +import org.eclipse.tcf.te.runtime.utils.ProgressHelper; +import org.eclipse.tcf.te.runtime.utils.StatusHelper; + +/** + * An abstract stepper implementation. + */ +public abstract class AbstractContextStepper extends ExecutableExtension implements IStepper, IContextManipulator { + + private boolean initialized = false; + private boolean finished = false; + private IPropertiesContainer data = null; + private IFullQualifiedId fullQualifiedId = null; + private IProgressMonitor monitor = null; + private String activeContextId = null; + private IContext activeContext = null; + private boolean cancelable = true; + + protected class ExecutedContextStep { + final IFullQualifiedId id; + final IContextStep step; + + public ExecutedContextStep(IFullQualifiedId id, IContextStep step) { + this.id = id; + this.step = step; + } + } + + /** + * Constructor. + */ + public AbstractContextStepper() { + super(); + } + + /** + * Returns the name of what is executed by the stepper. + */ + protected abstract String getName(); + + /** + * Returns the type if what is executed by the stepper. + */ + protected abstract String getType(); + + /** + * Returns the sub type if what is executed by the stepper. + */ + protected abstract String getSubType(); + + /** + * Returns the contexts the stepper is working with. + */ + protected abstract IContext[] getContexts(); + + /** + * Returns the variant delegate to use or <code>null</code>. + */ + protected abstract IVariantDelegate getVariantDelegate() throws CoreException; + + /** + * Creates a new instance of the step executor to use for executing a step. + */ + protected abstract IContextStepExecutor doCreateStepExecutor(IContextStep step, String secondaryId, IFullQualifiedId fullQualifiedStepId); + + /** + * Returns the step group for the given arguments. + */ + protected abstract IContextStepGroup getStepGroup(String type, String subType, String variant); + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#initialize(org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tcf.te.runtime.stepper.interfaces.IFullQualifiedId, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void initialize(IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws IllegalStateException { + Assert.isNotNull(data); + Assert.isNotNull(fullQualifiedId); + Assert.isNotNull(monitor); + + // Assert stepper is not in use + if (isInitialized()) { + throw new IllegalStateException("Stepper instance already initialized!"); //$NON-NLS-1$ + } + + // set the initial stepper attributes + this.data = data; + this.monitor = monitor; + this.fullQualifiedId = fullQualifiedId; + + // but not finished yet + this.finished = false; + + // set the initial stepper attributes + this.activeContext = null; + this.activeContextId = null; + + setInitialized(); + + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#initialize:" //$NON-NLS-1$ + + " type='" + getType() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + + ", mode='" + getSubType() + "'", //$NON-NLS-1$ //$NON-NLS-2$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + } + + /** + * Marks the stepper to be fully initialized. + */ + protected final void setInitialized() { + initialized = true; + } + + /* (non-Javadoc) + * @see org.eclipse.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; + } + + /** + * Sets the active context. + * + * @param context The active context or <code>null</code>. + */ + protected final void setActiveContext(IContext context) { + // do not use equals() here!!! + if (activeContext != context) { + if (activeContext instanceof IPropertiesContainer) { + ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), null); //$NON-NLS-1$ + } + activeContext = context; + if (activeContext instanceof IPropertiesContainer) { + ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), true); //$NON-NLS-1$ + } + } + } + + /** + * Get the active context. + * + * @return The active context or <code>null</code>. + */ + protected IContext getActiveContext() { + if (isInitialized() && activeContext == null) { + IContext newContext = (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, getFullQualifiedId(), getData()); + if (newContext != null) { + setActiveContext(newContext); + } + if (activeContext == null) { + IContext[] contexts = getContexts(); + if (contexts != null && contexts.length > 0) { + for (IContext context : contexts) { + setActiveContext(context); + StepperAttributeUtil.setProperty(IContextManipulator.CONTEXT, getFullQualifiedId(), getData(), activeContext); + break; + } + } + } + } + return activeContext; + } + + /** + * Sets the active context id. + * + * @param contextId The active context id or <code>null</code>. + */ + protected final void setActiveContextId(String contextId) { + activeContextId = contextId; + } + + /** + * Get the active context id. + * + * @return The active context id or <code>null</code>. + */ + protected String getActiveContextId() { + if (isInitialized() && activeContextId == null) { + String newContextId = (String)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT_ID, getFullQualifiedId(), getData()); + if (newContextId != null && newContextId.trim().length() > 0) { + activeContextId = newContextId.trim(); + } + if (activeContextId == null) { + IContext context = getActiveContext(); + if (context != null) { + activeContextId = context.getContextId(); + StepperAttributeUtil.setProperty(IContextManipulator.CONTEXT_ID, getFullQualifiedId(), getData(), activeContextId); + } + } + } + return activeContextId; + } + + /** + * Returns the currently associated data. The method returns + * <code>null</code> if the stepper is not in initialized state. + * + * @return The data or <code>null</code> + */ + protected final IPropertiesContainer getData() { + return isInitialized() ? data : null; + } + + /** + * Returns the full qualified id for this stepper. + * + * @return The full qualified stepper id. + */ + protected final IFullQualifiedId getFullQualifiedId() { + return fullQualifiedId; + } + + /** + * Returns the currently associated progress monitor. The method returns + * <code>null</code> if the stepper is not in initialized state. + * + * @return The progress monitor or <code>null</code> + */ + protected final IProgressMonitor getMonitor() { + return isInitialized() ? monitor : null; + } + + /** + * Marks the stepper to be finished. + */ + protected final void setFinished() { + finished = true; + if (activeContext instanceof IPropertiesContainer) { + ((IPropertiesContainer)activeContext).setProperty("stepperContext::" + getId(), null); //$NON-NLS-1$ + } + } + + /* (non-Javadoc) + * @see org.eclipse.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 + data = null; + monitor = null; + fullQualifiedId = null; + finished = false; + initialized = false; + + // Reset the initial stepper attributes + setActiveContext(null); + setActiveContextId(null); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); + buffer.append(" (" + getLabel() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append(": "); //$NON-NLS-1$ + buffer.append("id = " + getId()); //$NON-NLS-1$ + return buffer.toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper#execute() + */ + @Override + public final void execute() throws CoreException { + long startTime = System.currentTimeMillis(); + + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: *** ENTERED", //$NON-NLS-1$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + CoreBundleActivator.getTraceHandler().trace(" [" + ISharedConstants.TIME_FORMAT.format(new Date(startTime)) + "]" //$NON-NLS-1$ //$NON-NLS-2$ + + " ***", //$NON-NLS-1$ + 0, ITraceIds.PROFILE_STEPPING, IStatus.WARNING, this); + + try { + // stepper must be initialized before executing + if (!isInitialized()) { + throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), + Messages.AbstractContextStepper_error_initializeNotCalled)); + } + + // Create a container for collecting the non-severe status objects + // during the step execution. Non-severe status objects will + // be hold back till the execution completed or stopped with an error. + // Severe status objects are errors or cancellation. + List<IStatus> statusContainer = new ArrayList<IStatus>(); + + // start execution + internalExecute(statusContainer); + + // If the warnings container is not empty, create a new status and + // throw a core exception + if (!statusContainer.isEmpty()) { + IStatus status = null; + + // Check if we need a multi status + if (statusContainer.size() > 1) { + MultiStatus multiStatus = + new MultiStatus(CoreBundleActivator.getUniqueIdentifier(), 0, + NLS.bind(Messages.AbstractContextStepper_multiStatus_finishedWithWarnings, getName()), null); + for (IStatus subStatus : statusContainer) { + multiStatus.merge(subStatus); + } + status = multiStatus; + } + else { + status = statusContainer.get(0); + } + + throw new CoreException(status); + } + } + finally { + // Mark the stepper finished + setFinished(); + + long endTime = System.currentTimeMillis(); + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: *** DONE", //$NON-NLS-1$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + CoreBundleActivator.getTraceHandler().trace(" [" + ISharedConstants.TIME_FORMAT.format(new Date(endTime)) //$NON-NLS-1$ + + " , delay = " + (endTime - startTime) + " ms]" //$NON-NLS-1$ //$NON-NLS-2$ + + " ***", //$NON-NLS-1$ + 0, ITraceIds.PROFILE_STEPPING, IStatus.WARNING, this); + } + } + + /** + * Executes a step or step group. + * + * @param statusContainer The status container. Must not be <code>null</code>. + * @throws CoreException If the execution fails. + */ + protected void internalExecute(List<IStatus> statusContainer) throws CoreException { + Assert.isNotNull(statusContainer); + + // Get the variant delegate + IVariantDelegate variantDelegate = getVariantDelegate(); + String[] variants = null; + if (variantDelegate != null) { + // Determine the valid variants + variants = variantDelegate.getValidVariants(getActiveContext(), getData()); + } + + // Get the step group + IContextStepGroup stepGroup = null; + if (variants != null) { + for (String variant : variants) { + stepGroup = getStepGroup(getType(), getSubType(), variant); + if (stepGroup != null) { + break; + } + } + } + if (stepGroup == null) { + stepGroup = getStepGroup(getType(), getSubType(), null); + } + + // If no step group could be found for any of the valid variants, throw an exception + if (stepGroup == null) { + throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.AbstractContextStepper_error_missingStepGroup, getName()))); + } + + // Initialize the progress monitor + getMonitor().beginTask(stepGroup.getLabel(), calculateTotalWork(stepGroup)); + + IFullQualifiedId fullQualifiedId = getFullQualifiedId().createChildId(ID_TYPE_CONTEXT_ID, getActiveContextId(), null); + fullQualifiedId = fullQualifiedId.createChildId(ID_TYPE_STEP_GROUP_ID, stepGroup.getId(), null); + // Execute the step group + executeStepGroup(stepGroup, statusContainer, new ArrayList<ExecutedContextStep>(), fullQualifiedId); + } + + /** + * Executes a step group. + * + * @param stepGroup The step group. Must be not <code>null</code>. + * @param statusContainer A list holding the warnings occurred during the execution. Must be not <code>null</code>. + * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. + * @param fullQualifiedGroupId The hierarchy of all parent step group id's separated by "::". Must be not <code>null</code>. + * + * @throws CoreException If the execution fails. + */ + private void executeStepGroup(IContextStepGroup stepGroup, List<IStatus> statusContainer, List<ExecutedContextStep> executedSteps, IFullQualifiedId fullQualifiedGroupId) throws CoreException { + Assert.isNotNull(stepGroup); + Assert.isNotNull(statusContainer); + Assert.isNotNull(executedSteps); + Assert.isNotNull(fullQualifiedGroupId); + + // Return immediately if the user canceled the monitor in the meanwhile + if (isCancelable() && getMonitor().isCanceled()) { + rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); + throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); + } + + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#execute: step group: '" + stepGroup.getLabel() + "'", //$NON-NLS-1$ //$NON-NLS-2$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + + IContextStepGroupIterator iterator = stepGroup.getStepGroupIterator(); + IFullQualifiedId fullQualifiedIterationId = fullQualifiedGroupId; + int iteration = 0; + + if (iterator != null) { + iterator.initialize(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); + } + boolean next = iterator == null || iterator.hasNext(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); + + while (next) { + if (iterator != null) { + fullQualifiedIterationId = fullQualifiedGroupId.createChildId(ID_TYPE_STEP_GROUP_ITERATION_ID, iterator.getId(), ""+iteration); //$NON-NLS-1$ + iterator.next(getActiveContext(), getData(), fullQualifiedIterationId, getMonitor()); + // set the active context if the step has manipulated it + if (iterator instanceof IContextManipulator) { + IContext newContext = + (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, fullQualifiedIterationId, getData()); + String newContextId = + StepperAttributeUtil.getStringProperty(IContextManipulator.CONTEXT_ID, fullQualifiedIterationId, getData()); + if (newContext != null) { + setActiveContext(newContext); + } + if (newContextId != null && + newContextId.trim().length() > 0) { + setActiveContextId(newContextId.trim()); + } + } + } + // Get the list of steps or step groups to execute. + IContextStepGroupable[] groupables = stepGroup.getSteps(getType(), getSubType()); + for (IContextStepGroupable groupable : groupables) { + executeGroupable(groupable, statusContainer, executedSteps, fullQualifiedIterationId); + } + iteration++; + next = iterator != null && iterator.hasNext(getActiveContext(), getData(), fullQualifiedGroupId, getMonitor()); + } + } + + /** + * Executes a step groupable. The groupable might encapsulate a + * step or a step group. + * + * @param step The step groupable. Must be not <code>null</code>. + * @param statusContainer A list holding the warnings occurred during the execution. Must be not <code>null</code>. + * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. + * @param fullQualifiedParentId The hierarchy of all parent step group id's separated by "::". Must be not <code>null</code>. + * + * @throws CoreException If the execution failed. + */ + private void executeGroupable(IContextStepGroupable groupable, List<IStatus> statusContainer, List<ExecutedContextStep> executedSteps, IFullQualifiedId fullQualifiedParentId) throws CoreException { + Assert.isNotNull(groupable); + Assert.isNotNull(statusContainer); + Assert.isNotNull(executedSteps); + Assert.isNotNull(fullQualifiedParentId); + + // Return immediately if the user canceled the monitor in the meanwhile + if (isCancelable() && getMonitor() != null && getMonitor().isCanceled()) { + rollback(executedSteps, Status.CANCEL_STATUS, getMonitor()); + throw new CoreException(StatusHelper.getStatus(new OperationCanceledException())); + } + + // If the passed in groupable is disabled -> we are done immediately + if (groupable.isDisabled()) { + CoreBundleActivator.getTraceHandler().trace("AbstractContextStepper#executeGroupable: DROPPED DISABLED groupable: id = '" + groupable.getExtension().getId() + "'" //$NON-NLS-1$ //$NON-NLS-2$ + + ", secondaryId = '" + groupable.getSecondaryId() + "'", //$NON-NLS-1$ //$NON-NLS-2$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + return; + } + + // Check if all dependencies of the groupable have been executed before + checkForDependenciesExecuted(groupable, executedSteps); + + if (groupable.getExtension() instanceof IContextStepGroup) { + IFullQualifiedId id = fullQualifiedParentId.createChildId(ID_TYPE_STEP_GROUP_ID, groupable.getExtension().getId(), groupable.getSecondaryId()); + // If the passed in groupable is associated with a step group + // -> get the groupable from that group and execute them + executeStepGroup((IContextStepGroup)groupable.getExtension(), statusContainer, executedSteps, id); + } + else if (groupable.getExtension() instanceof IContextStep) { + // If the passed in groupable is associated with a step + // -> check if the required steps have been executed before, + // create a step executor and invoke the executor. + IContextStep step = (IContextStep)groupable.getExtension(); + + IFullQualifiedId id = fullQualifiedParentId.createChildId(ID_TYPE_STEP_ID, step.getId(), groupable.getSecondaryId()); + + // Create the step executor now + IContextStepExecutor executor = doCreateStepExecutor(step, groupable.getSecondaryId(), id); + Assert.isNotNull(executor); + + try { + executedSteps.add(new ExecutedContextStep(id, step)); + // Invoke the executor now + executor.execute(step, id, getActiveContext(), getData(), getMonitor()); + // set the active context if the step has manipulated it + if (step instanceof IContextManipulator) { + IContext newContext = (IContext)StepperAttributeUtil.getProperty(IContextManipulator.CONTEXT, id, getData()); + String newContextId = StepperAttributeUtil.getStringProperty(IContextManipulator.CONTEXT_ID, id, getData()); + if (newContext != null) { + setActiveContext(newContext); + } + if (newContextId != null && + newContextId.trim().length() > 0) { + setActiveContextId(newContextId.trim()); + } + } + } + catch (Exception e) { + // Catch the CoreException first hand as we need to continue the + // stepping if the step returned with warnings or information only. + CoreException coreException = normalizeStatus(e, statusContainer); + // If the exception has been not eaten, rollback previously executed + // steps and re-throw the exception. + if (coreException != null) { + // Rollback everything, if the step(s) are supporting this and + // the cleanup hasn't been done already. + if (isInitialized()) { + rollback(executedSteps, coreException.getStatus(), getMonitor()); + } + + // Re-throw the exception + throw coreException; + } + } + } + } + + /** + * Checks if all required dependencies have been executed before. If not, the method + * will throw an error status. + * + * @param groupable The groupable. Must be not <code>null</code>. + * @param executedSteps A list holding the id's of the steps executed before. Must be not <code>null</code>. + * + * @throws CoreException If a dependency has not been executed before. + */ + protected void checkForDependenciesExecuted(IContextStepGroupable groupable, List<ExecutedContextStep> executedSteps) throws CoreException { + Assert.isNotNull(groupable); + Assert.isNotNull(executedSteps); + + // Build up the complete list of dependencies. + List<String> dependencies = new ArrayList<String>(Arrays.asList(groupable.getDependencies())); + // If the groupable wraps a step, the step can have additional dependencies to check + if (groupable.getExtension() instanceof IContextStep) { + dependencies.addAll(Arrays.asList(((IContextStep)groupable.getExtension()).getDependencies())); + } + + // Check each dependency now. + for (String dependency : dependencies) { + // The dependencies might be fully qualified. Split out the primary id. + String[] splitted = dependency.split("##", 2); //$NON-NLS-1$ + String primaryId = splitted.length == 2 ? splitted[0] : dependency; + + // Check if the id is in the list of executed steps. As the list contains + // the fully qualified id's, we cannot just check for contained + boolean requiredStepExecuted = false; + for (ExecutedContextStep step : executedSteps) { + if (step.step.getId().equals(primaryId)) { + requiredStepExecuted = true; + break; + } + } + + if (!requiredStepExecuted) { + throw new CoreException(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.AbstractContextStepper_error_requiredStepNotExecuted, + NLS.bind((groupable.getExtension() instanceof IContextStep + ? Messages.AbstractContextStepper_error_step + : Messages.AbstractContextStepper_error_requiredStepOrGroup), dependency), + NLS.bind(Messages.AbstractContextStepper_error_typeAndSubtype, getType(), getSubType())))); + } + + // Recursive checking is not necessary here as the step or step group + // id's would have made it the executed steps list of they missed required + // steps or step groups. + } + + } + + /** + * Rollback the steps previously executed to the failed step. The rollback + * is executed in reverse order and the step must be of type {@link IWRExtendedTargetContextStep} + * to participate in the rollback. + * + * @param executedSteps + * @param progress + */ + protected final void rollback(final List<ExecutedContextStep> executedSteps, final IStatus rollBackStatus, IProgressMonitor progress) { + Assert.isNotNull(executedSteps); + + final IProgressMonitor rollbackProgress = ProgressHelper.getProgressMonitor(progress, 1); + ProgressHelper.beginTask(rollbackProgress, "Cancel", executedSteps.size()); //$NON-NLS-1$ + final Callback finalCallback = new Callback(); + final Callback rollbackCallback = new Callback() { + @Override + protected void internalDone(Object caller, IStatus status) { + if (!executedSteps.isEmpty()) { + setProperty(PROPERTY_IS_DONE, false); + ExecutedContextStep executedStep = executedSteps.remove(executedSteps.size()-1); + if (executedStep.step instanceof IExtendedContextStep) { + IExtendedContextStep step = (IExtendedContextStep)executedStep.step; + step.rollback(getActiveContext(), getData(), rollBackStatus, executedStep.id, rollbackProgress, this); + } + else { + this.done(this, status); + } + } + else { + finalCallback.done(this, Status.OK_STATUS); + } + } + }; + + rollbackCallback.done(this, rollBackStatus); + ExecutorsUtil.waitAndExecute(0, finalCallback.getDoneConditionTester(null)); + } + + /** + * Calculates the total work required for the step group. The total + * work is the sum of the total work of each sub step. If one of the + * steps returns {@link IProgressMonitor#UNKNOWN}, the total work will + * be unknown for the whole step group. + * + * @param stepGroup The step group. Must be not <code>null</code>. + * @return The total work required or {@link IProgressMonitor#UNKNOWN}. + * + * @throws CoreException If the total work of the step group cannot be determined. + */ + protected int calculateTotalWork(IContextStepGroup stepGroup) throws CoreException { + Assert.isNotNull(stepGroup); + + int totalWork = 0; + + // Loop the group steps and summarize the returned total work + IContextStepGroupable[] groupables = stepGroup.getSteps(getType(), getSubType()); + for (IContextStepGroupable groupable : groupables) { + int work = groupable.getExtension() instanceof IContextStep + ? ((IContextStep)groupable.getExtension()).getTotalWork(getActiveContext(), getData()) + : groupable.getExtension() instanceof IContextStepGroup + ? calculateTotalWork((IContextStepGroup)groupable.getExtension()) + : IProgressMonitor.UNKNOWN; + + if (work == IProgressMonitor.UNKNOWN) { + totalWork = IProgressMonitor.UNKNOWN; + break; + } + + totalWork += work; + } + + return totalWork; + } + + /** + * Normalize the associated status object of the given {@link CoreException}. + * <p> + * If the associated status contains only WARNING or INFORMATION status objects, + * the objects are added to the passed in status container. The passed in exception + * is dropped and the method will return <code>null</code>. + * <p> + * If the associated status contains only OK status objects, the passed in + * exception and the associated status are dropped and the method will return + * <code>null</code>. + * <p> + * If the associated status contain ERROR status objects, the passed in exception + * and the associated status objects are returned if the passed in status container + * is empty. If the status container is not empty, a new exception and multi status + * object is created and returned. The multi status object will contain all status + * objects from the status container and all objects of the originally associated + * status. + * <p> + * If the associated status contains a CANCEL status object, the passed in + * exception and the associated status objects are returned unmodified. + * + * @param e The core exception. Must be not <code>null</code>. + * @param statusContainer The list of non-severe status objects. Must be not <code>null</code>. + * @return The exception to re-throw or <code>null</code>. + */ + private CoreException normalizeStatus(Exception e, List<IStatus> statusContainer) { + Assert.isNotNull(statusContainer); + + CoreException coreException = null; + + IStatus status = Status.OK_STATUS; + // Get the associated status from the exception + if (e instanceof CoreException) { + status = ((CoreException)e).getStatus(); + coreException = (CoreException)e; + } + else if (e instanceof OperationCanceledException) { + status = new Status(IStatus.CANCEL, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); + coreException = new CoreException(status); + } + else if (e != null) { + status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); + coreException = new CoreException(status); + } + + // Check the severity + // PS: MultiStatus.getSeverity() returns always the highest severity. + if (status.getSeverity() == IStatus.OK) { + // OK -> drop completely and return null + coreException = null; + } + else if (status.getSeverity() == IStatus.CANCEL) { + // CANCEL -> Check monitor to be canceled. + if (isCancelable()) { + if (getMonitor() != null && !getMonitor().isCanceled()) { + getMonitor().setCanceled(true); + } + } + } + else if (status.getSeverity() == IStatus.WARNING || status.getSeverity() == IStatus.INFO) { + // WARNING or INFORMATION -> add to the list and return null + statusContainer.add(status); + coreException = null; + } + else if (status.getSeverity() == IStatus.ERROR) { + // Error -> If the warnings container not empty, create + // a new MultiStatus. + if (!statusContainer.isEmpty()) { + MultiStatus multiStatus = new MultiStatus(status.getPlugin(), status.getCode(), + NLS.bind(Messages.AbstractContextStepper_multiStatus_finishedWithErrors, getName()), null); + for (IStatus stat : statusContainer) { + multiStatus.merge(stat); + } + // Re-throw via a new CoreException + coreException = new CoreException(multiStatus); + } + } + + return coreException; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroup.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroup.java new file mode 100644 index 000000000..869310605 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroup.java @@ -0,0 +1,814 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +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.IContextStep; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IExtendedContextStep; +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.interfaces.extensions.IExecutableExtension; + +/** + * A default step group implementation. + */ +public class ContextStepGroup extends AbstractContextStepGroup { + + private boolean locked; + private String baseOn; + + private final List<ReferenceSubElement> references = new ArrayList<ReferenceSubElement>(); + + /** + * Step group reference sub element. + */ + protected final static class ReferenceSubElement implements org.eclipse.core.runtime.IExecutableExtension { + private String id; + private String secondaryId; + private String insertBefore; + private String insertAfter; + private String overwrite; + private boolean removable; + private boolean hidden; + private boolean disable; + private boolean singleton; + private final List<String> dependencies = new ArrayList<String>(); + + /** + * Returns the id of the referenced step or step group. + * + * @return The id of the referenced step or step group. + */ + public String getId() { + return id; + } + + /** + * Returns the secondary id of the referenced step or step group. + * + * @return The secondary id or <code>null</code>. + */ + public String getSecondaryId() { + return secondaryId; + } + + /** + * Sets the secondary id of the referenced step or step group. + * + * @return The secondary id or <code>null</code>. + */ + public void setSecondardId(String secondaryId) { + this.secondaryId = secondaryId; + } + + /** + * Returns the id of the step or step group the referenced + * step or group shall be inserted before. + * + * @return The id or <code>null</code>. + */ + public String getInsertBefore() { + return insertBefore; + } + + /** + * Returns the id of the step or step group the referenced + * step or group shall be inserted after. + * + * @return The id or <code>null</code>. + */ + public String getInsertAfter() { + return insertAfter; + } + + /** + * Returns the id of the step or step group the referenced + * step or group do overwrite. + * + * @return The id or <code>null</code>. + */ + public String getOverwrite() { + return overwrite; + } + + /** + * Returns if or if not the referenced step or step group + * can be removed by the user from the group. + * + * @return <code>True</code> if removable, <code>false</code> otherwise. + */ + public boolean isRemovable() { + return removable; + } + + /** + * Returns if or if not the referenced step or step group + * is hidden. + * + * @return <code>True</code> if hidden, <code>false</code> otherwise. + */ + public boolean isHidden() { + return hidden; + } + + /** + * Returns if or if not to disable the referenced step or step group. + * + * @return <code>True</code> if to disable, <code>false</code> otherwise. + */ + public boolean isDisable() { + return disable; + } + + /** + * Returns if or if not the referenced step or step group is a singleton. + * + * @return <code>True</code> if singleton, <code>false</code> otherwise. + */ + public boolean isSingleton() { + return singleton; + } + + /** + * Returns the list of dependencies. + * <p> + * The step or step group id might be fully qualified using the form + * <code>"primaryId##secondaryId</code>. The <code>secondaryId</code> is optional. + * + * @return The list of dependencies or an empty list. + */ + public String[] getDependencies() { + return dependencies.toArray(new String[dependencies.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + if (config == null) { + return; + } + + String value = config.getAttribute("id"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.id = value.trim(); + } + + value = config.getAttribute("secondaryId"); //$NON-NLS-1$ + setSecondardId(value != null && value.trim().length() > 0 ? value.trim() : null); + + value = config.getAttribute("insertBefore"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.insertBefore = value.trim(); + } + + value = config.getAttribute("insertAfter"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.insertAfter = value.trim(); + } + + value = config.getAttribute("overwrite"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.overwrite = value.trim(); + } + + value = config.getAttribute("removable"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.removable = Boolean.parseBoolean(value.trim()); + } + + value = config.getAttribute("hidden"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.hidden = Boolean.parseBoolean(value.trim()); + } + + value = config.getAttribute("disable"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.disable = Boolean.parseBoolean(value.trim()); + } + + value = config.getAttribute("singleton"); //$NON-NLS-1$ + if (value != null && value.trim().length() > 0) { + this.singleton = Boolean.parseBoolean(value.trim()); + } + + // Read in the list of dependencies if specified. + dependencies.clear(); + IConfigurationElement[] requires = config.getChildren("requires"); //$NON-NLS-1$ + for (IConfigurationElement require : requires) { + value = require.getAttribute("id"); //$NON-NLS-1$ + if (value == null || value.trim().length() == 0) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + 0, + NLS.bind(Messages.AbstractContextStep_error_missingRequiredAttribute, + "dependency id (requires)", //$NON-NLS-1$ + config.getName()), + null)); + } + if (!dependencies.contains(value.trim())) { + dependencies.add(value.trim()); + } + } + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (getId() != null && obj instanceof ReferenceSubElement) { + boolean secondaryIdEquals = false; + if (getSecondaryId() == null) { + secondaryIdEquals = ((ReferenceSubElement)obj).getSecondaryId() == null; + } + else { + secondaryIdEquals = getSecondaryId().equals(((ReferenceSubElement)obj).getSecondaryId()); + } + + return getId().equals(((ReferenceSubElement)obj).getId()) && secondaryIdEquals; + } + return super.equals(obj); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return getId() != null ? getId().hashCode() + (getSecondaryId() != null ? getSecondaryId().hashCode() : 0) : super.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(getClass().getSimpleName()); + buffer.append(": "); //$NON-NLS-1$ + buffer.append("id = " + getId()); //$NON-NLS-1$ + buffer.append(", secondaryId = " + getSecondaryId()); //$NON-NLS-1$ + buffer.append(", insertBefore = " + getInsertBefore()); //$NON-NLS-1$ + buffer.append(", insertAfter = " + getInsertAfter()); //$NON-NLS-1$ + buffer.append(", overwrite = " + getOverwrite()); //$NON-NLS-1$ + buffer.append(", removable = " + isRemovable()); //$NON-NLS-1$ + buffer.append(", hidden = " + isHidden()); //$NON-NLS-1$ + buffer.append(", disable = " + isDisable()); //$NON-NLS-1$ + buffer.append(", singleton = " + isSingleton()); //$NON-NLS-1$ + return buffer.toString(); + } + } + + /** + * Constructor. + */ + public ContextStepGroup() { + super(); + locked = false; + baseOn = null; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.AbstractContextStepGroup#isLocked() + */ + @Override + public boolean isLocked() { + return locked; + } + + /** + * Returns the id of the step group this step group is + * initially based on. + * + * @return The id or <code>null</code>. + */ + protected String getBaseOn() { + return baseOn; + } + + /** + * Returns the references. + */ + protected List<ReferenceSubElement> getReferences() { + return references; + } + + /** + * Check for duplicates of the referenced step or step group. The check + * will fail if multiple occurrence of a step or step group are found and + * the step or step group is supposed to be a singleton. + * + * @param steps The list of steps. Must not be <code>null</code>. + * @param reference The reference. Must not be <code>null</code>. + * @param type The type id. Must not be <code>null</code>. + * @param mode The sub type id. Must not be <code>null</code>. + * + * @throws CoreException If multiple occurrences of singleton references are found. + */ + protected void checkForDuplicates(List<IContextStepGroupable> steps, ReferenceSubElement reference, String type, String mode) throws CoreException { + assert steps != null && reference != null; + + // If the reference overwrites another reference, it is not a duplicate + String overwrite = reference.getOverwrite(); + if (overwrite != null && overwrite.length() > 0) { + return; + } + + boolean checkFailed = false; + + for (IContextStepGroupable step : steps) { + if (step.getExtension().getId().equals(reference.getId())) { + // We've found an existing groupable with the reference id. + // 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 IExtendedContextStep + && ((IExtendedContextStep)step.getExtension()).isSingleton()); + if (checkFailed) { + break; + } + } + } + + if (checkFailed) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.ContextStepGroup_error_multipleSingletonOccurrences, + NLS.bind(Messages.ContextStepGroup_error_stepGroup, getLabel()), + NLS.bind(Messages.ContextStepGroup_error_referencedStepOrGroup, reference.getId()), + NLS.bind(Messages.ContextStepGroup_error_typeAndMode, type, mode)) + )); + } + } + + /** + * Replace all references to a given step or step group with another one. + * + * @param steps The list of steps. Must not be <code>null</code>. + * @param oldId The id of the step or step group to replace. Must not be <code>null</code>. + * @param replacement The replacement. Must not be <code>null</code>. + * @param reference The reference sub element. Must not be <code>null</code>. + * + * @return The list of affected groupable's or an empty list. + */ + protected List<IContextStepGroupable> onOverwrite(List<IContextStepGroupable> steps, String oldId, IExecutableExtension replacement, ReferenceSubElement reference) { + assert steps != null && oldId != null && replacement != null && reference != null; + + List<IContextStepGroupable> affected = new ArrayList<IContextStepGroupable>(); + + // Isolate primary and secondary id + String primaryId = oldId; + String secondaryId = null; + + String[] splitted = oldId.split("##", 2); //$NON-NLS-1$ + if (splitted.length == 2) { + primaryId = splitted[0]; + secondaryId = splitted[1]; + } + + for (IContextStepGroupable step : steps) { + // A step is clearly affected if the primary id and the secondary + // id (if any) matches the overwritten id + if (step.getExtension().getId().equals(primaryId) + && (secondaryId == null || secondaryId.equals(step.getSecondaryId()))) { + if (step instanceof ContextStepGroupable) { + ContextStepGroupable groupable = ((ContextStepGroupable)step); + // Update the grouped extension + groupable.setExtension(replacement); + // Update the groupable secondary id + groupable.setSecondaryId(reference.getSecondaryId()); + // Add the groupable to the list of affected steps + affected.add(step); + } + } + + // A step is affected as well if the step depends on the overwritten step + // In this case we have to update the dependencies. + List<String> dependencies = new ArrayList<String>(Arrays.asList(step.getDependencies())); + if (dependencies.contains(oldId)) { + String fullId = replacement.getId() + (reference.getSecondaryId() != null ? "##" + reference.getSecondaryId() : ""); //$NON-NLS-1$ //$NON-NLS-2$ + // We have to replace the dependency at the exact position within the list + dependencies.set(dependencies.indexOf(oldId), fullId); + if (step instanceof ContextStepGroupable) { + ((ContextStepGroupable)step).setDependencies(dependencies.toArray(new String[dependencies.size()])); + } + } + } + + return affected; + } + + /** + * Insert the step before the specified step or step group. If no step or + * step group with the given id exist, the step is added to the end. + * + * @param steps The list of steps. Must not be <code>null</code>. + * @param id The id of the step or step group where to insert the new step before. Must not be <code>null</code>. + * @param newStep The step to add. Must not be <code>null</code>. + * @param reference The reference sub element. Must not be <code>null</code>. + * + * @return The list of affected groupable's or an empty list. + */ + protected List<IContextStepGroupable> onInsertBefore(List<IContextStepGroupable> steps, String id, IExecutableExtension newStep, ReferenceSubElement reference) { + assert steps != null && id != null && newStep != null && reference != null; + + List<IContextStepGroupable> affected = new ArrayList<IContextStepGroupable>(); + + // Isolate primary and secondary id + String primaryId = id; + String secondaryId = null; + + String[] splitted = id.split("##", 2); //$NON-NLS-1$ + if (splitted.length == 2) { + primaryId = splitted[0]; + secondaryId = splitted[1]; + } + + // Always loop over all steps in case the anchor step is available + // multiple times. In such case, the new step is inserted at all + // occurrences. + for (int i = 0; i < steps.size(); i++) { + IContextStepGroupable step = steps.get(i); + if (!step.getExtension().getId().equals(primaryId)) { + continue; + } + if (secondaryId != null && !secondaryId.equals(step.getSecondaryId())) { + continue; + } + + // Create a new groupable object for inserting + IContextStepGroupable groupable = new ContextStepGroupable(newStep, reference.getSecondaryId()); + // Insert the new step at the current position + steps.add(i, groupable); + // And increase the counter --> Otherwise we would see the + // same step we want to insert before again! + i++; + // Add the new groupable to the list of affected steps + affected.add(groupable); + } + + // If the step could not be added, add to the end of the list + if (affected.isEmpty()) { + IContextStepGroupable groupable = new ContextStepGroupable(newStep, reference.getSecondaryId()); + steps.add(groupable); + } + + return affected; + } + + /** + * Insert the step after the specified step or step group. If no step or + * step group with the given id exist, the step is added to the end. + * + * @param steps The list of steps. Must not be <code>null</code>. + * @param id The id of the step or step group where to insert the new step after. Must not be <code>null</code>. + * @param newStep The step to add. Must not be <code>null</code>. + * @param reference The reference sub element. Must not be <code>null</code>. + * + * @return The list of affected groupable's or an empty list. + */ + protected List<IContextStepGroupable> onInsertAfter(List<IContextStepGroupable> steps, String id, IExecutableExtension newStep, ReferenceSubElement reference) { + assert steps != null && id != null && newStep != null && reference != null; + + List<IContextStepGroupable> affected = new ArrayList<IContextStepGroupable>(); + + // Isolate primary and secondary id + String primaryId = id; + String secondaryId = null; + + String[] splitted = id.split("##", 2); //$NON-NLS-1$ + if (splitted.length == 2) { + primaryId = splitted[0]; + secondaryId = splitted[1]; + } + + // Always loop over all steps in case the anchor step is available + // multiple times. In such case, the new step is inserted at all + // occurrences. + for (int i = 0; i < steps.size(); i++) { + IContextStepGroupable step = steps.get(i); + if (!step.getExtension().getId().equals(primaryId)) { + continue; + } + if (secondaryId != null && !secondaryId.equals(step.getSecondaryId())) { + continue; + } + + // Create a new groupable object for inserting + IContextStepGroupable groupable = new ContextStepGroupable(newStep, reference.getSecondaryId()); + // Insert the new groupable after the current step or at the end (if i + 1 == steps.size()) + steps.add(i + 1, groupable); + // Add the new groupable to the list of affected steps + affected.add(groupable); + } + + // If the step could not be added, add to the end of the list + if (affected.isEmpty()) { + IContextStepGroupable groupable = new ContextStepGroupable(newStep, reference.getSecondaryId()); + steps.add(groupable); + } + + return affected; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup#getSteps(java.lang.String, java.lang.String) + */ + @Override + public IContextStepGroupable[] getSteps(String type, String mode) throws CoreException { + assert type != null && mode != null; + + // The list of resolved steps for the specified type and mode + List<IContextStepGroupable> steps = new ArrayList<IContextStepGroupable>(); + + // If this step group is based on another step group, we have to get the resolved + // steps from there first. + if (getBaseOn() != null) { + IContextStepGroup baseStepGroup = getStepGroup(getBaseOn()); + // If the base step group cannot be found, that's an error. We cannot continue + // without the base group. + if (baseStepGroup == null) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.ContextStepGroup_error_missingBaseStepGroup, + NLS.bind(Messages.ContextStepGroup_error_stepGroup, getLabel()), + NLS.bind(Messages.ContextStepGroup_error_referencedBaseGroup, getBaseOn()), + NLS.bind(Messages.ContextStepGroup_error_typeAndMode, type, mode)) + )); + } + + // Add all the steps from the base step group now to the list + steps.addAll(Arrays.asList(baseStepGroup.getSteps(type, mode))); + } + + // Now process the references and modify the steps list accordingly + for (ReferenceSubElement reference : getReferences()) { + // Get the step or step group for the referenced id. Try the steps first. + IExecutableExtension candidate = getStep(reference.getId()); + if (candidate == null) { + candidate = getStepGroup(reference.getId()); + } + + // If the candidate is null here, that's an error as a referenced step is missing. + if (candidate == null) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.ContextStepGroup_error_missingReferencedStep, + NLS.bind(Messages.ContextStepGroup_error_stepGroup, getLabel()), + NLS.bind(Messages.ContextStepGroup_error_referencedStepOrGroup, reference.getId()), + NLS.bind(Messages.ContextStepGroup_error_typeAndMode, type, mode)) + )); + } + + // Check if the step is valid for the current launch configuration type and mode. + if (candidate instanceof IContextStep) { + boolean valid = isValidStep(candidate.getId(), type, mode); + + if (!valid) { + CoreBundleActivator.getTraceHandler().trace( + "StepGroup#getSteps: SKIPPED step = '" + candidate.getLabel() + "'." //$NON-NLS-1$ //$NON-NLS-2$ + + " Not valid for type id '" + type + "'" //$NON-NLS-1$ //$NON-NLS-2$ + + " and mode '" + mode + "'", //$NON-NLS-1$ //$NON-NLS-2$ + 0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this); + continue; + } + } + + // Check for duplicates of singleton references. + checkForDuplicates(steps, reference, type, mode); + + // Check for the steps own dependencies to be valid for the current type id and mode + if (candidate instanceof IContextStep) { + checkForDependenciesValid((IContextStep) candidate, type, mode); + } + + // Will contain the list of affected groupables from the whole list + List<IContextStepGroupable> affectedGroupables = new ArrayList<IContextStepGroupable>(); + + // Check first for overwriting groupables + String overwrite = reference.getOverwrite(); + if (overwrite != null && overwrite.length() > 0) { + affectedGroupables.addAll(onOverwrite(steps, overwrite, candidate, reference)); + } else { + // overwrite is not set -> process insertBefore or insertAfter + String insertBefore = reference.getInsertBefore(); + String insertAfter = reference.getInsertAfter(); + + // If neither one is specified, the step or step group will be to the end of the list + if ((insertBefore == null || insertBefore.length() == 0) + && (insertAfter == null || insertAfter.length() == 0)) { + IContextStepGroupable groupable = new ContextStepGroupable(candidate, reference.getSecondaryId()); + steps.add(groupable); + affectedGroupables.add(groupable); + } else { + // insertBefore comes first + if (insertBefore != null && insertBefore.length() > 0) { + affectedGroupables.addAll(onInsertBefore(steps, insertBefore, candidate, reference)); + } else { + affectedGroupables.addAll(onInsertAfter(steps, insertAfter, candidate, reference)); + } + } + } + + // Process the groupable attributes on all affected groupables + for (IContextStepGroupable step : affectedGroupables) { + if (!(step instanceof ContextStepGroupable)) { + continue; + } + + ContextStepGroupable groupable = (ContextStepGroupable)step; + groupable.setDependencies(reference.getDependencies()); + + if (!reference.isRemovable() && groupable.isRemovable()) { + groupable.setRemovable(reference.isRemovable()); + } + if (reference.isHidden() && !groupable.isHidden()) { + groupable.setHidden(reference.isHidden()); + } + if (reference.isDisable() && !groupable.isDisabled()) { + groupable.setDisabled(reference.isDisable()); + } + if (reference.isSingleton() && !groupable.isSingleton()) { + groupable.setSingleton(reference.isSingleton()); + } + } + } + + return !steps.isEmpty() ? steps.toArray(new IContextStepGroupable[steps.size()]) : NO_STEPS; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.ExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + references.clear(); + super.setInitializationData(config, propertyName, data); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.extensions.AbstractContextStepGroup#doSetInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void doSetInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + super.doSetInitializationData(config, propertyName, data); + + if (!locked) { + String lockedAttribute = config.getAttribute("locked"); //$NON-NLS-1$ + if (lockedAttribute != null) { + this.locked = Boolean.parseBoolean(lockedAttribute); + } + } + + if (baseOn == null || baseOn.trim().length() == 0) { + String baseOnAttribute = config.getAttribute("baseOn"); //$NON-NLS-1$ + if (baseOnAttribute != null && baseOnAttribute.trim().length() > 0) { + this.baseOn = baseOnAttribute.trim(); + } + } + + Map<String, Integer> occurrences = new HashMap<String, Integer>(); + IConfigurationElement[] childElements = config.getChildren("references"); //$NON-NLS-1$ + for (IConfigurationElement childElement : childElements) { + IConfigurationElement[] references = childElement.getChildren("reference"); //$NON-NLS-1$ + for (IConfigurationElement reference : references) { + ReferenceSubElement candidate = new ReferenceSubElement(); + candidate.setInitializationData(reference, reference.getName(), null); + // If multiple references to the same step or step group exist, check + // for the secondaryId + if (occurrences.containsKey(candidate.getId())) { + // Occurrences are counted up always + int number = occurrences.get(candidate.getId()).intValue() + 1; + occurrences.put(candidate.getId(), Integer.valueOf(number)); + + if (candidate.getSecondaryId() == null) { + // secondaryId not explicitly set -> auto set + candidate.setSecondardId(Integer.toString(number)); + } + } else { + // remember the occurrence of the reference + occurrences.put(candidate.getId(), Integer.valueOf(1)); + } + + // References are not sorted out here. That's the task of the resolver. + this.references.add(candidate); + } + } + } + + + /** + * Checks is all dependencies of the given step are available + * and valid for the given type id and mode. + * + * @param step The step. Must not be <code>null</code>. + * @param type The type id. Must not be <code>null</code>. + * @param mode The mode. Must not be <code>null</code>. + * + * @throws CoreException If a required step or step group is not available or not valid. + */ + protected void checkForDependenciesValid(IContextStep step, String type, String mode) throws CoreException { + assert step != null && type != null && mode != null; + + String[] dependencies = step.getDependencies(); + for (String dependency : dependencies) { + // Get the step or step group. Try the steps first. + IExecutableExtension candidate = getStep(dependency); + if (candidate == null) { + candidate = getStepGroup(dependency); + } + + // If the candidate is null here, that's an error as a required step or step group is missing. + if (candidate == null) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.ContextStepGroup_error_missingRequiredStep, + NLS.bind(Messages.ContextStepGroup_error_step, step.getLabel()), + NLS.bind(Messages.ContextStepGroup_error_requiredStepOrGroup, dependency), + NLS.bind(Messages.ContextStepGroup_error_typeAndMode, type, mode)) + )); + } + + // If the candidate a step, validate the step + if (candidate instanceof IContextStep) { + IContextStep candidateStep = (IContextStep)candidate; + boolean valid = isValidStep(candidateStep.getId(), type, mode); + if (!valid) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + MessageFormat.format(Messages.ContextStepGroup_error_invalidRequiredStep, + NLS.bind(Messages.ContextStepGroup_error_step, step.getLabel()), + NLS.bind(Messages.ContextStepGroup_error_requiredStep, dependency), + NLS.bind(Messages.ContextStepGroup_error_typeAndMode, type, mode)) + )); + } + + // Step is valid -> recursively check required steps. + checkForDependenciesValid(candidateStep, type, mode); + } + } + } + + /** + * Convenience method returning a unique instance of the step + * identified by the given id. + * + * @param id The step id. Must not be <code>null</code>. + * @return The step instance or <code>null</code>. + */ + protected IContextStep getStep(String id) { + Assert.isNotNull(id); + return StepperManager.getInstance().getStepExtManager().getStep(id, true); + } + + /** + * Convenience method returning a unique instance of the step + * group identified by the given id. + * + * @param id The step id. Must not be <code>null</code>. + * @return The step group instance or <code>null</code>. + */ + protected IContextStepGroup getStepGroup(String id) { + Assert.isNotNull(id); + return StepperManager.getInstance().getStepGroupExtManager().getStepGroup(id, true); + } + + /** + * Returns if or if not the step identified by the given id is valid. + * <p> + * <b>Note:</b> The default implementation returns always <code>true</code>. + * + * @param id The step id. Must not be <code>null</code>. + * @param type The type id. Must not be <code>null</code>. + * @param mode The mode. Must not be <code>null</code>. + * + * @return <code>True</code> if the step is valid, <code>false</code> otherwise. + */ + protected boolean isValidStep(String id, String type, String mode) { + return true; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroupable.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroupable.java new file mode 100644 index 000000000..9486f248b --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/extensions/ContextStepGroupable.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * 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.stepper.extensions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable; +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; + +/** + * Context step groupable implementation. + */ +public class ContextStepGroupable implements IContextStepGroupable { + private String secondaryId = null; + private boolean disabled = false; + private boolean hidden = false; + private boolean removable = true; + private boolean singleton = false; + private final List<String> dependencies = new ArrayList<String>(); + + private IExecutableExtension extension; + + /** + * Constructor. + * + * @param extension The grouped extension. Must not be <code>null</code>. + */ + public ContextStepGroupable(IExecutableExtension extension) { + this(extension, null); + } + + /** + * Constructor. + * + * @param extension The grouped extension. Must not be <code>null</code>. + * @param secondaryId The groupable secondaryId or <code>null</code>. + */ + public ContextStepGroupable(IExecutableExtension extension, String secondaryId) { + super(); + setExtension(extension); + setSecondaryId(secondaryId); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#getExtension() + */ + @Override + public IExecutableExtension getExtension() { + return extension; + } + + /** + * Set the grouped extension instance. + * + * @param extension The grouped extension instance. Must not be <code>null</code>. + */ + public void setExtension(IExecutableExtension extension) { + Assert.isNotNull(extension); + this.extension = extension; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#getSecondaryId() + */ + @Override + public String getSecondaryId() { + return secondaryId; + } + + /** + * Steps the groupable secondary id. The primary id is the unique id of the extension. + * + * @param secondaryId The grouped extension secondary id or <code>null</code>. + */ + public void setSecondaryId(String secondaryId) { + this.secondaryId = secondaryId; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#isDisabled() + */ + @Override + public boolean isDisabled() { + return disabled; + } + + /** + * Sets if or if not the step is disabled. + * <p> + * The default value is <code>false</code> and can be changed exactly once to <code>true</code>. + * Once set to <code>true</code> it must not be changeable anymore. + * + * @param disabled Specify <code>true</code> if to disable the step, <code>false</code> otherwise. + */ + public void setDisabled(boolean disabled) { + Assert.isTrue(this.disabled == false); + this.disabled = disabled; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#isHidden() + */ + @Override + public boolean isHidden() { + return hidden; + } + + /** + * Sets if or if not the step is hidden from the user. + * <p> + * The default value is <code>false</code> and can be changed exactly once to <code>true</code>. + * Once set to <code>true</code> it must not be changeable anymore. + * + * @param hidden Specify <code>true</code> if to hide the step, <code>false</code> otherwise. + */ + public void setHidden(boolean hidden) { + Assert.isTrue(this.hidden == false); + this.hidden = hidden; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#isRemovable() + */ + @Override + public boolean isRemovable() { + return removable; + } + + /** + * Sets if or if not the step can be removed from a step group by the user. + * <p> + * The default value is <code>true</code> and can be changed exactly once to <code>false</code>. + * Once set to <code>false</code> it must not be changeable anymore. + * + * @param removable Specify <code>True</code> if the step can be removed, <code>false</code> otherwise. + */ + public void setRemovable(boolean removable) { + Assert.isTrue(this.removable == true); + this.removable = removable; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#isSingleton() + */ + @Override + public boolean isSingleton() { + return singleton; + } + + /** + * Sets if or if not the launch step is a singleton. Singleton steps can occur in step groups + * only once. Multiple occurrences are forbidden. + * + * @param singleton Specify <code>true</code> if the step is a singleton, <code>false</code> otherwise. + */ + public void setSingleton(boolean singleton) { + Assert.isTrue(this.singleton == false); + this.singleton = singleton; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroupable#getDependencies() + */ + @Override + public String[] getDependencies() { + return dependencies.toArray(new String[dependencies.size()]); + } + + /** + * Sets the list of dependencies. The dependencies of a groupable are checked on execution. If + * one of the listed dependencies have not been executed before, the execution of the groupable + * will fail. + * <p> + * The context step or context step group id might be fully qualified using the form + * <code>"primaryId##secondaryId</code>. The <code>secondaryId</code> is optional. + * + * @param dependencies The list of dependencies. Must not be <code>null</code>. + */ + public void setDependencies(String[] dependencies) { + Assert.isNotNull(dependencies); + this.dependencies.clear(); + this.dependencies.addAll(Arrays.asList(dependencies)); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); + buffer.append(" (" + getExtension().getLabel() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append(": "); //$NON-NLS-1$ + buffer.append("id = " + getExtension().getId()); //$NON-NLS-1$ + buffer.append(", secondaryId = " + getSecondaryId()); //$NON-NLS-1$ + return buffer.toString(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContext.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContext.java new file mode 100644 index 000000000..264ff6d44 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContext.java @@ -0,0 +1,41 @@ +/*******************************************************************************
+ * 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.stepper.interfaces;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Interface to be implemented by objects representing a context for a step.
+ */
+public interface IContext extends IAdaptable {
+
+ /**
+ * Returns the context id.
+ *
+ * @return The context id or <code>null</code>.
+ */
+ public String getContextId();
+
+ /**
+ * Returns a name/label to be used within the UI to represent this context
+ * to the user.
+ *
+ * @return The name or <code>null</code>.
+ */
+ public String getContextName();
+
+ /**
+ * Returns a possible multi-line string providing detail information
+ * about the context which shall be included in failure messages.
+ *
+ * @return The context information or <code>null</code>.
+ */
+ public String getContextInfo();
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextManipulator.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextManipulator.java new file mode 100644 index 000000000..61bb81817 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextManipulator.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +/** + * A step or step group capable of modifying the context the steps or step + * groups are operating on. + */ +public interface IContextManipulator { + + /** + * The suffix to append to the full qualified step id to + * get the delayed status object. + */ + public final static String CONTEXT_ID = "contextId"; //$NON-NLS-1$ + + /** + * The suffix to append to the full qualified step id to + * get the delayed status object. + */ + public final static String CONTEXT = "context"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStep.java new file mode 100644 index 000000000..f7a1e359e --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStep.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +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 associated with a context. + * <p> + * Context steps are assumed to be asynchronous. If the context step execution + * finished, the passed in <b>callback must be invoked</b>. The parent launch + * stepper suspend the step sequence execution till the callback is invoked. + * <p> + * Context steps signals the execution state to the parent launch 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 IContextStep 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(IContext 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(IContext 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(); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepExecutor.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepExecutor.java new file mode 100644 index 000000000..f5a977ca1 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepExecutor.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * A step executor. + */ +public interface IContextStepExecutor { + + /** + * Executes the associated step. + * + * @param step The step to execute. Must not be <code>null</code>. + * @param id The full qualified step id. Must not be <code>null</code>. + * @param context The context. Must not be <code>null</code>. + * @param data The data. 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 execute(IContextStep step, IFullQualifiedId id, IContext context, IPropertiesContainer data, IProgressMonitor monitor) throws CoreException; +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroup.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroup.java new file mode 100644 index 000000000..8e1aca910 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroup.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; + + +/** + * A step group. + * <p> + * A step group is a set of single steps or other step groups. + */ +public interface IContextStepGroup extends IExecutableExtension { + + /** + * Returns if or if not the step group is locked for user modifications. + * + * @return <code>True</code> if locked for user modifications, <code>false</code> otherwise. + */ + public boolean isLocked(); + + /** + * Returns the list of steps or step groups enlisted in the group for the specified stepper, + * type and sub type. + * + * @param type The type id. Must be not <code>null</code>. + * @param subType The sub type Must be not <code>null</code>. + * + * @return The list of steps and step groups or an empty array. + * + * @throws CoreException If the steps cannot be determined. + */ + public IContextStepGroupable[] getSteps(String type, String subType) throws CoreException; + + /** + * Return the step group iterator or <code>null</code>. The step group iterator can be used to + * generate loops and conditions for a step group. + */ + public IContextStepGroupIterator getStepGroupIterator(); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupIterator.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupIterator.java new file mode 100644 index 000000000..2d1da0289 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupIterator.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * A step group iterator. + */ +public interface IContextStepGroupIterator extends IExecutableExtension { + + /** + * Initialize the iterator. + * + * @param context The context. Must be not <code>null</code>. + * @param data The data. Must be not <code>null</code>. + * @param fullQualifiedId The full qualified id for this step. Must be not <code>null</code>. + * @param monitor The progress monitor. Must be not <code>null</code>. + */ + public void initialize(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor); + + /** + * Return the number of calculated iterations. If the iterator was not initialized, + * <code>-1</code> is returned. + */ + public int getNumIterations(); + + /** + * Check if there is a next iteration possible. + * + * @param context The context. Must be not <code>null</code>. + * @param data The data. Must be not <code>null</code>. + * @param fullQualifiedId The full qualified id for this step. Must be not <code>null</code>. + * @param monitor The progress monitor. Must be not <code>null</code>. + * @return <code>true</code> if another iteration is possible. + */ + public boolean hasNext(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor); + + /** + * Set the next iteration to the data using the full qualified id. + * + * @param context The context. Must be not <code>null</code>. + * @param data The data. Must be not <code>null</code>. + * @param fullQualifiedId The full qualified id for this step. Must be not <code>null</code>. + * @param monitor The progress monitor. Must be not <code>null</code>. + * @throws CoreException + */ + public void next(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws CoreException; +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupable.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupable.java new file mode 100644 index 000000000..89e21f93a --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IContextStepGroupable.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; + +/** + * A step groupable. + */ +public interface IContextStepGroupable { + + /** + * Returns the grouped extension instance. + * + * @return The grouped extension instance. + */ + public IExecutableExtension getExtension(); + + /** + * Returns the groupable secondary id. The primary id is the unique id of the extension. + * + * @return The groupable secondary id or <code>null</code>. + */ + public String getSecondaryId(); + + /** + * Returns if or if not the step is a singleton. Singleton steps can occur in step groups only + * once. Multiple occurrences are forbidden. + * + * @return <code>True</code> if the step is a singleton, <code>false</code> otherwise. + */ + public boolean isSingleton(); + + /** + * Returns if or if not the step can be removed from a step group by the user. + * <p> + * The default value is <code>true</code> and can be changed exactly once to <code>false</code>. + * Once set to <code>false</code> it must not be changeable anymore. + * + * @return <code>True</code> if the step can be removed, <code>false</code> otherwise. + */ + public boolean isRemovable(); + + /** + * Returns if or if not the step is hidden from the user. + * <p> + * The default value is <code>false</code> and can be changed exactly once to <code>true</code>. + * Once set to <code>true</code> it must not be changeable anymore. + * + * @return <code>True</code> if the step is hidden, <code>false</code> otherwise. + */ + public boolean isHidden(); + + /** + * Returns if or if not the step is disabled. + * <p> + * The default value is <code>false</code> and can be changed exactly once to <code>true</code>. + * Once set to <code>true</code> it must not be changeable anymore. + * + * @return <code>True</code> if the step is disable, <code>false</code> otherwise. + */ + public boolean isDisabled(); + + /** + * Returns the list of dependencies. The dependencies of a groupable are checked on execution. + * If one of the listed dependencies have not been executed before, the execution of the + * groupable will fail. + * <p> + * The launch step or launch step group id might be fully qualified using the form + * <code>"primaryId##secondaryId</code>. The <code>secondaryId</code> is optional. + * + * @return The list of dependencies or an empty list. + */ + public String[] getDependencies(); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedContextStep.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedContextStep.java new file mode 100644 index 000000000..a13e1a54d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IExtendedContextStep.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.core.runtime.CoreException; +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 IExtendedContextStep extends IContextStep { + + /** + * 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(IContext context, IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor); + + /** + * Validate execution conditions. + * <p> + * This method is called from + * {@link #execute(IContext, Object, IFullQualifiedId, IProgressMonitor, org.eclipse.tcf.te.runtime.interfaces.callback.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(IContext 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(IContext 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(IContext 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/IFullQualifiedId.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IFullQualifiedId.java new file mode 100644 index 000000000..765f85e81 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IFullQualifiedId.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +/** + * A unique, hierarchically id used by steps, step groups and others. + */ +public interface IFullQualifiedId { + + /** + * Get the parent id or <code>null</code> if this is the root. + * + * @return The parent id or <code>null</code>. + */ + public IFullQualifiedId getParentId(); + + /** + * Creates a new id using this id as the parent. + * + * @param type The type of the new child. + * @param id The id for the new child. + * @param secondaryId The secondary id of the new child. + * @return The new created full qualified id. + */ + public IFullQualifiedId createChildId(String type, String id, String secondaryId); + + /** + * Get the type of this id. + * + * @return The type. + */ + public String getType(); + + /** + * Get the id of this node. + * + * @return The id. + */ + public String getId(); + + /** + * Get the secondary id of this node or <code>null</code> + * if there is no secondary id. + * + * @return The secondary id or <code>null</code>. + */ + public String getSecondaryId(); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStepper.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStepper.java new file mode 100644 index 000000000..346181568 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IStepper.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.tcf.te.runtime.interfaces.IConditionTester; +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + + +/** + * A stepper. + * <p> + * Stepper are executing a set of steps and/or step groups read from a given type for the current + * sub type. The stepper is responsible for handling any exceptions which occurred during step + * execution. + * <p> + * Stepper are synchronous where steps are asynchronous. + * <p> + * Stepper must run in worker threads. + */ +public interface IStepper extends IExecutableExtension { + + public static final String ID_TYPE_STEPPER_ID = "Stepper"; //$NON-NLS-1$ + public static final String ID_TYPE_CONTEXT_ID = "Context"; //$NON-NLS-1$ + public static final String ID_TYPE_STEP_GROUP_ID = "StepGroup"; //$NON-NLS-1$ + public static final String ID_TYPE_STEP_GROUP_ITERATION_ID = "StepGroupIteration"; //$NON-NLS-1$ + public static final String ID_TYPE_STEP_ID = "Step"; //$NON-NLS-1$ + + /** + * Condition Tester to test for finished execution of the associated stepper. + */ + public static class ExecutionFinishedConditionTester implements IConditionTester { + private final IStepper stepper; + + /** + * Constructor. + * + * @param stepper The stepper. Must not be <code>null</code>. + */ + public ExecutionFinishedConditionTester(IStepper stepper) { + Assert.isNotNull(stepper); + this.stepper = stepper; + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#cleanup() + */ + @Override + public void cleanup() { + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.interfaces.IConditionTester#isConditionFulfilled() + */ + @Override + public boolean isConditionFulfilled() { + return stepper.isFinished(); + } + } + + /** + * Initialize the stepper for a run. This method must be called before <i><code>execute()</code> + * </i>. Once the stepper finished the execution, the initialization is reseted and must be + * renewed before <i><code>execute()</code></i> can be called again. + * + * @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>. + * + * @throws IllegalStateException If called if the stepper is in initialized state already. + */ + public void initialize(IPropertiesContainer data, IFullQualifiedId fullQualifiedId, IProgressMonitor monitor) throws IllegalStateException; + + /** + * Returns if or if not the stepper got initialized for a new run. + * <p> + * The <i><code>execute()</code></i> method cannot be called if the stepper is not correctly + * initialized for each run. The initialized state can be set only by calling the <i> + * <code>initialize(...)</code></i> method. <i> <code>cleanup()</code></i> will reset the + * initialized state back to uninitialized. + * + * @return <code>True</code> if initialized, <code>false</code> otherwise. + */ + public boolean isInitialized(); + + /** + * Executes the configured steps. The method is synchronous and must return only if all steps + * finished or an exception occurred. + * <p> + * Steps are assumed to be asynchronous. The stepper implementor must wait for callback(s) to be + * invoked by the step implementor(s) before the sequence can continue. + * <p> + * <b>Note:</b> Waiting for the step callback must not block the UI thread. + * + * @throws CoreException In case the execution fails or is canceled. + */ + public void execute() throws CoreException; + + /** + * Returns if or if not the stepper finished the execution. + * + * @return <code>True</code> if the execution is finished, <code>false</code> otherwise. + */ + public boolean isFinished(); + + /** + * Cleanup and reset the stepper into a defined state. + */ + public void cleanup(); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IVariantDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IVariantDelegate.java new file mode 100644 index 000000000..f6efb45c7 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/IVariantDelegate.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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.stepper.interfaces; + +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; +import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * The variant delegate is providing variants to the main modes. Variants can influence the executed + * steps or step groups. + */ +public interface IVariantDelegate extends IExecutableExtension { + + /** + * Returns the valid mode variants for the current context The returned list of variants is + * probed in the returned order. + * + * @param context The context. Must not be <code>null</code>. + * @param data The data. Must not be <code>null</code>. + * + * @return The valid variants or an empty array. + */ + public String[] getValidVariants(IContext context, IPropertiesContainer data); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/tracing/ITraceIds.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/tracing/ITraceIds.java new file mode 100644 index 000000000..4f526483d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/interfaces/tracing/ITraceIds.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.stepper.interfaces.tracing; + +/** + * Stepper Runtime plug-in trace slot identifiers. + */ +public interface ITraceIds { + + /** + * If activated, trace information about step execution is printed out. + */ + public static final String TRACE_STEPPING = "trace/stepping"; //$NON-NLS-1$ + + /** + * If activated, profile information about step execution is printed out. + */ + public static final String PROFILE_STEPPING = "profile/stepping"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepExtensionPointManager.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepExtensionPointManager.java new file mode 100644 index 000000000..55fb31408 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepExtensionPointManager.java @@ -0,0 +1,83 @@ +/*******************************************************************************
+ * 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.stepper.internal.extensions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStep;
+import org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager;
+import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy;
+
+/**
+ * Step extension point manager implementation.
+ */
+public class StepExtensionPointManager extends AbstractExtensionPointManager<IContextStep> {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getExtensionPointId()
+ */
+ @Override
+ protected String getExtensionPointId() {
+ return "org.eclipse.tcf.te.runtime.stepper.steps"; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getConfigurationElementName()
+ */
+ @Override
+ protected String getConfigurationElementName() {
+ return "step"; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the list of all contributed steps.
+ *
+ * @param unique If <code>true</code>, the method returns new instances for each
+ * contributed step.
+ *
+ * @return The list of contributed steps, or an empty array.
+ */
+ public IContextStep[] getSteps(boolean unique) {
+ List<IContextStep> contributions = new ArrayList<IContextStep>();
+ Collection<ExecutableExtensionProxy<IContextStep>> delegates = getExtensions().values();
+ for (ExecutableExtensionProxy<IContextStep> delegate : delegates) {
+ IContextStep instance = unique ? delegate.newInstance() : delegate.getInstance();
+ if (instance != null && !contributions.contains(instance)) {
+ contributions.add(instance);
+ }
+ }
+
+ return contributions.toArray(new IContextStep[contributions.size()]);
+ }
+
+ /**
+ * Returns the step identified by its unique id. If no step with the specified id is registered,
+ * <code>null</code> is returned.
+ *
+ * @param id The unique id of the step or <code>null</code>
+ * @param unique If <code>true</code>, the method returns new instances of the step contribution.
+ *
+ * @return The step instance or <code>null</code>.
+ */
+ public IContextStep getStep(String id, boolean unique) {
+ Assert.isNotNull(id);
+ IContextStep contribution = null;
+ if (getExtensions().containsKey(id)) {
+ ExecutableExtensionProxy<IContextStep> proxy = getExtensions().get(id);
+ // Get the extension instance
+ contribution = unique ? proxy.newInstance() : proxy.getInstance();
+ }
+
+ return contribution;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionPointManager.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionPointManager.java new file mode 100644 index 000000000..aaa9a55a8 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionPointManager.java @@ -0,0 +1,93 @@ +/*******************************************************************************
+ * 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.stepper.internal.extensions;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup;
+import org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager;
+import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy;
+
+/**
+ * Step group extension manager implementation.
+ */
+public class StepGroupExtensionPointManager extends AbstractExtensionPointManager<IContextStepGroup> {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getExtensionPointId()
+ */
+ @Override
+ protected String getExtensionPointId() {
+ return "org.eclipse.tcf.te.runtime.stepper.stepGroups"; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getConfigurationElementName()
+ */
+ @Override
+ protected String getConfigurationElementName() {
+ return "stepGroup"; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#doCreateExtensionProxy(org.eclipse.core.runtime.IConfigurationElement)
+ */
+ @Override
+ protected ExecutableExtensionProxy<IContextStepGroup> doCreateExtensionProxy(IConfigurationElement element) throws CoreException {
+ return new StepGroupExtensionProxy(element);
+ }
+
+ /**
+ * Returns the step group identified by its unique id. If no step group with the specified id is
+ * registered, <code>null</code> is returned.
+ *
+ * @param id The step group unique id. Must not be <code>null</code>
+ * @param unique If <code>true</code>, the method returns new instances of the step group contribution.
+ *
+ * @return The step group instance or <code>null</code>.
+ */
+ public IContextStepGroup getStepGroup(String id, boolean unique) {
+ Assert.isNotNull(id);
+ IContextStepGroup contribution = null;
+ if (getExtensions().containsKey(id)) {
+ ExecutableExtensionProxy<IContextStepGroup> proxy = getExtensions().get(id);
+ // Get the extension instance
+ contribution = unique ? proxy.newInstance() : proxy.getInstance();
+ }
+
+ return contribution;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#doStoreExtensionTo(java.util.Map, org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy, org.eclipse.core.runtime.IConfigurationElement)
+ */
+ @Override
+ protected void doStoreExtensionTo(Map<String, ExecutableExtensionProxy<IContextStepGroup>> extensions, ExecutableExtensionProxy<IContextStepGroup> candidate, IConfigurationElement element) throws CoreException {
+ Assert.isNotNull(extensions);
+ Assert.isNotNull(candidate);
+ Assert.isNotNull(element);
+
+ // If no extension with this id had been registered before, register now.
+ if (!extensions.containsKey(candidate.getId())) {
+ extensions.put(candidate.getId(), candidate);
+ }
+ else if (extensions.get(candidate.getId()) instanceof StepGroupExtensionProxy) {
+ StepGroupExtensionProxy proxy = (StepGroupExtensionProxy)extensions.get(candidate.getId());
+ proxy.addGroupExtension(element);
+ }
+ else {
+ super.doStoreExtensionTo(extensions, candidate, element);
+ }
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionProxy.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionProxy.java new file mode 100644 index 000000000..91839ff4c --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepGroupExtensionProxy.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.stepper.internal.extensions; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator; +import org.eclipse.tcf.te.runtime.stepper.extensions.ContextStepGroup; +import org.eclipse.tcf.te.runtime.stepper.interfaces.IContextStepGroup; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy; + +/** + * Step group extension proxy implementation. + */ +public class StepGroupExtensionProxy extends ExecutableExtensionProxy<IContextStepGroup> { + private List<IConfigurationElement> groupExtensions = new ArrayList<IConfigurationElement>(); + + /** + * Constructor. + * + * @param element The configuration element. Must not be <code>null</code>. + */ + public StepGroupExtensionProxy(IConfigurationElement element) throws CoreException { + super(element); + } + + /** + * Add a duplicate group extension that should be used to extend the launch group. + * + * @param element The configuration element. Must not be <code>null</code>. + */ + public void addGroupExtension(IConfigurationElement element) { + Assert.isNotNull(element); + groupExtensions.add(element); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy#newInstance() + */ + @Override + public IContextStepGroup newInstance() { + // Create the instance + ContextStepGroup instance = new ContextStepGroup(); + // and initialize + try { + instance.setInitializationData(getConfigurationElement(), getConfigurationElement().getName(), null); + for (IConfigurationElement groupExtension : groupExtensions) { + instance.doSetInitializationData(groupExtension, groupExtension.getName(), null); + } + } catch (CoreException e) { + // initialization failed -> reset instance + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(e.getStatus()); + instance = null; + } + return instance; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepperExtensionPointManager.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepperExtensionPointManager.java new file mode 100644 index 000000000..f7d46cec0 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/internal/extensions/StepperExtensionPointManager.java @@ -0,0 +1,83 @@ +/*******************************************************************************
+ * 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.stepper.internal.extensions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepper;
+import org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager;
+import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy;
+
+/**
+ * Stepper extension point manager implementation.
+ */
+public class StepperExtensionPointManager extends AbstractExtensionPointManager<IStepper> {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getExtensionPointId()
+ */
+ @Override
+ protected String getExtensionPointId() {
+ return "org.eclipse.tcf.te.runtime.stepper.steppers"; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getConfigurationElementName()
+ */
+ @Override
+ protected String getConfigurationElementName() {
+ return "stepper"; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the list of all contributed stepper.
+ *
+ * @param unique If <code>true</code>, the method returns new instances for each
+ * contributed stepper.
+ *
+ * @return The list of contributed stepper, or an empty array.
+ */
+ public IStepper[] getStepper(boolean unique) {
+ List<IStepper> contributions = new ArrayList<IStepper>();
+ Collection<ExecutableExtensionProxy<IStepper>> delegates = getExtensions().values();
+ for (ExecutableExtensionProxy<IStepper> delegate : delegates) {
+ IStepper instance = unique ? delegate.newInstance() : delegate.getInstance();
+ if (instance != null && !contributions.contains(instance)) {
+ contributions.add(instance);
+ }
+ }
+
+ return contributions.toArray(new IStepper[contributions.size()]);
+ }
+
+ /**
+ * Returns the stepper identified by its unique id. If no stepper with the specified id is registered,
+ * <code>null</code> is returned.
+ *
+ * @param id The unique id of the stepper or <code>null</code>
+ * @param unique If <code>true</code>, the method returns new instances of the stepper contribution.
+ *
+ * @return The stepper instance or <code>null</code>.
+ */
+ public IStepper getStepper(String id, boolean unique) {
+ Assert.isNotNull(id);
+ IStepper contribution = null;
+ if (getExtensions().containsKey(id)) {
+ ExecutableExtensionProxy<IStepper> proxy = getExtensions().get(id);
+ // Get the extension instance
+ contribution = unique ? proxy.newInstance() : proxy.getInstance();
+ }
+
+ return contribution;
+ }
+}
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 new file mode 100644 index 000000000..db90f107f --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * 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.stepper.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Stepper 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.stepper.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 AbstractContextStep_error_missingRequiredAttribute; + public static String AbstractContextStep_warning_stepFinishedWithWarnings; + + public static String AbstractContextStepper_error_typeAndSubtype; + public static String AbstractContextStepper_error_stepGroup; + public static String AbstractContextStepper_error_step; + public static String AbstractContextStepper_error_referencedBaseGroup; + public static String AbstractContextStepper_error_referencedStepOrGroup; + public static String AbstractContextStepper_error_requiredStepOrGroup; + public static String AbstractContextStepper_error_requiredStep; + public static String AbstractContextStepper_error_initializeNotCalled; + public static String AbstractContextStepper_error_missingStepGroup; + public static String AbstractContextStepper_multiStatus_finishedWithWarnings; + public static String AbstractContextStepper_multiStatus_finishedWithErrors; + public static String AbstractContextStepper_error_missingRequiredStep; + public static String AbstractContextStepper_error_requiredStepNotExecuted; + + public static String ContextStepGroup_error_missingBaseStepGroup; + public static String ContextStepGroup_error_missingReferencedStep; + public static String ContextStepGroup_error_missingRequiredStep; + public static String ContextStepGroup_error_invalidRequiredStep; + public static String ContextStepGroup_error_multipleSingletonOccurrences; + public static String ContextStepGroup_error_typeAndMode; + public static String ContextStepGroup_error_step; + public static String ContextStepGroup_error_stepGroup; + public static String ContextStepGroup_error_requiredStep; + public static String ContextStepGroup_error_referencedBaseGroup; + public static String ContextStepGroup_error_referencedStepOrGroup; + public static String ContextStepGroup_error_requiredStepOrGroup; +} 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 new file mode 100644 index 000000000..fa6e72872 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.stepper/src/org/eclipse/tcf/te/runtime/stepper/nls/Messages.properties @@ -0,0 +1,36 @@ +# +# org.eclipse.tcf.te.runtime.stepper +# Externalized Strings. +# + +AbstractContextStep_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"! +AbstractContextStep_warning_stepFinishedWithWarnings=Step ''{0}'' finished with warnings. + +AbstractContextStepper_error_typeAndSubtype=Type:\n\t{0}\nSubtype:\n\t{1} +AbstractContextStepper_error_stepGroup=Step group:\n\t{0} +AbstractContextStepper_error_step=Step:\n\t{0} +AbstractContextStepper_error_referencedBaseGroup=Referenced Base Step Group:\n\t{0} +AbstractContextStepper_error_referencedStepOrGroup=Referenced Step or Step Group:\n\t{0} +AbstractContextStepper_error_requiredStepOrGroup=Required Step or Step Group:\n\t{0} +AbstractContextStepper_error_requiredStep=Required Step:\n\t{0} +AbstractContextStepper_error_initializeNotCalled=initialize(...) must be called before execute()! +AbstractContextStepper_error_missingStepGroup=Execution failed. No steps configured for ''{0}''. +AbstractContextStepper_multiStatus_finishedWithWarnings=''{0}'' completed with warnings or information. +AbstractContextStepper_multiStatus_finishedWithErrors=''{0}'' failed. +AbstractContextStepper_error_missingRequiredStep=Step execution failed. \ +Required step or step group does not exist.\n\n{0}\n{1}\n\n{2} +AbstractContextStepper_error_requiredStepNotExecuted=Step execution failed. \ +Required step or step group not executed before.\n\n{0}\n{1}\n\n{2} + +ContextStepGroup_error_missingBaseStepGroup=Cannot determine steps for execution. Referenced base step group does not exist.\n\n{0}\n{1}\n\n{2} +ContextStepGroup_error_missingReferencedStep=Cannot determine steps for execution. Referenced step or step group does not exist.\n\n{0}\n{1}\n\n{2} +ContextStepGroup_error_missingRequiredStep=Invalid step. Required step or step group does not exist.\n\n{0}\n{1}\n\n{2} +ContextStepGroup_error_invalidRequiredStep=Invalid step. Required step is invalid.\n\n{0}\n{1}\n\n{2} +ContextStepGroup_error_multipleSingletonOccurrences=Cannot determine steps for execution. Only one reference allowed.\n\n{0}\n{1}\n\n{2} +ContextStepGroup_error_typeAndMode=Type:\n\t{0}\nMode:\n\t{1} +ContextStepGroup_error_step=Step:\n\t{0} +ContextStepGroup_error_stepGroup=Step group:\n\t{0} +ContextStepGroup_error_requiredStep=Required Step:\n\t{0} +ContextStepGroup_error_referencedBaseGroup=Referenced Base Step Group:\n\t{0} +ContextStepGroup_error_referencedStepOrGroup=Referenced Step or Step Group:\n\t{0} +ContextStepGroup_error_requiredStepOrGroup=Required Step or Step Group:\n\t{0} |