%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.turbine.util.SequencedHashtable |
|
|
1 | package org.apache.turbine.util; |
|
2 | ||
3 | /* |
|
4 | * Copyright 2001-2005 The Apache Software Foundation. |
|
5 | * |
|
6 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
7 | * you may not use this file except in compliance with the License. |
|
8 | * You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | ||
19 | import java.util.Collection; |
|
20 | import java.util.Hashtable; |
|
21 | import java.util.Iterator; |
|
22 | import java.util.LinkedList; |
|
23 | import java.util.List; |
|
24 | import java.util.Map; |
|
25 | import java.util.Set; |
|
26 | ||
27 | /** |
|
28 | * A {@link java.util.Hashtable} whose keys are sequenced. The |
|
29 | * sequencing of the keys allow easy access to the values in the order |
|
30 | * which they were added in. This class is thread safe. |
|
31 | * <p> |
|
32 | * Implementing the List interface is not possible due to a instance |
|
33 | * method name clash between the Collection and the List interface: |
|
34 | * |
|
35 | * <table> |
|
36 | * <tr><td>Collections</td><td>boolean remove(Object o)</td></tr> |
|
37 | * <tr><td>Lists</td><td>Object remove(Object o)</td></tr> |
|
38 | * </table> |
|
39 | * |
|
40 | * So one cannot implement both interfaces at the same, which is unfortunate |
|
41 | * because the List interface would be very nice in conjuction with Velocity. |
|
42 | * <p> |
|
43 | * A slightly more complex implementation and interface could involve |
|
44 | * the use of a list of <code>Map.Entry</code> objects. |
|
45 | * |
|
46 | * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> |
|
47 | * @version $Id: SequencedHashtable.java 264152 2005-08-29 14:50:22Z henning $ |
|
48 | * @deprecated Use SequencedHashMap from the commons collections. |
|
49 | */ |
|
50 | public class SequencedHashtable extends Hashtable |
|
51 | { |
|
52 | /** |
|
53 | * Indicator for an unknown index. |
|
54 | */ |
|
55 | private static final int UNKNOWN_INDEX = -1; |
|
56 | ||
57 | /** |
|
58 | * The sequence used to keep track of the hash keys. Younger objects are |
|
59 | * kept towards the end of the list. Does not allow duplicates. |
|
60 | */ |
|
61 | private LinkedList keySequence; |
|
62 | ||
63 | /** |
|
64 | * Creates a new instance with default storage. |
|
65 | */ |
|
66 | public SequencedHashtable() |
|
67 | 0 | { |
68 | 0 | keySequence = new LinkedList(); |
69 | 0 | } |
70 | ||
71 | /** |
|
72 | * Creates a new instance with the specified storage. |
|
73 | * |
|
74 | * @param size The storage to allocate up front. |
|
75 | */ |
|
76 | public SequencedHashtable(int size) |
|
77 | { |
|
78 | 0 | super(size); |
79 | 0 | keySequence = new LinkedList(); |
80 | 0 | } |
81 | ||
82 | /** |
|
83 | * Clears all elements. |
|
84 | */ |
|
85 | public synchronized void clear() |
|
86 | { |
|
87 | 0 | super.clear(); |
88 | 0 | keySequence.clear(); |
89 | 0 | } |
90 | ||
91 | /** |
|
92 | * Creates a shallow copy of this object, preserving the internal |
|
93 | * structure by copying only references. The keys, values, and |
|
94 | * sequence are not <code>clone()</code>'d. |
|
95 | * |
|
96 | * @return A clone of this instance. |
|
97 | */ |
|
98 | public synchronized Object clone() |
|
99 | { |
|
100 | 0 | SequencedHashtable seqHash = (SequencedHashtable) super.clone(); |
101 | 0 | seqHash.keySequence = (LinkedList) keySequence.clone(); |
102 | 0 | return seqHash; |
103 | } |
|
104 | ||
105 | /** |
|
106 | * Returns the key at the specified index. |
|
107 | */ |
|
108 | public Object get(int index) |
|
109 | { |
|
110 | 0 | return keySequence.get(index); |
111 | } |
|
112 | ||
113 | /** |
|
114 | * Returns the value at the specified index. |
|
115 | */ |
|
116 | public Object getValue(int index) |
|
117 | { |
|
118 | 0 | return get(get(index)); |
119 | } |
|
120 | ||
121 | /** |
|
122 | * Returns the index of the specified key. |
|
123 | */ |
|
124 | public int indexOf(Object key) |
|
125 | { |
|
126 | 0 | return keySequence.indexOf(key); |
127 | } |
|
128 | ||
129 | /** |
|
130 | * Returns a key iterator. |
|
131 | */ |
|
132 | public Iterator iterator() |
|
133 | { |
|
134 | 0 | return keySequence.iterator(); |
135 | } |
|
136 | ||
137 | /** |
|
138 | * Returns the last index of the specified key. |
|
139 | */ |
|
140 | public int lastIndexOf(Object key) |
|
141 | { |
|
142 | 0 | return keySequence.lastIndexOf(key); |
143 | } |
|
144 | ||
145 | /** |
|
146 | * Returns the ordered sequence of keys. |
|
147 | * |
|
148 | * This method is meant to be used for retrieval of Key / Value pairs |
|
149 | * in e.g. Velocity: |
|
150 | * <PRE> |
|
151 | * ## $table contains a sequenced hashtable |
|
152 | * #foreach ($key in $table.sequence()) |
|
153 | * <TR> |
|
154 | * <TD>Key: $key</TD> |
|
155 | * </TD>Value: $table.get($key)</TD> |
|
156 | * </TR> |
|
157 | * #end |
|
158 | * </PRE> |
|
159 | * |
|
160 | * @return The ordered list of keys. |
|
161 | */ |
|
162 | public List sequence() |
|
163 | { |
|
164 | 0 | return keySequence; |
165 | } |
|
166 | ||
167 | /** |
|
168 | * Stores the provided key/value pair. Freshens the sequence of existing |
|
169 | * elements. |
|
170 | * |
|
171 | * @param key The key to the provided value. |
|
172 | * @param value The value to store. |
|
173 | * @return The previous value for the specified key, or |
|
174 | * <code>null</code> if none. |
|
175 | */ |
|
176 | public synchronized Object put(Object key, Object value) |
|
177 | { |
|
178 | 0 | Object prevValue = super.put(key, value); |
179 | 0 | freshenSequence(key, prevValue); |
180 | 0 | return prevValue; |
181 | } |
|
182 | ||
183 | /** |
|
184 | * Freshens the sequence of the element <code>value</code> if |
|
185 | * <code>value</code> is not <code>null</code>. |
|
186 | * |
|
187 | * @param key The key whose sequence to freshen. |
|
188 | * @param value The value whose existance to check before removing the old |
|
189 | * key sequence. |
|
190 | */ |
|
191 | protected void freshenSequence(Object key, Object value) |
|
192 | { |
|
193 | 0 | if (value != null) |
194 | { |
|
195 | // Freshening existing element's sequence. |
|
196 | 0 | keySequence.remove(key); |
197 | } |
|
198 | 0 | keySequence.add(key); |
199 | 0 | } |
200 | ||
201 | /** |
|
202 | * Stores the provided key/value pairs. |
|
203 | * |
|
204 | * @param t The key/value pairs to store. |
|
205 | */ |
|
206 | public synchronized void putAll(Map t) |
|
207 | { |
|
208 | 0 | Set set = t.entrySet(); |
209 | 0 | for (Iterator iter = set.iterator(); iter.hasNext();) |
210 | { |
|
211 | 0 | Map.Entry e = (Map.Entry) iter.next(); |
212 | 0 | put(e.getKey(), e.getValue()); |
213 | } |
|
214 | 0 | } |
215 | ||
216 | /** |
|
217 | * Removes the element at the specified index. |
|
218 | * |
|
219 | * @param index The index of the object to remove. |
|
220 | * @return The previous value coressponding the <code>key</code>, or |
|
221 | * <code>null</code> if none existed. |
|
222 | */ |
|
223 | public Object remove(int index) |
|
224 | { |
|
225 | 0 | return remove(index, null); |
226 | } |
|
227 | ||
228 | /** |
|
229 | * Removes the element with the specified key. |
|
230 | * |
|
231 | * @param key The <code>Map</code> key of the object to remove. |
|
232 | * @return The previous value coressponding the <code>key</code>, or |
|
233 | * <code>null</code> if none existed. |
|
234 | */ |
|
235 | public Object remove(Object key) |
|
236 | { |
|
237 | 0 | return remove(UNKNOWN_INDEX, key); |
238 | } |
|
239 | ||
240 | /** |
|
241 | * Removes the element with the specified key or index. |
|
242 | * |
|
243 | * @param index The index of the object to remove, or |
|
244 | * <code>UNKNOWN_INDEX</code> if not known. |
|
245 | * @param key The <code>Map</code> key of the object to remove. |
|
246 | * @return The previous value coressponding the <code>key</code>, or |
|
247 | * <code>null</code> if none existed. |
|
248 | */ |
|
249 | private synchronized Object remove(int index, Object key) |
|
250 | { |
|
251 | 0 | if (index == UNKNOWN_INDEX) |
252 | { |
|
253 | 0 | index = indexOf(key); |
254 | } |
|
255 | 0 | if (key == null) |
256 | { |
|
257 | 0 | key = get(index); |
258 | } |
|
259 | 0 | if (index != UNKNOWN_INDEX) |
260 | { |
|
261 | 0 | keySequence.remove(index); |
262 | } |
|
263 | 0 | return super.remove(key); |
264 | } |
|
265 | ||
266 | /** |
|
267 | * Slightly cheaper implementation of <code>values()</code> method. |
|
268 | */ |
|
269 | public Collection values() |
|
270 | { |
|
271 | 0 | return keySequence; |
272 | } |
|
273 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |