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