diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ConfigurationPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ConfigurationPreferences.java index 3df9ba94be2..53c539e1edb 100644 --- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ConfigurationPreferences.java +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/ConfigurationPreferences.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2022 IBM Corporation and others. + * Copyright (c) 2004, 2023 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,38 +10,25 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Hannes Wellmann - Unify Configuration- and InstancePreferences into common super-class *******************************************************************************/ package org.eclipse.core.internal.preferences; -import java.net.URL; -import java.util.*; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; -import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.core.runtime.preferences.ConfigurationScope; /** * @since 3.0 */ -public class ConfigurationPreferences extends EclipsePreferences { +public class ConfigurationPreferences extends SingletonEclipsePreferences { - // cached values - private int segmentCount; - private String qualifier; - private IPath location; - private IEclipsePreferences loadLevel; // cache which nodes have been loaded from disk - private static Set loadedNodes = Collections.synchronizedSet(new HashSet()); - private static boolean initialized = false; - private static IPath baseLocation; - - static { - Location location = PreferencesOSGiUtils.getDefault().getConfigurationLocation(); - if (location != null) { - URL url = location.getURL(); - if (url != null) - baseLocation = IPath.fromOSString(url.getFile()); - } - } + private static final Set LOADED_NODES = ConcurrentHashMap.newKeySet(); + private static final AtomicBoolean INITIALIZED = new AtomicBoolean(); + private static final IPath BASE_LOCATION = ConfigurationScope.INSTANCE.getLocation(); /** * Default constructor. Should only be called by #createExecutableExtension. @@ -51,74 +38,12 @@ public ConfigurationPreferences() { } private ConfigurationPreferences(EclipsePreferences parent, String name) { - super(parent, name); - - initializeChildren(); - - // cache the segment count - String path = absolutePath(); - segmentCount = getSegmentCount(path); - if (segmentCount < 2) - return; - - // cache the qualifier - qualifier = getSegment(path, 1); - - // cache the location - if (qualifier == null) - return; - if (baseLocation != null) - location = computeLocation(baseLocation, qualifier); - } - - @Override - protected IPath getLocation() { - return location; + super(parent, name, LOADED_NODES, INITIALIZED); } @Override - protected boolean isAlreadyLoaded(IEclipsePreferences node) { - return loadedNodes.contains(node.name()); - } - - @Override - protected void loaded() { - loadedNodes.add(name()); - } - - /* - * Return the node at which these preferences are loaded/saved. - */ - @Override - 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 = (EclipsePreferences) node.parent(); - loadLevel = node; - } - return loadLevel; - } - - protected void initializeChildren() { - if (initialized || parent == null) - return; - try { - synchronized (this) { - if (baseLocation == null) - return; - for (String n : computeChildren(baseLocation)) { - addChild(n, null); - } - } - } finally { - initialized = true; - } + IPath getBaseLocation() { + return BASE_LOCATION; } @Override diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/InstancePreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/InstancePreferences.java index bc7e4fd03cb..c541c8d94c8 100644 --- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/InstancePreferences.java +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/InstancePreferences.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2022 IBM Corporation and others. + * Copyright (c) 2004, 2023 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,31 +10,29 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Hannes Wellmann - Unify Configuration- and InstancePreferences into common super-class *******************************************************************************/ package org.eclipse.core.internal.preferences; -import java.util.*; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.internal.runtime.MetaDataKeeper; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.osgi.service.datalocation.Location; /** * @since 3.0 */ -public class InstancePreferences extends EclipsePreferences { +public class InstancePreferences extends SingletonEclipsePreferences { - // cached values - private String qualifier; - private int segmentCount; - private IEclipsePreferences loadLevel; - private IPath location; // cache which nodes have been loaded from disk - private static Set loadedNodes = Collections.synchronizedSet(new HashSet()); - private static boolean initialized = false; + private static final Set LOADED_NODES = ConcurrentHashMap.newKeySet(); + private static final AtomicBoolean INITIALIZED = new AtomicBoolean(); private static IPath baseLocation; - /* package */static IPath getBaseLocation() { + @Override + IPath getBaseLocation() { // If we are running with -data=@none we won't have an instance location. // By leaving the value of baseLocation as null we still allow the users // to set preferences in this scope but the values will not be persisted @@ -55,77 +53,11 @@ public InstancePreferences() { } private InstancePreferences(EclipsePreferences parent, String name) { - super(parent, name); - - initializeChildren(); - - // cache the segment count - String path = absolutePath(); - segmentCount = getSegmentCount(path); - if (segmentCount < 2) - return; - - // cache the qualifier - qualifier = getSegment(path, 1); - + super(parent, name, LOADED_NODES, INITIALIZED); // don't cache the location until later in case instance prefs are // accessed before the instance location is set. } - @Override - protected boolean isAlreadyLoaded(IEclipsePreferences node) { - return loadedNodes.contains(node.name()); - } - - @Override - protected void loaded() { - loadedNodes.add(name()); - } - - @Override - protected IPath getLocation() { - if (location == null) - location = computeLocation(getBaseLocation(), qualifier); - return location; - } - - /* - * Return the node at which these preferences are loaded/saved. - */ - @Override - 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; - } - - /* - * Initialize the children for the root of this node. Store the names as keys in - * the children table so we can lazily load them later. - */ - protected void initializeChildren() { - if (initialized || parent == null) - return; - try { - synchronized (this) { - for (String n : computeChildren(getBaseLocation())) { - addChild(n, null); - } - } - } finally { - initialized = true; - } - } - @Override protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) { return new InstancePreferences(nodeParent, nodeName); diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SingletonEclipsePreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SingletonEclipsePreferences.java new file mode 100644 index 00000000000..dbcaba2bdab --- /dev/null +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SingletonEclipsePreferences.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2004, 2023 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Hannes Wellmann - Unify Configuration- and InstancePreferences into common super-class + *******************************************************************************/ +package org.eclipse.core.internal.preferences; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; + +public abstract class SingletonEclipsePreferences extends EclipsePreferences { + // cached values + String qualifier; + private int segmentCount; + private IPath location; + private IEclipsePreferences loadLevel; + private Set loadedNodes; + private AtomicBoolean initialized; + + SingletonEclipsePreferences(EclipsePreferences parent, String name, Set loadedNodes, + AtomicBoolean initialized) { + super(parent, name); + this.loadedNodes = loadedNodes; + this.initialized = initialized; + + initializeChildren(); + + // cache the segment count + String path = absolutePath(); + segmentCount = getSegmentCount(path); + if (segmentCount < 2) { + return; + } + // cache the qualifier + qualifier = getSegment(path, 1); + } + + abstract IPath getBaseLocation(); + + @Override + protected boolean isAlreadyLoaded(IEclipsePreferences node) { + return loadedNodes.contains(node.name()); + } + + @Override + protected void loaded() { + loadedNodes.add(name()); + } + + @Override + protected IPath getLocation() { + if (location == null && qualifier != null) { + location = computeLocation(getBaseLocation(), qualifier); + } + return location; + } + + /* + * Return the node at which these preferences are loaded/saved. + */ + @Override + 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; + } + + /* + * Initialize the children for the root of this node. Store the names as keys in + * the children table so we can lazily load them later. + */ + protected void initializeChildren() { + if (initialized.get() || parent == null) + return; + try { + synchronized (this) { + IPath baseLocation = getBaseLocation(); + if (baseLocation == null) { + return; + } + for (String n : computeChildren(baseLocation)) { + addChild(n, null); + } + } + } finally { + initialized.set(true); + } + } + +} diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java index 22385ea7166..6f752ff1f4d 100644 --- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java +++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/TestHelper.java @@ -24,6 +24,6 @@ public static Properties convertToProperties(EclipsePreferences node, String pre } public static IPath getInstanceBaseLocation() { - return InstancePreferences.getBaseLocation(); + return new InstancePreferences().getBaseLocation(); } }