/*******************************************************************************
* Copyright (c) 2010, 2015 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.cdt.tests.dsf.vm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdateListener;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
import org.junit.Assert;
/**
*
*/
public class FormattedValuesListener implements IFormattedValuesListener, IPropertiesUpdateListener {
private static final String ANY_FORMAT = "ANY_FORMAT";
private final TestModel fModel;
private List<IPropertiesUpdate> fPropertiesUpdates = new ArrayList<IPropertiesUpdate>();
private List<List<FormattedValueDMContext>> fFormattedValuesInPending = new ArrayList<List<FormattedValueDMContext>>();
private List<FormattedValueDMContext> fFormattedValuesInProgress = new LinkedList<FormattedValueDMContext>();
private List<FormattedValueDMContext> fFormattedValuesCompleted = new ArrayList<FormattedValueDMContext>();
private DsfRunnable fProcessUpdatedFormattedValuesRunnable = null;
private Set<String> fCachedFormats = new HashSet<String>();
public FormattedValuesListener(TestModel model) {
fModel = model;
}
public void setCachedFormats(String[] cachedFormats) {
fCachedFormats.clear();
fCachedFormats.addAll(Arrays.asList(cachedFormats));
}
@Override
public void propertiesUpdatesStarted(IPropertiesUpdate[] updates) {
fPropertiesUpdates.addAll(Arrays.asList(updates));
List<FormattedValueDMContext> pending = new ArrayList<FormattedValueDMContext>(updates.length);
for (IPropertiesUpdate update : updates) {
List<String> formatIds = getRequestedFormatIDs(update);
for (String formatId : formatIds) {
TestElement te = getPropertyUpdateTestElement(update);
pending.add(new FormattedValueDMContext(fModel, te, formatId));
}
}
if (!pending.isEmpty()) {
fFormattedValuesInPending.add(pending);
}
}
private List<String> getRequestedFormatIDs(IPropertiesUpdate update) {
List<String> formatIds = new ArrayList<String>(1);
for (String property : update.getProperties()) {
if (property.equals(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE)) {
formatIds.add(ANY_FORMAT);
}
if (property.startsWith(IDebugVMConstants.PROP_FORMATTED_VALUE_BASE)) {
formatIds.add(FormattedValueVMUtil.getFormatFromProperty(property, null));
}
}
return formatIds;
}
public void reset() {
reset(new String[0]);
}
public void reset(String[] cachedFormats) {
fPropertiesUpdates.clear();
fFormattedValuesInPending.clear();
fFormattedValuesInProgress.clear();
fFormattedValuesCompleted.clear();
setCachedFormats(cachedFormats);
}
public List<FormattedValueDMContext> getFormattedValuesCompleted() {
return fFormattedValuesCompleted;
}
public List<IPropertiesUpdate> getPropertiesUpdates() {
return fPropertiesUpdates;
}
public boolean isFinished() {
if ( !fFormattedValuesInProgress.isEmpty() ) {
return false;
}
if (!fFormattedValuesInPending.isEmpty() && fCachedFormats.isEmpty()) {
return false;
}
for (List<FormattedValueDMContext> pendingList : fFormattedValuesInPending) {
for (FormattedValueDMContext pending : pendingList) {
String pendingFormat = pending.getFormatID();
if (!pendingFormat.equals(ANY_FORMAT) && !fCachedFormats.contains(pendingFormat)) {
return false;
}
}
}
return true;
}
@Override
public void propertiesUpdateCompleted(IPropertiesUpdate update) {}
@Override
public void formattedValueUpdated(FormattedValueDMContext formattedValueDmc) {
Assert.assertFalse("Expected values with formats " + fCachedFormats + " to be cached.",
fCachedFormats.contains(formattedValueDmc.getFormatID()));
if (fProcessUpdatedFormattedValuesRunnable == null) {
fProcessUpdatedFormattedValuesRunnable = new DsfRunnable() {
@Override
public void run() {
fProcessUpdatedFormattedValuesRunnable = null;
processFormattedValuesInProgress();
}
};
fModel.getExecutor().execute(fProcessUpdatedFormattedValuesRunnable);
}
fFormattedValuesInProgress.add(formattedValueDmc);
}
private void processFormattedValuesInProgress() {
while (!fFormattedValuesInProgress.isEmpty()) {
List<FormattedValueDMContext> pendingList = findPendingList(fFormattedValuesInProgress.get(0));
for (FormattedValueDMContext pending : pendingList) {
int progressIdx = indexOfFormattedValueDMContext(fFormattedValuesInProgress, pending);
if (progressIdx != -1) {
// The pending DMC may contain the ANY_FORMAT format ID.
// The progress DMC must contain the exact format retrieved.
// To have a more accurate record, add the progress DMC to
// the completed updates list.
FormattedValueDMContext progress = fFormattedValuesInProgress.remove(progressIdx);
fFormattedValuesCompleted.add(progress);
} else {
Assert.fail("Pending Updates not processed in bulk \n " + pendingList);
}
}
}
}
private List<FormattedValueDMContext> findPendingList(FormattedValueDMContext dmc) {
for (Iterator<List<FormattedValueDMContext>> itr = fFormattedValuesInPending.iterator(); itr.hasNext();) {
List<FormattedValueDMContext> pendingList = itr.next();
int pendingIdx = indexOfFormattedValueDMContext(pendingList, dmc);
if (pendingIdx != -1) {
itr.remove();
return pendingList;
}
}
throw new RuntimeException("Pending update not found for element: " + dmc);
}
private int indexOfFormattedValueDMContext(List<FormattedValueDMContext> list, FormattedValueDMContext dmc) {
for (int i = 0; i < list.size(); i++) {
if (dmc.getParentValueDMContext().equals(list.get(i).getParentValueDMContext())) {
if ( ANY_FORMAT.equals(dmc.getFormatID()) ||
ANY_FORMAT.equals(list.get(i).getFormatID()) ||
dmc.getFormatID().equals(list.get(i).getFormatID()) )
{
return i;
}
}
}
return -1;
}
private TestElement getPropertyUpdateTestElement(IPropertiesUpdate update) {
Object element = update.getElement();
if (element instanceof TestElement) {
return (TestElement)element;
} else if (element instanceof TestElementVMContext) {
return ((TestElementVMContext)element).getElement();
}
throw new RuntimeException("Invalid element in properties update: " + update.getElement());
}
}