1 // ========================================================================
2 // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 // ========================================================================
14
15 package org.mortbay.util;
16
17 import java.util.Arrays;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 /* ------------------------------------------------------------ */
24 /** A multi valued Map.
25 * This Map specializes HashMap and provides methods
26 * that operate on multi valued items.
27 * <P>
28 * Implemented as a map of LazyList values
29 *
30 * @see LazyList
31 * @author Greg Wilkins (gregw)
32 */
33 public class MultiMap extends HashMap
34 implements Cloneable
35 {
36 /* ------------------------------------------------------------ */
37 /** Constructor.
38 */
39 public MultiMap()
40 {}
41
42 /* ------------------------------------------------------------ */
43 /** Constructor.
44 * @param size Capacity of the map
45 */
46 public MultiMap(int size)
47 {
48 super(size);
49 }
50
51 /* ------------------------------------------------------------ */
52 /** Constructor.
53 * @param map
54 */
55 public MultiMap(Map map)
56 {
57 super((map.size()*3)/2);
58 putAll(map);
59 }
60
61 /* ------------------------------------------------------------ */
62 /** Get multiple values.
63 * Single valued entries are converted to singleton lists.
64 * @param name The entry key.
65 * @return Unmodifieable List of values.
66 */
67 public List getValues(Object name)
68 {
69 return LazyList.getList(super.get(name),true);
70 }
71
72 /* ------------------------------------------------------------ */
73 /** Get a value from a multiple value.
74 * If the value is not a multivalue, then index 0 retrieves the
75 * value or null.
76 * @param name The entry key.
77 * @param i Index of element to get.
78 * @return Unmodifieable List of values.
79 */
80 public Object getValue(Object name,int i)
81 {
82 Object l=super.get(name);
83 if (i==0 && LazyList.size(l)==0)
84 return null;
85 return LazyList.get(l,i);
86 }
87
88
89 /* ------------------------------------------------------------ */
90 /** Get value as String.
91 * Single valued items are converted to a String with the toString()
92 * Object method. Multi valued entries are converted to a comma separated
93 * List. No quoting of commas within values is performed.
94 * @param name The entry key.
95 * @return String value.
96 */
97 public String getString(Object name)
98 {
99 Object l=super.get(name);
100 switch(LazyList.size(l))
101 {
102 case 0:
103 return null;
104 case 1:
105 Object o=LazyList.get(l,0);
106 return o==null?null:o.toString();
107 default:
108 StringBuffer values=new StringBuffer(128);
109 synchronized(values)
110 {
111 for (int i=0; i<LazyList.size(l); i++)
112 {
113 Object e=LazyList.get(l,i);
114 if (e!=null)
115 {
116 if (values.length()>0)
117 values.append(',');
118 values.append(e.toString());
119 }
120 }
121 return values.toString();
122 }
123 }
124 }
125
126 /* ------------------------------------------------------------ */
127 public Object get(Object name)
128 {
129 Object l=super.get(name);
130 switch(LazyList.size(l))
131 {
132 case 0:
133 return null;
134 case 1:
135 Object o=LazyList.get(l,0);
136 return o;
137 default:
138 return LazyList.getList(l,true);
139 }
140 }
141
142 /* ------------------------------------------------------------ */
143 /** Put and entry into the map.
144 * @param name The entry key.
145 * @param value The entry value.
146 * @return The previous value or null.
147 */
148 public Object put(Object name, Object value)
149 {
150 return super.put(name,LazyList.add(null,value));
151 }
152
153 /* ------------------------------------------------------------ */
154 /** Put multi valued entry.
155 * @param name The entry key.
156 * @param values The List of multiple values.
157 * @return The previous value or null.
158 */
159 public Object putValues(Object name, List values)
160 {
161 return super.put(name,values);
162 }
163
164 /* ------------------------------------------------------------ */
165 /** Put multi valued entry.
166 * @param name The entry key.
167 * @param values The String array of multiple values.
168 * @return The previous value or null.
169 */
170 public Object putValues(Object name, String[] values)
171 {
172 Object list=null;
173 for (int i=0;i<values.length;i++)
174 list=LazyList.add(list,values[i]);
175 return put(name,list);
176 }
177
178
179 /* ------------------------------------------------------------ */
180 /** Add value to multi valued entry.
181 * If the entry is single valued, it is converted to the first
182 * value of a multi valued entry.
183 * @param name The entry key.
184 * @param value The entry value.
185 */
186 public void add(Object name, Object value)
187 {
188 Object lo = super.get(name);
189 Object ln = LazyList.add(lo,value);
190 if (lo!=ln)
191 super.put(name,ln);
192 }
193
194 /* ------------------------------------------------------------ */
195 /** Add values to multi valued entry.
196 * If the entry is single valued, it is converted to the first
197 * value of a multi valued entry.
198 * @param name The entry key.
199 * @param values The List of multiple values.
200 */
201 public void addValues(Object name, List values)
202 {
203 Object lo = super.get(name);
204 Object ln = LazyList.addCollection(lo,values);
205 if (lo!=ln)
206 super.put(name,ln);
207 }
208
209 /* ------------------------------------------------------------ */
210 /** Add values to multi valued entry.
211 * If the entry is single valued, it is converted to the first
212 * value of a multi valued entry.
213 * @param name The entry key.
214 * @param values The String array of multiple values.
215 */
216 public void addValues(Object name, String[] values)
217 {
218 Object lo = super.get(name);
219 Object ln = LazyList.addCollection(lo,Arrays.asList(values));
220 if (lo!=ln)
221 super.put(name,ln);
222 }
223
224 /* ------------------------------------------------------------ */
225 /** Remove value.
226 * @param name The entry key.
227 * @param value The entry value.
228 * @return true if it was removed.
229 */
230 public boolean removeValue(Object name,Object value)
231 {
232 Object lo = super.get(name);
233 Object ln=lo;
234 int s=LazyList.size(lo);
235 if (s>0)
236 {
237 ln=LazyList.remove(lo,value);
238 if (ln==null)
239 super.remove(name);
240 else
241 super.put(name, ln);
242 }
243 return LazyList.size(ln)!=s;
244 }
245
246 /* ------------------------------------------------------------ */
247 /** Put all contents of map.
248 * @param m Map
249 */
250 public void putAll(Map m)
251 {
252 Iterator i = m.entrySet().iterator();
253 boolean multi=m instanceof MultiMap;
254 while(i.hasNext())
255 {
256 Map.Entry entry =
257 (Map.Entry)i.next();
258 if (multi)
259 super.put(entry.getKey(),LazyList.clone(entry.getValue()));
260 else
261 put(entry.getKey(),entry.getValue());
262 }
263 }
264
265 /* ------------------------------------------------------------ */
266 /**
267 * @return Map of String arrays
268 */
269 public Map toStringArrayMap()
270 {
271 HashMap map = new HashMap(size()*3/2);
272
273 Iterator i = super.entrySet().iterator();
274 while(i.hasNext())
275 {
276 Map.Entry entry = (Map.Entry)i.next();
277 Object l = entry.getValue();
278 String[] a = LazyList.toStringArray(l);
279 // for (int j=a.length;j-->0;)
280 // if (a[j]==null)
281 // a[j]="";
282 map.put(entry.getKey(),a);
283 }
284 return map;
285 }
286
287 /* ------------------------------------------------------------ */
288 public Object clone()
289 {
290 MultiMap mm = (MultiMap) super.clone();
291
292 Iterator iter = mm.entrySet().iterator();
293 while (iter.hasNext())
294 {
295 Map.Entry entry = (Map.Entry)iter.next();
296 entry.setValue(LazyList.clone(entry.getValue()));
297 }
298
299 return mm;
300 }
301 }