blob: 0c865883a04fc3c9aec7ef742e8a524051dd8efc [file] [log] [blame]
/*
* Copyright (c) OSGi Alliance (2017). All Rights Reserved.
*
* Licensed 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.osgi.util.converter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author $Id$
*/
class MapDelegate<K, V> implements Map<K,V> {
// not synchronized. Worst that can happen is that cloning is done more than
// once, which is harmless.
private volatile boolean cloned = false;
private final ConvertingImpl convertingImpl;
Map<K,V> delegate;
private MapDelegate(ConvertingImpl converting, Map<K,V> del) {
convertingImpl = converting;
delegate = del;
}
static MapDelegate<String,Object> forBean(Object b, Class< ? > beanClass,
ConvertingImpl converting) {
return new MapDelegate<>(converting,
new DynamicBeanFacade(b, beanClass, converting));
}
static <K, V> Map<K,V> forMap(Map<K,V> m, ConvertingImpl converting) {
return new MapDelegate<>(converting,
new DynamicMapFacade<>(m, converting));
}
static <K, V> MapDelegate<K,V> forDictionary(Dictionary<K,V> d,
ConvertingImpl converting) {
return new MapDelegate<>(converting,
new DynamicDictionaryFacade<>(d, converting));
}
static MapDelegate<String,Object> forDTO(Object obj, Class< ? > dtoClass,
ConvertingImpl converting) {
return new MapDelegate<>(converting,
new DynamicDTOFacade(obj, dtoClass, converting));
}
static MapDelegate<String,Object> forInterface(Object obj, Class< ? > intf,
ConvertingImpl converting) {
return new MapDelegate<>(converting,
new DynamicInterfaceFacade(obj, intf, converting));
}
@Override
public int size() {
// Need to convert the entire map to get the size
Set<Object> keys = new HashSet<>();
Set<K> ks = delegate.keySet();
for (K key : ks) {
keys.add(getConvertedKey(key));
}
return keys.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return keySet().contains(key);
}
@Override
public boolean containsValue(Object value) {
return values().contains(value);
}
@Override
@SuppressWarnings("unchecked")
public V get(Object key) {
V val = null;
if (internalKeySet().contains(key)) {
val = delegate.get(key);
}
if (val == null) {
key = findConvertedKey(internalKeySet(), key);
val = delegate.get(key);
}
if (val == null)
return null;
else
return (V) getConvertedValue(val);
}
private Object getConvertedKey(Object key) {
return convertingImpl.convertMapKey(key);
}
private Object getConvertedValue(Object val) {
return convertingImpl.convertMapValue(val);
}
private Object findConvertedKey(Set< ? > keySet, Object key) {
for (Object k : keySet) {
if (key.equals(k))
return k;
}
for (Object k : keySet) {
Object c = convertingImpl.converter.convert(k).to(key.getClass());
if (c != null && c.equals(key))
return k;
}
return key;
}
@Override
public V put(K key, V value) {
cloneDelegate();
return delegate.put(key, value);
}
@Override
public V remove(Object key) {
cloneDelegate();
return delegate.remove(key);
}
@Override
public void putAll(Map< ? extends K, ? extends V> m) {
cloneDelegate();
delegate.putAll(m);
}
@Override
public void clear() {
cloned = true;
delegate = new HashMap<>();
}
private Set<K> internalKeySet() {
return delegate.keySet();
}
@SuppressWarnings("unchecked")
@Override
public Set<K> keySet() {
Set<K> keys = new HashSet<>();
for (Object key : internalKeySet()) {
keys.add((K) getConvertedKey(key));
}
return keys;
}
@Override
public Collection<V> values() {
List<V> values = new ArrayList<>();
for (Map.Entry<K,V> entry : entrySet()) {
values.add(entry.getValue());
}
return values;
}
@Override
@SuppressWarnings("unchecked")
public Set<java.util.Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> result = new HashSet<>();
for (Map.Entry< ? , ? > entry : delegate.entrySet()) {
K key = (K) findConvertedKey(internalKeySet(), entry.getKey());
V val = (V) getConvertedValue(entry.getValue());
result.add(new MapEntry<K,V>(key, val));
}
return result;
}
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
private void cloneDelegate() {
if (cloned) {
return;
} else {
cloned = true;
delegate = new HashMap<>(delegate);
}
}
@Override
public String toString() {
return delegate.toString();
}
static class MapEntry<K, V> implements Map.Entry<K,V> {
private final K key;
private final V value;
MapEntry(K k, V v) {
key = k;
value = v;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
}
}