diff options
Diffstat (limited to 'debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java')
-rw-r--r-- | debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java new file mode 100644 index 00000000000..96ee541ef12 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2007 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.model.IDebugTarget; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Settings manager + * + * The settings manager stores a set of settings, + * (key/value) pairs in the launch configuration so they exist across debug sessions. + * + * All active settings are stored together in a single configuration entry + * (ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT). + * + * Every setting is identified by a string identifier. That string identifier can be used to + * store an additional setting, to remove an exiting one or to retrieve a previously stored setting. + * + * The setting value consists of a String. + * + * Settings fade out automatically so clients do not necessarily need to delete old settings. This makes it + * possible to build the string identifiers with names out of the user application, like function names or + * variable names, without the danger of a constantly growing launch configuration. + * However it also causes that the settings manager must only be used for configurations and customizations for which + * always reasonable defaults exist. + * + * As cleanup policy the settings manager only keeps a certain number of settings and drops the + * least recently used one when more settings are added. The least recently used order is maintained + * across debug sessions. + * + */ + +public class CSettingsManager { + + /** + * the name of the XML node for the list + */ + private static final String CONTENT_LIST = "contentList"; //$NON-NLS-1$ + + /** + * the name of the XML node for every format entry + */ + private static final String CONTENT = "content"; //$NON-NLS-1$ + + /** + * the attribute name used to identify the object to store the content for. + */ + private static final String ATTR_CONTENT_ID = "id"; //$NON-NLS-1$ + + /** + * the attribute name of the actual content + */ + private static final String ATTR_CONTENT_VALUE = "val"; //$NON-NLS-1$ + + /** + * Number defining how many settings are stored. + * Whenever an additional setting is added when there are already MAX_USED_COUNT settings, the + * least recently used setting is dropped. + * + * The actual value is chosen to be high enough for normal use cases, but still low enough to avoid that the launch configuration + * gets arbitrarily large + */ + private static int MAX_ELEMENT_COUNT = 100; + + /** + * the map used to actually store the format information + * as key String are used, values are of type String too. + * + * The map automatically is limited to MAX_ELEMENT_COUNT + * elements, dropping the least recently used one + * when more elements are added. + */ + private Map fContentMap = new LinkedHashMap(MAX_ELEMENT_COUNT, 0.75f, true) { + private static final long serialVersionUID = 1; + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_ELEMENT_COUNT; + } + }; + + /** + * the debug target we store the values for + */ + private CDebugTarget fDebugTarget; + + /** + * Store the value for the given id. + * @param id used to identify the information. Different objects/topics should use different identifiers. + * @param value content to be stored + */ + public synchronized void putValue( String id, String value ) { + fContentMap.put(id, value); + } + /** + * remove the stored format for the given id. + * @param id used to identify the formatting information. Different objects/topics should use different identifiers. + */ + public synchronized void removeValue( String id ) { + fContentMap.remove( id ); + } + + /** Retrieve the value for the given id. + * @param id used to identify the formatting information. Different objects/topics should use different identifiers. + * @return returns the entry information for the given id, or null if no such information is available. + */ + public synchronized String getValue( String id ) { + String entry= (String) fContentMap.get( id ); + return entry; + } + + /** constructor. + * @param debugTarget + */ + public CSettingsManager( CDebugTarget debugTarget ) { + fDebugTarget = debugTarget; + initialize(); + } + + /** get the string format of the current content. + * Only stores entries which have been used in the last MAX_USED_COUNT debug sessions. + * @return + */ + private String getMemento() { + Document document = null; + try { + document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + Element node = document.createElement( CONTENT_LIST ); + document.appendChild( node ); + Set entrySet = fContentMap.entrySet(); + Iterator it = entrySet.iterator(); + while ( it.hasNext() ) { + Map.Entry entry= (Map.Entry) it.next(); + String id= (String)entry.getKey(); + String value= (String)entry.getValue(); + Element child = document.createElement( CONTENT ); + child.setAttribute( ATTR_CONTENT_ID, id ); + child.setAttribute( ATTR_CONTENT_VALUE, value ); + node.appendChild( child ); + } + return CDebugUtils.serializeDocument( document, false ); + } + catch( ParserConfigurationException e ) { + DebugPlugin.log( e ); + } + catch( IOException e ) { + DebugPlugin.log( e ); + } + catch( TransformerException e ) { + DebugPlugin.log( e ); + } + return null; + } + + /** set the current state to the one given by the memento. + * @param memento a string representation of the state to be loaded. + * @throws CoreException + */ + private void initializeFromMemento( String memento ) throws CoreException { + try { + fContentMap.clear(); + DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + StringReader reader = new StringReader( memento ); + InputSource source = new InputSource( reader ); + Element root = parser.parse( source ).getDocumentElement(); + if ( root.getNodeName().equalsIgnoreCase( CONTENT_LIST ) ) { + NodeList list = root.getChildNodes(); + int i = list.getLength() - 1; // backwards to keep least recent access order. + for( ; i >= 0; i-- ) { + Node node = list.item( i ); + short type = node.getNodeType(); + if ( type == Node.ELEMENT_NODE ) { + Element elem = (Element)node; + if ( elem.getNodeName().equalsIgnoreCase( CONTENT ) ) { + String id = elem.getAttribute( ATTR_CONTENT_ID ); + String value= elem.getAttribute( ATTR_CONTENT_VALUE ); + if ( id == null || id.length() == 0 ) { + DebugPlugin.logMessage( "unexpected entry in CSettingsManager.initializeFromMemento", null ); //$NON-NLS-1$ + continue; + } + putValue( id, value ); + } + } + } + return; + } + DebugPlugin.logMessage( "unexpected content", null ); //$NON-NLS-1$ + } + catch( ParserConfigurationException e ) { + DebugPlugin.log( e ); + } + catch( SAXException e ) { + DebugPlugin.log( e ); + } + catch( IOException e ) { + DebugPlugin.log( e ); + } + } + + /** + * read the stored format from the launch configuration + */ + private void initialize() { + ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration(); + try { + String memento = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT, "" ); //$NON-NLS-1$ + if ( memento != null && memento.trim().length() != 0 ) + initializeFromMemento( memento ); + } + catch( CoreException e ) { + DebugPlugin.log( e ); + } + } + + /** + * store the current content in the launch configuration. + */ + public synchronized void save() { + ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration(); + try { + ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); + wc.setAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT, getMemento() ); + wc.doSave(); + } + catch( CoreException e ) { + DebugPlugin.log( e ); + } + } + + /** + * accessor to the debug target + */ + IDebugTarget getDebugTarget() { + return fDebugTarget; + } +} |