View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.mime4j.util;
21  
22  import java.io.Serializable;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Enumeration;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.NoSuchElementException;
31  
32  import org.apache.james.mime4j.message.Header;
33  import org.apache.james.mime4j.parser.ContentHandler;
34  import org.apache.james.mime4j.parser.Field;
35  
36  /**
37   * An object, which may be used to implement header, or parameter
38   * maps. The maps keys are the header or parameter names. The
39   * maps values are strings (single value), lists, or arrays.
40   * <p>
41   * Note that this class is not directly used anywhere in Mime4j.
42   * Instead a user might choose to use it instead of {@link Header}
43   * and {@link Field} in a custom {@link ContentHandler} implementation.
44   * See also MIME4j-24.
45   */
46  public class StringArrayMap implements Serializable {
47      private static final long serialVersionUID = -5833051164281786907L;
48      private final Map<String, Object> map = new HashMap<String, Object>();
49  
50      /**
51       * <p>Converts the given object into a string. The object may be either of:
52       * <ul>
53       *   <li>a string, which is returned without conversion</li>
54       *   <li>a list of strings, in which case the first element is returned</li>
55       *   <li>an array of strings, in which case the first element is returned</li>
56       * </ul>
57       */
58      public static String asString(Object pValue) {
59          if (pValue == null) {
60              return null;
61          }
62          if (pValue instanceof String) {
63              return (String) pValue;
64          }
65          if (pValue instanceof String[]) {
66              return ((String[]) pValue)[0];
67          }
68          if (pValue instanceof List) {
69              return (String) ((List<?>) pValue).get(0);
70          }
71          throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());
72      }
73  
74      /**
75       * <p>Converts the given object into a string array. The object may be either of:
76       * <ul>
77       *   <li>a string, which is returned as an array with one element</li>
78       *   <li>a list of strings, which is being converted into a string array</li>
79       *   <li>an array of strings, which is returned without conversion</li>
80       * </ul>
81       */
82      public static String[] asStringArray(Object pValue) {
83          if (pValue == null) {
84              return null;
85          }
86          if (pValue instanceof String) {
87              return new String[]{(String) pValue};
88          }
89          if (pValue instanceof String[]) {
90              return (String[]) pValue;
91          }
92          if (pValue instanceof List) {
93              final List<?> l = (List<?>) pValue;
94              return l.toArray(new String[l.size()]);
95          }
96          throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());
97      }
98  
99      /**
100      * <p>Converts the given object into a string enumeration. The object may be either of:
101      * <ul>
102      *   <li>a string, which is returned as an enumeration with one element</li>
103      *   <li>a list of strings, which is being converted into a string enumeration</li>
104      *   <li>an array of strings, which is being converted into a string enumeration</li>
105      * </ul>
106      */
107     public static Enumeration<String> asStringEnum(final Object pValue) {
108         if (pValue == null) {
109             return null;
110         }
111         if (pValue instanceof String) {
112             return new Enumeration<String>(){
113                 private Object value = pValue;
114                 public boolean hasMoreElements() {
115                     return value != null;
116                 }
117                 public String nextElement() {
118                     if (value == null) {
119                         throw new NoSuchElementException();
120                     }
121                     final String s = (String) value;
122                     value = null;
123                     return s;
124                 }
125             };
126         }
127         if (pValue instanceof String[]) {
128             final String[] values = (String[]) pValue;
129             return new Enumeration<String>() {
130                 private int offset;
131                 public boolean hasMoreElements() {
132                     return offset < values.length;
133                 }
134                 public String nextElement() {
135                     if (offset >= values.length) {
136                         throw new NoSuchElementException();
137                     }
138                     return values[offset++];
139                 }
140             };
141         }
142         if (pValue instanceof List) {
143             @SuppressWarnings("unchecked")
144             final List<String> stringList = (List<String>) pValue; 
145             return Collections.enumeration(stringList);
146         }
147         throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());
148     }
149 
150     /**
151      * Converts the given map into a string array map: The map values
152      * are string arrays.
153      */
154     public static Map<String, String[]> asMap(final Map<String, Object> pMap) {
155         Map<String, String[]> result = new HashMap<String, String[]>(pMap.size());
156         for (Map.Entry<String, Object> entry : pMap.entrySet()) {
157             final String[] value = asStringArray(entry.getValue());
158             result.put(entry.getKey(), value);
159         }
160         return Collections.unmodifiableMap(result);
161     }
162 
163     /**
164      * Adds a value to the given map.
165      */
166     protected void addMapValue(Map<String, Object> pMap, String pName, String pValue) {
167         Object o = pMap.get(pName);
168         if (o == null) {
169             o = pValue;
170         } else if (o instanceof String) {
171             final List<Object> list = new ArrayList<Object>();
172             list.add(o);
173             list.add(pValue);
174             o = list;
175         } else if (o instanceof List) {
176             @SuppressWarnings("unchecked")
177             final List<String> stringList = (List<String>) o; 
178             stringList.add(pValue);
179         } else if (o instanceof String[]) {
180             final List<String> list = new ArrayList<String>();
181             final String[] arr = (String[]) o;
182             for (String str : arr) {
183                 list.add(str);
184             }
185             list.add(pValue);
186             o = list;
187         } else {
188             throw new IllegalStateException("Invalid object type: " + o.getClass().getName());
189         }
190         pMap.put(pName, o);
191     }
192 
193     /**
194      * Lower cases the given name.
195      */
196     protected String convertName(String pName) {
197         return pName.toLowerCase();
198     }
199 
200     /**
201      * Returns the requested value.
202      */
203     public String getValue(String pName) {
204         return asString(map.get(convertName(pName)));
205     }
206 
207     /**
208      * Returns the requested values as a string array.
209      */
210     public String[] getValues(String pName) {
211         return asStringArray(map.get(convertName(pName)));
212     }
213 
214     /**
215      * Returns the requested values as an enumeration.
216      */
217     public Enumeration<String> getValueEnum(String pName) {
218         return asStringEnum(map.get(convertName(pName)));
219     }
220 
221     /**
222      * Returns the set of registered names as an enumeration.
223      * @see #getNameArray()
224      */
225     public Enumeration<String> getNames() {
226         return Collections.enumeration(map.keySet());
227     }
228 
229     /**
230      * Returns an unmodifiable map of name/value pairs. The map keys
231      * are the lower cased parameter/header names. The map values are
232      * string arrays.
233      */
234     public Map<String, String[]> getMap() {
235         return asMap(map);
236     }
237 
238     /**
239      * Adds a new name/value pair.
240      */
241     public void addValue(String pName, String pValue) {
242         addMapValue(map, convertName(pName), pValue);
243     }
244 
245     /**
246      * Returns the set of registered names.
247      * @see #getNames()
248      */
249     public String[] getNameArray() {
250         final Collection<String> c = map.keySet();
251         return c.toArray(new String[c.size()]);
252     }
253 }