/**************************************************************** | |
* Licensed to the Apache Software Foundation (ASF) under one * | |
* or more contributor license agreements. See the NOTICE file * | |
* distributed with this work for additional information * | |
* regarding copyright ownership. The ASF licenses this file * | |
* to you under the Apache License, Version 2.0 (the * | |
* "License"); you may not use this file except in compliance * | |
* with the License. You may obtain a copy of the License at * | |
* * | |
* http://www.apache.org/licenses/LICENSE-2.0 * | |
* * | |
* Unless required by applicable law or agreed to in writing, * | |
* software distributed under the License is distributed on an * | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * | |
* KIND, either express or implied. See the License for the * | |
* specific language governing permissions and limitations * | |
* under the License. * | |
****************************************************************/ | |
package org.apache.james.mime4j.util; | |
import java.io.Serializable; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Enumeration; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.NoSuchElementException; | |
import org.apache.james.mime4j.message.Header; | |
import org.apache.james.mime4j.parser.ContentHandler; | |
import org.apache.james.mime4j.parser.Field; | |
/** | |
* An object, which may be used to implement header, or parameter | |
* maps. The maps keys are the header or parameter names. The | |
* maps values are strings (single value), lists, or arrays. | |
* <p> | |
* Note that this class is not directly used anywhere in Mime4j. | |
* Instead a user might choose to use it instead of {@link Header} | |
* and {@link Field} in a custom {@link ContentHandler} implementation. | |
* See also MIME4j-24. | |
*/ | |
public class StringArrayMap implements Serializable { | |
private static final long serialVersionUID = -5833051164281786907L; | |
private final Map<String, Object> map = new HashMap<String, Object>(); | |
/** | |
* <p>Converts the given object into a string. The object may be either of: | |
* <ul> | |
* <li>a string, which is returned without conversion</li> | |
* <li>a list of strings, in which case the first element is returned</li> | |
* <li>an array of strings, in which case the first element is returned</li> | |
* </ul> | |
*/ | |
public static String asString(Object pValue) { | |
if (pValue == null) { | |
return null; | |
} | |
if (pValue instanceof String) { | |
return (String) pValue; | |
} | |
if (pValue instanceof String[]) { | |
return ((String[]) pValue)[0]; | |
} | |
if (pValue instanceof List) { | |
return (String) ((List<?>) pValue).get(0); | |
} | |
throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName()); | |
} | |
/** | |
* <p>Converts the given object into a string array. The object may be either of: | |
* <ul> | |
* <li>a string, which is returned as an array with one element</li> | |
* <li>a list of strings, which is being converted into a string array</li> | |
* <li>an array of strings, which is returned without conversion</li> | |
* </ul> | |
*/ | |
public static String[] asStringArray(Object pValue) { | |
if (pValue == null) { | |
return null; | |
} | |
if (pValue instanceof String) { | |
return new String[]{(String) pValue}; | |
} | |
if (pValue instanceof String[]) { | |
return (String[]) pValue; | |
} | |
if (pValue instanceof List) { | |
final List<?> l = (List<?>) pValue; | |
return l.toArray(new String[l.size()]); | |
} | |
throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName()); | |
} | |
/** | |
* <p>Converts the given object into a string enumeration. The object may be either of: | |
* <ul> | |
* <li>a string, which is returned as an enumeration with one element</li> | |
* <li>a list of strings, which is being converted into a string enumeration</li> | |
* <li>an array of strings, which is being converted into a string enumeration</li> | |
* </ul> | |
*/ | |
public static Enumeration<String> asStringEnum(final Object pValue) { | |
if (pValue == null) { | |
return null; | |
} | |
if (pValue instanceof String) { | |
return new Enumeration<String>(){ | |
private Object value = pValue; | |
public boolean hasMoreElements() { | |
return value != null; | |
} | |
public String nextElement() { | |
if (value == null) { | |
throw new NoSuchElementException(); | |
} | |
final String s = (String) value; | |
value = null; | |
return s; | |
} | |
}; | |
} | |
if (pValue instanceof String[]) { | |
final String[] values = (String[]) pValue; | |
return new Enumeration<String>() { | |
private int offset; | |
public boolean hasMoreElements() { | |
return offset < values.length; | |
} | |
public String nextElement() { | |
if (offset >= values.length) { | |
throw new NoSuchElementException(); | |
} | |
return values[offset++]; | |
} | |
}; | |
} | |
if (pValue instanceof List) { | |
@SuppressWarnings("unchecked") | |
final List<String> stringList = (List<String>) pValue; | |
return Collections.enumeration(stringList); | |
} | |
throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName()); | |
} | |
/** | |
* Converts the given map into a string array map: The map values | |
* are string arrays. | |
*/ | |
public static Map<String, String[]> asMap(final Map<String, Object> pMap) { | |
Map<String, String[]> result = new HashMap<String, String[]>(pMap.size()); | |
for (Map.Entry<String, Object> entry : pMap.entrySet()) { | |
final String[] value = asStringArray(entry.getValue()); | |
result.put(entry.getKey(), value); | |
} | |
return Collections.unmodifiableMap(result); | |
} | |
/** | |
* Adds a value to the given map. | |
*/ | |
protected void addMapValue(Map<String, Object> pMap, String pName, String pValue) { | |
Object o = pMap.get(pName); | |
if (o == null) { | |
o = pValue; | |
} else if (o instanceof String) { | |
final List<Object> list = new ArrayList<Object>(); | |
list.add(o); | |
list.add(pValue); | |
o = list; | |
} else if (o instanceof List) { | |
@SuppressWarnings("unchecked") | |
final List<String> stringList = (List<String>) o; | |
stringList.add(pValue); | |
} else if (o instanceof String[]) { | |
final List<String> list = new ArrayList<String>(); | |
final String[] arr = (String[]) o; | |
for (String str : arr) { | |
list.add(str); | |
} | |
list.add(pValue); | |
o = list; | |
} else { | |
throw new IllegalStateException("Invalid object type: " + o.getClass().getName()); | |
} | |
pMap.put(pName, o); | |
} | |
/** | |
* Lower cases the given name. | |
*/ | |
protected String convertName(String pName) { | |
return pName.toLowerCase(); | |
} | |
/** | |
* Returns the requested value. | |
*/ | |
public String getValue(String pName) { | |
return asString(map.get(convertName(pName))); | |
} | |
/** | |
* Returns the requested values as a string array. | |
*/ | |
public String[] getValues(String pName) { | |
return asStringArray(map.get(convertName(pName))); | |
} | |
/** | |
* Returns the requested values as an enumeration. | |
*/ | |
public Enumeration<String> getValueEnum(String pName) { | |
return asStringEnum(map.get(convertName(pName))); | |
} | |
/** | |
* Returns the set of registered names as an enumeration. | |
* @see #getNameArray() | |
*/ | |
public Enumeration<String> getNames() { | |
return Collections.enumeration(map.keySet()); | |
} | |
/** | |
* Returns an unmodifiable map of name/value pairs. The map keys | |
* are the lower cased parameter/header names. The map values are | |
* string arrays. | |
*/ | |
public Map<String, String[]> getMap() { | |
return asMap(map); | |
} | |
/** | |
* Adds a new name/value pair. | |
*/ | |
public void addValue(String pName, String pValue) { | |
addMapValue(map, convertName(pName), pValue); | |
} | |
/** | |
* Returns the set of registered names. | |
* @see #getNames() | |
*/ | |
public String[] getNameArray() { | |
final Collection<String> c = map.keySet(); | |
return c.toArray(new String[c.size()]); | |
} | |
} |