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

org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.osgi.framework.util;

import static java.util.Objects.requireNonNull;

import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Constants;

/**
 * CaseInsensitiveDictionaryMap classes. This class implements Dictionary and Map with
 * the following behavior:
 * 
    *
  • String keys are case-preserved, * but the lookup operations are case-insensitive.
  • *
  • Keys and values must not be null.
  • *
* @since 3.13 */ public class CaseInsensitiveDictionaryMap extends Dictionary implements Map { // common core service property keys private static final CaseInsensitiveKey KEY_SERVICE_OBJECTCLASS = new CaseInsensitiveKey(Constants.OBJECTCLASS); private static final CaseInsensitiveKey KEY_SERVICE_BUNDLE_ID = new CaseInsensitiveKey(Constants.SERVICE_BUNDLEID); private static final CaseInsensitiveKey KEY_SERVICE_CHANGECOUNT = new CaseInsensitiveKey(Constants.SERVICE_CHANGECOUNT); private static final CaseInsensitiveKey KEY_SERVICE_DESCRIPTION = new CaseInsensitiveKey(Constants.SERVICE_DESCRIPTION); private static final CaseInsensitiveKey KEY_SERVICE_ID = new CaseInsensitiveKey(Constants.SERVICE_ID); private static final CaseInsensitiveKey KEY_SERVICE_PID = new CaseInsensitiveKey(Constants.SERVICE_PID); private static final CaseInsensitiveKey KEY_SERVICE_RANKING = new CaseInsensitiveKey(Constants.SERVICE_RANKING); private static final CaseInsensitiveKey KEY_SERVICE_SCOPE = new CaseInsensitiveKey(Constants.SERVICE_SCOPE); private static final CaseInsensitiveKey KEY_SERVICE_VENDER = new CaseInsensitiveKey(Constants.SERVICE_VENDOR); // common SCR service property keys private static final CaseInsensitiveKey KEY_COMPONENT_NAME = new CaseInsensitiveKey("component.name"); //$NON-NLS-1$ private static final CaseInsensitiveKey KEY_COMPONENT_ID = new CaseInsensitiveKey("component.id"); //$NON-NLS-1$ // common meta-type property keys private static final CaseInsensitiveKey KEY_METATYPE_PID = new CaseInsensitiveKey("metatype.pid"); //$NON-NLS-1$ private static final CaseInsensitiveKey KEY_METATYPE_FACTORY_PID = new CaseInsensitiveKey("metatype.factory.pid"); //$NON-NLS-1$ // common event admin keys private static final CaseInsensitiveKey KEY_EVENT_TOPICS = new CaseInsensitiveKey("event.topics"); //$NON-NLS-1$ private static final CaseInsensitiveKey KEY_EVENT_FILTER = new CaseInsensitiveKey("event.filter"); //$NON-NLS-1$ // jmx keys private static final CaseInsensitiveKey KEY_JMX_OBJECTNAME = new CaseInsensitiveKey("jmx.objectname"); //$NON-NLS-1$ // common bundle manifest headers private static final CaseInsensitiveKey KEY_JAR_MANIFESTVERSION = new CaseInsensitiveKey("Manifest-Version"); //$NON-NLS-1$ private static final CaseInsensitiveKey KEY_BUNDLE_ACTIVATIONPOLICY = new CaseInsensitiveKey(Constants.BUNDLE_ACTIVATIONPOLICY); private static final CaseInsensitiveKey KEY_BUNDLE_ACTIVATOR = new CaseInsensitiveKey(Constants.BUNDLE_ACTIVATOR); private static final CaseInsensitiveKey KEY_BUNDLE_CLASSPATH = new CaseInsensitiveKey(Constants.BUNDLE_CLASSPATH); private static final CaseInsensitiveKey KEY_BUNDLE_DESCRIPTION = new CaseInsensitiveKey(Constants.BUNDLE_DESCRIPTION); private static final CaseInsensitiveKey KEY_BUNDLE_LICENSE = new CaseInsensitiveKey(Constants.BUNDLE_LICENSE); private static final CaseInsensitiveKey KEY_BUNDLE_LOCALIZATION = new CaseInsensitiveKey(Constants.BUNDLE_LOCALIZATION); private static final CaseInsensitiveKey KEY_BUNDLE_MANIFESTVERSION = new CaseInsensitiveKey(Constants.BUNDLE_MANIFESTVERSION); private static final CaseInsensitiveKey KEY_BUNDLE_NAME = new CaseInsensitiveKey(Constants.BUNDLE_NAME); private static final CaseInsensitiveKey KEY_BUNDLE_NATIVECODE = new CaseInsensitiveKey(Constants.BUNDLE_NATIVECODE); @SuppressWarnings("deprecation") private static final CaseInsensitiveKey KEY_BUNDLE_REQUIREDEXECUTIONENVIRONMENT = new CaseInsensitiveKey(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); private static final CaseInsensitiveKey KEY_BUNDLE_SCM = new CaseInsensitiveKey(Constants.BUNDLE_SCM); private static final CaseInsensitiveKey KEY_BUNDLE_SYMBOLICNAME = new CaseInsensitiveKey(Constants.BUNDLE_SYMBOLICNAME); private static final CaseInsensitiveKey KEY_BUNDLE_VENDOR = new CaseInsensitiveKey(Constants.BUNDLE_VENDOR); private static final CaseInsensitiveKey KEY_BUNDLE_VERSION = new CaseInsensitiveKey(Constants.BUNDLE_VERSION); private static final CaseInsensitiveKey KEY_BUNDLE_DYNAMICIMPORT_PACKAGE = new CaseInsensitiveKey(Constants.DYNAMICIMPORT_PACKAGE); private static final CaseInsensitiveKey KEY_BUNDLE_EXPORT_PACKAGE = new CaseInsensitiveKey(Constants.EXPORT_PACKAGE); private static final CaseInsensitiveKey KEY_BUNDLE_FRAGMENT_HOST = new CaseInsensitiveKey(Constants.FRAGMENT_HOST); private static final CaseInsensitiveKey KEY_BUNDLE_IMPORT_PACKAGE = new CaseInsensitiveKey(Constants.IMPORT_PACKAGE); private static final CaseInsensitiveKey KEY_BUNDLE_REQUIRE_BUNDLE = new CaseInsensitiveKey(Constants.REQUIRE_BUNDLE); private static final CaseInsensitiveKey KEY_BUNDLE_REQUIRE_CAPABILITY = new CaseInsensitiveKey(Constants.REQUIRE_CAPABILITY); private static final CaseInsensitiveKey KEY_BUNDLE_PROVIDE_CAPABILITY = new CaseInsensitiveKey(Constants.PROVIDE_CAPABILITY); @SuppressWarnings("deprecation") public static CaseInsensitiveKey findCommonKeyIndex(String key) { switch (key) { // common core service property keys case Constants.OBJECTCLASS : return KEY_SERVICE_OBJECTCLASS; case Constants.SERVICE_BUNDLEID : return KEY_SERVICE_BUNDLE_ID; case Constants.SERVICE_CHANGECOUNT : return KEY_SERVICE_CHANGECOUNT; case Constants.SERVICE_DESCRIPTION : return KEY_SERVICE_DESCRIPTION; case Constants.SERVICE_ID : return KEY_SERVICE_ID; case Constants.SERVICE_PID : return KEY_SERVICE_PID; case Constants.SERVICE_RANKING : return KEY_SERVICE_RANKING; case Constants.SERVICE_SCOPE : return KEY_SERVICE_SCOPE; case Constants.SERVICE_VENDOR : return KEY_SERVICE_VENDER; // common SCR service property keys case "component.name" : //$NON-NLS-1$ return KEY_COMPONENT_NAME; case "component.id" : //$NON-NLS-1$ return KEY_COMPONENT_ID; // common meta-type property keys case "metatype.pid" : //$NON-NLS-1$ return KEY_METATYPE_PID; case "metatype.factory.pid" : //$NON-NLS-1$ return KEY_METATYPE_FACTORY_PID; // common event admin keys case "event.topics" : //$NON-NLS-1$ return KEY_EVENT_TOPICS; case "event.filter" : //$NON-NLS-1$ return KEY_EVENT_FILTER; // jmx keys case "jmx.objectname" : //$NON-NLS-1$ return KEY_JMX_OBJECTNAME; // common bundle manifest headers case "Manifest-Version" : //$NON-NLS-1$ return KEY_JAR_MANIFESTVERSION; case Constants.BUNDLE_ACTIVATIONPOLICY : return KEY_BUNDLE_ACTIVATIONPOLICY; case Constants.BUNDLE_ACTIVATOR : return KEY_BUNDLE_ACTIVATOR; case Constants.BUNDLE_CLASSPATH : return KEY_BUNDLE_CLASSPATH; case Constants.BUNDLE_DESCRIPTION : return KEY_BUNDLE_DESCRIPTION; case Constants.BUNDLE_LICENSE : return KEY_BUNDLE_LICENSE; case Constants.BUNDLE_LOCALIZATION : return KEY_BUNDLE_LOCALIZATION; case Constants.BUNDLE_MANIFESTVERSION : return KEY_BUNDLE_MANIFESTVERSION; case Constants.BUNDLE_NAME : return KEY_BUNDLE_NAME; case Constants.BUNDLE_NATIVECODE : return KEY_BUNDLE_NATIVECODE; case Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT : return KEY_BUNDLE_REQUIREDEXECUTIONENVIRONMENT; case Constants.BUNDLE_SCM : return KEY_BUNDLE_SCM; case Constants.BUNDLE_SYMBOLICNAME : return KEY_BUNDLE_SYMBOLICNAME; case Constants.BUNDLE_VENDOR : return KEY_BUNDLE_VENDOR; case Constants.BUNDLE_VERSION : return KEY_BUNDLE_VERSION; case Constants.DYNAMICIMPORT_PACKAGE : return KEY_BUNDLE_DYNAMICIMPORT_PACKAGE; case Constants.EXPORT_PACKAGE : return KEY_BUNDLE_EXPORT_PACKAGE; case Constants.FRAGMENT_HOST : return KEY_BUNDLE_FRAGMENT_HOST; case Constants.IMPORT_PACKAGE : return KEY_BUNDLE_IMPORT_PACKAGE; case Constants.REQUIRE_BUNDLE : return KEY_BUNDLE_REQUIRE_BUNDLE; case Constants.REQUIRE_CAPABILITY : return KEY_BUNDLE_REQUIRE_CAPABILITY; case Constants.PROVIDE_CAPABILITY : return KEY_BUNDLE_PROVIDE_CAPABILITY; } return null; } final Map map; /** * Create an empty CaseInsensitiveDictionaryMap. */ public CaseInsensitiveDictionaryMap() { map = new HashMap<>(); } /** * Create an empty CaseInsensitiveDictionaryMap. * * @param initialCapacity The initial capacity. */ public CaseInsensitiveDictionaryMap(int initialCapacity) { map = new HashMap<>(initialCapacity); } /** * Create a CaseInsensitiveDictionaryMap dictionary from a Dictionary. * * @param dictionary The initial dictionary for this CaseInsensitiveDictionaryMap object. * @throws IllegalArgumentException If a case-variants of a key are * in the dictionary parameter. */ public CaseInsensitiveDictionaryMap(Dictionary dictionary) { this(initialCapacity(dictionary.size())); /* initialize the keys and values */ Enumeration keys = dictionary.keys(); while (keys.hasMoreElements()) { K key = keys.nextElement(); // ignore null keys if (key != null) { V value = dictionary.get(key); // ignore null values if (value != null) { if (put(key, value) != null) { throw new IllegalArgumentException(NLS.bind(Msg.HEADER_DUPLICATE_KEY_EXCEPTION, key)); } } } } } /** * Create a CaseInsensitiveDictionaryMap dictionary from a Map. * * @param map The initial map for this CaseInsensitiveDictionaryMap object. * @throws IllegalArgumentException If a case-variants of a key are * in the map parameter. */ public CaseInsensitiveDictionaryMap(Map map) { this(initialCapacity(map.size())); /* initialize the keys and values */ for (Entry e : map.entrySet()) { K key = e.getKey(); // ignore null keys if (key != null) { V value = e.getValue(); // ignore null values if (value != null) { if (put(key, value) != null) { throw new IllegalArgumentException(NLS.bind(Msg.HEADER_DUPLICATE_KEY_EXCEPTION, key)); } } } } } /** * Compute the initial capacity of a map for the specified number of entries * based upon the load factor of 0.75f. * * @param size The desired number of entries. * @return The initial capacity of a map. */ protected static int initialCapacity(int size) { return Math.max((int) (size / 0.75f) + 1, 16); } /** * {@inheritDoc} */ @Override public Enumeration keys() { return Collections.enumeration(keySet()); } /** * {@inheritDoc} */ @Override public Enumeration elements() { return Collections.enumeration(values()); } /** * {@inheritDoc} *

* If the key is a String, the key is located in a case-insensitive manner. */ @Override public V get(Object key) { return map.get(keyWrap(key)); } /** * Returns the specified key or, if the key is a String, returns * a case-insensitive wrapping of the key. * * @param key * @return The specified key or a case-insensitive wrapping of the key. */ private Object keyWrap(Object key) { if (key instanceof String) { CaseInsensitiveKey commonKey = findCommonKeyIndex((String) key); if (commonKey != null) { return commonKey; } return new CaseInsensitiveKey((String) key); } return key; } /** * {@inheritDoc} */ @Override public int size() { return map.size(); } /** * {@inheritDoc} */ @Override public boolean isEmpty() { return map.isEmpty(); } /** * {@inheritDoc} *

* The key and value must be non-null. *

* If the key is a String, any case-variant will be replaced. */ @Override public V put(K key, V value) { requireNonNull(value); if (key instanceof String) { Object wrappedKey = keyWrap(key); V existing = map.put(wrappedKey, value); if (existing != null) { // must remove to replace key if case has changed map.remove(wrappedKey); map.put(wrappedKey, value); } return existing; } return map.put(requireNonNull(key), value); } /** * {@inheritDoc} *

* If the key is a String, the key is removed in a case-insensitive manner. */ @Override public V remove(Object key) { return map.remove(keyWrap(key)); } /** * {@inheritDoc} */ @Override public String toString() { return map.toString(); } /** * {@inheritDoc} */ @Override public void clear() { map.clear(); } /** * {@inheritDoc} *

* If the key is a String, the key is located in a case-insensitive manner. */ @Override public boolean containsKey(Object key) { return map.containsKey(keyWrap(key)); } /** * {@inheritDoc} */ @Override public boolean containsValue(Object value) { return map.containsValue(value); } private transient Set> entrySet = null; /** * {@inheritDoc} */ @Override public Set> entrySet() { Set> es = entrySet; if (es == null) { return entrySet = new EntrySet(); } return es; } private transient Set keySet = null; /** * {@inheritDoc} */ @Override public Set keySet() { Set ks = keySet; if (ks == null) { return keySet = new KeySet(); } return ks; } /** * {@inheritDoc} */ @Override public Collection values() { return map.values(); } /** * {@inheritDoc} *

* If the specified map has case-variants of a String key, only the last case-variant * found while iterating over the entrySet will be present in this object. */ @Override public void putAll(Map m) { for (Entry e : m.entrySet()) { put(e.getKey(), e.getValue()); } } /** * {@inheritDoc} */ @Override public int hashCode() { return map.hashCode(); } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } return map.equals(obj); } /** * Return an unmodifiable map wrapping this CaseInsensitiveDictionaryMap. * * @return An unmodifiable map wrapping this CaseInsensitiveDictionaryMap. */ public Map asUnmodifiableMap() { return Collections.unmodifiableMap(this); } /** * Return an unmodifiable dictionary wrapping this CaseInsensitiveDictionaryMap. * * @return An unmodifiable dictionary wrapping this CaseInsensitiveDictionaryMap. */ public Dictionary asUnmodifiableDictionary() { return unmodifiableDictionary(this); } /** * Return an unmodifiable dictionary wrapping the specified dictionary. * * @return An unmodifiable dictionary wrapping the specified dictionary. */ public static Dictionary unmodifiableDictionary(Dictionary d) { return new UnmodifiableDictionary<>(d); } private static final class UnmodifiableDictionary extends Dictionary { private final Dictionary d; UnmodifiableDictionary(Dictionary d) { this.d = requireNonNull(d); } @Override public int size() { return d.size(); } @Override public boolean isEmpty() { return d.isEmpty(); } @SuppressWarnings("unchecked") @Override public Enumeration keys() { return (Enumeration) d.keys(); } @SuppressWarnings("unchecked") @Override public Enumeration elements() { return (Enumeration) d.elements(); } @Override public V get(Object key) { return d.get(key); } @Override public V put(K key, V value) { throw new UnsupportedOperationException(); } @Override public V remove(Object key) { throw new UnsupportedOperationException(); } @Override public String toString() { return d.toString(); } @Override public int hashCode() { return d.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } return d.equals(obj); } } static int computeHashCode(String key) { int h = 1; for (char c : key.toCharArray()) { if (c < 0x80) { // ASCII if (c >= 'A' && c <= 'Z') { c += 'a' - 'A'; // convert to ASCII lowercase } } else { c = Character.toLowerCase(Character.toUpperCase(c)); } h = 31 * h + c; } return h; } private static final class CaseInsensitiveKey { final String key; final private int hashCode; CaseInsensitiveKey(String key) { this.key = key; this.hashCode = computeHashCode(key); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof CaseInsensitiveKey) { return key.equalsIgnoreCase(((CaseInsensitiveKey) obj).key); } return false; } @Override public String toString() { return key; } } private final class KeySet extends AbstractSet { KeySet() { } @Override public int size() { return CaseInsensitiveDictionaryMap.this.size(); } @Override public boolean isEmpty() { return CaseInsensitiveDictionaryMap.this.isEmpty(); } @Override public boolean contains(Object o) { return CaseInsensitiveDictionaryMap.this.containsKey(o); } @Override public Iterator iterator() { return new KeyIterator<>(map.keySet()); } @Override public boolean remove(Object o) { return CaseInsensitiveDictionaryMap.this.remove(o) != null; } @Override public void clear() { CaseInsensitiveDictionaryMap.this.clear(); } } private static final class KeyIterator implements Iterator { private final Iterator i; KeyIterator(Collection c) { this.i = c.iterator(); } @Override public boolean hasNext() { return i.hasNext(); } @SuppressWarnings("unchecked") @Override public K next() { Object k = i.next(); if (k instanceof CaseInsensitiveKey) { k = ((CaseInsensitiveKey) k).key; } return (K) k; } @Override public void remove() { i.remove(); } } private final class EntrySet extends AbstractSet> { EntrySet() { } @Override public int size() { return CaseInsensitiveDictionaryMap.this.size(); } @Override public boolean isEmpty() { return CaseInsensitiveDictionaryMap.this.isEmpty(); } @Override public Iterator> iterator() { return new EntryIterator<>(map.entrySet()); } @Override public void clear() { CaseInsensitiveDictionaryMap.this.clear(); } } private static final class EntryIterator implements Iterator> { private final Iterator> i; EntryIterator(Collection> c) { this.i = c.iterator(); } @Override public boolean hasNext() { return i.hasNext(); } @Override public Entry next() { return new CaseInsentiveEntry<>(i.next()); } @Override public void remove() { i.remove(); } } private static final class CaseInsentiveEntry implements Entry { private final Entry entry; CaseInsentiveEntry(Entry entry) { this.entry = entry; } @SuppressWarnings("unchecked") @Override public K getKey() { Object k = entry.getKey(); if (k instanceof CaseInsensitiveKey) { k = ((CaseInsensitiveKey) k).key; } return (K) k; } @Override public V getValue() { return entry.getValue(); } @Override public V setValue(V value) { return entry.setValue(requireNonNull(value)); } @Override public int hashCode() { return Objects.hashCode(entry.getKey()) ^ Objects.hashCode(entry.getValue()); } @Override public boolean equals(Object obj) { if (obj instanceof Entry) { Entry other = (Entry) obj; Object k1 = entry.getKey(); @SuppressWarnings("unchecked") Object k2 = (other instanceof CaseInsentiveEntry) ? ((CaseInsentiveEntry) other).entry.getKey() : other.getKey(); return Objects.equals(k1, k2) && Objects.equals(entry.getValue(), other.getValue()); } return false; } @Override public String toString() { return entry.toString(); } } }