blob: 7d167c5905a9ca4c845e438d6a383e7d65245755 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.felix.useradmin.impl.role;
import java.io.Serializable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import org.osgi.service.useradmin.UserAdminPermission;
/**
* Provides an observable {@link Dictionary} implementation that emits change
* events for the put and remove operations aside checking for security
* permissions for all accessor methods.
* <p>
* This class is <b>not</b> guaranteed to be thread-safe!
* </p>
*/
class ObservableDictionary extends Dictionary implements Serializable {
private static final long serialVersionUID = 3161552287666253189L;
/**
* Provides a listener for changes to a {@link ObservableDictionary}.
*/
static interface DictionaryChangeListener {
/**
* Called when a new entry is added.
*
* @param key the key of the entry;
* @param value the value associated to the key.
*/
void entryAdded(Object key, Object value);
/**
* Called when an entry is changed.
*
* @param key the key of the entry;
* @param oldValue the old value associated to the key;
* @param newValue the new value associated to the key.
*/
void entryChanged(Object key, Object oldValue, Object newValue);
/**
* Called when an entry is removed.
*
* @param key the key of the entry.
*/
void entryRemoved(Object key);
}
private final Dictionary m_dictionary;
private final String m_getAction;
private final String m_changeAction;
private transient volatile DictionaryChangeListener m_listener;
/**
* Creates a new, empty, {@link ObservableDictionary} instance.
*/
public ObservableDictionary(String getAction, String changeAction) {
this(getAction, changeAction, new Hashtable());
}
/**
* Creates a new {@link ObservableDictionary} instance with the given dictionary as defaults.
*
* @param dictionary the defaults to set for this properties, cannot be <code>null</code>.
*/
public ObservableDictionary(String getAction, String changeAction, Dictionary dictionary) {
if (dictionary == null) {
throw new IllegalArgumentException("Dictionary cannot be null!");
}
m_getAction = getAction;
m_changeAction = changeAction;
m_dictionary = dictionary;
}
/**
* {@inheritDoc}
*/
public Enumeration elements() {
return m_dictionary.elements();
}
/**
* {@inheritDoc}
*/
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || (getClass() != object.getClass())) {
return false;
}
ObservableDictionary other = (ObservableDictionary) object;
if (m_dictionary == null) {
if (other.m_dictionary != null) {
return false;
}
} else if (!m_dictionary.equals(other.m_dictionary)) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
public Object get(Object key) {
if (key == null) {
throw new IllegalArgumentException("Key cannot be null!");
}
if (m_getAction != null) {
checkPermissions(getAsPermissionKey(key), m_getAction);
}
return m_dictionary.get(key);
}
/**
* {@inheritDoc}
*/
public int hashCode() {
final int prime = 37;
int result = 1;
result = prime * result + ((m_dictionary == null) ? 0 : m_dictionary.hashCode());
return result;
}
/**
* {@inheritDoc}
*/
public boolean isEmpty() {
return m_dictionary.isEmpty();
}
/**
* {@inheritDoc}
*/
public Enumeration keys() {
return m_dictionary.keys();
}
/**
* {@inheritDoc}
*/
public Object put(Object key, Object value) {
if (key == null) {
throw new IllegalArgumentException("Key cannot be null!");
}
if (value == null) {
throw new IllegalArgumentException("Value cannot be null!");
}
if (m_changeAction != null) {
checkPermissions(getAsPermissionKey(key), m_changeAction);
}
Object oldValue = m_dictionary.put(key, value);
final DictionaryChangeListener listener = m_listener;
if (listener != null) {
if (oldValue == null) {
listener.entryAdded(key, value);
} else {
listener.entryChanged(key, oldValue, value);
}
}
return oldValue;
}
/**
* {@inheritDoc}
*/
public Object remove(Object key) {
if (key == null) {
throw new IllegalArgumentException("Key cannot be null!");
}
if (m_changeAction != null) {
checkPermissions(getAsPermissionKey(key), m_changeAction);
}
Object oldValue = m_dictionary.remove(key);
final DictionaryChangeListener listener = m_listener;
if (listener != null) {
listener.entryRemoved(key);
}
return oldValue;
}
/**
* Sets a new {@link DictionaryChangeListener} to observe changes to this dictionary.
*
* @param listener the listener to add, can be <code>null</code> to stop listening for changes.
*/
public void setDictionaryChangeListener(DictionaryChangeListener listener) {
m_listener = listener;
}
/**
* {@inheritDoc}
*/
public int size() {
return m_dictionary.size();
}
/**
* @param key
* @return
*/
protected String getAsPermissionKey(Object key) {
String k = UserAdminPermission.ADMIN;
if (key instanceof String) {
k = (String) key;
}
return k;
}
/**
* Verifies whether the caller has the right permissions to get or change the given key.
*
* @param key the name of the property that is to be accessed or changed, cannot be <code>null</code>;
* @param action the action name to perform, cannot be <code>null</code>.
* @throws SecurityException in case the caller has not the right permissions to perform the action.
*/
private void checkPermissions(String key, String action) throws SecurityException {
SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null) {
securityManager.checkPermission(new UserAdminPermission(key, action));
}
}
}