diff options
author | DJ Houghton | 2009-12-01 18:34:24 +0000 |
---|---|---|
committer | DJ Houghton | 2009-12-01 18:34:24 +0000 |
commit | d0667de09b490da27f357759f89accbac42dbbff (patch) | |
tree | 01f5feecf138e200552aede396fbd2f8e23b5969 /bundles/org.eclipse.equinox.preferences/src | |
parent | 7143726365b6921b405cf0ce6e067aefe10224e5 (diff) | |
download | rt.equinox.bundles-d0667de09b490da27f357759f89accbac42dbbff.tar.gz rt.equinox.bundles-d0667de09b490da27f357759f89accbac42dbbff.tar.xz rt.equinox.bundles-d0667de09b490da27f357759f89accbac42dbbff.zip |
Bug 293331 - API to determine when preference settings have been overridden
Diffstat (limited to 'bundles/org.eclipse.equinox.preferences/src')
4 files changed, 271 insertions, 7 deletions
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/BundleDefaultPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/BundleDefaultPreferences.java new file mode 100644 index 000000000..acbf2cd94 --- /dev/null +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/BundleDefaultPreferences.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2009 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.preferences; + +import java.util.*; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.preferences.*; + +/** + * This class represents a preference node in the "bundle_defaults" scope. This scope is + * used to represent default values which are set by the bundle in either its preference + * initializer or in a file included with the bundle. + * + * This differs from the regular default scope because it does not contain values set + * by the product preference customization or the command-line. + * + * @since 3.3 + */ +public class BundleDefaultPreferences extends EclipsePreferences { + + private static Set loadedNodes = Collections.synchronizedSet(new HashSet()); + private String qualifier; + private int segmentCount; + private IEclipsePreferences loadLevel; + + /* + * Default constructor. + */ + public BundleDefaultPreferences() { + this(null, null); + } + + private BundleDefaultPreferences(EclipsePreferences parent, String name) { + super(parent, name); + // cache the segment count + IPath path = new Path(absolutePath()); + segmentCount = path.segmentCount(); + if (segmentCount < 2) + return; + + // cache the qualifier + String scope = path.segment(0); + if (BundleDefaultsScope.SCOPE.equals(scope)) + qualifier = path.segment(1); + + // cache the location + if (qualifier == null) + return; + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#getLoadLevel() + */ + protected IEclipsePreferences getLoadLevel() { + if (loadLevel == null) { + if (qualifier == null) + return null; + // Make it relative to this node rather than navigating to it from the root. + // Walk backwards up the tree starting at this node. + // This is important to avoid a chicken/egg thing on startup. + IEclipsePreferences node = this; + for (int i = 2; i < segmentCount; i++) + node = (IEclipsePreferences) node.parent(); + loadLevel = node; + } + return loadLevel; + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#isAlreadyLoaded(org.eclipse.core.runtime.preferences.IEclipsePreferences) + */ + protected boolean isAlreadyLoaded(IEclipsePreferences node) { + return loadedNodes.contains(node.name()); + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#loaded() + */ + protected void loaded() { + loadedNodes.add(name()); + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#load() + */ + protected void load() { + // ensure that the same node in the "default" scope is loaded so this one is + // initialized properly + String relativePath = DefaultPreferences.getScopeRelativePath(absolutePath()); + if (relativePath != null) { + // touch the node to force a load + PreferencesService.getDefault().getRootNode().node(DefaultScope.SCOPE).node(relativePath); + } + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#internalCreate(org.eclipse.core.internal.preferences.EclipsePreferences, java.lang.String, java.lang.Object) + */ + protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) { + return new BundleDefaultPreferences(nodeParent, nodeName); + } +} diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java index c42f904b2..d96f1ab88 100644 --- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2008 IBM Corporation and others. + * Copyright (c) 2004, 2009 IBM Corporation 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 @@ -18,10 +18,12 @@ import java.util.*; import org.eclipse.core.internal.preferences.exchange.IProductPreferencesService; import org.eclipse.core.internal.runtime.RuntimeLog; import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.preferences.BundleDefaultsScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.service.prefs.Preferences; import org.osgi.util.tracker.ServiceTracker; /** @@ -39,6 +41,7 @@ public class DefaultPreferences extends EclipsePreferences { private static Properties productTranslation; private static Properties commandLineCustomization; private EclipsePreferences loadLevel; + private Thread initializingThread; // cached values private String qualifier; @@ -229,16 +232,90 @@ public class DefaultPreferences extends EclipsePreferences { * @see org.eclipse.core.internal.preferences.EclipsePreferences#load() */ protected void load() { - loadDefaults(); - } - - private void loadDefaults() { - applyRuntimeDefaults(); - applyBundleDefaults(); + setInitializingBundleDefaults(); + try { + applyRuntimeDefaults(); + applyBundleDefaults(); + } finally { + clearInitializingBundleDefaults(); + } applyProductDefaults(); applyCommandLineDefaults(); } + /* (non-Javadoc) + * @see org.eclipse.core.internal.preferences.EclipsePreferences#internalPut(java.lang.String, java.lang.String) + */ + protected String internalPut(String key, String newValue) { + // set the value in this node + String result = super.internalPut(key, newValue); + + // if we are setting the bundle defaults, then set the corresponding value in + // the bundle_defaults scope + if (isInitializingBundleDefaults()) { + String relativePath = getScopeRelativePath(absolutePath()); + if (relativePath != null) { + Preferences node = PreferencesService.getDefault().getRootNode().node(BundleDefaultsScope.SCOPE).node(relativePath); + node.put(key, newValue); + } + } + return result; + } + + /* + * Set that we are in the middle of initializing the bundle defaults. + * This is stored on the load level so we know where to look when + * we are setting values on sub-nodes. + */ + private void setInitializingBundleDefaults() { + IEclipsePreferences node = getLoadLevel(); + if (node instanceof DefaultPreferences) { + DefaultPreferences loader = (DefaultPreferences) node; + loader.initializingThread = Thread.currentThread(); + } + } + + /* + * Clear the bit saying we are in the middle of initializing the bundle defaults. + * This is stored on the load level so we know where to look when + * we are setting values on sub-nodes. + */ + private void clearInitializingBundleDefaults() { + IEclipsePreferences node = getLoadLevel(); + if (node instanceof DefaultPreferences) { + DefaultPreferences loader = (DefaultPreferences) node; + loader.initializingThread = null; + } + } + + /* + * Are we in the middle of initializing defaults from the bundle + * initializer or found in the bundle itself? Look on the load level in + * case we are in a sub-node. + */ + private boolean isInitializingBundleDefaults() { + IEclipsePreferences node = getLoadLevel(); + if (node instanceof DefaultPreferences) { + DefaultPreferences loader = (DefaultPreferences) node; + return loader.initializingThread == Thread.currentThread(); + } + return false; + } + + /* + * Return a path which is relative to the scope of this node. + * e.g. com.example.foo for /instance/com.example.foo + */ + protected static String getScopeRelativePath(String absolutePath) { + // shouldn't happen but handle empty or root + if (absolutePath.length() < 2) + return null; + int index = absolutePath.indexOf('/', 1); + if (index == -1 || index + 1 >= absolutePath.length()) + return null; + return absolutePath.substring(index + 1); + } + private Properties loadProperties(URL url) { Properties result = new Properties(); if (url == null) diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java index a563f9876..62df2fc7d 100644 --- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java @@ -370,6 +370,8 @@ public class PreferencesService implements IPreferencesService { } private void initializeDefaultScopes() { + defaultScopes.put(BundleDefaultsScope.SCOPE, new BundleDefaultPreferences()); + root.addChild(BundleDefaultsScope.SCOPE, null); defaultScopes.put(DefaultScope.SCOPE, new DefaultPreferences()); root.addChild(DefaultScope.SCOPE, null); defaultScopes.put(InstanceScope.SCOPE, new InstancePreferences()); diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/BundleDefaultsScope.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/BundleDefaultsScope.java new file mode 100644 index 000000000..bbeb9ab6b --- /dev/null +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/BundleDefaultsScope.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.runtime.preferences; + +import org.eclipse.core.internal.preferences.AbstractScope; +import org.eclipse.core.runtime.IPath; + +/** + * Object representing the bundle defaults scope in the Eclipse preferences + * hierarchy. Can be used as a context for searching for preference + * values (in the IPreferencesService APIs) or for determining the + * correct preference node to set values in the store. + * <p> + * The bundle defaults are the defaults are default values which have + * been set either by the bundle's preference initializer or by a customization + * file supplied with the bundle. + * <p> + * Bundle default preferences are not persisted to disk. + * </p> + * <p> + * The path for preferences defined in the bundle defaults scope hierarchy + * is as follows: <code>/bundle_defaults/<qualifier></code> + * </p> + * <p> + * This class is not intended to be subclassed. This class may be instantiated. + * </p> + * @since 3.3 + * @noextend This class is not intended to be subclassed by clients. + */ +public final class BundleDefaultsScope extends AbstractScope implements IScopeContext { + + /** + * String constant (value of <code>"default"</code>) used for the + * scope name for the default preference scope. + */ + public static final String SCOPE = "bundle_defaults"; //$NON-NLS-1$ + + /** + * Create and return a new default scope instance. + */ + public BundleDefaultsScope() { + super(); + } + + /* + * @see org.eclipse.core.runtime.preferences.IScopeContext#getName() + */ + public String getName() { + return SCOPE; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IScopeContext#getNode(java.lang.String) + */ + public IEclipsePreferences getNode(String qualifier) { + return super.getNode(qualifier); + } + + /* + * @see org.eclipse.core.runtime.preferences.IScopeContext#getLocation() + */ + public IPath getLocation() { + // We don't persist defaults so return null. + return null; + } +} |