| /** |
| * 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)); |
| } |
| } |
| } |