1 package org.apache.turbine.util;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.Collection;
58 import java.util.Hashtable;
59 import java.util.Iterator;
60 import java.util.LinkedList;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Set;
64
65 /***
66 * A {@link java.util.Hashtable} whose keys are sequenced. The
67 * sequencing of the keys allow easy access to the values in the order
68 * which they were added in. This class is thread safe.
69 * <p>
70 * Implementing the List interface is not possible due to a instance
71 * method name clash between the Collection and the List interface:
72 *
73 * <table>
74 * <tr><td>Collections</td><td>boolean remove(Object o)</td></tr>
75 * <tr><td>Lists</td><td>Object remove(Object o)</td></tr>
76 * </table>
77 *
78 * So one cannot implement both interfaces at the same, which is unfortunate
79 * because the List interface would be very nice in conjuction with Velocity.
80 * <p>
81 * A slightly more complex implementation and interface could involve
82 * the use of a list of <code>Map.Entry</code> objects.
83 *
84 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
85 * @version $Id: SequencedHashtable.java,v 1.1.1.1 2001/08/16 05:09:41 jvanzyl Exp $
86 */
87 public class SequencedHashtable extends Hashtable
88 {
89 /***
90 * Indicator for an unknown index.
91 */
92 private static final int UNKNOWN_INDEX = -1;
93
94 /***
95 * The sequence used to keep track of the hash keys. Younger objects are
96 * kept towards the end of the list. Does not allow duplicates.
97 */
98 private LinkedList keySequence;
99
100 /***
101 * Creates a new instance with default storage.
102 */
103 public SequencedHashtable ()
104 {
105 keySequence = new LinkedList();
106 }
107
108 /***
109 * Creates a new instance with the specified storage.
110 *
111 * @param size The storage to allocate up front.
112 */
113 public SequencedHashtable (int size)
114 {
115 super(size);
116 keySequence = new LinkedList();
117 }
118
119 /***
120 * Clears all elements.
121 */
122 public synchronized void clear ()
123 {
124 super.clear();
125 keySequence.clear();
126 }
127
128 /***
129 * Creates a shallow copy of this object, preserving the internal
130 * structure by copying only references. The keys, values, and
131 * sequence are not <code>clone()</code>'d.
132 *
133 * @return A clone of this instance.
134 */
135 public synchronized Object clone ()
136 {
137 SequencedHashtable seqHash = (SequencedHashtable) super.clone();
138 seqHash.keySequence = (LinkedList) keySequence.clone();
139 return seqHash;
140 }
141
142 /***
143 * Returns the key at the specified index.
144 */
145 public Object get (int index)
146 {
147 return keySequence.get(index);
148 }
149
150 /***
151 * Returns the value at the specified index.
152 */
153 public Object getValue (int index)
154 {
155 return get(get(index));
156 }
157
158 /***
159 * Returns the index of the specified key.
160 */
161 public int indexOf (Object key)
162 {
163 return keySequence.indexOf(key);
164 }
165
166 /***
167 * Returns a key iterator.
168 */
169 public Iterator iterator ()
170 {
171 return keySequence.iterator();
172 }
173
174 /***
175 * Returns the last index of the specified key.
176 */
177 public int lastIndexOf (Object key)
178 {
179 return keySequence.lastIndexOf(key);
180 }
181
182 /***
183 * Returns the ordered sequence of keys.
184 *
185 * This method is meant to be used for retrieval of Key / Value pairs
186 * in e.g. Velocity:
187 * <PRE>
188 * ## $table contains a sequenced hashtable
189 * #foreach ($key in $table.sequence())
190 * <TR>
191 * <TD>Key: $key</TD>
192 * </TD>Value: $table.get($key)</TD>
193 * </TR>
194 * #end
195 * </PRE>
196 *
197 * @return The ordered list of keys.
198 */
199 public List sequence()
200 {
201 return keySequence;
202 }
203
204 /***
205 * Stores the provided key/value pair. Freshens the sequence of existing
206 * elements.
207 *
208 * @param key The key to the provided value.
209 * @param value The value to store.
210 * @return The previous value for the specified key, or
211 * <code>null</code> if none.
212 */
213 public synchronized Object put (Object key, Object value)
214 {
215 Object prevValue = super.put(key, value);
216 freshenSequence(key, prevValue);
217 return prevValue;
218 }
219
220 /***
221 * Freshens the sequence of the element <code>value</code> if
222 * <code>value</code> is not <code>null</code>.
223 *
224 * @param key The key whose sequence to freshen.
225 * @param value The value whose existance to check before removing the old
226 * key sequence.
227 */
228 protected void freshenSequence(Object key, Object value)
229 {
230 if (value != null)
231 {
232 // Freshening existing element's sequence.
233 keySequence.remove(key);
234 }
235 keySequence.add(key);
236 }
237
238 /***
239 * Stores the provided key/value pairs.
240 *
241 * @param t The key/value pairs to store.
242 */
243 public synchronized void putAll (Map t)
244 {
245 Set set = t.entrySet();
246 for (Iterator iter = set.iterator(); iter.hasNext(); )
247 {
248 Map.Entry e = (Map.Entry)iter.next();
249 put(e.getKey(), e.getValue());
250 }
251 }
252
253 /***
254 * Removes the element at the specified index.
255 *
256 * @param index The index of the object to remove.
257 * @return The previous value coressponding the <code>key</code>, or
258 * <code>null</code> if none existed.
259 */
260 public Object remove (int index)
261 {
262 return remove(index, null);
263 }
264
265 /***
266 * Removes the element with the specified key.
267 *
268 * @param key The <code>Map</code> key of the object to remove.
269 * @return The previous value coressponding the <code>key</code>, or
270 * <code>null</code> if none existed.
271 */
272 public Object remove (Object key)
273 {
274 return remove(UNKNOWN_INDEX, key);
275 }
276
277 /***
278 * Removes the element with the specified key or index.
279 *
280 * @param index The index of the object to remove, or
281 * <code>UNKNOWN_INDEX</code> if not known.
282 * @param key The <code>Map</code> key of the object to remove.
283 * @return The previous value coressponding the <code>key</code>, or
284 * <code>null</code> if none existed.
285 */
286 private final synchronized Object remove (int index, Object key)
287 {
288 if (index == UNKNOWN_INDEX) index = indexOf(key);
289 if (key == null) key = get(index);
290 if (index != UNKNOWN_INDEX) keySequence.remove(index);
291 return super.remove(key);
292 }
293
294 /***
295 * Slightly cheaper implementation of <code>values()</code> method.
296 */
297 public Collection values ()
298 {
299 return keySequence;
300 }
301 }
This page was automatically generated by Maven