View Javadoc

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