Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/Headers.java338
1 files changed, 338 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/Headers.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/Headers.java
new file mode 100644
index 000000000..0a03d8d29
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/Headers.java
@@ -0,0 +1,338 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * 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:
+ * <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.
+ *
+ * @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.
+ *
+ * @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.
+ */
+ public synchronized Enumeration<K> keys() {
+ return new ArrayEnumeration<>(headers, size);
+ }
+
+ /**
+ * Values.
+ */
+ 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.
+ *
+ * @param key name.
+ */
+ 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @return the number of keys in this dictionary.
+ */
+ public synchronized int size() {
+ return size;
+ }
+
+ /**
+ * 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.
+ */
+ public synchronized boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @param key header name.
+ * @param value header value.
+ * @throws UnsupportedOperationException
+ */
+ public synchronized V put(K key, V value) {
+ if (readOnly)
+ throw new UnsupportedOperationException();
+ return set(key, value, true);
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @param key header name.
+ * @throws UnsupportedOperationException
+ */
+ public V remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ 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);
+ }
+
+ public boolean hasMoreElements() {
+ return cur < array.length;
+ }
+
+ public E nextElement() {
+ return array[cur++];
+ }
+ }
+
+ public synchronized void clear() {
+ if (readOnly)
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized boolean containsKey(Object key) {
+ return getIndex(key) >= 0;
+ }
+
+ public boolean containsValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Set<Map.Entry<K, V>> entrySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Set<K> keySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void putAll(Map<? extends K, ? extends V> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Collection<V> values() {
+ throw new UnsupportedOperationException();
+ }
+}

Back to the top