diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java
new file mode 100644
index 00000000000..889d59475dc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ICache;
+import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Transaction;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * A data generator which performs a sum computation on data retrieved from a
+ * number of other data generators. The data retrieval from other generators
+ * is performed using ACPM caches and the result is calculated once all caches
+ * are valid.
+ *
+ * Unlike {@link AsyncSumDataGenerator}, this data generator listens to events
+ * from the individual the data providers. Theve events are used to
+ * invalidate caches to make sure that they don't return incorrect data. This
+ * generator also sends out events to its clients to notify them to update, or
+ * invalidate their caches.
+ *
+ */
+public class ACPMSumDataGenerator
+ implements IDataGenerator, IDataGenerator.Listener
+{
+
+ /**
+ * DSF executor used to serialize data access within this data generator.
+ */
+ final private DsfExecutor fExecutor;
+
+ /**
+ * Data generators to retrieve original data to perform calculations on.
+ * The generators are accessed through the cache manager wrappers.
+ */
+ final private DataGeneratorCacheManager[] fDataGeneratorCMs;
+
+ /**
+ * List of listeners for this data generator.
+ */
+ final private List fListeners = new LinkedList();
+
+ public ACPMSumDataGenerator(DsfExecutor executor,
+ IDataGenerator[] generators)
+ {
+ fExecutor = executor;
+
+ // Create wrappers for data generators and add ourselves as listener
+ // to their events.
+ fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
+ ImmediateInDsfExecutor immediateExecutor =
+ new ImmediateInDsfExecutor(fExecutor);
+ for (int i = 0; i < generators.length; i++) {
+ fDataGeneratorCMs[i] = new DataGeneratorCacheManager(
+ immediateExecutor, generators[i]);
+ generators[i].addListener(this);
+ }
+ }
+
+ public void getCount(final DataRequestMonitor rm) {
+ // Artificially delay the retrieval of the sum data to simulate
+ // real processing time.
+ fExecutor.schedule( new Runnable() {
+ public void run() {
+ // Create the transaction here to put all the ugly
+ // code in one place.
+ new Transaction() {
+ @Override
+ protected Integer process()
+ throws Transaction.InvalidCacheException,
+ CoreException
+ {
+ return processCount(this);
+ }
+ }.request(rm);
+ }
+ },
+ PROCESSING_DELAY, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Perform the calculation to get the max count for the given transaction.
+ * @param transaction The ACPM transaction to use for calculation.
+ * @return Calculated count.
+ * @throws Transaction.InvalidCacheException {@link Transaction#process}
+ * @throws CoreException See {@link Transaction#process}
+ */
+ private Integer processCount(Transaction transaction)
+ throws Transaction.InvalidCacheException, CoreException
+ {
+ // Assemble all needed count caches into a collection.
+ List> countCaches =
+ new ArrayList>(fDataGeneratorCMs.length);
+ for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
+ countCaches.add(dataGeneratorCM.getCount());
+ }
+ // Validate all count caches at once. This executes needed requests
+ // in parallel.
+ transaction.validate(countCaches);
+
+ // Calculate the max value and return.
+ int maxCount = 0;
+ for (ICache countCache : countCaches) {
+ maxCount = Math.max(maxCount, countCache.getData());
+ }
+ return maxCount;
+ }
+
+ public void getValue(final int index, final DataRequestMonitor rm)
+ {
+ // Add a processing delay.
+ fExecutor.schedule( new Runnable() {
+ public void run() {
+ new Transaction() {
+ @Override
+ protected Integer process()
+ throws Transaction.InvalidCacheException,
+ CoreException
+ {
+ return processValue(this, index);
+ }
+ }.request(rm);
+ }
+ },
+ PROCESSING_DELAY, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Perform the calculation to get the sum of values at given index.
+ * @param transaction The ACPM transaction to use for calculation.
+ * @param index Index of value to calculate.
+ * @return Calculated value.
+ * @throws Transaction.InvalidCacheException {@link Transaction#process}
+ * @throws CoreException See {@link Transaction#process}
+ */
+ private Integer processValue(Transaction transaction, int index)
+ throws Transaction.InvalidCacheException, CoreException
+ {
+ List> valueCaches =
+ new ArrayList>(fDataGeneratorCMs.length);
+ for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
+ valueCaches.add(dataGeneratorCM.getValue(index));
+ }
+ // Validate all value caches at once. This executes needed requests
+ // in parallel.
+ transaction.validate(valueCaches);
+
+ int sum = 0;
+ for (ICache valueCache : valueCaches) {
+ sum += valueCache.getData();
+ }
+ return sum;
+ }
+
+ public void shutdown(final RequestMonitor rm) {
+ for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
+ dataGeneratorCM.getDataGenerator().removeListener(this);
+ dataGeneratorCM.dispose();
+ rm.done();
+ }
+ rm.done();
+ }
+
+ public void addListener(final Listener listener) {
+ // Must access fListeners on executor thread.
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fListeners.add(listener);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ public void removeListener(final Listener listener) {
+ // Must access fListeners on executor thread.
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fListeners.remove(listener);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ public void countChanged() {
+ // Must access fListeners on executor thread.
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ for (Listener listener : fListeners) {
+ listener.countChanged();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ public void valuesChanged(final Set changed) {
+ // Must access fListeners on executor thread.
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ for (Object listener : fListeners) {
+ ((Listener)listener).valuesChanged(changed);
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java
new file mode 100644
index 00000000000..fd526e74f72
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java
@@ -0,0 +1,482 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ICache;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.Transaction;
+import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
+import org.eclipse.core.runtime.CoreException;
+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 from multiple data
+ * providers using ACPM methods and performs a computation on the
+ * retrieved data.
+ *
+ * This example builds on the {@link AsyncSumDataViewer} example. It
+ * demonstrates using ACPM to solve the data consistency problem when
+ * retrieving data from multiple sources asynchronously.
+ *
+ */
+@ConfinedToDsfExecutor("fDisplayExecutor")
+public class ACPMSumDataViewer implements ILazyContentProvider
+{
+ /** View update frequency interval. */
+ final private static int UPDATE_INTERVAL = 10000;
+
+ /** Executor to use instead of Display.asyncExec(). **/
+ @ThreadSafe
+ final private DsfExecutor fDisplayExecutor;
+
+ /** Executor to use when retrieving data from data providers */
+ @ThreadSafe
+ final private ImmediateInDsfExecutor fDataExecutor;
+
+ // The viewer and generator that this content provider using.
+ final private TableViewer fViewer;
+ final private DataGeneratorCacheManager[] fDataGeneratorCMs;
+ final private DataGeneratorCacheManager fSumGeneratorCM;
+
+ // Fields used in request cancellation logic.
+ private List fItemDataRequestMonitors =
+ new LinkedList();
+ private Set fIndexesToCancel = new HashSet();
+ private int fCancelCallsPending = 0;
+ private Future> fRefreshFuture;
+
+ public ACPMSumDataViewer(TableViewer viewer,
+ ImmediateInDsfExecutor dataExecutor, IDataGenerator[] generators,
+ IDataGenerator sumGenerator)
+ {
+ fViewer = viewer;
+ fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
+ fViewer.getTable().getDisplay());
+ fDataExecutor = dataExecutor;
+
+ // Create wrappers for data generators. Don't need to register as
+ // listeners to generator events because the cache managers ensure data
+ // are already registered for them.
+ fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
+ for (int i = 0; i < generators.length; i++) {
+ fDataGeneratorCMs[i] =
+ new DataGeneratorCacheManager(fDataExecutor, generators[i]);
+ }
+ fSumGeneratorCM =
+ new DataGeneratorCacheManager(fDataExecutor, sumGenerator);
+
+ // Schedule a task to refresh the viewer periodically.
+ fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate(
+ new Runnable() {
+ public void run() {
+ queryItemCount();
+ }
+ },
+ UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
+ }
+
+ public void dispose() {
+ // Cancel the periodic task of refreshing the view.
+ fRefreshFuture.cancel(false);
+
+ // Need to dispose cache managers that were created in this class. This
+ // needs to be done on the cache manager's thread.
+ Query