001: /*******************************************************************************
002: * Copyright (c) 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.core.util;
011:
012: import java.util.Collection;
013: import java.util.Dictionary;
014: import java.util.Enumeration;
015: import java.util.Map;
016: import java.util.Set;
017:
018: /**
019: * Headers classes. This class implements a Dictionary that has
020: * the following behavior:
021: * <ul>
022: * <li>put and remove clear throw UnsupportedOperationException.
023: * The Dictionary is thus read-only to others.
024: * <li>The String keys in the Dictionary are case-preserved,
025: * but the get operation is case-insensitive.
026: * </ul>
027: * @since 3.3
028: */
029: public class Headers extends Dictionary implements Map {
030: private boolean readOnly = false;
031: private Object[] headers;
032: private Object[] values;
033: private int size = 0;
034:
035: /**
036: * Create an empty Headers dictionary.
037: *
038: * @param initialCapacity The initial capacity of this Headers object.
039: */
040: public Headers(int initialCapacity) {
041: super ();
042: headers = new Object[initialCapacity];
043: values = new Object[initialCapacity];
044: }
045:
046: /**
047: * Create a Headers dictionary from a Dictionary.
048: *
049: * @param values The initial dictionary for this Headers object.
050: * @exception IllegalArgumentException If a case-variant of the key is
051: * in the dictionary parameter.
052: */
053: public Headers(Dictionary values) {
054: this (values.size());
055: /* initialize the headers and values */
056: Enumeration keys = values.keys();
057: while (keys.hasMoreElements()) {
058: Object key = keys.nextElement();
059: set(key, values.get(key));
060: }
061: }
062:
063: /**
064: * Case-preserved keys.
065: */
066: public synchronized Enumeration keys() {
067: return new ArrayEnumeration(headers, size);
068: }
069:
070: /**
071: * Values.
072: */
073: public synchronized Enumeration elements() {
074: return new ArrayEnumeration(values, size);
075: }
076:
077: private int getIndex(Object key) {
078: boolean stringKey = key instanceof String;
079: for (int i = 0; i < size; i++) {
080: if (stringKey && (headers[i] instanceof String)) {
081: if (((String) headers[i])
082: .equalsIgnoreCase((String) key))
083: return i;
084: } else {
085: if (headers[i].equals(key))
086: return i;
087: }
088: }
089: return -1;
090: }
091:
092: private Object remove(int remove) {
093: Object removed = values[remove];
094: for (int i = remove; i < size; i++) {
095: if (i == headers.length - 1) {
096: headers[i] = null;
097: values[i] = null;
098: } else {
099: headers[i] = headers[i + 1];
100: values[i] = values[i + 1];
101: }
102: }
103: if (remove < size)
104: size--;
105: return removed;
106: }
107:
108: private void add(Object header, Object value) {
109: if (size == headers.length) {
110: // grow the arrays
111: Object[] newHeaders = new Object[headers.length + 10];
112: Object[] newValues = new Object[values.length + 10];
113: System.arraycopy(headers, 0, newHeaders, 0, headers.length);
114: System.arraycopy(values, 0, newValues, 0, values.length);
115: headers = newHeaders;
116: values = newValues;
117: }
118: headers[size] = header;
119: values[size] = value;
120: size++;
121: }
122:
123: /**
124: * Support case-insensitivity for keys.
125: *
126: * @param key name.
127: */
128: public synchronized Object get(Object key) {
129: int i = -1;
130: if ((i = getIndex(key)) != -1)
131: return values[i];
132: return null;
133: }
134:
135: /**
136: * Set a header value or optionally replace it if it already exists.
137: *
138: * @param key Key name.
139: * @param value Value of the key or null to remove key.
140: * @param replace A value of true will allow a previous
141: * value of the key to be replaced. A value of false
142: * will cause an IllegalArgumentException to be thrown
143: * if a previous value of the key exists.
144: * @return the previous value to which the key was mapped,
145: * or null if the key did not have a previous mapping.
146: *
147: * @exception IllegalArgumentException If a case-variant of the key is
148: * already present.
149: * @since 3.2
150: */
151: public synchronized Object set(Object key, Object value,
152: boolean replace) {
153: if (readOnly)
154: throw new UnsupportedOperationException();
155: if (key instanceof String)
156: key = ((String) key).intern();
157: int i = getIndex(key);
158: if (value == null) { /* remove */
159: if (i != -1)
160: return remove(i);
161: } else { /* put */
162: if (i != -1) { /* duplicate key */
163: if (!replace)
164: throw new IllegalArgumentException();
165: Object oldVal = values[i];
166: values[i] = value;
167: return oldVal;
168: }
169: add(key, value);
170: }
171: return null;
172: }
173:
174: /**
175: * Set a header value.
176: *
177: * @param key Key name.
178: * @param value Value of the key or null to remove key.
179: * @return the previous value to which the key was mapped,
180: * or null if the key did not have a previous mapping.
181: *
182: * @exception IllegalArgumentException If a case-variant of the key is
183: * already present.
184: */
185: public synchronized Object set(Object key, Object value) {
186: return set(key, value, false);
187: }
188:
189: public synchronized void setReadOnly() {
190: readOnly = true;
191: }
192:
193: /**
194: * Returns the number of entries (distinct keys) in this dictionary.
195: *
196: * @return the number of keys in this dictionary.
197: */
198: public synchronized int size() {
199: return size;
200: }
201:
202: /**
203: * Tests if this dictionary maps no keys to value. The general contract
204: * for the <tt>isEmpty</tt> method is that the result is true if and only
205: * if this dictionary contains no entries.
206: *
207: * @return <code>true</code> if this dictionary maps no keys to values;
208: * <code>false</code> otherwise.
209: */
210: public synchronized boolean isEmpty() {
211: return size == 0;
212: }
213:
214: /**
215: * Always throws UnsupportedOperationException.
216: *
217: * @param key header name.
218: * @param value header value.
219: * @throws UnsupportedOperationException
220: */
221: public synchronized Object put(Object key, Object value) {
222: if (readOnly)
223: throw new UnsupportedOperationException();
224: return set(key, value, true);
225: }
226:
227: /**
228: * Always throws UnsupportedOperationException.
229: *
230: * @param key header name.
231: * @throws UnsupportedOperationException
232: */
233: public Object remove(Object key) {
234: throw new UnsupportedOperationException();
235: }
236:
237: public String toString() {
238: return (values.toString());
239: }
240:
241: class ArrayEnumeration implements Enumeration {
242: private Object[] array;
243: int cur = 0;
244:
245: public ArrayEnumeration(Object[] array, int size) {
246: this .array = new Object[size];
247: System
248: .arraycopy(array, 0, this .array, 0,
249: this .array.length);
250: }
251:
252: public boolean hasMoreElements() {
253: return cur < array.length;
254: }
255:
256: public Object nextElement() {
257: return array[cur++];
258: }
259: }
260:
261: public synchronized void clear() {
262: if (readOnly)
263: throw new UnsupportedOperationException();
264: }
265:
266: public synchronized boolean containsKey(Object key) {
267: return getIndex(key) >= 0;
268: }
269:
270: public boolean containsValue(Object var0) {
271: throw new UnsupportedOperationException();
272: }
273:
274: public Set entrySet() {
275: throw new UnsupportedOperationException();
276: }
277:
278: public Set keySet() {
279: throw new UnsupportedOperationException();
280: }
281:
282: public void putAll(Map var0) {
283: throw new UnsupportedOperationException();
284: }
285:
286: public Collection values() {
287: throw new UnsupportedOperationException();
288: }
289: }
|