All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.util.CaseInsensitiveMapWrapper Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.util;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Represents a Map from String to {@link T} where the key's case is not taken into account when looking for it, but
 * remembered when the key set is retrieved from the map.
 * The backing map used will be an instance of the given class passed to the constructor. This allows to make case
 * insensitive different kinds of Map implementations, particularly a ConcurrentHashMap, used to achieve high concurrence.
 * 

* When a key/value pair is put in the map the key case is remembered so when the key set or the entry set is retrieved * the correct case is returned. This is useful to store, for example, camel case keys. However, two keys that only * differ in their case will be assumed to be the same key and only one value (the last) will be kept. * Note: as this map uses a provided class to create the backing map, key rewrite is not ensured. It is possible that * when redefining a value associated to a key, the key case won't be overwritten and the already existing key case * will remains in the key set and entry set. * * @param The class of the values referenced in the map. * * @since 3.6.0 */ public class CaseInsensitiveMapWrapper implements Map, Serializable { private final Map baseMap; public CaseInsensitiveMapWrapper(Class mapClass, Object... parameters) { try { baseMap = ClassUtils.instanciateClass(mapClass, parameters); } catch (Exception e) { throw new RuntimeException(String.format("Can not create an instance of %s", mapClass.getCanonicalName()), e); } } @Override public int size() { return baseMap.size(); } @Override public boolean isEmpty() { return baseMap.isEmpty(); } @Override public boolean containsKey(Object key) { return baseMap.containsKey(new CaseInsensitiveMapKey(key)); } @Override public boolean containsValue(Object value) { return baseMap.containsValue(value); } @Override public T get(Object key) { return baseMap.get(new CaseInsensitiveMapKey(key)); } @Override public T put(String key, T value) { return baseMap.put(new CaseInsensitiveMapKey(key), value); } @Override public T remove(Object key) { return baseMap.remove(new CaseInsensitiveMapKey(key)); } @Override public void putAll(Map other) { if (other instanceof CaseInsensitiveMapWrapper) { baseMap.putAll(((CaseInsensitiveMapWrapper) other).baseMap); } else { for (Map.Entry otherEntry : other.entrySet()) { put(otherEntry.getKey(), otherEntry.getValue()); } } } @Override public void clear() { baseMap.clear(); } @Override public Set keySet() { return new KeySet(baseMap.keySet()); } @Override public Collection values() { return baseMap.values(); } @Override public Set> entrySet() { return new EntrySet<>(baseMap.entrySet()); } private static class CaseInsensitiveMapKey implements Serializable { private final String key; private final String keyLowerCase; private final int keyHash; public CaseInsensitiveMapKey(Object key) { this.key = key.toString(); keyLowerCase = this.key.toLowerCase(); keyHash = keyLowerCase.hashCode(); } public String getKey() { return key; } @Override public int hashCode() { return keyHash; } @Override public boolean equals(Object obj) { return (obj instanceof CaseInsensitiveMapKey) && keyLowerCase.equals(((CaseInsensitiveMapKey) obj).keyLowerCase); } } private static class KeySet extends AbstractConverterSet { public KeySet(Set keys) { super(keys); } @Override protected Iterator createIterator(Set keys) { return new KeyIterator(keys); } } private static class EntrySet extends AbstractConverterSet, Entry> { public EntrySet(Set> entries) { super(entries); } @Override protected Iterator> createIterator(Set> entries) { return new EntryIterator<>(entries); } } private static abstract class AbstractConverterSet extends AbstractSet { private final Set aSet; public AbstractConverterSet(Set set) { this.aSet = set; } @Override public int size() { return aSet.size(); } @Override public Iterator iterator() { return createIterator(aSet); } protected abstract Iterator createIterator(Set aSet); } private static class KeyIterator extends AbstractConverterIterator { public KeyIterator(Set keys) { super(keys); } @Override protected String convert(CaseInsensitiveMapKey next) { return next.getKey(); } } private static class EntryIterator extends AbstractConverterIterator, Entry> { public EntryIterator(Set> entries) { super(entries); } @Override protected Entry convert(Entry next) { return new AbstractMap.SimpleEntry<>(next.getKey().getKey(), next.getValue()); } } private static abstract class AbstractConverterIterator implements Iterator { private final Iterator aIterator; public AbstractConverterIterator(Set set) { aIterator = set.iterator(); } @Override public boolean hasNext() { return aIterator.hasNext(); } @Override public final void remove() { aIterator.remove(); } @Override public final B next() { return convert(aIterator.next()); } protected abstract B convert(A next); } }