/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.graph.convert;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.joda.convert.StringConvert;
import org.joda.convert.StringConverter;
import com.opengamma.core.link.ConfigLink;
import com.opengamma.sesame.function.ArrayType;
import com.opengamma.sesame.function.CollectionType;
import com.opengamma.sesame.function.MapType;
import com.opengamma.sesame.function.ParameterType;
import com.opengamma.util.ArgumentChecker;
/**
* <p>Converter that can convert between strings and objects used in the function configuration.
* There are three types of converters, each of which handles a different type of object</p>
*
* <ul>
* <li>Simple types - A string is converted to a single instance. e.g. number, date, tenor</li>
* <li>Collections - A delimited string is converted to a collection of simple types</li>
* <li>Maps - A delimited string is converted to a set key / value pairs</li>
* </ul>
*
* <p>All elements of a collection must be of the same type. The collection type must be {@link Collection},
* {@link List}, {@link Set} or an array. A simple converter is used for converting the elements.</p>
*
* <p>All map keys must be of the same type and the values must be of the same type. Simple converters are used
* for converting the keys and values.</p>
*
* <p>Strings are delimited with commas, spaces or a mixture of the two. Strings can be quoted with double quotes.
* Quotes can be embedded in strings if they are escaped using a backslash.</p>
*/
@SuppressWarnings("unchecked")
public class DefaultArgumentConverter implements ArgumentConverter {
private final StringConvert _stringConvert;
// TODO do we need another constructor to allow converters to be added or replaced?
public DefaultArgumentConverter() {
_stringConvert = StringConvert.create();
_stringConvert.register(String.class, new StringConverter<String>() {
@Override
public String convertFromString(Class<? extends String> cls, String str) {
return str;
}
@Override
public String convertToString(String object) {
return object;
}
});
_stringConvert.register(ConfigLink.class, new StringConverter<ConfigLink>() {
@Override
public ConfigLink convertFromString(Class<? extends ConfigLink> cls, String str) {
throw new UnsupportedOperationException("This should not be called for ConfigLink");
}
@Override
public String convertToString(ConfigLink link) {
// TODO link API needs to include link identifier PLAT-6467
//return link.get
throw new UnsupportedOperationException("need changes to the ConfigLink API to implement this");
}
});
}
@Override
public boolean isConvertible(ParameterType type) {
return getConverter(type) != null;
}
@Override
public String convertToString(ParameterType parameterType, Object object) {
StringConverter<Object> converter = getConverter(parameterType);
if (converter == null) {
throw new IllegalArgumentException("Unable to convert parameter type " + parameterType);
}
return converter.convertToString(object);
}
@Override
public Object convertFromString(ParameterType parameterType, String str) {
StringConverter<Object> converter = getConverter(parameterType);
if (converter == null) {
throw new IllegalArgumentException("Unable to convert parameter type " + parameterType);
}
return converter.convertFromString(parameterType.getType(), str);
}
private StringConverter<Object> getConverter(ParameterType type) {
ArgumentChecker.notNull(type, "type");
if (type instanceof ArrayType) {
Class<?> elementType = ((ArrayType) type).getElementType();
StringConverter elementConverter = getConverterByClass(elementType);
if (elementConverter == null) {
return null;
} else {
return new ArrayConverter(elementType, elementConverter);
}
}
if (type instanceof CollectionType) {
Class<?> collectionType = type.getType();
Class<?> elementType = ((CollectionType) type).getElementType();
StringConverter elementConverter = getConverterByClass(elementType);
if (elementConverter == null) {
return null;
} else {
return CollectionConverter.create(collectionType, elementConverter);
}
}
if (type instanceof MapType) {
MapType mapType = (MapType) type;
Class<?> keyType = mapType.getKeyType();
Class<?> valueType = mapType.getValueType();
StringConverter keyConverter = getConverterByClass(keyType);
StringConverter valueConverter = getConverterByClass(valueType);
if (keyConverter == null || valueConverter == null) {
return null;
}
return new MapConverter(keyType, keyConverter, valueType, valueConverter);
}
return getConverterByClass(type.getType());
}
private StringConverter getConverterByClass(Class<?> type) {
if (!_stringConvert.isConvertible(type)) {
return null;
}
return _stringConvert.findConverter(type);
}
}