blob: 3497f08ce211c8266f3b7d63c597fc62f82d8a68 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 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.equinox.internal.security.storage;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.equinox.security.storage.provider.IPreferencesContainer;
/**
* NOTE NOTE NOTE: this Javadoc is implementation details - this is not an API
* but a few notes on implementation design.
*
* For a URL we get one secure preference tree that contains data. The top node
* of that tree has a "root" type, it has special properties - the location, status,
* and knowledge as to how persist the tree.
*
* On the user side - let's say we have the following preferences open via factory:
*
* UserPreferences1 (Options1, URL1)
* UserPreferences2 (Options2, URL1)
* UserPreferences3 (Options3, URL2)
* UserPreferences4 (Options4, URL2)
*
* When we'll have 2 actual "back end" secure preferences tree with data:
*
* [UserPreferences1] -> [Options1] +
* \
* [secure preferences1] <- 1 : 1 -> URL1
* /
* [UserPreferences2] -> [Options2] +
*
* [UserPreferences3] -> [Options3] +
* \
* [secure preferences2] <- 1 : 1 -> URL2
* /
* [UserPreferences4] -> [Options4] +
*
* The user-facing nodes are actually a (node + options for this container). User-facing
* nodes are called wrappers as they primarily wrap secure preferences nodes.
*
* Containers are used to combine all wrappers created for the set of options. This way
* users don't have to specify options on each get...() / put...() method.
*
* Additionally, containers cache wrappers so that navigation on preferences tree won't
* create new wrappers every time process navigates from one node on the tree to another.
*
* Password provider modules:
*
* Note that only a single instance of each password provider is ever created. However,
* those instances are passed options as arguments.
*/
public class SecurePreferencesContainer implements IPreferencesContainer {
private Map wrappers = new HashMap(); // node -> SecurePreferencesWrapper
final private Map options;
final private SecurePreferencesRoot root;
public SecurePreferencesContainer(SecurePreferencesRoot root, Map options) {
this.root = root;
if (options != null) { // make a copy to avoid problems if original is modified later
this.options = new HashMap(options.size());
this.options.putAll(options);
} else
this.options = new HashMap(2);
}
public ISecurePreferences wrapper(SecurePreferences node) {
synchronized (wrappers) {
if (wrappers.containsKey(node))
return (ISecurePreferences) wrappers.get(node);
SecurePreferencesWrapper newWrapper = new SecurePreferencesWrapper(node, this);
wrappers.put(node, newWrapper);
return newWrapper;
}
}
public void removeWrapper(SecurePreferences node) {
synchronized (wrappers) {
if (wrappers.containsKey(node))
wrappers.remove(node);
}
}
public URL getLocation() {
return root.getLocation();
}
public ISecurePreferences getPreferences() {
return wrapper(root);
}
public SecurePreferencesRoot getRootData() {
return root;
}
//////////////////////////////////////////////////////////////////////////////////
// Handling of options
public boolean hasOption(Object key) {
synchronized (options) {
return options.containsKey(key);
}
}
public Object getOption(Object key) {
synchronized (options) {
return options.get(key);
}
}
public Object setOption(Object key, Object value) {
synchronized (options) {
return options.put(key, value);
}
}
public Object removeOption(Object key) {
synchronized (options) {
return options.remove(key);
}
}
}