Skip to content

Commit

Permalink
Unify Configuration- and InstancePreferences into common super-class
Browse files Browse the repository at this point in the history
  • Loading branch information
HannesWell committed Dec 19, 2023
1 parent bb97960 commit 232b1ef
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 168 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<String> loadedNodes = Collections.synchronizedSet(new HashSet<String>());
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<String> 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.
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<String> loadedNodes = Collections.synchronizedSet(new HashSet<String>());
private static boolean initialized = false;
private static final Set<String> 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
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> loadedNodes;
private AtomicBoolean initialized;

SingletonEclipsePreferences(EclipsePreferences parent, String name, Set<String> 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);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public static Properties convertToProperties(EclipsePreferences node, String pre
}

public static IPath getInstanceBaseLocation() {
return InstancePreferences.getBaseLocation();
return new InstancePreferences().getBaseLocation();
}
}

0 comments on commit 232b1ef

Please sign in to comment.