1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[221899] Removed pre-processed example sources from CVS.

This commit is contained in:
Pawel Piech 2008-05-12 22:06:30 +00:00
parent def2b2d472
commit c9c4a33ef3
19 changed files with 18 additions and 2581 deletions

View file

@ -1,272 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,336 +0,0 @@
/*******************************************************************************
* 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);
}
}
}

View file

@ -1,238 +0,0 @@
/*******************************************************************************
* 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);
}
}
}

View file

@ -1,59 +0,0 @@
/*******************************************************************************
* 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);
}

View file

@ -1,183 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,272 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,311 +0,0 @@
/*******************************************************************************
* 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);
}
}
}

View file

@ -1,238 +0,0 @@
/*******************************************************************************
* 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);
}
}
}

View file

@ -1,59 +0,0 @@
/*******************************************************************************
* 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);
}

View file

@ -1,182 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,40 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,46 +0,0 @@
/*******************************************************************************
* 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.
}

View file

@ -1,111 +0,0 @@
/*******************************************************************************
* 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);
}
}

View file

@ -1,40 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,44 +0,0 @@
/*******************************************************************************
* 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();
}
}

View file

@ -1,113 +0,0 @@
/*******************************************************************************
* 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);
}
}

View file

@ -43,32 +43,22 @@ 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 service is available and find the trigger and timer contexts.
if ( getServicesTracker().getService(AlarmService.class) == null ) { // If not found, fail.
handleFailedUpdate(update); AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
return;
}
if ( getServicesTracker().getService(TimerService.class) == null ) {
handleFailedUpdate(update);
return;
}
// Find the trigger and timer contexts. If not found, fail.
TriggerDMContext alarmDmc = findDmcInPath( TriggerDMContext alarmDmc = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class); update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
TimerDMContext timerDmc = findDmcInPath( TimerDMContext timerDmc = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TimerDMContext.class); update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
if (alarmDmc == null || timerDmc == null) { if (alarmService == null || alarmDmc == null || timerDmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path")); update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path"));
update.done(); update.done();
return; return;
} }
// Get the alarm context then check the triggered value. // Get the alarm context then check the triggered value.
final AlarmDMContext alarmStatusDmc = getServicesTracker().getService(AlarmService.class). final AlarmDMContext alarmStatusDmc = alarmService.getAlarm(alarmDmc, timerDmc);
getAlarm(alarmDmc, timerDmc); boolean triggered = alarmService.isAlarmTriggered(alarmStatusDmc);
boolean triggered = getServicesTracker().getService(AlarmService.class).
isAlarmTriggered(alarmStatusDmc);
// Only return the alarm in list of elements if it is triggered. // Only return the alarm in list of elements if it is triggered.
if (triggered) { if (triggered) {

View file

@ -84,14 +84,15 @@ class TimersVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if ( getServicesTracker().getService(TimerService.class) == null ) { TimerService timerService = getServicesTracker().getService(TimerService.class, null);
if ( timerService == null ) {
handleFailedUpdate(update); handleFailedUpdate(update);
return; 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 = getServicesTracker().getService(TimerService.class).getTimers(); TimerDMContext[] timers = timerService.getTimers();
fillUpdateWithVMCs(update, timers); fillUpdateWithVMCs(update, timers);
update.done(); update.done();
} }
@ -116,21 +117,15 @@ class TimersVMNode extends AbstractDMVMNode
@ConfinedToDsfExecutor("getSession#getExecutor") @ConfinedToDsfExecutor("getSession#getExecutor")
private void updatePropertiesInSessionThread(final IPropertiesUpdate update) { private void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
// Find the timer context in the element being updated // Find the timer context in the element being updated
final TimerDMContext dmc = findDmcInPath( TimerDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
update.getViewerInput(), update.getElementPath(), TimerDMContext.class); TimerService timerService = getServicesTracker().getService(TimerService.class, null);
// 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 ( dmc == null ) { if ( dmc == null || timerService == null) {
handleFailedUpdate(update); handleFailedUpdate(update);
return; return;
} }
TimerService timerService = 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) {

View file

@ -85,12 +85,13 @@ class TriggersVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if ( getServicesTracker().getService(AlarmService.class) == null ) { AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
if ( alarmService == null ) {
handleFailedUpdate(update); handleFailedUpdate(update);
return; return;
} }
TriggerDMContext[] triggers = getServicesTracker().getService(AlarmService.class).getTriggers(); TriggerDMContext[] triggers = alarmService.getTriggers();
fillUpdateWithVMCs(update, triggers); fillUpdateWithVMCs(update, triggers);
update.done(); update.done();
} }
@ -120,19 +121,14 @@ class TriggersVMNode extends AbstractDMVMNode
// Find the trigger context in the element being updated // Find the trigger context in the element being updated
TriggerDMContext triggerCtx = findDmcInPath( TriggerDMContext triggerCtx = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class); update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
// If either update or service are not valid, fail the update and return. // If either update or service are not valid, fail the update and return.
if ( triggerCtx == null ) { if ( triggerCtx == null || alarmService == null) {
handleFailedUpdate(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.
int value = alarmService.getTriggerValue(triggerCtx); int value = alarmService.getTriggerValue(triggerCtx);