/*
* Copyright 2009 Alin Dreghiciu.
*
* Licensed 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.ops4j.pax.swissbox.converter.java.lang;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Pattern;
import org.osgi.service.blueprint.container.Converter;
import org.osgi.service.blueprint.container.ReifiedType;
import static org.ops4j.pax.swissbox.converter.internal.Primitives.*;
import static org.ops4j.pax.swissbox.converter.java.lang.AssignableConverter.*;
import static org.ops4j.pax.swissbox.converter.java.lang.FromNullConverter.*;
/**
* JAVADOC
*
* NOTICE: This class contains code originally developed by "Apache Geronimo Project", OSGi Blueprint Implementation.
*
* @author <a href="mailto:dev@geronimo.apache.org">Apache Geronimo Project</a>
* @author Alin Dreghiciu (adreghiciu@gmail.com)
*/
public class FromStringConverter
implements Converter
{
public static final FromStringConverter INSTANCE = new FromStringConverter();
public boolean canConvert( final Object sourceObject,
final ReifiedType targetType )
{
return fromNullConverter().canConvert( sourceObject, targetType )
|| assignableConverter().canConvert( sourceObject, targetType )
|| ( sourceObject instanceof String
&& targetType != null
&& !( targetType.getRawClass() == Class.class )
&& !( targetType.getRawClass() == ReifiedType.class ) );
}
public Object convert( final Object sourceObject,
final ReifiedType targetType )
throws Exception
{
if( !canConvert( sourceObject, targetType ) )
{
throw new Exception(
String.format(
"%s cannot convert an %s", FromStringConverter.class.getSimpleName(), sourceObject.getClass()
)
);
}
if( fromNullConverter().canConvert( sourceObject, targetType ) )
{
return fromNullConverter().convert( sourceObject, targetType );
}
if( assignableConverter().canConvert( sourceObject, targetType ) )
{
return assignableConverter().convert( sourceObject, targetType );
}
return convertFromString( (String) sourceObject, targetType.getRawClass() );
}
public Object convertFromString( final String sourceObject,
final Class targetType )
throws Exception
{
final Class type = unwrap( targetType );
if( Locale.class == type )
{
String[] tokens = sourceObject.split( "_" );
if( tokens.length == 1 )
{
return new Locale( tokens[ 0 ] );
}
else if( tokens.length == 2 )
{
return new Locale( tokens[ 0 ], tokens[ 1 ] );
}
else if( tokens.length == 3 )
{
return new Locale( tokens[ 0 ], tokens[ 1 ], tokens[ 2 ] );
}
else
{
throw new Exception( "Invalid locale string:" + sourceObject );
}
}
if( Pattern.class == type )
{
return Pattern.compile( sourceObject );
}
if( Properties.class == type )
{
Properties props = new Properties();
ByteArrayInputStream in = new ByteArrayInputStream( sourceObject.getBytes( "UTF8" ) );
props.load( in );
return props;
}
if( Boolean.class == type )
{
if( "yes".equalsIgnoreCase( sourceObject )
|| "true".equalsIgnoreCase( sourceObject )
|| "on".equalsIgnoreCase( sourceObject ) )
{
return Boolean.TRUE;
}
else if( "no".equalsIgnoreCase( sourceObject )
|| "false".equalsIgnoreCase( sourceObject )
|| "off".equalsIgnoreCase( sourceObject ) )
{
return Boolean.FALSE;
}
else
{
throw new RuntimeException( "Invalid boolean value: " + sourceObject );
}
}
if( Integer.class == type )
{
return Integer.valueOf( sourceObject );
}
if( Short.class == type )
{
return Short.valueOf( sourceObject );
}
if( Long.class == type )
{
return Long.valueOf( sourceObject );
}
if( Float.class == type )
{
return Float.valueOf( sourceObject );
}
if( Double.class == type )
{
return Double.valueOf( sourceObject );
}
if( Character.class == type )
{
if( sourceObject.length() == 6 && sourceObject.startsWith( "\\u" ) )
{
int code = Integer.parseInt( sourceObject.substring( 2 ), 16 );
return (char) code;
}
else if( sourceObject.length() == 1 )
{
return sourceObject.charAt( 0 );
}
else
{
throw new Exception( "Invalid value for character type: " + sourceObject );
}
}
if( Byte.class == type )
{
return Byte.valueOf( sourceObject );
}
if( Enum.class.isAssignableFrom( type ) )
{
return Enum.valueOf( (Class<Enum>) type, sourceObject );
}
return createObject( sourceObject, type );
}
private Object createObject( final String sourceObject,
final Class targetType )
throws Exception
{
if( targetType.isInterface()
|| Modifier.isAbstract( targetType.getModifiers() ) )
{
throw new Exception(
"Unable to convert value " + sourceObject + " to type " + targetType + ". Type " + targetType
+ " is an interface or an abstract class"
);
}
try
{
final Constructor constructor = targetType.getConstructor( String.class );
return constructor.newInstance( sourceObject );
}
catch( NoSuchMethodException e )
{
throw new RuntimeException( "Unable to convert to " + targetType );
}
}
public static FromStringConverter fromStringConverter()
{
return INSTANCE;
}
}