blob: a2f7e8a561f43bdac1bebb44e45642b99c373f1b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2012 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.ui.viewmodel.expression;
import java.util.List;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
/**
* Base class for VM Nodes which can be used in the expressions view.
* <p>
* This base class uses the methods {@link #canParseExpression(IExpression)} and
* {@link #update(IChildrenUpdate[])} to implement the
* {@link IExpressionVMNode#update(IExpressionUpdate)}
* method. Two additional abstract protected methods need to be implemented
* by the sub-class as well.
* </p>
*/
public abstract class AbstractExpressionVMNode extends AbstractDMVMNode implements IExpressionVMNode {
/**
* @since 2.0
*/
protected static final String PROP_ELEMENT_EXPRESSION = "element_expression"; //$NON-NLS-1$
public AbstractExpressionVMNode(AbstractDMVMProvider provider, DsfSession session,
Class<? extends IDMContext> dmcClassType) {
super(provider, session, dmcClassType);
}
@Override
public void update(final IExpressionUpdate update) {
if (!canParseExpression(update.getExpression())) {
// This method should not be called if canParseExpression() returns false.
// Return an internal error status.
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
"Cannot parse expression", null)); //$NON-NLS-1$
update.done();
return;
}
// Retrieve the list of all elements from the sub-class. Then compare
// each returned element to the expression in the update, using
// testElementForExpression(). The element that matches the expression
// is returned to the client.
// If no matching element is found, the createInvalidExpressionVMContext()
// method is called to a special context.
update(new IChildrenUpdate[] {
new VMChildrenUpdate(update, -1, -1, new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
@Override
protected void handleSuccess() {
if (getData().size() == 0) {
update.setExpressionElement(createInvalidExpressionVMContext(update.getExpression()));
update.done();
} else {
final List<Object> elements = getData();
final MultiRequestMonitor<DataRequestMonitor<Boolean>> multiRm = new MultiRequestMonitor<>(
getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isSuccess()) {
boolean foundMatchingContext = false;
for (int i = 0; i < getRequestMonitors().size(); i++) {
if (getRequestMonitors().get(i).getData()) {
Object element = elements.get(i);
associateExpression(element, update.getExpression());
update.setExpressionElement(element);
foundMatchingContext = true;
break;
}
}
if (!foundMatchingContext) {
update.setExpressionElement(
createInvalidExpressionVMContext(update.getExpression()));
}
} else {
update.setStatus(getStatus());
}
update.done();
}
};
multiRm.requireDoneAdding();
for (Object element : elements) {
testElementForExpression(element, update.getExpression(),
multiRm.add(new DataRequestMonitor<Boolean>(getExecutor(), null) {
@Override
protected void handleCompleted() {
multiRm.requestMonitorDone(this);
}
}));
}
multiRm.doneAdding();
}
}
@Override
protected void handleFailure() {
update.setStatus(getStatus());
update.done();
}
}) });
}
/**
* Tests whether the given element matches the given expression.
*
* @param element Element to test against the given expression.
* @param expression Expression to use to check if the element is matching.
* @param rm The request monitor for the result.
*/
@ConfinedToDsfExecutor("#getSession#getExecutor")
protected void testElementForExpression(Object element, IExpression expression,
final DataRequestMonitor<Boolean> rm) {
rm.setData(false);
rm.done();
}
/**
* Sets the given expression as the expression belonging to the given
* element.
* <p>
* This base class creates VM context elements using the extending class's
* {@link #update(IChildrenUpdate[])} method. The element matching the
* expression is found using {@link #testElementForExpression(Object, IExpression, DataRequestMonitor)}.
* Once the matching element is found it needs to be linked to the expression
* so that it can be distinguished from other contexts created for identical
* but distinct expressions. This method accomplishes this task. Elements
* which are associated with expressions should use the expression object
* for implementation of {@link #equals(Object)} and {@link #hashCode()}
* methods.
* </p>
*
* @param element
* @param expression
*/
protected void associateExpression(Object element, IExpression expression) {
}
/**
* Create a place holder for an invalid expression. If for a given expression,
* this VM node returns true from {@link #canParseExpression(IExpression)}, which
* indicates that the expression matches the node's expected format, but the node
* then is not able to find the element represented by the expression, then an
* "invalid" expression context needs to be created.
* <p>
* This method can be overriden to provide a node-specific invalid expression
* context.
* </p>
*
* @param expression Expression to create the context for.
* @return Returns a VM context object representing an invalid expression with
*
* @since 1.1
*/
protected IVMContext createInvalidExpressionVMContext(IExpression expression) {
return new InvalidExpressionVMContext(this, expression);
}
}