From d38aa3229672d7fd2a8cd4a28dae3cf52a77c816 Mon Sep 17 00:00:00 2001 From: Marc Dumais Date: Fri, 27 Feb 2015 09:41:26 -0500 Subject: [PATCH] Bug 460837 - [visualizer] Add persistent information storage in the MV Change-Id: I18bf08043c17f3bf4c1a2da86cbd6ef5b46d0120 --- .../ui/MulticoreVisualizerUIPlugin.java | 10 +- .../internal/ui/view/MulticoreVisualizer.java | 60 ++++-- .../internal/utils/MementoUtils.java | 202 ++++++++++++++++++ .../utils/PersistentSettingsManager.java | 193 +++++++++++++++++ 4 files changed, 451 insertions(+), 14 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/MementoUtils.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/PersistentSettingsManager.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/MulticoreVisualizerUIPlugin.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/MulticoreVisualizerUIPlugin.java index f489092e2ce..2a32270a00e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/MulticoreVisualizerUIPlugin.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/MulticoreVisualizerUIPlugin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Ericsson and others. + * Copyright (c) 2012, 2015 Ericsson 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 @@ -8,6 +8,7 @@ * Contributors: * Marc Khouzam (Ericsson) - initial API and implementation * William R. Swanson (Tilera Corporation) - added resource support + * Marc Dumais (Ericsson) - Bug 460837 *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui; @@ -16,6 +17,8 @@ import org.eclipse.cdt.visualizer.ui.plugin.CDTVisualizerUIPlugin; import org.eclipse.cdt.visualizer.ui.util.UIResourceManager; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.Font; @@ -283,4 +286,9 @@ public class MulticoreVisualizerUIPlugin extends AbstractUIPlugin public static Font getFont(String fontName, int height, int style) { return getDefault().getPluginResources().getFont(fontName, height, style); } + + /** Get the preference store for this Eclipse plug-in */ + public static IEclipsePreferences getEclipsePreferenceStore() { + return InstanceScope.INSTANCE.getNode(PLUGIN_ID); + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java index d54ecc68503..15d2a195c9e 100755 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/ui/view/MulticoreVisualizer.java @@ -24,6 +24,7 @@ * Marc Dumais (Ericsson) - Bug 458076 * Alvaro Sanchez-Leon (Ericsson) - Bug 459114 - override construction of the data model * Marc Dumais (Ericsson) - Bug 460737 + * Marc Dumais (Ericsson) - Bug 460837 *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.view; @@ -62,6 +63,8 @@ import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DSFDebugModel; import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DSFSessionState; import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.DebugViewUtils; import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.IDSFTargetDataProxy; +import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.PersistentSettingsManager; +import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils.PersistentSettingsManager.PersistentParameter; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICPUDMContext; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICoreDMContext; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.ILoadInfo; @@ -158,11 +161,13 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin /** Main switch that determines if we should display the load meters */ - protected boolean m_loadMetersEnabled = false; + private PersistentParameter m_loadMetersEnabled; + /** Timer used to trigger the update of the CPU/core load meters */ protected Timer m_updateLoadMeterTimer = null; + /** update period for the load meters */ - protected int m_loadMeterTimerPeriod = LOAD_METER_TIMER_MEDIUM; // default 1000ms + private PersistentParameter m_loadMeterTimerPeriod; // Load meters refresh periods, in ms /** constant for the very short load meters update period */ @@ -233,6 +238,9 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin /** Menu action */ protected PinToDebugSessionAction m_pinToDbgSessionAction = null; + + /** persistent settings manager */ + protected PersistentSettingsManager m_persistentSettingsManager = null; // --- constructors/destructors --- @@ -272,14 +280,29 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin if (m_visualizerInstanceId == null) { m_visualizerInstanceId = "0"; //$NON-NLS-1$ } + initializePersistentParameters(m_visualizerInstanceId); } + /** + * Initialize the persistent parameters + */ + protected void initializePersistentParameters(String visualizerInstanceId) { + // setting managers + m_persistentSettingsManager = new PersistentSettingsManager("MulticoreVisualizer", visualizerInstanceId); //$NON-NLS-1$ + + // define persistent parameters: + m_loadMetersEnabled = m_persistentSettingsManager.getNewParameter(Boolean.class, + "enableLoadMeters", true, false); //$NON-NLS-1$ + m_loadMeterTimerPeriod = m_persistentSettingsManager.getNewParameter(Integer.class, + "loadMeterTimerPeriod", true, LOAD_METER_TIMER_MEDIUM); //$NON-NLS-1$ + } + /** * Sets-up the timer associated to load meters refresh */ protected void initializeLoadMeterTimer() { - if (!m_loadMetersEnabled) return; - m_updateLoadMeterTimer = getLoadTimer(m_sessionState, m_loadMeterTimerPeriod); + if (!getLoadMetersEnabled()) return; + m_updateLoadMeterTimer = getLoadTimer(m_sessionState, getLoadMeterTimerPeriod()); // one-shot timer (re-scheduled upon successful triggering) m_updateLoadMeterTimer.setRepeating(false); } @@ -328,24 +351,34 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin */ public void setLoadMeterTimerPeriod(int p) { assert (p > LOAD_METER_TIMER_MIN); - if (m_loadMeterTimerPeriod == p) return; - m_loadMeterTimerPeriod = p > LOAD_METER_TIMER_MIN ? p : LOAD_METER_TIMER_MIN; + if (getLoadMeterTimerPeriod() == p) return; + m_loadMeterTimerPeriod.set(p > LOAD_METER_TIMER_MIN ? p : LOAD_METER_TIMER_MIN); disposeLoadMeterTimer(); initializeLoadMeterTimer(); } + /** Gets the load meter period */ + public int getLoadMeterTimerPeriod() { + return m_loadMeterTimerPeriod != null ? m_loadMeterTimerPeriod.value() : 0; + } + /** * enables or disables the load meters */ public void setLoadMetersEnabled(boolean enabled) { - if (m_loadMetersEnabled == enabled) return; - m_loadMetersEnabled = enabled; + if (m_loadMetersEnabled.value() == enabled) return; + m_loadMetersEnabled.set(enabled); // save load meter enablement in model - fDataModel.setLoadMetersEnabled(m_loadMetersEnabled); + fDataModel.setLoadMetersEnabled(getLoadMetersEnabled()); disposeLoadMeterTimer(); initializeLoadMeterTimer(); } + /** Returns whether the load meters are enabled */ + public boolean getLoadMetersEnabled() { + return m_loadMetersEnabled != null? m_loadMetersEnabled.value() : false; + } + // --- canvas management --- /** Creates and returns visualizer canvas control. */ @@ -457,7 +490,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin m_loadMetersRefreshSubSubmenu = new MenuManager(MulticoreVisualizerUIPlugin.getString( "MulticoreVisualizer.actions.LoadMetersRefreshSubSubmenu.text")); //$NON-NLS-1$ - m_enableLoadMetersAction = new EnableLoadMetersAction(m_loadMetersEnabled); + m_enableLoadMetersAction = new EnableLoadMetersAction(getLoadMetersEnabled()); m_enableLoadMetersAction.init(this); // enable the load meter sub-menu m_enableLoadMetersAction.setEnabled(true); @@ -467,6 +500,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin MulticoreVisualizerUIPlugin.getString("MulticoreVisualizer.actions.SetLoadMeterPeriod.fast.text"), //$NON-NLS-1$ LOAD_METER_TIMER_FAST)); + // TODO: the default load meter refresh speed is set here but we could instead rely on the value saved in the data store SetLoadMeterPeriodAction defaultAction = new SetLoadMeterPeriodAction( MulticoreVisualizerUIPlugin.getString("MulticoreVisualizer.actions.SetLoadMeterPeriod.medium.text"), //$NON-NLS-1$ LOAD_METER_TIMER_MEDIUM); @@ -520,7 +554,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin // show the load meter refresh speed sub-menu only // if the load meters are enabled - m_loadMetersRefreshSubSubmenu.setVisible(m_loadMetersEnabled); + m_loadMetersRefreshSubSubmenu.setVisible(getLoadMetersEnabled()); // Enable pinning menu item when there is a current debug session m_pinToDbgSessionAction.setEnabled(m_sessionState != null); @@ -1158,7 +1192,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin /** Invoked when getModel() request completes. */ @ConfinedToDsfExecutor("getSession().getExecutor()") public void getVisualizerModelDone(VisualizerModel model) { - model.setLoadMetersEnabled(m_loadMetersEnabled); + model.setLoadMetersEnabled(getLoadMetersEnabled()); updateLoads(model); model.sort(); setCanvasModel(model); @@ -1395,7 +1429,7 @@ public class MulticoreVisualizer extends GraphicCanvasVisualizer implements IPin return; } // if meters not enabled, do not query backend - if (!m_loadMetersEnabled) { + if (!getLoadMetersEnabled()) { return; } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/MementoUtils.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/MementoUtils.java new file mode 100644 index 00000000000..806665a6519 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/MementoUtils.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson 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: + * Marc Dumais (Ericsson) - initial API and implementation (bug 460837) + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils; + +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** encodes and decodes memento to and from different data types; list, map, String*/ +public class MementoUtils { + + protected static final String ROOT_ELEMENT_TAGNAME = "root_element"; //$NON-NLS-1$ + protected static final String ELEMENT_TAGNAME = "elem"; //$NON-NLS-1$ + protected static final String ATTRIBUTE_NAME = "value"; //$NON-NLS-1$ + + + /** Returns a XML memento, that encodes a single String parameter */ + public static String encodeStringIntoMemento(String str) { + List list = new ArrayList(); + list.add(str); + return encodeListIntoMemento(list); + } + + + /** Returns a single String parameter, decoded from a XML memento */ + public static String decodeStringFromMemento(String memento) { + return decodeListFromMemento(memento).get(0); + } + + /** Returns a XML memento, that encodes a Map of Strings */ + public static String encodeMapIntoMemento(Map keyPairValues) { + String returnValue = null; + + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = null; + try { + docBuilder = dfactory.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Element rootElement = doc.createElement(ROOT_ELEMENT_TAGNAME); + doc.appendChild(rootElement); + // create one XML element per map entry + for (String key : keyPairValues.keySet()) { + Element elem = doc.createElement(ELEMENT_TAGNAME); + elem.setAttribute(key, keyPairValues.get(key)); + rootElement.appendChild(elem); + } + + ByteArrayOutputStream s = new ByteArrayOutputStream(); + + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + + DOMSource source = new DOMSource(doc); + StreamResult outputTarget = new StreamResult(s); + transformer.transform(source, outputTarget); + + returnValue = s.toString("UTF8"); //$NON-NLS-1$ + } catch (Exception e) { + e.printStackTrace(); + } + return returnValue; + } + + + /** Returns a Map of Strings, decoded from a XML memento */ + public static Map decodeMapFromMemento(String memento) { + Map keyPairValues = new HashMap(); + + Element root = null; + DocumentBuilder parser; + try { + parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + parser.setErrorHandler(new DefaultHandler()); + root = parser.parse(new InputSource(new StringReader(memento))).getDocumentElement(); + NodeList nodeList = root.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element elem = (Element) node; + NamedNodeMap nodeMap = elem.getAttributes(); + for(int idx = 0; idx < nodeMap.getLength(); idx++) { + Node attrNode = nodeMap.item(idx); + if (attrNode.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr attr = (Attr) attrNode; + String key = attr.getName(); + String value = attr.getValue(); + if (key != null && value != null) { + keyPairValues.put(key, value); + } + else { + throw new Exception(); + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return keyPairValues; + } + + + /** Returns a XML memento, that encodes a List of Strings */ + public static String encodeListIntoMemento(List labels) { + String returnValue = null; + + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = null; + try { + docBuilder = dfactory.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Element rootElement = doc.createElement(ROOT_ELEMENT_TAGNAME); + doc.appendChild(rootElement); + // create one XML element per list entry to save + for (String lbl : labels) { + Element elem = doc.createElement(ELEMENT_TAGNAME); + elem.setAttribute(ATTRIBUTE_NAME, lbl); + rootElement.appendChild(elem); + } + + ByteArrayOutputStream s = new ByteArrayOutputStream(); + + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + + DOMSource source = new DOMSource(doc); + StreamResult outputTarget = new StreamResult(s); + transformer.transform(source, outputTarget); + + returnValue = s.toString("UTF8"); //$NON-NLS-1$ + } catch (Exception e) { + e.printStackTrace(); + } + return returnValue; + } + + /** Returns a List of Strings, decoded from a XML memento */ + public static List decodeListFromMemento(String memento) { + List list = new ArrayList(); + + Element root = null; + DocumentBuilder parser; + try { + parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + parser.setErrorHandler(new DefaultHandler()); + root = parser.parse(new InputSource(new StringReader(memento))).getDocumentElement(); + NodeList nodeList = root.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element elem = (Element) node; + String value = elem.getAttribute(ATTRIBUTE_NAME); + if (value != null) { + list.add(value); + } + else { + throw new Exception(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/PersistentSettingsManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/PersistentSettingsManager.java new file mode 100644 index 00000000000..f7a9364ed7f --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.multicorevisualizer.ui/src/org/eclipse/cdt/dsf/gdb/multicorevisualizer/internal/utils/PersistentSettingsManager.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson 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: + * Marc Dumais (Ericsson) - initial API and implementation (bug 460837) + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils; + +import java.security.InvalidParameterException; + +import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.MulticoreVisualizerUIPlugin; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.osgi.service.prefs.BackingStoreException; + +/** This class manages one or more PersistentSetting objects, using a commmon + * name-space and optionally an instance id so that multiple instances can + * each have their own version of the parameter persisted */ +public class PersistentSettingsManager { + // TODO: add a way to notify clients that the value of a global (shared) parameter + // has been updated, and that they should re-read it. + + /** Class for a specific persistent parameter */ + public class PersistentParameter { + private String m_storeKey; + private T m_value; + private T m_defaultValue; + private Class myClazz; + private boolean m_perInstance; + + /** + * Constructor + * @param name: unique (for the namespace) label that identifies this parameter + * @param perInstance: whether the parameter's value is persisted per client instance or + * globally (one common shared stored value for all instances) + * @param storeKey : The key used to store the parameter in the store + */ + public PersistentParameter(Class clazz, boolean perInstance, String storeKey) { + myClazz = clazz; + m_perInstance = perInstance; + m_storeKey = storeKey; + } + + /** Sets the default value to use if no persistent + * value is found for this parameter */ + public void setDefault(T defaultValue) { + m_defaultValue = defaultValue; + } + + /** Sets the persistent value to set */ + public void set(T value) { + m_value = value; + // save value in preference store + persistParameter(value); + } + + /** Gets the persistent value, if found, else the default value */ + public T value() { + if (m_value == null) { + // attempt to get the value from the preference store + m_value = restoreParameter(); + } + // parameter has one value for any/all instances + else if(!m_perInstance) { + // do not rely on cached value, since another instance might have + // changed it - reread from data store + m_value = restoreParameter(); + } + return (m_value!=null)? m_value : m_defaultValue; + } + + /** Attempts to find the parameter in the preference store. Returns null if not found */ + private T restoreParameter() { + IEclipsePreferences store = MulticoreVisualizerUIPlugin.getEclipsePreferenceStore(); + String memento = store.get(m_storeKey, null); + if (memento == null) return null; + + String val = MementoUtils.decodeStringFromMemento(memento); + + T convertedVal = convertToT(val); + return convertedVal; + } + + /** Saves parameter's value in preference store */ + private void persistParameter(T value) { + // create memento + String memento = MementoUtils.encodeStringIntoMemento(value.toString()); + + // save memento in store + if (memento != null) { + IEclipsePreferences store = MulticoreVisualizerUIPlugin.getEclipsePreferenceStore(); + store.put(m_storeKey, memento); + try { + store.flush(); + } catch (BackingStoreException e) { + e.printStackTrace(); + } + } + } + + @SuppressWarnings("unchecked") + /** Converts the stored value from a String to its expected type */ + private T convertToT(String val) { + // TODO: Add other types? Float, etc + if (String.class.isAssignableFrom(myClazz)) { + return (T) val; + } + else if (Integer.class.isAssignableFrom(myClazz)) { + return (T) Integer.valueOf(val); + } + else if (Boolean.class.isAssignableFrom(myClazz)) { + return (T) Boolean.valueOf(val); + } + + return null; + } + } + + /** String that is used to insulate the namespace for the parameters + * saved by a specific instance of the class */ + private final String m_category; + + /** an identifier that differentiates different client instances. For example, to save the + * value of a parameter that is applicable per-view, the view secondary id could be used so + * that each view has its own stored value */ + private final String m_instance; + + /** + * Constructor + * @param category : an optional id that is used to insulate the namespace for the parameters + * saved by this instance of the class. Using different category values permits to distinguish + * two or more parameters with the same label. Example: class name where the parameter is used. + * This can be set to null if unused. + * @param instance : a unique id that identifies the client's instance. Used when + * a parameter is defined as per-instance + */ + public PersistentSettingsManager(String category, String instance) { + m_category = category != null ? category : ""; //$NON-NLS-1$ + m_instance = instance != null ? instance : ""; //$NON-NLS-1$ + } + + /** Constructor + * @param instance: a unique id that identifies the client's instance. Used when + * a parameter is not global (i.e. meant to be persisted per instance). + */ + public PersistentSettingsManager(String instance) { + this(null, instance); + } + + /** Constructor */ + public PersistentSettingsManager() { + this(null, null); + } + + /** + * Creates a new persistent parameter, using the namespace and instance id of this manager. + * @param clazz: the class of the persistent parameter. Supported types: String, Integer, Boolean + * @param label: unique label that identifies this parameter. + * @param perInstance: whether the parameter's value should be persisted per client instance or + * globally (one common shared stored value for all instances) + * @param defaultValue: default value to use (mandatory) + */ + public PersistentParameter getNewParameter(Class clazz, String label, boolean perInstance, T defaultValue) { + // check that we're dealing with one of a few supported types + // TODO: Add other types? Float, etc + if (String.class.isAssignableFrom(clazz) || + Integer.class.isAssignableFrom(clazz) || + Boolean.class.isAssignableFrom(clazz)) + { + PersistentParameter setting; + // build the final store key with category, parameter label and specific instance, if applicable + setting = new PersistentParameter(clazz, perInstance, getStorageKey(perInstance) + "." + label); //$NON-NLS-1$ + setting.setDefault(defaultValue); + + return setting; + } + else { + throw new InvalidParameterException("Unsupported class type: " + clazz.toString()); //$NON-NLS-1$ + } + } + + + /** Returns the key to be used to save parameter, taking into account the + * instance id, if applicable */ + private String getStorageKey(boolean perInstance) { + return (perInstance ? m_instance : "") + (!m_category.equals("") ? "." + m_category : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + +}