• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18 
19 package org.eclipse.jetty.util;
20 
21 import java.io.Serializable;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 
31 /* ------------------------------------------------------------ */
32 /** A multi valued Map.
33  * This Map specializes HashMap and provides methods
34  * that operate on multi valued items.
35  * <P>
36  * Implemented as a map of LazyList values
37  * @param <K> The key type of the map.
38  *
39  * @see LazyList
40  *
41  */
42 public class MultiMap<K> implements ConcurrentMap<K,Object>, Serializable
43 {
44     private static final long serialVersionUID = -6878723138353851005L;
45     Map<K,Object> _map;
46     ConcurrentMap<K, Object> _cmap;
47 
MultiMap()48     public MultiMap()
49     {
50         _map=new HashMap<K, Object>();
51     }
52 
MultiMap(Map<K,Object> map)53     public MultiMap(Map<K,Object> map)
54     {
55         if (map instanceof ConcurrentMap)
56             _map=_cmap=new ConcurrentHashMap<K, Object>(map);
57         else
58             _map=new HashMap<K, Object>(map);
59     }
60 
MultiMap(MultiMap<K> map)61     public MultiMap(MultiMap<K> map)
62     {
63         if (map._cmap!=null)
64             _map=_cmap=new ConcurrentHashMap<K, Object>(map._cmap);
65         else
66             _map=new HashMap<K,Object>(map._map);
67     }
68 
MultiMap(int capacity)69     public MultiMap(int capacity)
70     {
71         _map=new HashMap<K, Object>(capacity);
72     }
73 
MultiMap(boolean concurrent)74     public MultiMap(boolean concurrent)
75     {
76         if (concurrent)
77             _map=_cmap=new ConcurrentHashMap<K, Object>();
78         else
79             _map=new HashMap<K, Object>();
80     }
81 
82 
83     /* ------------------------------------------------------------ */
84     /** Get multiple values.
85      * Single valued entries are converted to singleton lists.
86      * @param name The entry key.
87      * @return Unmodifieable List of values.
88      */
getValues(Object name)89     public List getValues(Object name)
90     {
91         return LazyList.getList(_map.get(name),true);
92     }
93 
94     /* ------------------------------------------------------------ */
95     /** Get a value from a multiple value.
96      * If the value is not a multivalue, then index 0 retrieves the
97      * value or null.
98      * @param name The entry key.
99      * @param i Index of element to get.
100      * @return Unmodifieable List of values.
101      */
getValue(Object name,int i)102     public Object getValue(Object name,int i)
103     {
104         Object l=_map.get(name);
105         if (i==0 && LazyList.size(l)==0)
106             return null;
107         return LazyList.get(l,i);
108     }
109 
110 
111     /* ------------------------------------------------------------ */
112     /** Get value as String.
113      * Single valued items are converted to a String with the toString()
114      * Object method. Multi valued entries are converted to a comma separated
115      * List.  No quoting of commas within values is performed.
116      * @param name The entry key.
117      * @return String value.
118      */
getString(Object name)119     public String getString(Object name)
120     {
121         Object l=_map.get(name);
122         switch(LazyList.size(l))
123         {
124           case 0:
125               return null;
126           case 1:
127               Object o=LazyList.get(l,0);
128               return o==null?null:o.toString();
129           default:
130           {
131               StringBuilder values=new StringBuilder(128);
132               for (int i=0; i<LazyList.size(l); i++)
133               {
134                   Object e=LazyList.get(l,i);
135                   if (e!=null)
136                   {
137                       if (values.length()>0)
138                           values.append(',');
139                       values.append(e.toString());
140                   }
141               }
142               return values.toString();
143           }
144         }
145     }
146 
147     /* ------------------------------------------------------------ */
get(Object name)148     public Object get(Object name)
149     {
150         Object l=_map.get(name);
151         switch(LazyList.size(l))
152         {
153           case 0:
154               return null;
155           case 1:
156               Object o=LazyList.get(l,0);
157               return o;
158           default:
159               return LazyList.getList(l,true);
160         }
161     }
162 
163     /* ------------------------------------------------------------ */
164     /** Put and entry into the map.
165      * @param name The entry key.
166      * @param value The entry value.
167      * @return The previous value or null.
168      */
put(K name, Object value)169     public Object put(K name, Object value)
170     {
171         return _map.put(name,LazyList.add(null,value));
172     }
173 
174     /* ------------------------------------------------------------ */
175     /** Put multi valued entry.
176      * @param name The entry key.
177      * @param values The List of multiple values.
178      * @return The previous value or null.
179      */
putValues(K name, List<? extends Object> values)180     public Object putValues(K name, List<? extends Object> values)
181     {
182         return _map.put(name,values);
183     }
184 
185     /* ------------------------------------------------------------ */
186     /** Put multi valued entry.
187      * @param name The entry key.
188      * @param values The String array of multiple values.
189      * @return The previous value or null.
190      */
putValues(K name, String... values)191     public Object putValues(K name, String... values)
192     {
193         Object list=null;
194         for (int i=0;i<values.length;i++)
195             list=LazyList.add(list,values[i]);
196         return _map.put(name,list);
197     }
198 
199 
200     /* ------------------------------------------------------------ */
201     /** Add value to multi valued entry.
202      * If the entry is single valued, it is converted to the first
203      * value of a multi valued entry.
204      * @param name The entry key.
205      * @param value The entry value.
206      */
add(K name, Object value)207     public void add(K name, Object value)
208     {
209         Object lo = _map.get(name);
210         Object ln = LazyList.add(lo,value);
211         if (lo!=ln)
212             _map.put(name,ln);
213     }
214 
215     /* ------------------------------------------------------------ */
216     /** Add values to multi valued entry.
217      * If the entry is single valued, it is converted to the first
218      * value of a multi valued entry.
219      * @param name The entry key.
220      * @param values The List of multiple values.
221      */
addValues(K name, List<? extends Object> values)222     public void addValues(K name, List<? extends Object> values)
223     {
224         Object lo = _map.get(name);
225         Object ln = LazyList.addCollection(lo,values);
226         if (lo!=ln)
227             _map.put(name,ln);
228     }
229 
230     /* ------------------------------------------------------------ */
231     /** Add values to multi valued entry.
232      * If the entry is single valued, it is converted to the first
233      * value of a multi valued entry.
234      * @param name The entry key.
235      * @param values The String array of multiple values.
236      */
addValues(K name, String[] values)237     public void addValues(K name, String[] values)
238     {
239         Object lo = _map.get(name);
240         Object ln = LazyList.addCollection(lo,Arrays.asList(values));
241         if (lo!=ln)
242             _map.put(name,ln);
243     }
244 
245     /* ------------------------------------------------------------ */
246     /** Remove value.
247      * @param name The entry key.
248      * @param value The entry value.
249      * @return true if it was removed.
250      */
removeValue(K name,Object value)251     public boolean removeValue(K name,Object value)
252     {
253         Object lo = _map.get(name);
254         Object ln=lo;
255         int s=LazyList.size(lo);
256         if (s>0)
257         {
258             ln=LazyList.remove(lo,value);
259             if (ln==null)
260                 _map.remove(name);
261             else
262                 _map.put(name, ln);
263         }
264         return LazyList.size(ln)!=s;
265     }
266 
267 
268     /* ------------------------------------------------------------ */
269     /** Put all contents of map.
270      * @param m Map
271      */
putAll(Map<? extends K, ? extends Object> m)272     public void putAll(Map<? extends K, ? extends Object> m)
273     {
274         boolean multi = (m instanceof MultiMap);
275 
276         if (multi)
277         {
278             for (Map.Entry<? extends K, ? extends Object> entry : m.entrySet())
279             {
280                 _map.put(entry.getKey(),LazyList.clone(entry.getValue()));
281             }
282         }
283         else
284         {
285             _map.putAll(m);
286         }
287     }
288 
289     /* ------------------------------------------------------------ */
290     /**
291      * @return Map of String arrays
292      */
toStringArrayMap()293     public Map<K,String[]> toStringArrayMap()
294     {
295         HashMap<K,String[]> map = new HashMap<K,String[]>(_map.size()*3/2)
296         {
297             public String toString()
298             {
299                 StringBuilder b=new StringBuilder();
300                 b.append('{');
301                 for (K k:keySet())
302                 {
303                     if(b.length()>1)
304                         b.append(',');
305                     b.append(k);
306                     b.append('=');
307                     b.append(Arrays.asList(get(k)));
308                 }
309 
310                 b.append('}');
311                 return b.toString();
312             }
313         };
314 
315         for(Map.Entry<K,Object> entry: _map.entrySet())
316         {
317             String[] a = LazyList.toStringArray(entry.getValue());
318             map.put(entry.getKey(),a);
319         }
320         return map;
321     }
322 
323     @Override
toString()324     public String toString()
325     {
326         return _cmap==null?_map.toString():_cmap.toString();
327     }
328 
clear()329     public void clear()
330     {
331         _map.clear();
332     }
333 
containsKey(Object key)334     public boolean containsKey(Object key)
335     {
336         return _map.containsKey(key);
337     }
338 
containsValue(Object value)339     public boolean containsValue(Object value)
340     {
341         return _map.containsValue(value);
342     }
343 
entrySet()344     public Set<Entry<K, Object>> entrySet()
345     {
346         return _map.entrySet();
347     }
348 
349     @Override
equals(Object o)350     public boolean equals(Object o)
351     {
352         return _map.equals(o);
353     }
354 
355     @Override
hashCode()356     public int hashCode()
357     {
358         return _map.hashCode();
359     }
360 
isEmpty()361     public boolean isEmpty()
362     {
363         return _map.isEmpty();
364     }
365 
keySet()366     public Set<K> keySet()
367     {
368         return _map.keySet();
369     }
370 
remove(Object key)371     public Object remove(Object key)
372     {
373         return _map.remove(key);
374     }
375 
size()376     public int size()
377     {
378         return _map.size();
379     }
380 
values()381     public Collection<Object> values()
382     {
383         return _map.values();
384     }
385 
386 
387 
putIfAbsent(K key, Object value)388     public Object putIfAbsent(K key, Object value)
389     {
390         if (_cmap==null)
391             throw new UnsupportedOperationException();
392         return _cmap.putIfAbsent(key,value);
393     }
394 
remove(Object key, Object value)395     public boolean remove(Object key, Object value)
396     {
397         if (_cmap==null)
398             throw new UnsupportedOperationException();
399         return _cmap.remove(key,value);
400     }
401 
replace(K key, Object oldValue, Object newValue)402     public boolean replace(K key, Object oldValue, Object newValue)
403     {
404         if (_cmap==null)
405             throw new UnsupportedOperationException();
406         return _cmap.replace(key,oldValue,newValue);
407     }
408 
replace(K key, Object value)409     public Object replace(K key, Object value)
410     {
411         if (_cmap==null)
412             throw new UnsupportedOperationException();
413         return _cmap.replace(key,value);
414     }
415 }
416