/******************************************************************************* * 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()); } }