]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/MultiMap.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / util / MultiMap.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 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.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28
29 /** 
30  * A multi valued Map.
31  */
32 @SuppressWarnings("serial")
33 public class MultiMap<V> extends HashMap<String,List<V>>
34 {
35     public MultiMap()
36     {
37         super();
38     }
39
40     public MultiMap(Map<String,List<V>> map)
41     {
42         super(map);
43     }
44
45     public MultiMap(MultiMap<V> map)
46     {
47         super(map);
48     }
49
50
51     /* ------------------------------------------------------------ */
52     /** Get multiple values.
53      * Single valued entries are converted to singleton lists.
54      * @param name The entry key. 
55      * @return Unmodifieable List of values.
56      */
57     public List<V> getValues(String name)
58     {
59         List<V> vals = super.get(name);
60         if((vals == null) || vals.isEmpty()) {
61             return null;
62         }
63         return vals;
64     }
65     
66     /* ------------------------------------------------------------ */
67     /** Get a value from a multiple value.
68      * If the value is not a multivalue, then index 0 retrieves the
69      * value or null.
70      * @param name The entry key.
71      * @param i Index of element to get.
72      * @return Unmodifieable List of values.
73      */
74     public V getValue(String name,int i)
75     {
76         List<V> vals = getValues(name);
77         if(vals == null) {
78             return null;
79         }
80         if (i==0 && vals.isEmpty()) {
81             return null;
82         }
83         return vals.get(i);
84     }
85     
86     
87     /* ------------------------------------------------------------ */
88     /** Get value as String.
89      * Single valued items are converted to a String with the toString()
90      * Object method. Multi valued entries are converted to a comma separated
91      * List.  No quoting of commas within values is performed.
92      * @param name The entry key. 
93      * @return String value.
94      */
95     public String getString(String name)
96     {
97         List<V> vals =get(name);
98         if ((vals == null) || (vals.isEmpty()))
99         {
100             return null;
101         }
102         
103         if (vals.size() == 1)
104         {
105             // simple form.
106             return vals.get(0).toString();
107         }
108         
109         // delimited form
110         StringBuilder values=new StringBuilder(128);
111         for (V e : vals)
112         {
113             if (e != null)
114             {
115                 if (values.length() > 0)
116                     values.append(',');
117                 values.append(e.toString());
118             }
119         }   
120         return values.toString();
121     }
122     
123     /** 
124      * Put multi valued entry.
125      * @param name The entry key. 
126      * @param value The simple value
127      * @return The previous value or null.
128      */
129     public List<V> put(String name, V value) 
130     {
131         if(value == null) {
132             return super.put(name, null);
133         }
134         List<V> vals = new ArrayList<>();
135         vals.add(value);
136         return put(name,vals);
137     }
138
139     /**
140      * Shorthand version of putAll
141      * @param input the input map
142      */
143     public void putAllValues(Map<String, V> input)
144     {
145         for(Map.Entry<String,V> entry: input.entrySet())
146         {
147             put(entry.getKey(), entry.getValue());
148         }
149     }
150     
151     /* ------------------------------------------------------------ */
152     /** Put multi valued entry.
153      * @param name The entry key. 
154      * @param values The List of multiple values.
155      * @return The previous value or null.
156      */
157     public List<V> putValues(String name, List<V> values) 
158     {
159         return super.put(name,values);
160     }
161     
162     /* ------------------------------------------------------------ */
163     /** Put multi valued entry.
164      * @param name The entry key. 
165      * @param values The array of multiple values.
166      * @return The previous value or null.
167      */
168     @SafeVarargs
169     public final List<V> putValues(String name, V... values) 
170     {
171         List<V> list = new ArrayList<>();
172         list.addAll(Arrays.asList(values));
173         return super.put(name,list);
174     }
175     
176     
177     /* ------------------------------------------------------------ */
178     /** Add value to multi valued entry.
179      * If the entry is single valued, it is converted to the first
180      * value of a multi valued entry.
181      * @param name The entry key. 
182      * @param value The entry value.
183      */
184     public void add(String name, V value) 
185     {
186         List<V> lo = get(name);
187         if(lo == null) {
188             lo = new ArrayList<>();
189         }
190         lo.add(value);
191         super.put(name,lo);
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(String name, List<V> values) 
202     {
203         List<V> lo = get(name);
204         if(lo == null) {
205             lo = new ArrayList<>();
206         }
207         lo.addAll(values);
208         put(name,lo);
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 String array of multiple values.
217      */
218     public void addValues(String name, V[] values) 
219     {
220         List<V> lo = get(name);
221         if(lo == null) {
222             lo = new ArrayList<>();
223         }
224         lo.addAll(Arrays.asList(values));
225         put(name,lo);
226     }
227     
228     /**
229      * Merge values.
230      * 
231      * @param map
232      *            the map to overlay on top of this one, merging together values if needed.
233      * @return true if an existing key was merged with potentially new values, false if either no change was made, or there were only new keys.
234      */
235     public boolean addAllValues(MultiMap<V> map)
236     {
237         boolean merged = false;
238
239         if ((map == null) || (map.isEmpty()))
240         {
241             // done
242             return merged;
243         }
244
245         for (Map.Entry<String, List<V>> entry : map.entrySet())
246         {
247             String name = entry.getKey();
248             List<V> values = entry.getValue();
249
250             if (this.containsKey(name))
251             {
252                 merged = true;
253             }
254
255             this.addValues(name,values);
256         }
257
258         return merged;
259     }
260     
261     /* ------------------------------------------------------------ */
262     /** Remove value.
263      * @param name The entry key. 
264      * @param value The entry value. 
265      * @return true if it was removed.
266      */
267     public boolean removeValue(String name,V value)
268     {
269         List<V> lo = get(name);
270         if((lo == null)||(lo.isEmpty())) {
271             return false;
272         }
273         boolean ret = lo.remove(value);
274         if(lo.isEmpty()) {
275             remove(name);
276         } else {
277             put(name,lo);
278         }
279         return ret;
280     }
281     
282     /**
283      * Test for a specific single value in the map.
284      * <p>
285      * NOTE: This is a SLOW operation, and is actively discouraged.
286      * @param value
287      * @return true if contains simple value
288      */
289     public boolean containsSimpleValue(V value)
290     {
291         for (List<V> vals : values())
292         {
293             if ((vals.size() == 1) && vals.contains(value))
294             {
295                 return true;
296             }
297         }
298         return false;
299     }
300     
301     @Override
302     public String toString()
303     {
304         Iterator<Entry<String, List<V>>> iter = entrySet().iterator();
305         StringBuilder sb = new StringBuilder();
306         sb.append('{');
307         boolean delim = false;
308         while (iter.hasNext())
309         {
310             Entry<String, List<V>> e = iter.next();
311             if (delim)
312             {
313                 sb.append(", ");
314             }
315             String key = e.getKey();
316             List<V> vals = e.getValue();
317             sb.append(key);
318             sb.append('=');
319             if (vals.size() == 1)
320             {
321                 sb.append(vals.get(0));
322             }
323             else
324             {
325                 sb.append(vals);
326             }
327             delim = true;
328         }
329         sb.append('}');
330         return sb.toString();
331     }
332     
333     /* ------------------------------------------------------------ */
334     /** 
335      * @return Map of String arrays
336      */
337     public Map<String,String[]> toStringArrayMap()
338     {
339         HashMap<String,String[]> map = new HashMap<String,String[]>(size()*3/2)
340         {
341             @Override
342             public String toString()
343             {
344                 StringBuilder b=new StringBuilder();
345                 b.append('{');
346                 for (String k:super.keySet())
347                 {
348                     if(b.length()>1)
349                         b.append(',');
350                     b.append(k);
351                     b.append('=');
352                     b.append(Arrays.asList(super.get(k)));
353                 }
354
355                 b.append('}');
356                 return b.toString();
357             }
358         };
359         
360         for(Map.Entry<String,List<V>> entry: entrySet())
361         {
362             String[] a = null;
363             if (entry.getValue() != null)
364             {
365                 a = new String[entry.getValue().size()];
366                 a = entry.getValue().toArray(a);
367             }
368             map.put(entry.getKey(),a);
369         }
370         return map;
371     }
372
373 }