blob: 8a13cc0d4eaeea8bd702bcf8556ccf0cee6f0d51 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 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.io.File;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.osgi.service.prefs.*;
import org.osgi.service.prefs.Preferences;
import org.osgi.service.prefs.PreferencesService;
/**
* <p>
* Implements OSGi PreferencesService using the Eclipse preference system.
* </p>
*
* <p>
* Note: Eclipse preferences are not 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.
*
*/
private static final class OSGiPreferences extends EclipsePreferences implements Preferences {
private IPath location;
private IEclipsePreferences loadLevel;
private OSGiPreferencesServiceImpl prefsServiceImpl;
private OSGiPreferences(File prefsDir, OSGiPreferencesServiceImpl prefsServiceImpl) {
super(null, ""); //$NON-NLS-1$
this.prefsServiceImpl = prefsServiceImpl;
this.location = new Path(prefsDir.getPath());
this.loadLevel = this;
}
private OSGiPreferences(EclipsePreferences nodeParent, String nodeName, OSGiPreferencesServiceImpl prefsServiceImpl) {
super(nodeParent, nodeName);
this.loadLevel = nodeParent.getLoadLevel();
this.prefsServiceImpl = prefsServiceImpl;
}
protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) {
return new OSGiPreferences(nodeParent, nodeName, prefsServiceImpl);
}
protected IPath getLocation() {
return location;
}
protected IEclipsePreferences getLoadLevel() {
return loadLevel;
}
/**
* Override node(String pathName) to be more strict about forbidden names -
* EclipsePreferences implementation does a best-effort instead of throwing
* {@link IllegalArgumentException}.
*/
public Preferences node(String pathName) {
if ((pathName.length() > 1 && pathName.endsWith("/")) //$NON-NLS-1$
|| pathName.indexOf("//") != -1) { //$NON-NLS-1$
throw new IllegalArgumentException();
}
return super.node(pathName);
}
/**
* Override removeNode() to allow removal of root nodes. EclipsePreferences ignores
* attempts to remove the root node, but in OSGi Preferences there are many root nodes
* and removal is permitted.
*/
public void removeNode() throws BackingStoreException {
if (parent() == null) {
flush();
if (this == prefsServiceImpl.systemPreferences) {
prefsServiceImpl.systemPreferences = null;
} else {
prefsServiceImpl.userPreferences.values().remove(this);
}
}
super.removeNode();
removed = true;
}
/**
* <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>
*/
public byte[] getByteArray(String key, byte[] defaultValue) {
String value = internalGet(key);
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;
}
}
private File systemPrefsDir;
private File userPrefsDir;
Preferences systemPreferences;
//Map of String user name -> Preferences
Map userPreferences;
OSGiPreferencesServiceImpl(File prefsLocation) {
systemPrefsDir = new File(prefsLocation, "system"); //$NON-NLS-1$
userPrefsDir = new File(prefsLocation, "user"); //$NON-NLS-1$
userPreferences = new TreeMap(); //use TreeMap since keys are strings
}
public Preferences getSystemPreferences() {
if (systemPreferences == null) {
systemPreferences = new OSGiPreferences(systemPrefsDir, this);
try {
systemPreferences.sync();
} catch (BackingStoreException e) {
//nothing
}
}
return systemPreferences;
}
public Preferences getUserPreferences(String name) {
Preferences userPref = (Preferences) userPreferences.get(name);
if (userPref == null) {
userPref = new OSGiPreferences(new File(userPrefsDir, name), this);
try {
userPref.sync();
} catch (BackingStoreException e) {
//nothing
}
userPreferences.put(name, userPref);
}
return userPref;
}
public String[] getUsers() {
return userPrefsDir.list();
}
/**
* Called when Bundle ungets Preferences Service - flushes all preferences to disk.
*/
void destroy() {
try {
if (systemPreferences != null && systemPreferences.nodeExists("")) { //$NON-NLS-1$
systemPreferences.flush();
}
} catch (BackingStoreException e) {
//nothing
}
Iterator it = userPreferences.values().iterator();
while (it.hasNext()) {
Preferences userPreference = (Preferences) it.next();
try {
if (userPreference.nodeExists("")) { //$NON-NLS-1$
userPreference.flush();
}
} catch (BackingStoreException e) {
//nothing
}
}
}
}