mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bugzilla 205603 & 221899.
This commit is contained in:
parent
34baaa437d
commit
b80e85ffde
28 changed files with 2988 additions and 112 deletions
|
@ -71,7 +71,11 @@ public class StackFramesVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(IStack.class, null, update)) return;
|
|
||||||
|
if ( getServicesTracker().getService(IStack.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
|
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
|
||||||
if (execDmc == null) {
|
if (execDmc == null) {
|
||||||
|
@ -88,7 +92,10 @@ public class StackFramesVMNode extends AbstractDMVMNode
|
||||||
// Failed to retrieve frames. If we are stepping, we
|
// Failed to retrieve frames. If we are stepping, we
|
||||||
// might still be able to retrieve just the top stack
|
// might still be able to retrieve just the top stack
|
||||||
// frame, which would still be useful in Debug View.
|
// frame, which would still be useful in Debug View.
|
||||||
if (!checkService(IRunControl.class, null, update)) return;
|
if ( getServicesTracker().getService(IRunControl.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
|
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
|
||||||
getElementsTopStackFrameOnly(update);
|
getElementsTopStackFrameOnly(update);
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,8 +128,11 @@ public class StackFramesVMNode extends AbstractDMVMNode
|
||||||
try {
|
try {
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
getSession().getExecutor().execute(new DsfRunnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!checkService(IStack.class, null, update)) return;
|
if ( getServicesTracker().getService(IStack.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getServicesTracker().getService(IStack.class).getTopFrame(
|
getServicesTracker().getService(IStack.class).getTopFrame(
|
||||||
execDmc,
|
execDmc,
|
||||||
new DataRequestMonitor<IFrameDMContext>(getExecutor(), null) {
|
new DataRequestMonitor<IFrameDMContext>(getExecutor(), null) {
|
||||||
|
@ -173,7 +183,16 @@ public class StackFramesVMNode extends AbstractDMVMNode
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
|
final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
|
||||||
if (!checkDmc(dmc, update) || !checkService(IStack.class, null, update)) continue;
|
|
||||||
|
if ( dmc == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( getServicesTracker().getService(IStack.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getDMVMProvider().getModelData(
|
getDMVMProvider().getModelData(
|
||||||
this, update,
|
this, update,
|
||||||
|
|
|
@ -42,7 +42,11 @@ public class ModulesVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(IModules.class, null, update)) return;
|
|
||||||
|
if ( getServicesTracker().getService(IModules.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ;
|
final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ;
|
||||||
|
|
||||||
|
@ -83,7 +87,16 @@ public class ModulesVMNode extends AbstractDMVMNode
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class);
|
final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class);
|
||||||
if (!checkDmc(dmc, update) || !checkService(IModules.class, null, update)) continue;
|
// If either update or service are not valid, fail the update and exit.
|
||||||
|
if ( dmc == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( getServicesTracker().getService(IModules.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented.
|
// Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented.
|
||||||
update.setImageDescriptor(DsfDebugUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0);
|
update.setImageDescriptor(DsfDebugUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.I
|
||||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
|
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
|
||||||
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
|
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
|
||||||
|
import org.eclipse.dd.dsf.debug.service.IMemory;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
||||||
|
@ -69,9 +70,8 @@ import org.eclipse.swt.widgets.Composite;
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
implements IElementEditor, IElementLabelProvider
|
implements IElementEditor, IElementLabelProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
protected class BitFieldVMC extends DMVMContext
|
protected class BitFieldVMC extends DMVMContext
|
||||||
implements IFormattedValueVMContext
|
implements IFormattedValueVMContext
|
||||||
{
|
{
|
||||||
|
@ -271,7 +271,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
|
||||||
|
*/
|
||||||
public void update(final ILabelUpdate[] updates) {
|
public void update(final ILabelUpdate[] updates) {
|
||||||
try {
|
try {
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
getSession().getExecutor().execute(new DsfRunnable() {
|
||||||
|
@ -285,17 +288,25 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the requested label based on the specified column.
|
||||||
|
*/
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
|
|
||||||
if (!checkService(IRegisters.class, null, update)) continue;
|
final IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IBitFieldDMContext.class);
|
final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IBitFieldDMContext.class);
|
||||||
|
|
||||||
getDMVMProvider().getModelData(
|
getDMVMProvider().getModelData(
|
||||||
this, update,
|
this,
|
||||||
getServicesTracker().getService(IRegisters.class),
|
update,
|
||||||
|
regService,
|
||||||
dmc,
|
dmc,
|
||||||
new DataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -422,6 +433,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
|
final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
|
||||||
|
@ -431,9 +446,15 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkService(IRegisters.class, null, update)) return;
|
IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
|
||||||
getServicesTracker().getService(IRegisters.class).getBitFields(
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
regService.getBitFields(
|
||||||
regDmc,
|
regDmc,
|
||||||
new DataRequestMonitor<IBitFieldDMContext[]>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IBitFieldDMContext[]>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -449,11 +470,19 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected IDMVMContext createVMContext(IDMContext dmc) {
|
protected IDMVMContext createVMContext(IDMContext dmc) {
|
||||||
return new BitFieldVMC(dmc);
|
return new BitFieldVMC(dmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlags(Object e) {
|
public int getDeltaFlags(Object e) {
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
|
@ -463,6 +492,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.STATE;
|
return IModelDelta.STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
return IModelDelta.CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
if (e instanceof PropertyChangeEvent &&
|
if (e instanceof PropertyChangeEvent &&
|
||||||
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
||||||
{
|
{
|
||||||
|
@ -472,6 +505,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
// Create a delta that the whole register group has changed.
|
// Create a delta that the whole register group has changed.
|
||||||
|
@ -479,14 +516,17 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof IRegisters.IBitFieldChangedDMEvent) {
|
if (e instanceof IRegisters.IBitFieldChangedDMEvent) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a delta indicating the bit field has changed.
|
* Create a delta indicating the bit field has changed.
|
||||||
*/
|
*/
|
||||||
parentDelta.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
|
parentDelta.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof PropertyChangeEvent &&
|
if (e instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e instanceof PropertyChangeEvent &&
|
||||||
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
||||||
{
|
{
|
||||||
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
|
@ -495,6 +535,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
|
||||||
|
*/
|
||||||
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
||||||
|
|
||||||
if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
|
if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
|
||||||
|
@ -541,6 +585,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
|
||||||
|
*/
|
||||||
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -628,6 +676,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
||||||
if (!(element instanceof IDMVMContext)) {
|
if (!(element instanceof IDMVMContext)) {
|
||||||
|
@ -670,6 +722,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void associateExpression(Object element, IExpression expression) {
|
protected void associateExpression(Object element, IExpression expression) {
|
||||||
if (element instanceof BitFieldVMC) {
|
if (element instanceof BitFieldVMC) {
|
||||||
|
@ -677,33 +733,56 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
||||||
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event instanceof PropertyChangeEvent &&
|
if (event instanceof PropertyChangeEvent &&
|
||||||
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) {
|
||||||
{
|
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
return IModelDelta.CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
|
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
|
||||||
{
|
{
|
||||||
if (event instanceof ISuspendedDMEvent) {
|
if (event instanceof ISuspendedDMEvent) {
|
||||||
// Mark the parent delta indicating that elements were added and/or removed.
|
// Mark the parent delta indicating that elements were added and/or removed.
|
||||||
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
} else if (event instanceof IRegisters.IRegisterChangedDMEvent) {
|
}
|
||||||
|
else if (event instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
}
|
}
|
||||||
|
else if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
|
}
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
||||||
{
|
{
|
||||||
|
if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
parentDelta.addNode(element, IModelDelta.STATE);
|
||||||
|
}
|
||||||
|
|
||||||
if (event instanceof IBitFieldChangedDMEvent) {
|
if (event instanceof IBitFieldChangedDMEvent) {
|
||||||
parentDelta.addNode(element, IModelDelta.STATE);
|
parentDelta.addNode(element, IModelDelta.STATE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@ import org.eclipse.swt.widgets.Composite;
|
||||||
public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
implements IElementEditor, IElementLabelProvider
|
implements IElementEditor, IElementLabelProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
protected class RegisterGroupVMC extends DMVMContext
|
protected class RegisterGroupVMC extends DMVMContext
|
||||||
{
|
{
|
||||||
private IExpression fExpression;
|
private IExpression fExpression;
|
||||||
|
@ -134,10 +133,21 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
return fSyncRegisterDataAccess;
|
return fSyncRegisterDataAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(IRegisters.class, null, update)) return;
|
|
||||||
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
|
IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
regService.getRegisterGroups(
|
||||||
createCompositeDMVMContext(update),
|
createCompositeDMVMContext(update),
|
||||||
new DataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,12 +161,19 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected IDMVMContext createVMContext(IDMContext dmc) {
|
protected IDMVMContext createVMContext(IDMContext dmc) {
|
||||||
return new RegisterGroupVMC(dmc);
|
return new RegisterGroupVMC(dmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
|
||||||
|
*/
|
||||||
public void update(final ILabelUpdate[] updates) {
|
public void update(final ILabelUpdate[] updates) {
|
||||||
try {
|
try {
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
getSession().getExecutor().execute(new DsfRunnable() {
|
||||||
|
@ -170,15 +187,28 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the labels with the required information for each visible column.
|
||||||
|
*/
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
|
|
||||||
final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class);
|
final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class);
|
||||||
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue;
|
if ( dmc == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
getDMVMProvider().getModelData(
|
getDMVMProvider().getModelData(
|
||||||
this, update,
|
this,
|
||||||
getServicesTracker().getService(IRegisters.class, null),
|
update,
|
||||||
|
regService,
|
||||||
dmc,
|
dmc,
|
||||||
new DataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -214,6 +244,9 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Based on the specified visible column, provide the appropriate value/label.
|
||||||
|
*/
|
||||||
protected void fillColumnLabel(IRegisterGroupDMContext dmContext, IRegisterGroupDMData dmData,
|
protected void fillColumnLabel(IRegisterGroupDMContext dmContext, IRegisterGroupDMData dmData,
|
||||||
String columnId, int idx, ILabelUpdate update)
|
String columnId, int idx, ILabelUpdate update)
|
||||||
{
|
{
|
||||||
|
@ -247,7 +280,11 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER_GROUP), idx);
|
update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER_GROUP), idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlags(Object e) {
|
public int getDeltaFlags(Object e) {
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
|
@ -261,6 +298,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
// Create a delta that indicates all groups have changed
|
// Create a delta that indicates all groups have changed
|
||||||
|
@ -277,6 +318,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#canParseExpression(org.eclipse.debug.core.model.IExpression)
|
||||||
|
*/
|
||||||
public boolean canParseExpression(IExpression expression) {
|
public boolean canParseExpression(IExpression expression) {
|
||||||
return parseExpressionForGroupName(expression.getExpressionText()) != null;
|
return parseExpressionForGroupName(expression.getExpressionText()) != null;
|
||||||
}
|
}
|
||||||
|
@ -298,6 +343,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
||||||
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
|
@ -306,6 +355,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
|
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
|
||||||
TreePath path, RequestMonitor rm)
|
TreePath path, RequestMonitor rm)
|
||||||
{
|
{
|
||||||
|
@ -316,6 +369,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
||||||
{
|
{
|
||||||
if (event instanceof IRegisters.IGroupsChangedDMEvent) {
|
if (event instanceof IRegisters.IGroupsChangedDMEvent) {
|
||||||
|
@ -327,6 +384,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
||||||
if (!(element instanceof IDMVMContext)) {
|
if (!(element instanceof IDMVMContext)) {
|
||||||
|
@ -368,6 +429,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void associateExpression(Object element, IExpression expression) {
|
protected void associateExpression(Object element, IExpression expression) {
|
||||||
if (element instanceof RegisterGroupVMC) {
|
if (element instanceof RegisterGroupVMC) {
|
||||||
|
@ -375,15 +440,22 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
|
||||||
|
*/
|
||||||
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
||||||
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
|
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
|
||||||
return new TextCellEditor(parent);
|
return new TextCellEditor(parent);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
|
||||||
|
*/
|
||||||
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
||||||
return fWatchExpressionCellModifier;
|
return fWatchExpressionCellModifier;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.I
|
||||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.IFormattedValueVMContext;
|
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.IFormattedValueVMContext;
|
||||||
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
|
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
|
||||||
|
import org.eclipse.dd.dsf.debug.service.IMemory;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
||||||
|
@ -159,9 +160,13 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
*/
|
*/
|
||||||
private void updateFormattedRegisterValue(final ILabelUpdate update, final int labelIndex, final IRegisterDMContext dmc)
|
private void updateFormattedRegisterValue(final ILabelUpdate update, final int labelIndex, final IRegisterDMContext dmc)
|
||||||
{
|
{
|
||||||
if (!checkService(IRegisters.class, null, update)) return;
|
|
||||||
|
|
||||||
final IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
final IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First select the format to be used. This involves checking so see that the preference
|
* First select the format to be used. This involves checking so see that the preference
|
||||||
* page format is supported by the register service. If the format is not supported then
|
* page format is supported by the register service. If the format is not supported then
|
||||||
|
@ -259,7 +264,11 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
|
||||||
|
*/
|
||||||
|
|
||||||
public void update(final ILabelUpdate[] updates) {
|
public void update(final ILabelUpdate[] updates) {
|
||||||
try {
|
try {
|
||||||
|
@ -274,15 +283,29 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the labels which are controlled by the column being requested.
|
||||||
|
*/
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
|
|
||||||
final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IRegisterDMContext.class);
|
final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IRegisterDMContext.class);
|
||||||
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue;
|
if ( dmc == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getDMVMProvider().getModelData(
|
getDMVMProvider().getModelData(
|
||||||
this, update,
|
this,
|
||||||
getServicesTracker().getService(IRegisters.class),
|
update,
|
||||||
|
regService,
|
||||||
dmc,
|
dmc,
|
||||||
new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -409,10 +432,21 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(IRegisters.class, null, update)) return;
|
|
||||||
getServicesTracker().getService(IRegisters.class).getRegisters(
|
IRegisters regService = getServicesTracker().getService(IRegisters.class);
|
||||||
|
|
||||||
|
if ( regService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
regService.getRegisters(
|
||||||
createCompositeDMVMContext(update),
|
createCompositeDMVMContext(update),
|
||||||
new DataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), null) {
|
new DataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -427,21 +461,20 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected IDMVMContext createVMContext(IDMContext dmc) {
|
protected IDMVMContext createVMContext(IDMContext dmc) {
|
||||||
return new RegisterVMC(dmc);
|
return new RegisterVMC(dmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlags(Object e) {
|
public int getDeltaFlags(Object e) {
|
||||||
/* In theory we want each node to act independently in terms of events. It might be
|
|
||||||
* the case that we would only have elements of this type at the root level. It is
|
|
||||||
* the case that the current layout model always starts with the GROUPS followed by
|
|
||||||
* REGISTERS followed by BITFIELDS. But if we do this when a run-control event has
|
|
||||||
* occured we generate a DELTA for every element, which can create a massive list
|
|
||||||
* of entries all of which say update the entire view. So for now we will just have
|
|
||||||
* the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
|
|
||||||
* there is a way for the nodes to operate independently and efficiently.
|
|
||||||
*/
|
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
}
|
}
|
||||||
|
@ -450,10 +483,14 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
return IModelDelta.CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
/*
|
/*
|
||||||
* Logically one would think that STATE should be specified here. But we specifiy CONTENT
|
* Logically one would think that STATE should be specified here. But we specify CONTENT
|
||||||
* as well so that if there are subregisters ( BIT FIELDS ) they will be forced to update
|
* as well so that if there are sub-registers ( BIT FIELDS ) they will be forced to update
|
||||||
* and show new values when the total register changes.
|
* and show new values when the total register changes.
|
||||||
*/
|
*/
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
|
@ -467,6 +504,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
// Create a delta that the whole register group has changed.
|
// Create a delta that the whole register group has changed.
|
||||||
|
@ -477,6 +518,11 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);;
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
// Mark the parent delta indicating that elements were added and/or removed.
|
||||||
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
|
parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
|
||||||
}
|
}
|
||||||
|
@ -539,6 +585,11 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
|
||||||
if (!(element instanceof IDMVMContext)) {
|
if (!(element instanceof IDMVMContext)) {
|
||||||
|
@ -580,6 +631,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void associateExpression(Object element, IExpression expression) {
|
protected void associateExpression(Object element, IExpression expression) {
|
||||||
if (element instanceof RegisterVMC) {
|
if (element instanceof RegisterVMC) {
|
||||||
|
@ -587,6 +642,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
|
||||||
|
*/
|
||||||
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
|
||||||
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
if (event instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
|
@ -597,9 +656,17 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
return IModelDelta.CONTENT;
|
return IModelDelta.CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
return IModelDelta.CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
return IModelDelta.NO_CHANGE;
|
return IModelDelta.NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
|
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
|
||||||
TreePath path, RequestMonitor rm)
|
TreePath path, RequestMonitor rm)
|
||||||
{
|
{
|
||||||
|
@ -607,9 +674,18 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
// Mark the parent delta indicating that elements were added and/or removed.
|
// Mark the parent delta indicating that elements were added and/or removed.
|
||||||
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
|
||||||
|
*/
|
||||||
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
|
||||||
{
|
{
|
||||||
if (event instanceof IRegisters.IRegisterChangedDMEvent) {
|
if (event instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
|
@ -620,6 +696,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
parentDelta.addNode(element, IModelDelta.STATE);
|
parentDelta.addNode(element, IModelDelta.STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event instanceof IMemory.IMemoryChangedEvent) {
|
||||||
|
parentDelta.addNode(element, IModelDelta.CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
if (event instanceof PropertyChangeEvent &&
|
if (event instanceof PropertyChangeEvent &&
|
||||||
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
|
||||||
{
|
{
|
||||||
|
@ -629,7 +709,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
|
||||||
|
*/
|
||||||
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
|
||||||
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
|
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
|
||||||
return new TextCellEditor(parent);
|
return new TextCellEditor(parent);
|
||||||
|
@ -648,6 +731,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
|
||||||
|
*/
|
||||||
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
|
||||||
return new RegisterCellModifier(
|
return new RegisterCellModifier(
|
||||||
getDMVMProvider(), fFormattedPrefStore, fSyncRegisterDataAccess );
|
getDMVMProvider(), fFormattedPrefStore, fSyncRegisterDataAccess );
|
||||||
|
|
|
@ -68,10 +68,10 @@ import org.eclipse.swt.widgets.Composite;
|
||||||
|
|
||||||
@SuppressWarnings({"restriction", "nls"})
|
@SuppressWarnings({"restriction", "nls"})
|
||||||
public class VariableVMNode extends AbstractExpressionVMNode
|
public class VariableVMNode extends AbstractExpressionVMNode
|
||||||
implements IElementEditor, IElementLabelProvider
|
implements IElementEditor, IElementLabelProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
private final static int MAX_STRING_VALUE_LENGTH = 40;
|
//private final static int MAX_STRING_VALUE_LENGTH = 40;
|
||||||
|
|
||||||
public int getDeltaFlags(Object e) {
|
public int getDeltaFlags(Object e) {
|
||||||
/*
|
/*
|
||||||
|
@ -408,11 +408,9 @@ public class VariableVMNode extends AbstractExpressionVMNode
|
||||||
update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
|
update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
|
||||||
|
|
||||||
// Color based on change history
|
// Color based on change history
|
||||||
FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(
|
FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, valueDmc);
|
||||||
VariableVMNode.this, update, valueDmc);
|
|
||||||
|
|
||||||
IExpressionDMData oldDMData = (IExpressionDMData) getDMVMProvider().getArchivedModelData(
|
IExpressionDMData oldDMData = (IExpressionDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, dmc);
|
||||||
VariableVMNode.this, update, dmc);
|
|
||||||
/* Commented out, to be replaced. See bug 225612.
|
/* Commented out, to be replaced. See bug 225612.
|
||||||
String oldStringValue = oldDMData == null ? null : oldDMData.getStringValue();*/
|
String oldStringValue = oldDMData == null ? null : oldDMData.getStringValue();*/
|
||||||
|
|
||||||
|
@ -421,9 +419,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
|
||||||
/* Commented out, to be replaced. See bug 225612.
|
/* Commented out, to be replaced. See bug 225612.
|
||||||
|| (oldStringValue != null && !oldStringValue.equals(stringValue))) {*/
|
|| (oldStringValue != null && !oldStringValue.equals(stringValue))) {*/
|
||||||
update.setBackground(
|
update.setBackground(
|
||||||
DebugUIPlugin.getPreferenceColor(
|
DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(), labelIndex);
|
||||||
IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(),
|
|
||||||
labelIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update.done();
|
update.done();
|
||||||
|
|
|
@ -182,8 +182,25 @@ abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode
|
||||||
* appropriate error message is set in the update.
|
* appropriate error message is set in the update.
|
||||||
* @param dmc Data Model Context (DMC) to check.
|
* @param dmc Data Model Context (DMC) to check.
|
||||||
* @param update Update to handle in case the DMC is null.
|
* @param update Update to handle in case the DMC is null.
|
||||||
* @return true if the DMC is NOT null, indicating that it's OK to proceed.
|
* @return true if the DMC is NOT null, indicating that it's OK to proceed.
|
||||||
|
*
|
||||||
|
* This method has been deprecated. Users should simply perform this functionality in-line
|
||||||
|
*
|
||||||
|
* Example :
|
||||||
|
*
|
||||||
|
* IExampleDmc dmc = final TimerDMContext dmc = findDmcInPath(...)
|
||||||
|
* if ( dmc == null ) {
|
||||||
|
* handleFailedUpdate(update);
|
||||||
|
* //
|
||||||
|
* // Perform whatever cleanup or completion is needed because of a lack of
|
||||||
|
* // a valid data model context.
|
||||||
|
* //
|
||||||
|
* ........
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
|
protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
|
||||||
if (dmc == null) {
|
if (dmc == null) {
|
||||||
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
|
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
|
||||||
|
@ -200,7 +217,21 @@ abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode
|
||||||
* @param serviceClass Service class to find.
|
* @param serviceClass Service class to find.
|
||||||
* @param filter Service filter to use in addition to the service class name.
|
* @param filter Service filter to use in addition to the service class name.
|
||||||
* @param update Update object to fill in.
|
* @param update Update object to fill in.
|
||||||
* @return true if service IS found, indicating that it's OK to proceed.
|
* @return true if service IS found, indicating that it's OK to proceed.
|
||||||
|
*
|
||||||
|
* This method has been deprecated. Users should simply perform this functionality in-line
|
||||||
|
*
|
||||||
|
* Example :
|
||||||
|
*
|
||||||
|
* IExampleService service = getServicesTracker().getService(IExampleService.class,null);
|
||||||
|
* if ( service == null ) {
|
||||||
|
* handleFailedUpdate(update);
|
||||||
|
* //
|
||||||
|
* // Perform whatever cleanup or completion is needed because of a lack of the service.
|
||||||
|
* //
|
||||||
|
* ........
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {
|
protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {
|
||||||
|
|
|
@ -0,0 +1,272 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.Query;
|
||||||
|
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
|
||||||
|
import org.eclipse.jface.viewers.ILazyContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.TableViewer;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Font;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
import org.eclipse.swt.widgets.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data viewer based on a table, which reads data using asynchronous methods.
|
||||||
|
* <p>
|
||||||
|
* This viewer implements the {@link ILazyContentProvider} interface
|
||||||
|
* which is used by the JFace TableViewer class to populate a Table. This
|
||||||
|
* interface contains separate asynchronous methods for requesting the count
|
||||||
|
* and values for individual indexes, which neatly correspond to the methods
|
||||||
|
* in {@link IDataGenerator}. As an added optimization, this viewer
|
||||||
|
* implementation checks for the range of visible items in the view upon each
|
||||||
|
* request, and it cancels old requests which scroll out of view but have not
|
||||||
|
* been completed yet. However, it is up to the data generator implementation
|
||||||
|
* to check the canceled state of the requests and ignore them.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@ConfinedToDsfExecutor("fDisplayExecutor")
|
||||||
|
public class AsyncDataViewer
|
||||||
|
implements ILazyContentProvider, IDataGenerator.Listener
|
||||||
|
{
|
||||||
|
// Executor to use instead of Display.asyncExec().
|
||||||
|
@ThreadSafe
|
||||||
|
final private DsfExecutor fDisplayExecutor;
|
||||||
|
|
||||||
|
// The viewer and generator that this content provider using.
|
||||||
|
final private TableViewer fViewer;
|
||||||
|
final private IDataGenerator fDataGenerator;
|
||||||
|
|
||||||
|
// Fields used in request cancellation logic.
|
||||||
|
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
|
||||||
|
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
|
||||||
|
private int fCancelCallsPending = 0;
|
||||||
|
|
||||||
|
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
|
||||||
|
fViewer = viewer;
|
||||||
|
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
|
||||||
|
fDataGenerator = generator;
|
||||||
|
fDataGenerator.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
fDataGenerator.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// Set the initial count to the viewer after the input is set.
|
||||||
|
queryItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateElement(final int index) {
|
||||||
|
// Calculate the visible index range.
|
||||||
|
final int topIdx = fViewer.getTable().getTopIndex();
|
||||||
|
final int botIdx = topIdx + getVisibleItemCount(topIdx);
|
||||||
|
|
||||||
|
// Request the item for the given index.
|
||||||
|
queryValue(index);
|
||||||
|
|
||||||
|
// Invoke a cancel task with a delay. The delay allows multiple cancel
|
||||||
|
// calls to be combined together improving performance of the viewer.
|
||||||
|
fCancelCallsPending++;
|
||||||
|
fDisplayExecutor.schedule(
|
||||||
|
new Runnable() { public void run() {
|
||||||
|
cancelStaleRequests(topIdx, botIdx);
|
||||||
|
}},
|
||||||
|
1, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getVisibleItemCount(int top) {
|
||||||
|
Table table = fViewer.getTable();
|
||||||
|
int itemCount = table.getItemCount();
|
||||||
|
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
public void countChanged() {
|
||||||
|
queryItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
public void valuesChanged(final Set<Integer> indexes) {
|
||||||
|
// Mark the changed items in table viewer as dirty, this will
|
||||||
|
// trigger update requests for these indexes if they are
|
||||||
|
// visible in the viewer.
|
||||||
|
final TableViewer tableViewer = fViewer;
|
||||||
|
fDisplayExecutor.execute( new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
for (Integer index : indexes) {
|
||||||
|
tableViewer.clear(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void queryItemCount() {
|
||||||
|
// Request count from data provider. When the count is returned, we
|
||||||
|
// have to re-dispatch into the display thread to avoid calling
|
||||||
|
// the table widget on the DSF dispatch thread.
|
||||||
|
fIndexesToCancel.clear();
|
||||||
|
fDataGenerator.getCount(
|
||||||
|
// Use the display executor to construct the request monitor, this
|
||||||
|
// will cause the handleCompleted() method to be automatically
|
||||||
|
// called on the display thread.
|
||||||
|
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
fViewer.setItemCount(getData());
|
||||||
|
fViewer.getTable().clearAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dedicated class for data item requests. This class holds the index
|
||||||
|
// argument so it can be examined when canceling stale requests.
|
||||||
|
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
|
||||||
|
|
||||||
|
/** Index is used when canceling stale requests. */
|
||||||
|
int fIndex;
|
||||||
|
|
||||||
|
ValueDataRequestMonitor(int index) {
|
||||||
|
super(fDisplayExecutor, null);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
fItemDataRequestMonitors.remove(this);
|
||||||
|
|
||||||
|
// Check if the request completed successfully, otherwise ignore it.
|
||||||
|
if (isSuccess()) {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
fViewer.replace(getData(), fIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryValue(final int index) {
|
||||||
|
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
|
||||||
|
fItemDataRequestMonitors.add(rm);
|
||||||
|
fDataGenerator.getValue(index, rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelStaleRequests(int topIdx, int botIdx) {
|
||||||
|
// Decrement the count of outstanding cancel calls.
|
||||||
|
fCancelCallsPending--;
|
||||||
|
|
||||||
|
// Must check again, in case disposed while re-dispatching.
|
||||||
|
if (fDataGenerator == null || fViewer.getTable().isDisposed()) return;
|
||||||
|
|
||||||
|
// Go through the outstanding requests and cancel any that
|
||||||
|
// are not visible anymore.
|
||||||
|
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
|
||||||
|
ValueDataRequestMonitor item = itr.next();
|
||||||
|
if (item.fIndex < topIdx || item.fIndex > botIdx) {
|
||||||
|
// Set the item to canceled status, so that the data provider
|
||||||
|
// will ignore it.
|
||||||
|
item.cancel();
|
||||||
|
|
||||||
|
// Add the item index to list of indexes that were canceled,
|
||||||
|
// which will be sent to the table widget.
|
||||||
|
fIndexesToCancel.add(item.fIndex);
|
||||||
|
|
||||||
|
// Remove the item from the outstanding cancel requests.
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
|
||||||
|
Set<Integer> canceledIdxs = fIndexesToCancel;
|
||||||
|
fIndexesToCancel = new HashSet<Integer>();
|
||||||
|
|
||||||
|
// Clear the indexes of the canceled request, so that the
|
||||||
|
// viewer knows to request them again when needed.
|
||||||
|
// Note: clearing using TableViewer.clear(int) seems very
|
||||||
|
// inefficient, it's better to use Table.clear(int[]).
|
||||||
|
int[] canceledIdxsArray = new int[canceledIdxs.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Integer index : canceledIdxs) {
|
||||||
|
canceledIdxsArray[i++] = index;
|
||||||
|
}
|
||||||
|
fViewer.getTable().clear(canceledIdxsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create the shell to hold the viewer.
|
||||||
|
Display display = new Display();
|
||||||
|
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||||
|
shell.setLayout(new GridLayout());
|
||||||
|
GridData data = new GridData(GridData.FILL_BOTH);
|
||||||
|
shell.setLayoutData(data);
|
||||||
|
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||||
|
|
||||||
|
// Create the table viewer.
|
||||||
|
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||||
|
tableViewer.getControl().setLayoutData(data);
|
||||||
|
|
||||||
|
// Create the data generator.
|
||||||
|
final IDataGenerator generator = new DataGeneratorWithExecutor();
|
||||||
|
|
||||||
|
// Create the content provider which will populate the viewer.
|
||||||
|
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
|
||||||
|
tableViewer.setContentProvider(contentProvider);
|
||||||
|
tableViewer.setInput(new Object());
|
||||||
|
|
||||||
|
// Open the shell and service the display dispatch loop until user
|
||||||
|
// closes the shell.
|
||||||
|
shell.open();
|
||||||
|
while (!shell.isDisposed()) {
|
||||||
|
if (!display.readAndDispatch())
|
||||||
|
display.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||||
|
// using a query again in order to wait for its completion.
|
||||||
|
Query<Object> shutdownQuery = new Query<Object>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Object> rm) {
|
||||||
|
generator.shutdown(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(shutdownQuery);
|
||||||
|
try {
|
||||||
|
shutdownQuery.get();
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
// Shut down the display.
|
||||||
|
font.dispose();
|
||||||
|
display.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006 Wind River Systems 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.dd.examples.dsf.dataviewer;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DSF Executor-based implementation of the data generator.
|
||||||
|
* <p>
|
||||||
|
* This generator uses a queue of client requests and processes these
|
||||||
|
* requests periodically using a DSF executor. The main feature of this
|
||||||
|
* generator is that it uses the executor as its only synchronization object.
|
||||||
|
* This means that all the fields with the exception of the executor can only
|
||||||
|
* be accessed while running in the executor thread.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
//TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
//indicating allowed thread access to this class/method/member
|
||||||
|
public class DataGeneratorWithExecutor implements IDataGenerator {
|
||||||
|
|
||||||
|
// Request objects are used to serialize the interface calls into objects
|
||||||
|
// which can then be pushed into a queue.
|
||||||
|
// TODO Ecercise 4 - Add an annotationindicating allowed concurrency access
|
||||||
|
// Hint: Request and its subclasses have all their fields declared as final.
|
||||||
|
abstract class Request {
|
||||||
|
final RequestMonitor fRequestMonitor;
|
||||||
|
|
||||||
|
Request(RequestMonitor rm) {
|
||||||
|
fRequestMonitor = rm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
class CountRequest extends Request {
|
||||||
|
CountRequest(DataRequestMonitor<Integer> rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
class ItemRequest extends Request {
|
||||||
|
final int fIndex;
|
||||||
|
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||||
|
super(rm);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The executor used to access all internal data of the generator.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
// Hint: If a member does not have an annotation, the programmer can assume
|
||||||
|
// that the concurrency rule that applies to the class also applies to this
|
||||||
|
// member.
|
||||||
|
private DsfExecutor fExecutor;
|
||||||
|
|
||||||
|
// Main request queue of the data generator. The getValue(), getCount(),
|
||||||
|
// and shutdown() methods write into the queue, while the serviceQueue()
|
||||||
|
// method reads from it.
|
||||||
|
// The executor used to access all internal data of the generator.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private List<Request> fQueue = new LinkedList<Request>();
|
||||||
|
|
||||||
|
// List of listeners is not synchronized, it also has to be accessed
|
||||||
|
// using the executor.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private List<Listener> fListeners = new LinkedList<Listener>();
|
||||||
|
|
||||||
|
// Current number of elements in this generator.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private int fCount = MIN_COUNT;
|
||||||
|
|
||||||
|
// Counter used to determine when to reset the element count.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private int fCountResetTrigger = 0;
|
||||||
|
|
||||||
|
// Elements which were modified since the last reset.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
|
||||||
|
|
||||||
|
// Flag used to ensure that requests are processed sequentially.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private boolean fServiceQueueInProgress = false;
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public DataGeneratorWithExecutor() {
|
||||||
|
// Create the executor
|
||||||
|
fExecutor = new DefaultDsfExecutor("Supplier Executor");
|
||||||
|
|
||||||
|
// Schedule a runnable to make the random changes.
|
||||||
|
fExecutor.scheduleAtFixedRate(
|
||||||
|
new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
randomChanges();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RANDOM_CHANGE_INTERVAL,
|
||||||
|
RANDOM_CHANGE_INTERVAL,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public void shutdown(final RequestMonitor rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
// Empty the queue of requests and fail them.
|
||||||
|
for (Request request : fQueue) {
|
||||||
|
request.fRequestMonitor.setStatus(
|
||||||
|
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
request.fRequestMonitor.done();
|
||||||
|
}
|
||||||
|
fQueue.clear();
|
||||||
|
|
||||||
|
// Kill executor.
|
||||||
|
fExecutor.shutdown();
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public void getCount(final DataRequestMonitor<Integer> rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fQueue.add(new CountRequest(rm));
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public void getValue(final int index, final DataRequestMonitor<String> rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fQueue.add(new ItemRequest(index, rm));
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public void addListener(final Listener listener) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fListeners.add(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public void removeListener(final Listener listener) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fListeners.remove(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main processing function of this generator.
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void serviceQueue() {
|
||||||
|
|
||||||
|
// TODO Exercise 3 - Add logic to discard cancelled requests from queue.
|
||||||
|
// Hint: Since serviceQueue() is called using the executor, and the
|
||||||
|
// fQueue list can only be modified when running in the executor
|
||||||
|
// thread. This method can safely iterate and modify fQueue without
|
||||||
|
// risk of race conditions or concurrent modification exceptions.
|
||||||
|
|
||||||
|
// If a queue servicing is already scheduled, do nothing.
|
||||||
|
if (fServiceQueueInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fQueue.size() != 0) {
|
||||||
|
// If there are requests to service, remove one from the queue and
|
||||||
|
// schedule a runnable to process the request after a processing
|
||||||
|
// delay.
|
||||||
|
fServiceQueueInProgress = true;
|
||||||
|
final Request request = fQueue.remove(0);
|
||||||
|
fExecutor.schedule(
|
||||||
|
new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
if (request instanceof CountRequest) {
|
||||||
|
processCountRequest((CountRequest)request);
|
||||||
|
} else if (request instanceof ItemRequest) {
|
||||||
|
processItemRequest((ItemRequest)request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the processing flag and process next
|
||||||
|
// request.
|
||||||
|
fServiceQueueInProgress = false;
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void processCountRequest(CountRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
rm.setData(fCount);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void processItemRequest(ItemRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
if (fChangedIndexes.contains(request.fIndex)) {
|
||||||
|
rm.setData("Changed: " + request.fIndex);
|
||||||
|
} else {
|
||||||
|
rm.setData(Integer.toString(request.fIndex));
|
||||||
|
}
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method simulates changes in the supplier's data set.
|
||||||
|
*/
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void randomChanges() {
|
||||||
|
// Once every number of changes, reset the count, the rest of the
|
||||||
|
// times just change certain values.
|
||||||
|
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
|
||||||
|
randomCountReset();
|
||||||
|
} else {
|
||||||
|
randomDataChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates new size for provider's data set.
|
||||||
|
*/
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void randomCountReset() {
|
||||||
|
// Calculate the new count.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||||
|
|
||||||
|
// Reset the changed values.
|
||||||
|
fChangedIndexes.clear();
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Listener listener : fListeners) {
|
||||||
|
listener.countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates a random range of indexes.
|
||||||
|
*/
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
private void randomDataChange() {
|
||||||
|
// Calculate the indexes to change.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
Set<Integer> set = new HashSet<Integer>();
|
||||||
|
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||||
|
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the indexes to an overall set of changed indexes.
|
||||||
|
fChangedIndexes.addAll(set);
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Listener listener : fListeners) {
|
||||||
|
listener.valuesChanged(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.ListenerList;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-based implementation of the data generator.
|
||||||
|
* <p>
|
||||||
|
* This generator is based around a queue of client requests and a thread which
|
||||||
|
* reads the requests from the queue and processes them. The distinguishing
|
||||||
|
* feature of this generator is that it uses a a blocking queue as the main
|
||||||
|
* synchronization object. However, fListeners, fShutdown, and fChangedIndexes
|
||||||
|
* fields also need to be thread-safe and so they implement their own
|
||||||
|
* synchronization.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
||||||
|
|
||||||
|
// Request objects are used to serialize the interface calls into objects
|
||||||
|
// which can then be pushed into a queue.
|
||||||
|
abstract class Request {
|
||||||
|
final RequestMonitor fRequestMonitor;
|
||||||
|
|
||||||
|
Request(RequestMonitor rm) {
|
||||||
|
fRequestMonitor = rm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CountRequest extends Request {
|
||||||
|
CountRequest(DataRequestMonitor<Integer> rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemRequest extends Request {
|
||||||
|
final int fIndex;
|
||||||
|
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||||
|
super(rm);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShutdownRequest extends Request {
|
||||||
|
ShutdownRequest(RequestMonitor rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main request queue of the data generator. The getValue(), getCount(),
|
||||||
|
// and shutdown() methods write into the queue, while the run() method
|
||||||
|
// reads from it.
|
||||||
|
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
|
||||||
|
|
||||||
|
// ListenerList class provides thread safety.
|
||||||
|
private ListenerList fListeners = new ListenerList();
|
||||||
|
|
||||||
|
// Current number of elements in this generator.
|
||||||
|
private int fCount = MIN_COUNT;
|
||||||
|
|
||||||
|
// Counter used to determine when to reset the element count.
|
||||||
|
private int fCountResetTrigger = 0;
|
||||||
|
|
||||||
|
// Elements which were modified since the last reset.
|
||||||
|
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
|
||||||
|
|
||||||
|
// Used to determine when to make changes in data.
|
||||||
|
private long fLastChangeTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Flag indicating when the generator has been shut down.
|
||||||
|
private AtomicBoolean fShutdown = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public DataGeneratorWithThread() {
|
||||||
|
// Immediately kick off the request processing thread.
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown(RequestMonitor rm) {
|
||||||
|
// Mark the generator as shut down. After the fShutdown flag is set,
|
||||||
|
// all new requests should be shut down.
|
||||||
|
if (!fShutdown.getAndSet(true)) {
|
||||||
|
fQueue.add(new ShutdownRequest(rm));
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getCount(DataRequestMonitor<Integer> rm) {
|
||||||
|
if (!fShutdown.get()) {
|
||||||
|
fQueue.add(new CountRequest(rm));
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getValue(int index, DataRequestMonitor<String> rm) {
|
||||||
|
if (!fShutdown.get()) {
|
||||||
|
fQueue.add(new ItemRequest(index, rm));
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(Listener listener) {
|
||||||
|
fListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(Listener listener) {
|
||||||
|
fListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while(true) {
|
||||||
|
// Get the next request from the queue. The time-out
|
||||||
|
// ensures that that the random changes get processed.
|
||||||
|
final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
// If a request was dequeued, process it.
|
||||||
|
if (request != null) {
|
||||||
|
// Simulate a processing delay.
|
||||||
|
Thread.sleep(PROCESSING_DELAY);
|
||||||
|
|
||||||
|
if (request instanceof CountRequest) {
|
||||||
|
processCountRequest((CountRequest)request);
|
||||||
|
} else if (request instanceof ItemRequest) {
|
||||||
|
processItemRequest((ItemRequest)request);
|
||||||
|
} else if (request instanceof ShutdownRequest) {
|
||||||
|
// If shutting down, just break out of the while(true)
|
||||||
|
// loop and thread will exit.
|
||||||
|
request.fRequestMonitor.done();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate data changes.
|
||||||
|
randomChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException x) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCountRequest(CountRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
rm.setData(fCount);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processItemRequest(ItemRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
if (fChangedIndexes.contains(request.fIndex)) {
|
||||||
|
rm.setData("Changed: " + request.fIndex);
|
||||||
|
} else {
|
||||||
|
rm.setData(Integer.toString(request.fIndex));
|
||||||
|
}
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void randomChanges() {
|
||||||
|
// Check if enough time is elapsed.
|
||||||
|
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
|
||||||
|
fLastChangeTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Once every number of changes, reset the count, the rest of the
|
||||||
|
// times just change certain values.
|
||||||
|
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
|
||||||
|
randomCountReset();
|
||||||
|
} else {
|
||||||
|
randomDataChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void randomCountReset() {
|
||||||
|
// Calculate the new count.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||||
|
|
||||||
|
// Reset the changed values.
|
||||||
|
fChangedIndexes.clear();
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Object listener : fListeners.getListeners()) {
|
||||||
|
((Listener)listener).countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void randomDataChange() {
|
||||||
|
// Calculate the indexes to change.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
Set<Integer> set = new HashSet<Integer>();
|
||||||
|
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||||
|
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the indexes to an overall set of changed indexes.
|
||||||
|
fChangedIndexes.addAll(set);
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Object listener : fListeners.getListeners()) {
|
||||||
|
((Listener)listener).valuesChanged(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data generator is simple source of data used to populate the example table
|
||||||
|
* view. It contains two asynchronous methods for retrieving the data
|
||||||
|
* parameters: the count and the value for a given index. It also allows the
|
||||||
|
* view to receive events indicating when the data supplied by the generator
|
||||||
|
* is changed.
|
||||||
|
*/
|
||||||
|
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||||
|
// indicating allowed thread access to this class/method/member
|
||||||
|
public interface IDataGenerator {
|
||||||
|
|
||||||
|
// Constants which control the data generator behavior.
|
||||||
|
// Changing the count range can stress the scalability of the system, while
|
||||||
|
// changing of the process delay and random change interval can stress
|
||||||
|
// its performance.
|
||||||
|
final static int MIN_COUNT = 100;
|
||||||
|
final static int MAX_COUNT = 200;
|
||||||
|
final static int PROCESSING_DELAY = 10;
|
||||||
|
final static int RANDOM_CHANGE_INTERVAL = 10000;
|
||||||
|
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
|
||||||
|
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
|
||||||
|
|
||||||
|
|
||||||
|
// Listener interface that the view needs to implement to react
|
||||||
|
// to the changes in data.
|
||||||
|
public interface Listener {
|
||||||
|
void countChanged();
|
||||||
|
void valuesChanged(Set<Integer> indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data access methods.
|
||||||
|
void getCount(DataRequestMonitor<Integer> rm);
|
||||||
|
void getValue(int index, DataRequestMonitor<String> rm);
|
||||||
|
|
||||||
|
// Method used to shutdown the data generator including any threads that
|
||||||
|
// it may use.
|
||||||
|
void shutdown(RequestMonitor rm);
|
||||||
|
|
||||||
|
// Methods for registering change listeners.
|
||||||
|
void addListener(Listener listener);
|
||||||
|
void removeListener(Listener listener);
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.dataviewer;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.Query;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.TableViewer;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Font;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data viewer based on a table, which reads data using synchronous methods.
|
||||||
|
* <p>
|
||||||
|
* This viewer implements the {@link IStructuredContentProvider} interface
|
||||||
|
* which is used by the JFace TableViewer class to populate a Table. This
|
||||||
|
* interface contains one principal methods for reading data {@link #getElements(Object)},
|
||||||
|
* which synchronously returns an array of elements. In order to implement this
|
||||||
|
* method using the asynchronous data generator, this provider uses the
|
||||||
|
* {@link Query} object.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class SyncDataViewer
|
||||||
|
implements IStructuredContentProvider, IDataGenerator.Listener
|
||||||
|
{
|
||||||
|
// The viewer and generator that this content provider using.
|
||||||
|
final private TableViewer fViewer;
|
||||||
|
final private IDataGenerator fDataGenerator;
|
||||||
|
|
||||||
|
public SyncDataViewer(TableViewer viewer, IDataGenerator generator) {
|
||||||
|
fViewer = viewer;
|
||||||
|
fDataGenerator = generator;
|
||||||
|
fDataGenerator.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// Not used
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
|
||||||
|
// Create the query object for reading data count.
|
||||||
|
Query<Integer> countQuery = new Query<Integer>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Integer> rm) {
|
||||||
|
fDataGenerator.getCount(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Submit the query to be executed. A query implements a runnable
|
||||||
|
// interface and it has to be executed in order to do its work.
|
||||||
|
ImmediateExecutor.getInstance().execute(countQuery);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// Block until the query completes, which will happen when the request
|
||||||
|
// monitor of the execute() method is marked done.
|
||||||
|
try {
|
||||||
|
count = countQuery.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// InterruptedException and ExecutionException can be thrown here.
|
||||||
|
// ExecutionException containing a CoreException will be thrown
|
||||||
|
// if an error status is set to the Query's request monitor.
|
||||||
|
return new Object[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the array that will be filled with elements.
|
||||||
|
// For each index in the array execute a query to get the element at
|
||||||
|
// that index.
|
||||||
|
final Object[] elements = new Object[count];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final int index = i;
|
||||||
|
Query<String> valueQuery = new Query<String>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<String> rm) {
|
||||||
|
fDataGenerator.getValue(index, rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(valueQuery);
|
||||||
|
try {
|
||||||
|
elements[i] = valueQuery.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
elements[i] = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
fDataGenerator.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void countChanged() {
|
||||||
|
// For any event from the generator, refresh the whole viewer.
|
||||||
|
refreshViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void valuesChanged(Set<Integer> indexes) {
|
||||||
|
// For any event from the generator, refresh the whole viewer.
|
||||||
|
refreshViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshViewer() {
|
||||||
|
// TODO Exercise 5 - Add a call to getElements() to force a deadlock.
|
||||||
|
|
||||||
|
// This method may be called on any thread, switch to the display
|
||||||
|
// thread before calling the viewer.
|
||||||
|
Display display = fViewer.getControl().getDisplay();
|
||||||
|
display.asyncExec( new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (!fViewer.getControl().isDisposed()) {
|
||||||
|
fViewer.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create the shell to hold the viewer.
|
||||||
|
Display display = new Display();
|
||||||
|
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||||
|
shell.setLayout(new GridLayout());
|
||||||
|
GridData data = new GridData(GridData.FILL_BOTH);
|
||||||
|
shell.setLayoutData(data);
|
||||||
|
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||||
|
|
||||||
|
// Create the table viewer.
|
||||||
|
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER);
|
||||||
|
tableViewer.getControl().setLayoutData(data);
|
||||||
|
|
||||||
|
// Create the data generator.
|
||||||
|
// TODO Exercise 5 - Use the DataGeneratorWithExecutor() instead.
|
||||||
|
final IDataGenerator generator = new DataGeneratorWithThread();
|
||||||
|
|
||||||
|
// Create the content provider which will populate the viewer.
|
||||||
|
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
|
||||||
|
tableViewer.setContentProvider(contentProvider);
|
||||||
|
tableViewer.setInput(new Object());
|
||||||
|
|
||||||
|
// Open the shell and service the display dispatch loop until user
|
||||||
|
// closes the shell.
|
||||||
|
shell.open();
|
||||||
|
while (!shell.isDisposed()) {
|
||||||
|
if (!display.readAndDispatch())
|
||||||
|
display.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||||
|
// using a query again in order to wait for its completion.
|
||||||
|
Query<Object> shutdownQuery = new Query<Object>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Object> rm) {
|
||||||
|
generator.shutdown(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(shutdownQuery);
|
||||||
|
try {
|
||||||
|
shutdownQuery.get();
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
// Shut down the display.
|
||||||
|
font.dispose();
|
||||||
|
display.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer.answers;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.Query;
|
||||||
|
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
|
||||||
|
import org.eclipse.jface.viewers.ILazyContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.TableViewer;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Font;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
import org.eclipse.swt.widgets.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data viewer based on a table, which reads data using asynchronous methods.
|
||||||
|
* <p>
|
||||||
|
* This viewer implements the {@link ILazyContentProvider} interface
|
||||||
|
* which is used by the JFace TableViewer class to populate a Table. This
|
||||||
|
* interface contains separate asynchronous methods for requesting the count
|
||||||
|
* and values for individual indexes, which neatly correspond to the methods
|
||||||
|
* in {@link IDataGenerator}. As an added optimization, this viewer
|
||||||
|
* implementation checks for the range of visible items in the view upon each
|
||||||
|
* request, and it cancels old requests which scroll out of view but have not
|
||||||
|
* been completed yet. However, it is up to the data generator implementation
|
||||||
|
* to check the canceled state of the requests and ignore them.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@ConfinedToDsfExecutor("fDisplayExecutor")
|
||||||
|
public class AsyncDataViewer
|
||||||
|
implements ILazyContentProvider, IDataGenerator.Listener
|
||||||
|
{
|
||||||
|
// Executor to use instead of Display.asyncExec().
|
||||||
|
@ThreadSafe
|
||||||
|
final private DsfExecutor fDisplayExecutor;
|
||||||
|
|
||||||
|
// The viewer and generator that this content provider using.
|
||||||
|
final private TableViewer fViewer;
|
||||||
|
final private IDataGenerator fDataGenerator;
|
||||||
|
|
||||||
|
// Fields used in request cancellation logic.
|
||||||
|
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
|
||||||
|
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
|
||||||
|
private int fCancelCallsPending = 0;
|
||||||
|
|
||||||
|
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
|
||||||
|
fViewer = viewer;
|
||||||
|
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
|
||||||
|
fDataGenerator = generator;
|
||||||
|
fDataGenerator.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
fDataGenerator.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// Set the initial count to the viewer after the input is set.
|
||||||
|
queryItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateElement(final int index) {
|
||||||
|
// Calculate the visible index range.
|
||||||
|
final int topIdx = fViewer.getTable().getTopIndex();
|
||||||
|
final int botIdx = topIdx + getVisibleItemCount(topIdx);
|
||||||
|
|
||||||
|
// Request the item for the given index.
|
||||||
|
queryValue(index);
|
||||||
|
|
||||||
|
// Invoke a cancel task with a delay. The delay allows multiple cancel
|
||||||
|
// calls to be combined together improving performance of the viewer.
|
||||||
|
fCancelCallsPending++;
|
||||||
|
fDisplayExecutor.schedule(
|
||||||
|
new Runnable() { public void run() {
|
||||||
|
cancelStaleRequests(topIdx, botIdx);
|
||||||
|
}},
|
||||||
|
1, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getVisibleItemCount(int top) {
|
||||||
|
Table table = fViewer.getTable();
|
||||||
|
int itemCount = table.getItemCount();
|
||||||
|
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
public void countChanged() {
|
||||||
|
queryItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
public void valuesChanged(final Set<Integer> indexes) {
|
||||||
|
// Mark the changed items in table viewer as dirty, this will
|
||||||
|
// trigger update requests for these indexes if they are
|
||||||
|
// visible in the viewer.
|
||||||
|
final TableViewer tableViewer = fViewer;
|
||||||
|
fDisplayExecutor.execute( new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
for (Integer index : indexes) {
|
||||||
|
tableViewer.clear(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void queryItemCount() {
|
||||||
|
// Request count from data provider. When the count is returned, we
|
||||||
|
// have to re-dispatch into the display thread to avoid calling
|
||||||
|
// the table widget on the DSF dispatch thread.
|
||||||
|
fIndexesToCancel.clear();
|
||||||
|
fDataGenerator.getCount(
|
||||||
|
// Use the display executor to construct the request monitor, this
|
||||||
|
// will cause the handleCompleted() method to be automatically
|
||||||
|
// called on the display thread.
|
||||||
|
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
fViewer.setItemCount(getData());
|
||||||
|
fViewer.getTable().clearAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dedicated class for data item requests. This class holds the index
|
||||||
|
// argument so it can be examined when canceling stale requests.
|
||||||
|
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
|
||||||
|
|
||||||
|
/** Index is used when canceling stale requests. */
|
||||||
|
int fIndex;
|
||||||
|
|
||||||
|
ValueDataRequestMonitor(int index) {
|
||||||
|
super(fDisplayExecutor, null);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
fItemDataRequestMonitors.remove(this);
|
||||||
|
|
||||||
|
// Check if the request completed successfully, otherwise ignore it.
|
||||||
|
if (isSuccess()) {
|
||||||
|
if (!fViewer.getTable().isDisposed()) {
|
||||||
|
fViewer.replace(getData(), fIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryValue(final int index) {
|
||||||
|
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
|
||||||
|
fItemDataRequestMonitors.add(rm);
|
||||||
|
fDataGenerator.getValue(index, rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelStaleRequests(int topIdx, int botIdx) {
|
||||||
|
// Decrement the count of outstanding cancel calls.
|
||||||
|
fCancelCallsPending--;
|
||||||
|
|
||||||
|
// Must check again, in case disposed while re-dispatching.
|
||||||
|
if (fDataGenerator == null || fViewer.getTable().isDisposed()) return;
|
||||||
|
|
||||||
|
// Go through the outstanding requests and cancel any that
|
||||||
|
// are not visible anymore.
|
||||||
|
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
|
||||||
|
ValueDataRequestMonitor item = itr.next();
|
||||||
|
if (item.fIndex < topIdx || item.fIndex > botIdx) {
|
||||||
|
// Set the item to canceled status, so that the data provider
|
||||||
|
// will ignore it.
|
||||||
|
item.cancel();
|
||||||
|
|
||||||
|
// Add the item index to list of indexes that were canceled,
|
||||||
|
// which will be sent to the table widget.
|
||||||
|
fIndexesToCancel.add(item.fIndex);
|
||||||
|
|
||||||
|
// Remove the item from the outstanding cancel requests.
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
|
||||||
|
Set<Integer> canceledIdxs = fIndexesToCancel;
|
||||||
|
fIndexesToCancel = new HashSet<Integer>();
|
||||||
|
|
||||||
|
// Clear the indexes of the canceled request, so that the
|
||||||
|
// viewer knows to request them again when needed.
|
||||||
|
// Note: clearing using TableViewer.clear(int) seems very
|
||||||
|
// inefficient, it's better to use Table.clear(int[]).
|
||||||
|
int[] canceledIdxsArray = new int[canceledIdxs.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Integer index : canceledIdxs) {
|
||||||
|
canceledIdxsArray[i++] = index;
|
||||||
|
}
|
||||||
|
fViewer.getTable().clear(canceledIdxsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create the shell to hold the viewer.
|
||||||
|
Display display = new Display();
|
||||||
|
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||||
|
shell.setLayout(new GridLayout());
|
||||||
|
GridData data = new GridData(GridData.FILL_BOTH);
|
||||||
|
shell.setLayoutData(data);
|
||||||
|
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||||
|
|
||||||
|
// Create the table viewer.
|
||||||
|
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||||
|
tableViewer.getControl().setLayoutData(data);
|
||||||
|
|
||||||
|
// Create the data generator.
|
||||||
|
final IDataGenerator generator = new DataGeneratorWithExecutor();
|
||||||
|
|
||||||
|
// Create the content provider which will populate the viewer.
|
||||||
|
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
|
||||||
|
tableViewer.setContentProvider(contentProvider);
|
||||||
|
tableViewer.setInput(new Object());
|
||||||
|
|
||||||
|
// Open the shell and service the display dispatch loop until user
|
||||||
|
// closes the shell.
|
||||||
|
shell.open();
|
||||||
|
while (!shell.isDisposed()) {
|
||||||
|
if (!display.readAndDispatch())
|
||||||
|
display.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||||
|
// using a query again in order to wait for its completion.
|
||||||
|
Query<Object> shutdownQuery = new Query<Object>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Object> rm) {
|
||||||
|
generator.shutdown(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(shutdownQuery);
|
||||||
|
try {
|
||||||
|
shutdownQuery.get();
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
// Shut down the display.
|
||||||
|
font.dispose();
|
||||||
|
display.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,311 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006 Wind River Systems 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.dd.examples.dsf.dataviewer.answers;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.Immutable;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DSF Executor-based implementation of the data generator.
|
||||||
|
* <p>
|
||||||
|
* This generator uses a queue of client requests and processes these
|
||||||
|
* requests periodically using a DSF executor. The main feature of this
|
||||||
|
* generator is that it uses the executor as its only synchronization object.
|
||||||
|
* This means that all the fields with the exception of the executor can only
|
||||||
|
* be accessed while running in the executor thread.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
public class DataGeneratorWithExecutor implements IDataGenerator {
|
||||||
|
|
||||||
|
// Request objects are used to serialize the interface calls into objects
|
||||||
|
// which can then be pushed into a queue.
|
||||||
|
@Immutable
|
||||||
|
abstract class Request {
|
||||||
|
final RequestMonitor fRequestMonitor;
|
||||||
|
|
||||||
|
Request(RequestMonitor rm) {
|
||||||
|
fRequestMonitor = rm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class CountRequest extends Request {
|
||||||
|
CountRequest(DataRequestMonitor<Integer> rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class ItemRequest extends Request {
|
||||||
|
final int fIndex;
|
||||||
|
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||||
|
super(rm);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The executor used to access all internal data of the generator.
|
||||||
|
private DsfExecutor fExecutor;
|
||||||
|
|
||||||
|
// Main request queue of the data generator. The getValue(), getCount(),
|
||||||
|
// and shutdown() methods write into the queue, while the serviceQueue()
|
||||||
|
// method reads from it.
|
||||||
|
// The executor used to access all internal data of the generator.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private List<Request> fQueue = new LinkedList<Request>();
|
||||||
|
|
||||||
|
// List of listeners is not synchronized, it also has to be accessed
|
||||||
|
// using the executor.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private List<Listener> fListeners = new LinkedList<Listener>();
|
||||||
|
|
||||||
|
// Current number of elements in this generator.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private int fCount = MIN_COUNT;
|
||||||
|
|
||||||
|
// Counter used to determine when to reset the element count.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private int fCountResetTrigger = 0;
|
||||||
|
|
||||||
|
// Elements which were modified since the last reset.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
|
||||||
|
|
||||||
|
// Flag used to ensure that requests are processed sequentially.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private boolean fServiceQueueInProgress = false;
|
||||||
|
|
||||||
|
public DataGeneratorWithExecutor() {
|
||||||
|
// Create the executor
|
||||||
|
fExecutor = new DefaultDsfExecutor("Supplier Executor");
|
||||||
|
|
||||||
|
// Schedule a runnable to make the random changes.
|
||||||
|
fExecutor.scheduleAtFixedRate(
|
||||||
|
new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
randomChanges();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RANDOM_CHANGE_INTERVAL,
|
||||||
|
RANDOM_CHANGE_INTERVAL,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown(final RequestMonitor rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
// Empty the queue of requests and fail them.
|
||||||
|
for (Request request : fQueue) {
|
||||||
|
request.fRequestMonitor.setStatus(
|
||||||
|
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
request.fRequestMonitor.done();
|
||||||
|
}
|
||||||
|
fQueue.clear();
|
||||||
|
|
||||||
|
// Kill executor.
|
||||||
|
fExecutor.shutdown();
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getCount(final DataRequestMonitor<Integer> rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fQueue.add(new CountRequest(rm));
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getValue(final int index, final DataRequestMonitor<String> rm) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fQueue.add(new ItemRequest(index, rm));
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(final Listener listener) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fListeners.add(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(final Listener listener) {
|
||||||
|
try {
|
||||||
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
fListeners.remove(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main processing function of this generator.
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void serviceQueue() {
|
||||||
|
|
||||||
|
for (Iterator<Request> requestItr = fQueue.iterator(); requestItr.hasNext();) {
|
||||||
|
Request request = requestItr.next();
|
||||||
|
if (request.fRequestMonitor.isCanceled()) {
|
||||||
|
request.fRequestMonitor.setStatus(
|
||||||
|
new Status(IStatus.CANCEL, DsfExamplesPlugin.PLUGIN_ID, "Request canceled"));
|
||||||
|
request.fRequestMonitor.done();
|
||||||
|
requestItr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a queue servicing is already scheduled, do nothing.
|
||||||
|
if (fServiceQueueInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fQueue.size() != 0) {
|
||||||
|
// If there are requests to service, remove one from the queue and
|
||||||
|
// schedule a runnable to process the request after a processing
|
||||||
|
// delay.
|
||||||
|
fServiceQueueInProgress = true;
|
||||||
|
final Request request = fQueue.remove(0);
|
||||||
|
fExecutor.schedule(
|
||||||
|
new DsfRunnable() {
|
||||||
|
public void run() {
|
||||||
|
if (request instanceof CountRequest) {
|
||||||
|
processCountRequest((CountRequest)request);
|
||||||
|
} else if (request instanceof ItemRequest) {
|
||||||
|
processItemRequest((ItemRequest)request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the processing flag and process next
|
||||||
|
// request.
|
||||||
|
fServiceQueueInProgress = false;
|
||||||
|
serviceQueue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void processCountRequest(CountRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
rm.setData(fCount);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void processItemRequest(ItemRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
if (fChangedIndexes.contains(request.fIndex)) {
|
||||||
|
rm.setData("Changed: " + request.fIndex);
|
||||||
|
} else {
|
||||||
|
rm.setData(Integer.toString(request.fIndex));
|
||||||
|
}
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method simulates changes in the supplier's data set.
|
||||||
|
*/
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void randomChanges() {
|
||||||
|
// Once every number of changes, reset the count, the rest of the
|
||||||
|
// times just change certain values.
|
||||||
|
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
|
||||||
|
randomCountReset();
|
||||||
|
} else {
|
||||||
|
randomDataChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates new size for provider's data set.
|
||||||
|
*/
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void randomCountReset() {
|
||||||
|
// Calculate the new count.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||||
|
|
||||||
|
// Reset the changed values.
|
||||||
|
fChangedIndexes.clear();
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Listener listener : fListeners) {
|
||||||
|
listener.countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates a random range of indexes.
|
||||||
|
*/
|
||||||
|
@ConfinedToDsfExecutor("fExecutor")
|
||||||
|
private void randomDataChange() {
|
||||||
|
// Calculate the indexes to change.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
Set<Integer> set = new HashSet<Integer>();
|
||||||
|
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||||
|
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the indexes to an overall set of changed indexes.
|
||||||
|
fChangedIndexes.addAll(set);
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Listener listener : fListeners) {
|
||||||
|
listener.valuesChanged(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer.answers;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.ListenerList;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-based implementation of the data generator.
|
||||||
|
* <p>
|
||||||
|
* This generator is based around a queue of client requests and a thread which
|
||||||
|
* reads the requests from the queue and processes them. The distinguishing
|
||||||
|
* feature of this generator is that it uses a a blocking queue as the main
|
||||||
|
* synchronization object. However, fListeners, fShutdown, and fChangedIndexes
|
||||||
|
* fields also need to be thread-safe and so they implement their own
|
||||||
|
* synchronization.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
||||||
|
|
||||||
|
// Request objects are used to serialize the interface calls into objects
|
||||||
|
// which can then be pushed into a queue.
|
||||||
|
abstract class Request {
|
||||||
|
final RequestMonitor fRequestMonitor;
|
||||||
|
|
||||||
|
Request(RequestMonitor rm) {
|
||||||
|
fRequestMonitor = rm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CountRequest extends Request {
|
||||||
|
CountRequest(DataRequestMonitor<Integer> rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemRequest extends Request {
|
||||||
|
final int fIndex;
|
||||||
|
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||||
|
super(rm);
|
||||||
|
fIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShutdownRequest extends Request {
|
||||||
|
ShutdownRequest(RequestMonitor rm) {
|
||||||
|
super(rm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main request queue of the data generator. The getValue(), getCount(),
|
||||||
|
// and shutdown() methods write into the queue, while the run() method
|
||||||
|
// reads from it.
|
||||||
|
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
|
||||||
|
|
||||||
|
// ListenerList class provides thread safety.
|
||||||
|
private ListenerList fListeners = new ListenerList();
|
||||||
|
|
||||||
|
// Current number of elements in this generator.
|
||||||
|
private int fCount = MIN_COUNT;
|
||||||
|
|
||||||
|
// Counter used to determine when to reset the element count.
|
||||||
|
private int fCountResetTrigger = 0;
|
||||||
|
|
||||||
|
// Elements which were modified since the last reset.
|
||||||
|
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
|
||||||
|
|
||||||
|
// Used to determine when to make changes in data.
|
||||||
|
private long fLastChangeTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Flag indicating when the generator has been shut down.
|
||||||
|
private AtomicBoolean fShutdown = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public DataGeneratorWithThread() {
|
||||||
|
// Immediately kick off the request processing thread.
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown(RequestMonitor rm) {
|
||||||
|
// Mark the generator as shut down. After the fShutdown flag is set,
|
||||||
|
// all new requests should be shut down.
|
||||||
|
if (!fShutdown.getAndSet(true)) {
|
||||||
|
fQueue.add(new ShutdownRequest(rm));
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getCount(DataRequestMonitor<Integer> rm) {
|
||||||
|
if (!fShutdown.get()) {
|
||||||
|
fQueue.add(new CountRequest(rm));
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getValue(int index, DataRequestMonitor<String> rm) {
|
||||||
|
if (!fShutdown.get()) {
|
||||||
|
fQueue.add(new ItemRequest(index, rm));
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(Listener listener) {
|
||||||
|
fListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(Listener listener) {
|
||||||
|
fListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while(true) {
|
||||||
|
// Get the next request from the queue. The time-out
|
||||||
|
// ensures that that the random changes get processed.
|
||||||
|
final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
// If a request was dequeued, process it.
|
||||||
|
if (request != null) {
|
||||||
|
// Simulate a processing delay.
|
||||||
|
Thread.sleep(PROCESSING_DELAY);
|
||||||
|
|
||||||
|
if (request instanceof CountRequest) {
|
||||||
|
processCountRequest((CountRequest)request);
|
||||||
|
} else if (request instanceof ItemRequest) {
|
||||||
|
processItemRequest((ItemRequest)request);
|
||||||
|
} else if (request instanceof ShutdownRequest) {
|
||||||
|
// If shutting down, just break out of the while(true)
|
||||||
|
// loop and thread will exit.
|
||||||
|
request.fRequestMonitor.done();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate data changes.
|
||||||
|
randomChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException x) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCountRequest(CountRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
rm.setData(fCount);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processItemRequest(ItemRequest request) {
|
||||||
|
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||||
|
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||||
|
|
||||||
|
if (fChangedIndexes.contains(request.fIndex)) {
|
||||||
|
rm.setData("Changed: " + request.fIndex);
|
||||||
|
} else {
|
||||||
|
rm.setData(Integer.toString(request.fIndex));
|
||||||
|
}
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void randomChanges() {
|
||||||
|
// Check if enough time is elapsed.
|
||||||
|
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
|
||||||
|
fLastChangeTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Once every number of changes, reset the count, the rest of the
|
||||||
|
// times just change certain values.
|
||||||
|
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
|
||||||
|
randomCountReset();
|
||||||
|
} else {
|
||||||
|
randomDataChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void randomCountReset() {
|
||||||
|
// Calculate the new count.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||||
|
|
||||||
|
// Reset the changed values.
|
||||||
|
fChangedIndexes.clear();
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Object listener : fListeners.getListeners()) {
|
||||||
|
((Listener)listener).countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void randomDataChange() {
|
||||||
|
// Calculate the indexes to change.
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
Set<Integer> set = new HashSet<Integer>();
|
||||||
|
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||||
|
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the indexes to an overall set of changed indexes.
|
||||||
|
fChangedIndexes.addAll(set);
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
for (Object listener : fListeners.getListeners()) {
|
||||||
|
((Listener)listener).valuesChanged(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006, 2008 Wind River Systems 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.dd.examples.dsf.dataviewer.answers;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data generator is simple source of data used to populate the example table
|
||||||
|
* view. It contains two asynchronous methods for retrieving the data
|
||||||
|
* parameters: the count and the value for a given index. It also allows the
|
||||||
|
* view to receive events indicating when the data supplied by the generator
|
||||||
|
* is changed.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
public interface IDataGenerator {
|
||||||
|
|
||||||
|
// Constants which control the data generator behavior.
|
||||||
|
// Changing the count range can stress the scalability of the system, while
|
||||||
|
// changing of the process delay and random change interval can stress
|
||||||
|
// its performance.
|
||||||
|
final static int MIN_COUNT = 100;
|
||||||
|
final static int MAX_COUNT = 200;
|
||||||
|
final static int PROCESSING_DELAY = 10;
|
||||||
|
final static int RANDOM_CHANGE_INTERVAL = 10000;
|
||||||
|
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
|
||||||
|
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
|
||||||
|
|
||||||
|
|
||||||
|
// Listener interface that the view needs to implement to react
|
||||||
|
// to the changes in data.
|
||||||
|
public interface Listener {
|
||||||
|
void countChanged();
|
||||||
|
void valuesChanged(Set<Integer> indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data access methods.
|
||||||
|
void getCount(DataRequestMonitor<Integer> rm);
|
||||||
|
void getValue(int index, DataRequestMonitor<String> rm);
|
||||||
|
|
||||||
|
// Method used to shutdown the data generator including any threads that
|
||||||
|
// it may use.
|
||||||
|
void shutdown(RequestMonitor rm);
|
||||||
|
|
||||||
|
// Methods for registering change listeners.
|
||||||
|
void addListener(Listener listener);
|
||||||
|
void removeListener(Listener listener);
|
||||||
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.dataviewer.answers;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.Query;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.TableViewer;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Font;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data viewer based on a table, which reads data using synchronous methods.
|
||||||
|
* <p>
|
||||||
|
* This viewer implements the {@link IStructuredContentProvider} interface
|
||||||
|
* which is used by the JFace TableViewer class to populate a Table. This
|
||||||
|
* interface contains one principal methods for reading data {@link #getElements(Object)},
|
||||||
|
* which synchronously returns an array of elements. In order to implement this
|
||||||
|
* method using the asynchronous data generator, this provider uses the
|
||||||
|
* {@link Query} object.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class SyncDataViewer
|
||||||
|
implements IStructuredContentProvider, IDataGenerator.Listener
|
||||||
|
{
|
||||||
|
// The viewer and generator that this content provider using.
|
||||||
|
final private TableViewer fViewer;
|
||||||
|
final private IDataGenerator fDataGenerator;
|
||||||
|
|
||||||
|
public SyncDataViewer(TableViewer viewer, IDataGenerator generator) {
|
||||||
|
fViewer = viewer;
|
||||||
|
fDataGenerator = generator;
|
||||||
|
fDataGenerator.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// Not used
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
|
||||||
|
// Create the query object for reading data count.
|
||||||
|
Query<Integer> countQuery = new Query<Integer>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Integer> rm) {
|
||||||
|
fDataGenerator.getCount(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Submit the query to be executed. A query implements a runnable
|
||||||
|
// interface and it has to be executed in order to do its work.
|
||||||
|
ImmediateExecutor.getInstance().execute(countQuery);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// Block until the query completes, which will happen when the request
|
||||||
|
// monitor of the execute() method is marked done.
|
||||||
|
try {
|
||||||
|
count = countQuery.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// InterruptedException and ExecutionException can be thrown here.
|
||||||
|
// ExecutionException containing a CoreException will be thrown
|
||||||
|
// if an error status is set to the Query's request monitor.
|
||||||
|
return new Object[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the array that will be filled with elements.
|
||||||
|
// For each index in the array execute a query to get the element at
|
||||||
|
// that index.
|
||||||
|
final Object[] elements = new Object[count];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final int index = i;
|
||||||
|
Query<String> valueQuery = new Query<String>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<String> rm) {
|
||||||
|
fDataGenerator.getValue(index, rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(valueQuery);
|
||||||
|
try {
|
||||||
|
elements[i] = valueQuery.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
elements[i] = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
fDataGenerator.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void countChanged() {
|
||||||
|
// For any event from the generator, refresh the whole viewer.
|
||||||
|
refreshViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void valuesChanged(Set<Integer> indexes) {
|
||||||
|
// For any event from the generator, refresh the whole viewer.
|
||||||
|
refreshViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshViewer() {
|
||||||
|
getElements(null);
|
||||||
|
|
||||||
|
// This method may be called on any thread, switch to the display
|
||||||
|
// thread before calling the viewer.
|
||||||
|
Display display = fViewer.getControl().getDisplay();
|
||||||
|
display.asyncExec( new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (!fViewer.getControl().isDisposed()) {
|
||||||
|
fViewer.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create the shell to hold the viewer.
|
||||||
|
Display display = new Display();
|
||||||
|
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||||
|
shell.setLayout(new GridLayout());
|
||||||
|
GridData data = new GridData(GridData.FILL_BOTH);
|
||||||
|
shell.setLayoutData(data);
|
||||||
|
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||||
|
|
||||||
|
// Create the table viewer.
|
||||||
|
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER);
|
||||||
|
tableViewer.getControl().setLayoutData(data);
|
||||||
|
|
||||||
|
// Create the data generator.
|
||||||
|
final IDataGenerator generator = new DataGeneratorWithExecutor();
|
||||||
|
|
||||||
|
// Create the content provider which will populate the viewer.
|
||||||
|
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
|
||||||
|
tableViewer.setContentProvider(contentProvider);
|
||||||
|
tableViewer.setInput(new Object());
|
||||||
|
|
||||||
|
// Open the shell and service the display dispatch loop until user
|
||||||
|
// closes the shell.
|
||||||
|
shell.open();
|
||||||
|
while (!shell.isDisposed()) {
|
||||||
|
if (!display.readAndDispatch())
|
||||||
|
display.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||||
|
// using a query again in order to wait for its completion.
|
||||||
|
Query<Object> shutdownQuery = new Query<Object>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DataRequestMonitor<Object> rm) {
|
||||||
|
generator.shutdown(rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ImmediateExecutor.getInstance().execute(shutdownQuery);
|
||||||
|
try {
|
||||||
|
shutdownQuery.get();
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
// Shut down the display.
|
||||||
|
font.dispose();
|
||||||
|
display.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of using a DataRequestMonitor to retrieve a result from an
|
||||||
|
* asynchronous method.
|
||||||
|
*/
|
||||||
|
public class Async2Plus2 {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Executor executor = ImmediateExecutor.getInstance();
|
||||||
|
DataRequestMonitor<Integer> rm =
|
||||||
|
new DataRequestMonitor<Integer>(executor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
System.out.println("2 + 2 = " + getData());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
asyncAdd(2, 2, rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncAdd(int value1, int value2, DataRequestMonitor<Integer> rm) {
|
||||||
|
rm.setData(value1 + value2);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Hello world" example which uses an asynchronous method to print out
|
||||||
|
* the result.
|
||||||
|
* <p>
|
||||||
|
* The main method uses an immediate executor, which executes runnables
|
||||||
|
* as soon as they are submitted, in creating its request monitor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AsyncHelloWorld {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Executor executor = ImmediateExecutor.getInstance();
|
||||||
|
RequestMonitor rm = new RequestMonitor(executor, null);
|
||||||
|
asyncHelloWorld(rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncHelloWorld(RequestMonitor rm) {
|
||||||
|
System.out.println("Hello world");
|
||||||
|
// TODO Exercise 1: - Call the second async. "Hello world 2" method.
|
||||||
|
// Hint: Calling an asynchronous method requires passing to it a
|
||||||
|
// request monitor. A new request monitor can be constructed with
|
||||||
|
// a parent RequestMonitor as an argument argument. The parent gets
|
||||||
|
// completed automatically when the lower level request monitor is
|
||||||
|
// completed.
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Exercise 1 - Add a second async. "Hello world 2" method.
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of using a CountingRequestMonitor to wait for multiple
|
||||||
|
* asynchronous calls to complete.
|
||||||
|
*/
|
||||||
|
public class AsyncQuicksort {
|
||||||
|
|
||||||
|
static Executor fgExecutor = ImmediateExecutor.getInstance();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
final int[] array = {5, 7, 8, 3, 2, 1, 9, 5, 4};
|
||||||
|
|
||||||
|
System.out.println("To sort: " + Arrays.toString(array));
|
||||||
|
asyncQuicksort(
|
||||||
|
array, 0, array.length - 1,
|
||||||
|
new RequestMonitor(fgExecutor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
System.out.println("Sorted: " + Arrays.toString(array));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncQuicksort(final int[] array, final int left,
|
||||||
|
final int right, final RequestMonitor rm)
|
||||||
|
{
|
||||||
|
if (right > left) {
|
||||||
|
int pivot = left;
|
||||||
|
// TODO: Exercise 2 - Convert the call to partition into an
|
||||||
|
// asynchronous call to asyncPartition().
|
||||||
|
// Hint: The rest of the code below should be executed inside
|
||||||
|
// the DataRequestMonitor.handleCompleted() overriding method.
|
||||||
|
int newPivot = partition(array, left, right, pivot);
|
||||||
|
printArray(array, left, right, newPivot);
|
||||||
|
|
||||||
|
CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
|
||||||
|
asyncQuicksort(array, left, newPivot - 1, countingRm);
|
||||||
|
asyncQuicksort(array, newPivot + 1, right, countingRm);
|
||||||
|
countingRm.setDoneCount(2);
|
||||||
|
} else {
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Exercise 2 - Convert partition to an asynchronous method.
|
||||||
|
// Hint: a DataRequestMonitor<Integer> should be used to carry the
|
||||||
|
// return value to the caller.
|
||||||
|
static int partition(int[] array, int left, int right, int pivot)
|
||||||
|
{
|
||||||
|
int pivotValue = array[pivot];
|
||||||
|
array[pivot] = array[right];
|
||||||
|
array[right] = pivotValue;
|
||||||
|
int store = left;
|
||||||
|
for (int i = left; i < right; i++) {
|
||||||
|
if (array[i] <= pivotValue) {
|
||||||
|
int tmp = array[store];
|
||||||
|
array[store] = array[i];
|
||||||
|
array[i] = tmp;
|
||||||
|
store++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array[right] = array[store];
|
||||||
|
array[store] = pivotValue;
|
||||||
|
|
||||||
|
// TODO: Request Monitors Exercise 2 - Return the data to caller using
|
||||||
|
// a request monitor.
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printArray(int[] array, int left, int right, int pivot) {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
for (int i = 0; i < array.length; i++ ) {
|
||||||
|
if (i == left) {
|
||||||
|
buffer.append('>');
|
||||||
|
} else if (i == pivot) {
|
||||||
|
buffer.append('-');
|
||||||
|
} else {
|
||||||
|
buffer.append(' ');
|
||||||
|
}
|
||||||
|
buffer.append(array[i]);
|
||||||
|
|
||||||
|
if (i == right) {
|
||||||
|
buffer.append('<');
|
||||||
|
} else if (i == pivot) {
|
||||||
|
buffer.append('-');
|
||||||
|
} else {
|
||||||
|
buffer.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(buffer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor.answers;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of using a DataRequestMonitor to retrieve a result from an
|
||||||
|
* asynchronous method.
|
||||||
|
*/
|
||||||
|
public class Async2Plus2 {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Executor executor = ImmediateExecutor.getInstance();
|
||||||
|
DataRequestMonitor<Integer> rm =
|
||||||
|
new DataRequestMonitor<Integer>(executor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
System.out.println("2 + 2 = " + getData());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
asyncAdd(2, 2, rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncAdd(int value1, int value2, DataRequestMonitor<Integer> rm) {
|
||||||
|
rm.setData(value1 + value2);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor.answers;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Hello world" example which uses an asynchronous method to print out
|
||||||
|
* the result.
|
||||||
|
* <p>
|
||||||
|
* The main method uses an immediate executor, which executes runnables
|
||||||
|
* as soon as they are submitted, in creating its request monitor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AsyncHelloWorld {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Executor executor = ImmediateExecutor.getInstance();
|
||||||
|
RequestMonitor rm = new RequestMonitor(executor, null);
|
||||||
|
asyncHelloWorld(rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncHelloWorld(RequestMonitor rm) {
|
||||||
|
System.out.println("Hello world");
|
||||||
|
RequestMonitor rm2 = new RequestMonitor(ImmediateExecutor.getInstance(), rm);
|
||||||
|
asyncHelloWorld2(rm2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncHelloWorld2(RequestMonitor rm) {
|
||||||
|
System.out.println("Hello world 2");
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 Wind River Systems 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.dd.examples.dsf.requestmonitor.answers;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of using a CountingRequestMonitor to wait for multiple
|
||||||
|
* asynchronous calls to complete.
|
||||||
|
*/
|
||||||
|
public class AsyncQuicksort {
|
||||||
|
|
||||||
|
static Executor fgExecutor = ImmediateExecutor.getInstance();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
final int[] array = {5, 7, 8, 3, 2, 1, 9, 5, 4};
|
||||||
|
|
||||||
|
System.out.println("To sort: " + Arrays.toString(array));
|
||||||
|
asyncQuicksort(
|
||||||
|
array, 0, array.length - 1,
|
||||||
|
new RequestMonitor(fgExecutor, null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
System.out.println("Sorted: " + Arrays.toString(array));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncQuicksort(final int[] array, final int left,
|
||||||
|
final int right, final RequestMonitor rm)
|
||||||
|
{
|
||||||
|
if (right > left) {
|
||||||
|
int pivot = left;
|
||||||
|
asyncPartition(
|
||||||
|
array, left, right, pivot,
|
||||||
|
new DataRequestMonitor<Integer>(fgExecutor, rm) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
int newPivot = getData();
|
||||||
|
printArray(array, left, right, newPivot);
|
||||||
|
|
||||||
|
CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
|
||||||
|
asyncQuicksort(array, left, newPivot - 1, countingRm);
|
||||||
|
asyncQuicksort(array, newPivot + 1, right, countingRm);
|
||||||
|
countingRm.setDoneCount(2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asyncPartition(int[] array, int left, int right, int pivot, DataRequestMonitor<Integer> rm)
|
||||||
|
{
|
||||||
|
int pivotValue = array[pivot];
|
||||||
|
array[pivot] = array[right];
|
||||||
|
array[right] = pivotValue;
|
||||||
|
int store = left;
|
||||||
|
for (int i = left; i < right; i++) {
|
||||||
|
if (array[i] <= pivotValue) {
|
||||||
|
int tmp = array[store];
|
||||||
|
array[store] = array[i];
|
||||||
|
array[i] = tmp;
|
||||||
|
store++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array[right] = array[store];
|
||||||
|
array[store] = pivotValue;
|
||||||
|
|
||||||
|
// Java 5 automatically converts the int type of the store variable
|
||||||
|
// to an Integer object.
|
||||||
|
rm.setData(store);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printArray(int[] array, int left, int right, int pivot) {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
for (int i = 0; i < array.length; i++ ) {
|
||||||
|
if (i == left) {
|
||||||
|
buffer.append('>');
|
||||||
|
} else if (i == pivot) {
|
||||||
|
buffer.append('-');
|
||||||
|
} else {
|
||||||
|
buffer.append(' ');
|
||||||
|
}
|
||||||
|
buffer.append(array[i]);
|
||||||
|
|
||||||
|
if (i == right) {
|
||||||
|
buffer.append('<');
|
||||||
|
} else if (i == pivot) {
|
||||||
|
buffer.append('-');
|
||||||
|
} else {
|
||||||
|
buffer.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(buffer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,8 +44,14 @@ class AlarmsVMNode extends AbstractDMVMNode
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
// Check that the services are available
|
// Check that the services are available
|
||||||
if (!checkService(AlarmService.class, null, update)) return;
|
if ( getServicesTracker().getService(AlarmService.class) == null ) {
|
||||||
if (!checkService(TimerService.class, null, update)) return;
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( getServicesTracker().getService(TimerService.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the trigger and timer contexts. If not found, fail.
|
// Find the trigger and timer contexts. If not found, fail.
|
||||||
TriggerDMContext alarmDmc = findDmcInPath(
|
TriggerDMContext alarmDmc = findDmcInPath(
|
||||||
|
|
|
@ -84,12 +84,14 @@ class TimersVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(AlarmService.class, null, update)) return;
|
if ( getServicesTracker().getService(TimerService.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the timer DMContexts, create the corresponding VMCs array, and
|
// Retrieve the timer DMContexts, create the corresponding VMCs array, and
|
||||||
// set them as result.
|
// set them as result.
|
||||||
TimerDMContext[] timers =
|
TimerDMContext[] timers = getServicesTracker().getService(TimerService.class).getTimers();
|
||||||
getServicesTracker().getService(TimerService.class).getTimers();
|
|
||||||
fillUpdateWithVMCs(update, timers);
|
fillUpdateWithVMCs(update, timers);
|
||||||
update.done();
|
update.done();
|
||||||
}
|
}
|
||||||
|
@ -118,14 +120,17 @@ class TimersVMNode extends AbstractDMVMNode
|
||||||
update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
|
update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
|
||||||
|
|
||||||
// If either update or service are not valid, fail the update and exit.
|
// If either update or service are not valid, fail the update and exit.
|
||||||
if (!checkDmc(dmc, update) ||
|
if ( dmc == null ) {
|
||||||
!checkService(TimerService.class, null, update))
|
handleFailedUpdate(update);
|
||||||
{
|
return;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerService timerService =
|
TimerService timerService = getServicesTracker().getService(TimerService.class, null);
|
||||||
getServicesTracker().getService(TimerService.class, null);
|
if ( timerService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int value = timerService.getTimerValue(dmc);
|
int value = timerService.getTimerValue(dmc);
|
||||||
|
|
||||||
if (value == -1) {
|
if (value == -1) {
|
||||||
|
|
|
@ -85,10 +85,12 @@ class TriggersVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(AlarmService.class, null, update)) return;
|
if ( getServicesTracker().getService(AlarmService.class) == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TriggerDMContext[] triggers =
|
TriggerDMContext[] triggers = getServicesTracker().getService(AlarmService.class).getTriggers();
|
||||||
getServicesTracker().getService(AlarmService.class).getTriggers();
|
|
||||||
fillUpdateWithVMCs(update, triggers);
|
fillUpdateWithVMCs(update, triggers);
|
||||||
update.done();
|
update.done();
|
||||||
}
|
}
|
||||||
|
@ -119,16 +121,19 @@ class TriggersVMNode extends AbstractDMVMNode
|
||||||
TriggerDMContext triggerCtx = findDmcInPath(
|
TriggerDMContext triggerCtx = findDmcInPath(
|
||||||
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
|
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
|
||||||
|
|
||||||
// If either update or service are not valid, fail the update and exit.
|
// If either update or service are not valid, fail the update and return.
|
||||||
if (!checkDmc(triggerCtx, update) ||
|
if ( triggerCtx == null ) {
|
||||||
!checkService(AlarmService.class, null, update))
|
handleFailedUpdate(update);
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
|
||||||
|
if ( alarmService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate and set the update properties.
|
// Calculate and set the update properties.
|
||||||
AlarmService alarmService =
|
|
||||||
getServicesTracker().getService(AlarmService.class, null);
|
|
||||||
int value = alarmService.getTriggerValue(triggerCtx);
|
int value = alarmService.getTriggerValue(triggerCtx);
|
||||||
|
|
||||||
if (value == -1) {
|
if (value == -1) {
|
||||||
|
|
|
@ -54,9 +54,14 @@ public class ContainerVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(IChildrenUpdate update) {
|
||||||
if (!checkService(AbstractMIControl.class, null, update)) return;
|
|
||||||
|
|
||||||
MIControlDMContext containerCtx = getServicesTracker().getService(AbstractMIControl.class).getControlDMContext();
|
AbstractMIControl controlService = getServicesTracker().getService(AbstractMIControl.class);
|
||||||
|
if ( controlService == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MIControlDMContext containerCtx = controlService.getControlDMContext();
|
||||||
update.setChild(createVMContext(containerCtx), 0);
|
update.setChild(createVMContext(containerCtx), 0);
|
||||||
update.done();
|
update.done();
|
||||||
}
|
}
|
||||||
|
@ -77,9 +82,12 @@ public class ContainerVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
if (!checkService(GDBRunControl.class, null, update)) continue;
|
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
|
||||||
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
|
if ( runControl == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);
|
final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);
|
||||||
|
|
||||||
String imageKey = null;
|
String imageKey = null;
|
||||||
|
|
|
@ -61,26 +61,30 @@ public class ThreadVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (!checkService(IRunControl.class, null, update)) return;
|
IRunControl runControl = getServicesTracker().getService(IRunControl.class);
|
||||||
final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class);
|
if ( runControl == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (contDmc == null) {
|
final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class);
|
||||||
handleFailedUpdate(update);
|
if (contDmc == null) {
|
||||||
return;
|
handleFailedUpdate(update);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
getServicesTracker().getService(IRunControl.class).getExecutionContexts(contDmc,
|
|
||||||
new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null){
|
runControl.getExecutionContexts(contDmc,
|
||||||
@Override
|
new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null){
|
||||||
public void handleCompleted() {
|
@Override
|
||||||
if (!isSuccess()) {
|
public void handleCompleted() {
|
||||||
handleFailedUpdate(update);
|
if (!isSuccess()) {
|
||||||
return;
|
handleFailedUpdate(update);
|
||||||
}
|
return;
|
||||||
fillUpdateWithVMCs(update, getData());
|
}
|
||||||
update.done();
|
fillUpdateWithVMCs(update, getData());
|
||||||
}
|
update.done();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,8 +199,11 @@ public class ThreadVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
|
||||||
for (final ILabelUpdate update : updates) {
|
for (final ILabelUpdate update : updates) {
|
||||||
if (!checkService(GDBRunControl.class, null, update)) continue;
|
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
|
||||||
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
|
if ( runControl == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final IMIExecutionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IMIExecutionDMContext.class);
|
final IMIExecutionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IMIExecutionDMContext.class);
|
||||||
|
|
||||||
|
@ -220,7 +227,11 @@ public class ThreadVMNode extends AbstractDMVMNode
|
||||||
|
|
||||||
// We're in a new dispatch cycle, and we have to check whether the
|
// We're in a new dispatch cycle, and we have to check whether the
|
||||||
// service reference is still valid.
|
// service reference is still valid.
|
||||||
if (!checkService(GDBRunControl.class, null, update)) return;
|
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
|
||||||
|
if ( runControl == null ) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final StateChangeReason reason = getData().getStateChangeReason();
|
final StateChangeReason reason = getData().getStateChangeReason();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue