/*******************************************************************************
* Copyright (c) 2011, 2014 Wind River Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the terms
* of the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.runtime.stepper.extensions;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
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.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.eclipse.tcf.te.runtime.extensions.ExecutableExtension;
import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy;
import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension;
import org.eclipse.tcf.te.runtime.stepper.StepperManager;
import org.eclipse.tcf.te.runtime.stepper.activator.CoreBundleActivator;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStep;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroupIterator;
import org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroupable;
import org.eclipse.tcf.te.runtime.stepper.interfaces.tracing.ITraceIds;
import org.eclipse.tcf.te.runtime.stepper.nls.Messages;
/**
* A default step group implementation.
*/
public class StepGroup extends ExecutableExtension implements IStepGroup {
private boolean locked;
private String baseOn;
private final List<ReferenceSubElement> references = new ArrayList<ReferenceSubElement>();
// Map of parameters of the step reference
private Map<String,String> parameters = new HashMap<String,String>();
private ExecutableExtensionProxy<IStepGroupIterator> iteratorProxy = null;
/**
* Constant to be returned in case the step group contains no steps.
*/
protected final static IStepGroupable[] NO_STEPS = new IStepGroupable[0];
/**
* 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 boolean savePoint;
private boolean optional;
private final List<String> dependencies = new ArrayList<String>();
private Expression expression;
private Map<String,String> parameters = new HashMap<String, 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;
}
/**
* If a reference is marked as savepoint, the step or step group will not
* be rolled back if it was executed successfully.
* @return <code>true</code> if rollback should be done after successful execution.
*/
public boolean isSavePoint() {
return savePoint;
}
/**
* If a reference is marked as optional, the step or step group will be
* ignored if not known.
* @return <code>true</code> if reference should be ignored when not known.
*/
public boolean isOptional() {
return optional;
}
/**
* 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()]);
}
/**
* Returns the enablement expression which is associated with this reference.
*
* @return The enablement expression or <code>null</code>.
*/
public Expression getEnablement() {
return expression;
}
/**
* Returns the parameters for the step.
*
* @return The parameters or an empty Map.
*/
public Map<String,String> getParameters() {
return parameters;
}
/* (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());
}
value = config.getAttribute("savePoint"); //$NON-NLS-1$
if (value != null && value.trim().length() > 0) {
this.savePoint = Boolean.parseBoolean(value.trim());
}
value = config.getAttribute("optional"); //$NON-NLS-1$
if (value != null && value.trim().length() > 0) {
this.optional = 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.AbstractStep_error_missingRequiredAttribute,
"dependency id (requires)", //$NON-NLS-1$
config.getName()),
null));
}
if (!dependencies.contains(value.trim())) {
dependencies.add(value.trim());
}
}
// Read the sub elements of the extension
IConfigurationElement[] enablements = config.getChildren("enablement"); //$NON-NLS-1$
// The "enablement" element is the only expected one
if (enablements != null && enablements.length > 0) {
expression = ExpressionConverter.getDefault().perform(enablements[0]);
}
// Read the sub elements of the extension
IConfigurationElement[] params = config.getChildren("parameter"); //$NON-NLS-1$
// The "paramter" element is the only expected one
if (params != null && params.length > 0) {
for (IConfigurationElement parameter : params) {
parameters.put(parameter.getAttribute("name"), parameter.getAttribute("value")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
/* (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$
buffer.append(", savePoint = " + isSavePoint()); //$NON-NLS-1$
buffer.append(", optional = " + isOptional()); //$NON-NLS-1$
buffer.append(", parameters = " + getParameters()); //$NON-NLS-1$
return buffer.toString();
}
}
/**
* Constructor.
*/
public StepGroup() {
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>.
*
* @throws CoreException If multiple occurrences of singleton references are found.
*/
protected void checkForDuplicates(List<IStepGroupable> steps, ReferenceSubElement reference) throws CoreException {
Assert.isNotNull(steps);
Assert.isNotNull(reference);
// 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 (IStepGroupable 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 IStep && ((IStep)step.getExtension()).isSingleton());
if (checkFailed) {
break;
}
}
}
if (checkFailed) {
throw new CoreException(new Status(IStatus.ERROR,
CoreBundleActivator.getUniqueIdentifier(),
MessageFormat.format(Messages.StepGroup_error_multipleSingletonOccurrences,
NLS.bind(Messages.StepGroup_error_stepGroup, getLabel()),
NLS.bind(Messages.StepGroup_error_referencedStepOrGroup, reference.getId()))
));
}
}
/**
* 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<IStepGroupable> onOverwrite(List<IStepGroupable> steps, String oldId, IExecutableExtension replacement, ReferenceSubElement reference) {
Assert.isNotNull(steps);
Assert.isNotNull(oldId);
Assert.isNotNull(replacement);
Assert.isNotNull(reference);
List<IStepGroupable> affected = new ArrayList<IStepGroupable>();
// 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 (IStepGroupable 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 StepGroupable) {
StepGroupable groupable = ((StepGroupable)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 StepGroupable) {
((StepGroupable)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<IStepGroupable> onInsertBefore(List<IStepGroupable> steps, String id, IExecutableExtension newStep, ReferenceSubElement reference) {
Assert.isNotNull(steps);
Assert.isNotNull(id);
Assert.isNotNull(newStep);
Assert.isNotNull(reference);
List<IStepGroupable> affected = new ArrayList<IStepGroupable>();
// 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++) {
IStepGroupable 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
IStepGroupable groupable = new StepGroupable(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()) {
IStepGroupable groupable = new StepGroupable(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<IStepGroupable> onInsertAfter(List<IStepGroupable> steps, String id, IExecutableExtension newStep, ReferenceSubElement reference) {
Assert.isNotNull(steps);
Assert.isNotNull(id);
Assert.isNotNull(newStep);
Assert.isNotNull(reference);
List<IStepGroupable> affected = new ArrayList<IStepGroupable>();
// 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++) {
IStepGroupable 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
IStepGroupable groupable = new StepGroupable(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()) {
IStepGroupable groupable = new StepGroupable(newStep, reference.getSecondaryId());
steps.add(groupable);
}
return affected;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup#getSteps(org.eclipse.tcf.te.runtime.stepper.interfaces.IStepContext)
*/
@Override
public IStepGroupable[] getSteps(IStepContext context) throws CoreException {
Assert.isNotNull(context);
// The list of resolved steps for the specified type and mode
List<IStepGroupable> steps = new ArrayList<IStepGroupable>();
// If this step group is based on another step group, we have to get the resolved
// steps from there first.
if (getBaseOn() != null) {
IStepGroup baseStepGroup = StepperManager.getInstance().getStepGroupExtManager().getStepGroup(getBaseOn(), true);
// 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.StepGroup_error_missingBaseStepGroup,
NLS.bind(Messages.StepGroup_error_stepGroup, getLabel()),
NLS.bind(Messages.StepGroup_error_referencedBaseGroup, getBaseOn()))
));
}
// Add all the steps from the base step group now to the list
steps.addAll(Arrays.asList(baseStepGroup.getSteps(context)));
}
// 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 = getCandidate(reference.getId(), reference);
// If the candidate is null here, that's an error as a referenced step is missing.
if (candidate == null) {
if (reference.isOptional()) {
CoreBundleActivator.getTraceHandler().trace(
"StepGroup#getSteps: SKIPPED optional not existing reference = '" + reference.getId(), //$NON-NLS-1$
0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this);
continue;
}
throw new CoreException(new Status(IStatus.ERROR,
CoreBundleActivator.getUniqueIdentifier(),
MessageFormat.format(Messages.StepGroup_error_missingReferencedStep,
NLS.bind(Messages.StepGroup_error_stepGroup, getLabel()),
NLS.bind(Messages.StepGroup_error_referencedStepOrGroup, reference.getId()))
));
}
// Check if the step is valid for the current contexts.
boolean valid = isValidReference(reference, context);
if (!valid) {
CoreBundleActivator.getTraceHandler().trace(
"StepGroup#getSteps: SKIPPED reference = '" + candidate.getLabel() + "'." //$NON-NLS-1$ //$NON-NLS-2$
+ " Not valid for contexts '" + context, //$NON-NLS-1$
0, ITraceIds.TRACE_STEPPING, IStatus.WARNING, this);
continue;
}
// Check for duplicates of singleton references.
checkForDuplicates(steps, reference);
// Check for the steps own dependencies to be valid for the current type id and mode
if (candidate instanceof IStep) {
checkForDependenciesValid((IStep)candidate, context);
}
// Will contain the list of affected groupables from the whole list
List<IStepGroupable> affectedGroupables = new ArrayList<IStepGroupable>();
// 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)) {
IStepGroupable groupable = new StepGroupable(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 (IStepGroupable step : affectedGroupables) {
if (!(step instanceof StepGroupable)) {
continue;
}
StepGroupable groupable = (StepGroupable)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());
}
if (reference.isSavePoint() && !groupable.isSavePoint()) {
groupable.setIsSavePoint(reference.isSavePoint());
}
if (reference.isOptional() && !groupable.isOptional()) {
groupable.setOptional(reference.isOptional());
}
}
}
return !steps.isEmpty() ? steps.toArray(new IStepGroupable[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.AbstractStepGroup#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<IStepGroupIterator>(config) {
@Override
protected String getExecutableExtensionAttributeName() {
return "iterator"; //$NON-NLS-1$
}
};
}
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 if 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 context The context. Must not be <code>null</code>.
*
* @throws CoreException If a required step or step group is not available or not valid.
*/
protected void checkForDependenciesValid(IStep step, IStepContext context) throws CoreException {
Assert.isNotNull(step);
Assert.isNotNull(context);
String[] dependencies = step.getDependencies();
for (String dependency : dependencies) {
IExecutableExtension candidate = getCandidate(dependency, null);
// 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.StepGroup_error_missingRequiredStep,
NLS.bind(Messages.StepGroup_error_step, step.getLabel()),
NLS.bind(Messages.StepGroup_error_requiredStepOrGroup, dependency))
));
}
}
}
/**
* Returns a candidate for the given reference.
* @param reference The reference.
* @return The candidate. Can be either an IStep or IStepGroup.
*/
protected IExecutableExtension getCandidate(String id, ReferenceSubElement reference) {
Assert.isNotNull(id);
IExecutableExtension candidate = StepperManager.getInstance().getStepExtManager().getStep(id, true);
Map<String,String> parameters = new HashMap<String, String>();
parameters.putAll(getParameters());
if (reference != null) {
parameters.putAll(reference.getParameters());
}
if (candidate == null) {
candidate = StepperManager.getInstance().getStepGroupExtManager().getStepGroup(id, true);
((IStepGroup)candidate).setParameters(parameters);
}
else if (reference != null && candidate instanceof IStep) {
((IStep)candidate).setParameters(parameters);
}
return candidate;
}
/**
* Returns if or if not the reference is valid for the given contexts.
*
* @param reference The reference. Must not be <code>null</code>.
* @param context The context or <code>null</code>.
*
* @return <code>True</code> if the step is valid, <code>false</code> otherwise.
*/
protected boolean isValidReference(ReferenceSubElement reference, IStepContext context) {
Assert.isNotNull(reference);
// Get the enablement.
Expression enablement = reference.getEnablement();
if (enablement != null) {
if (context != null) {
// Set the default variable to the context.
EvaluationContext evalContext = new EvaluationContext(null, context.getContextObject());
// Initialize the evaluation context named variables
evalContext.addVariable("context", context); //$NON-NLS-1$
evalContext.addVariable("id", context.getId()); //$NON-NLS-1$
// Allow plugin activation
evalContext.setAllowPluginActivation(true);
// Evaluate the expression
try {
return enablement.evaluate(evalContext).equals(EvaluationResult.TRUE);
} catch (CoreException e) {
IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(),
e.getLocalizedMessage(), e);
Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status);
}
}
return false;
}
return true;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup#getStepGroupIterator()
*/
@Override
public IStepGroupIterator getStepGroupIterator() {
return iteratorProxy != null ? iteratorProxy.newInstance() : null;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup#setParameters(java.util.Map)
*/
@Override
public void setParameters(Map<String,String> parameters) {
if (parameters != null) {
this.parameters = parameters;
}
else {
this.parameters = Collections.EMPTY_MAP;
}
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.stepper.interfaces.IStepGroup#getParameters()
*/
@Override
public Map<String, String> getParameters() {
return parameters;
}
}