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