Copyright (c) 2004, 2015 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
/*******************************************************************************
* Copyright (c) 2004, 2015 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
*******************************************************************************/
package org.eclipse.core.internal.preferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import org.osgi.service.prefs.PreferencesService;
Implements OSGi PreferencesService using the Eclipse preference system.
Note: Eclipse preferences are accessible through the OSGi Preferences API and vice
versa.
/**
* <p>
* Implements OSGi PreferencesService using the Eclipse preference system.
* </p>
*
* <p>
* Note: Eclipse preferences are accessible through the OSGi Preferences API and vice
* versa.
* </p>
*/
public class OSGiPreferencesServiceImpl implements PreferencesService {
Adaptor that implements OSGi Preferences interface on top of EclipsePreferences.
Creates a "local root" since OSGi preferences have lots of roots but eclipse
only has one.
/**
* Adaptor that implements OSGi Preferences interface on top of EclipsePreferences.
* Creates a "local root" since OSGi preferences have lots of roots but eclipse
* only has one.
*/
private static final class OSGiLocalRootPreferences implements Preferences {
//The "local" root of this preference tree (not the real Eclipse root)
private Preferences root;
//the node this node is wrappering
private Preferences wrapped;
private OSGiLocalRootPreferences(Preferences root) {
this(root, root);
}
private OSGiLocalRootPreferences(Preferences wrapped, Preferences root) {
this.root = root;
this.wrapped = wrapped;
}
If pathName is absolute make it "absolute" with respect to this root.
If pathName is relative, just return it
/**
* If pathName is absolute make it "absolute" with respect to this root.
* If pathName is relative, just return it
*/
private String fixPath(String pathName) {
if (pathName.startsWith("/")) { //$NON-NLS-1$
if (pathName.equals("/")) { //$NON-NLS-1$
return root.absolutePath();
}
//fix absolute path
return root.absolutePath().concat(pathName);
}
//pass-through relative path
return pathName;
}
Override node(String pathName) to be more strict about forbidden names - EclipsePreferences implementation does a best-effort instead of throwing IllegalArgumentException
. /**
* Override node(String pathName) to be more strict about forbidden names -
* EclipsePreferences implementation does a best-effort instead of throwing
* {@link IllegalArgumentException}.
*/
@Override
public Preferences node(String pathName) {
pathName = fixPath(pathName);
if ((pathName.length() > 1 && pathName.endsWith("/")) //$NON-NLS-1$
|| pathName.indexOf("//") != -1) { //$NON-NLS-1$
throw new IllegalArgumentException();
}
return new OSGiLocalRootPreferences(wrapped.node(pathName), root);
}
Override getByteArray(String key, byte [] defaultValue) to be more strict when
decoding byte values. EclipsePreferences implementation pads bytes if they are not 4
bytes long, but the OSGi TCK expects this function to return null if the length of
the byte array is not an even multiple of 4.
Also catches any decoding exceptions and returns the default value instead of
propagating the exception.
/**
* <p>
* Override getByteArray(String key, byte [] defaultValue) to be more strict when
* decoding byte values. EclipsePreferences implementation pads bytes if they are not 4
* bytes long, but the OSGi TCK expects this function to return null if the length of
* the byte array is not an even multiple of 4.
* </p>
* <p>
* Also catches any decoding exceptions and returns the default value instead of
* propagating the exception.
* </p>
*/
@Override
public byte[] getByteArray(String key, byte[] defaultValue) {
String value = wrapped.get(key, null);
byte[] byteArray = null;
if (value != null) {
byte[] encodedBytes = value.getBytes();
if (encodedBytes.length % 4 == 0) {
try {
byteArray = Base64.decode(encodedBytes);
} catch (Exception e) {
//do not raise exception - return defaultValue
}
}
}
return byteArray == null ? defaultValue : byteArray;
}
@Override
public Preferences parent() {
if (wrapped == root) {
try {
if (!wrapped.nodeExists("")) { //$NON-NLS-1$
throw new IllegalStateException();
}
} catch (BackingStoreException e) {
//best effort
}
return null;
}
return new OSGiLocalRootPreferences(wrapped.parent(), root);
}
@Override
public boolean nodeExists(String pathName) throws BackingStoreException {
return wrapped.nodeExists(fixPath(pathName));
}
@Override
public String absolutePath() {
if (wrapped == root) {
return "/"; //$NON-NLS-1$
}
return wrapped.absolutePath().substring(root.absolutePath().length(), wrapped.absolutePath().length());
}
@Override
public String name() {
if (wrapped == root) {
return ""; //$NON-NLS-1$
}
return wrapped.name();
}
//delegate to wrapped preference
@Override
public void put(String key, String value) {
wrapped.put(key, value);
}
@Override
public String get(String key, String def) {
return wrapped.get(key, def);
}
@Override
public void remove(String key) {
wrapped.remove(key);
}
@Override
public void clear() throws BackingStoreException {
wrapped.clear();
}
@Override
public void putInt(String key, int value) {
wrapped.putInt(key, value);
}
@Override
public int getInt(String key, int def) {
return wrapped.getInt(key, def);
}
@Override
public void putLong(String key, long value) {
wrapped.putLong(key, value);
}
@Override
public long getLong(String key, long def) {
return wrapped.getLong(key, def);
}
@Override
public void putBoolean(String key, boolean value) {
wrapped.putBoolean(key, value);
}
@Override
public boolean getBoolean(String key, boolean def) {
return wrapped.getBoolean(key, def);
}
@Override
public void putFloat(String key, float value) {
wrapped.putFloat(key, value);
}
@Override
public float getFloat(String key, float def) {
return wrapped.getFloat(key, def);
}
@Override
public void putDouble(String key, double value) {
wrapped.putDouble(key, value);
}
@Override
public double getDouble(String key, double def) {
return wrapped.getDouble(key, def);
}
@Override
public void putByteArray(String key, byte[] value) {
wrapped.putByteArray(key, value);
}
@Override
public String[] keys() throws BackingStoreException {
return wrapped.keys();
}
@Override
public String[] childrenNames() throws BackingStoreException {
return wrapped.childrenNames();
}
@Override
public void removeNode() throws BackingStoreException {
wrapped.removeNode();
}
@Override
public void flush() throws BackingStoreException {
wrapped.flush();
}
@Override
public void sync() throws BackingStoreException {
wrapped.sync();
}
} //end static inner class OSGiLocalRootPreferences
private IEclipsePreferences bundlePreferences;
OSGiPreferencesServiceImpl(IEclipsePreferences bundlePreferences) {
this.bundlePreferences = bundlePreferences;
}
@Override
public Preferences getSystemPreferences() {
return new OSGiLocalRootPreferences(bundlePreferences.node("system")); //$NON-NLS-1$
}
@Override
public Preferences getUserPreferences(String name) {
return new OSGiLocalRootPreferences(bundlePreferences.node("user/" + name)); //$NON-NLS-1$
}
@Override
public String[] getUsers() {
String[] users = null;
try {
users = bundlePreferences.node("user").childrenNames(); //$NON-NLS-1$
} catch (BackingStoreException e) {
//best effort
}
return users == null ? new String[0] : users;
}
}