Copyright (c) 2003, 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
/*******************************************************************************
* Copyright (c) 2003, 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 java.io.IOException;
import java.io.InputStream;
import java.util.*;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleException;
Headers classes. This class implements a Dictionary that has
the following behavior:
- put and remove clear throw UnsupportedOperationException.
The Dictionary is thus read-only to others.
- The String keys in the Dictionary are case-preserved,
but the get operation is case-insensitive.
Since: 3.1 Deprecated: As of 3.13. Replaced by CaseInsensitiveDictionaryMap
.
/**
* Headers classes. This class implements a Dictionary that has
* the following behavior:
* <ul>
* <li>put and remove clear throw UnsupportedOperationException.
* The Dictionary is thus read-only to others.
* <li>The String keys in the Dictionary are case-preserved,
* but the get operation is case-insensitive.
* </ul>
* @since 3.1
* @deprecated As of 3.13. Replaced by {@link CaseInsensitiveDictionaryMap}.
*/
@Deprecated
public class Headers<K, V> extends Dictionary<K, V> implements Map<K, V> {
private boolean readOnly = false;
private K[] headers;
private V[] values;
private int size = 0;
Create an empty Headers dictionary.
Params: - initialCapacity – The initial capacity of this Headers object.
/**
* Create an empty Headers dictionary.
*
* @param initialCapacity The initial capacity of this Headers object.
*/
public Headers(int initialCapacity) {
super();
@SuppressWarnings("unchecked")
K[] k = (K[]) new Object[initialCapacity];
headers = k;
@SuppressWarnings("unchecked")
V[] v = (V[]) new Object[initialCapacity];
values = v;
}
Create a Headers dictionary from a Dictionary.
Params: - values – The initial dictionary for this Headers object.
Throws: - IllegalArgumentException – If a case-variant of the key is
in the dictionary parameter.
/**
* Create a Headers dictionary from a Dictionary.
*
* @param values The initial dictionary for this Headers object.
* @exception IllegalArgumentException If a case-variant of the key is
* in the dictionary parameter.
*/
public Headers(Dictionary<? extends K, ? extends V> values) {
this(values.size());
/* initialize the headers and values */
Enumeration<? extends K> keys = values.keys();
while (keys.hasMoreElements()) {
K key = keys.nextElement();
set(key, values.get(key));
}
}
Case-preserved keys.
/**
* Case-preserved keys.
*/
@Override
public synchronized Enumeration<K> keys() {
return new ArrayEnumeration<>(headers, size);
}
Values.
/**
* Values.
*/
@Override
public synchronized Enumeration<V> elements() {
return new ArrayEnumeration<>(values, size);
}
private int getIndex(Object key) {
boolean stringKey = key instanceof String;
for (int i = 0; i < size; i++) {
if (stringKey && (headers[i] instanceof String)) {
if (((String) headers[i]).equalsIgnoreCase((String) key))
return i;
} else {
if (headers[i].equals(key))
return i;
}
}
return -1;
}
private V remove(int remove) {
V removed = values[remove];
for (int i = remove; i < size; i++) {
if (i == headers.length - 1) {
headers[i] = null;
values[i] = null;
} else {
headers[i] = headers[i + 1];
values[i] = values[i + 1];
}
}
if (remove < size)
size--;
return removed;
}
private void add(K header, V value) {
if (size == headers.length) {
// grow the arrays
@SuppressWarnings("unchecked")
K[] nh = (K[]) new Object[headers.length + 10];
K[] newHeaders = nh;
@SuppressWarnings("unchecked")
V[] nv = (V[]) new Object[values.length + 10];
V[] newValues = nv;
System.arraycopy(headers, 0, newHeaders, 0, headers.length);
System.arraycopy(values, 0, newValues, 0, values.length);
headers = newHeaders;
values = newValues;
}
headers[size] = header;
values[size] = value;
size++;
}
Support case-insensitivity for keys.
Params: - key – name.
/**
* Support case-insensitivity for keys.
*
* @param key name.
*/
@Override
public synchronized V get(Object key) {
int i = -1;
if ((i = getIndex(key)) != -1)
return values[i];
return null;
}
Set a header value or optionally replace it if it already exists.
Params: - key – Key name.
- value – Value of the key or null to remove key.
- replace – A value of true will allow a previous
value of the key to be replaced. A value of false
will cause an IllegalArgumentException to be thrown
if a previous value of the key exists.
Throws: - IllegalArgumentException – If a case-variant of the key is
already present.
Returns: the previous value to which the key was mapped,
or null if the key did not have a previous mapping. Since: 3.2
/**
* Set a header value or optionally replace it if it already exists.
*
* @param key Key name.
* @param value Value of the key or null to remove key.
* @param replace A value of true will allow a previous
* value of the key to be replaced. A value of false
* will cause an IllegalArgumentException to be thrown
* if a previous value of the key exists.
* @return the previous value to which the key was mapped,
* or null if the key did not have a previous mapping.
*
* @exception IllegalArgumentException If a case-variant of the key is
* already present.
* @since 3.2
*/
public synchronized V set(K key, V value, boolean replace) {
if (readOnly)
throw new UnsupportedOperationException();
if (key instanceof String) {
@SuppressWarnings("unchecked")
K k = (K) ((String) key).intern();
key = k;
}
int i = getIndex(key);
if (value == null) { /* remove */
if (i != -1)
return remove(i);
} else { /* put */
if (i != -1) { /* duplicate key */
if (!replace)
throw new IllegalArgumentException(NLS.bind(Msg.HEADER_DUPLICATE_KEY_EXCEPTION, key));
V oldVal = values[i];
values[i] = value;
return oldVal;
}
add(key, value);
}
return null;
}
Set a header value.
Params: - key – Key name.
- value – Value of the key or null to remove key.
Throws: - IllegalArgumentException – If a case-variant of the key is
already present.
Returns: the previous value to which the key was mapped,
or null if the key did not have a previous mapping.
/**
* Set a header value.
*
* @param key Key name.
* @param value Value of the key or null to remove key.
* @return the previous value to which the key was mapped,
* or null if the key did not have a previous mapping.
*
* @exception IllegalArgumentException If a case-variant of the key is
* already present.
*/
public synchronized V set(K key, V value) {
return set(key, value, false);
}
public synchronized void setReadOnly() {
readOnly = true;
}
Returns the number of entries (distinct keys) in this dictionary.
Returns: the number of keys in this dictionary.
/**
* Returns the number of entries (distinct keys) in this dictionary.
*
* @return the number of keys in this dictionary.
*/
@Override
public synchronized int size() {
return size;
}
Tests if this dictionary maps no keys to value. The general contract
for the isEmpty method is that the result is true if and only
if this dictionary contains no entries.
Returns: true
if this dictionary maps no keys to values;
false
otherwise.
/**
* Tests if this dictionary maps no keys to value. The general contract
* for the <tt>isEmpty</tt> method is that the result is true if and only
* if this dictionary contains no entries.
*
* @return <code>true</code> if this dictionary maps no keys to values;
* <code>false</code> otherwise.
*/
@Override
public synchronized boolean isEmpty() {
return size == 0;
}
Always throws UnsupportedOperationException.
Params: - key – header name.
- value – header value.
Throws:
/**
* Always throws UnsupportedOperationException.
*
* @param key header name.
* @param value header value.
* @throws UnsupportedOperationException
*/
@Override
public synchronized V put(K key, V value) {
if (readOnly)
throw new UnsupportedOperationException();
return set(key, value, true);
}
Always throws UnsupportedOperationException.
Params: - key – header name.
Throws:
/**
* Always throws UnsupportedOperationException.
*
* @param key header name.
* @throws UnsupportedOperationException
*/
@Override
public V remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('{');
for (int i = 0; i < size; i++) {
if (i != 0) {
sb.append(", "); //$NON-NLS-1$
}
K header = headers[i];
if (header == this) {
sb.append("(this Dictionary)"); //$NON-NLS-1$
} else {
sb.append(header);
}
sb.append('=');
V value = values[i];
if (value == this) {
sb.append("(this Dictionary)"); //$NON-NLS-1$
} else {
sb.append(value);
}
}
sb.append('}');
return sb.toString();
}
public static Headers<String, String> parseManifest(InputStream in) throws BundleException {
Headers<String, String> headers = new Headers<>(10);
try {
ManifestElement.parseBundleManifest(in, headers);
} catch (IOException e) {
throw new BundleException(Msg.MANIFEST_IOEXCEPTION, BundleException.MANIFEST_ERROR, e);
}
headers.setReadOnly();
return headers;
}
private static class ArrayEnumeration<E> implements Enumeration<E> {
private E[] array;
int cur = 0;
public ArrayEnumeration(E[] array, int size) {
@SuppressWarnings("unchecked")
E[] a = (E[]) new Object[size];
this.array = a;
System.arraycopy(array, 0, this.array, 0, this.array.length);
}
@Override
public boolean hasMoreElements() {
return cur < array.length;
}
@Override
public E nextElement() {
return array[cur++];
}
}
@Override
public synchronized void clear() {
if (readOnly)
throw new UnsupportedOperationException();
}
@Override
public synchronized boolean containsKey(Object key) {
return getIndex(key) >= 0;
}
@Override
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}
@Override
public Set<K> keySet() {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map<? extends K, ? extends V> c) {
throw new UnsupportedOperationException();
}
@Override
public Collection<V> values() {
throw new UnsupportedOperationException();
}
}