@@ -7,19 +7,13 @@
*/
*/
package org.apache.myrmidon.components.converter;
package org.apache.myrmidon.components.converter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.aut.converter.Converter;
import org.apache.aut.converter.Converter;
import org.apache.aut.converter.ConverterException;
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.myrmidon.interfaces.converter.ConverterRegistry;
import org.apache.myrmidon.interfaces.type.TypeFactory;
import org.apache.myrmidon.interfaces.type.TypeFactory;
import org.apache.myrmidon.interfaces.type.TypeManager;
import org.apache.myrmidon.interfaces.type.TypeManager;
import org.apache.myrmidon.interfaces.converter.ConverterRegistry;
/**
/**
* Converter engine to handle converting between types.
* Converter engine to handle converting between types.
@@ -28,24 +22,11 @@ import org.apache.myrmidon.interfaces.converter.ConverterRegistry;
* @version $Revision$ $Date$
* @version $Revision$ $Date$
*/
*/
public class DefaultMasterConverter
public class DefaultMasterConverter
implements Converter, ConverterRegistry, Serviceable
extends AbstractMasterConverter
implements ConverterRegistry, Serviceable
{
{
private final static Resources REZ =
ResourceManager.getPackageResources( DefaultMasterConverter.class );
private TypeManager m_typeManager;
private TypeManager m_typeManager;
/**
* Map from converter classname to instance of converter.
*/
private final Map m_converters = new HashMap();
/**
* This holds the mapping between source/destination
* and converter name.
*/
private final HashMap m_mapping = new HashMap();
/**
/**
* Retrieve relevent services needed to deploy.
* Retrieve relevent services needed to deploy.
*
*
@@ -69,70 +50,7 @@ public class DefaultMasterConverter
final String source,
final String source,
final String destination )
final String destination )
{
{
HashMap map = (HashMap)m_mapping.get( source );
if( null == map )
{
map = new HashMap();
m_mapping.put( source, map );
}
map.put( destination, className );
}
/**
* Convert object to destination type.
*
* @param destination the destination type
* @param original the original object
* @param context the context in which to convert
* @return the converted object
* @exception ConverterException if an error occurs
*/
public Object convert( final Class destination,
final Object original,
final Object context )
throws ConverterException
{
final Class originalClass = original.getClass();
if( destination.isAssignableFrom( originalClass ) )
{
return original;
}
try
{
// Search inheritance hierarchy for converter
final String name = findConverter( originalClass, destination );
// Create the converter
Converter converter = (Converter)m_converters.get( name );
if( converter == null )
{
converter = createConverter( name );
m_converters.put( name, converter );
}
// Convert
final Object object = converter.convert( destination, original, context );
if( destination.isInstance( object ) )
{
return object;
}
final String message =
REZ.getString( "bad-return-type.error",
object.getClass().getName(),
destination.getName() );
throw new ConverterException( message );
}
catch( final Exception e )
{
final String message = REZ.getString( "convert.error",
originalClass.getName(),
destination.getName() );
throw new ConverterException( message, e );
}
super.registerConverter( className, source, destination );
}
}
/**
/**
@@ -142,99 +60,10 @@ public class DefaultMasterConverter
* @return the created converter instance
* @return the created converter instance
* @throws Exception if converter can not be created.
* @throws Exception if converter can not be created.
*/
*/
private Converter createConverter( final String name )
protected Converter createConverter( final String name )
throws Exception
throws Exception
{
{
final TypeFactory factory = m_typeManager.getFactory( Converter.ROLE );
final TypeFactory factory = m_typeManager.getFactory( Converter.ROLE );
return (Converter)factory.create( name );
return (Converter)factory.create( name );
}
}
/**
* Determine the name of the converter to use to convert between
* original and destination classes.
*/
private String findConverter( final Class originalClass,
final Class destination )
throws ConverterException
{
//TODO: Maybe we should search the destination classes hierarchy as well
// Recursively iterate over the super-types of the original class,
// looking for a converter from source type -> destination type.
// If more than one is found, choose the most specialised.
Class match = null;
String converterName = null;
ArrayList queue = new ArrayList();
queue.add( originalClass );
while( !queue.isEmpty() )
{
Class clazz = (Class)queue.remove( 0 );
// Add superclass and all interfaces
if( clazz.getSuperclass() != null )
{
queue.add( clazz.getSuperclass() );
}
final Class[] interfaces = clazz.getInterfaces();
for( int i = 0; i < interfaces.length; i++ )
{
queue.add( interfaces[ i ] );
}
// Check if we can convert from current class to destination
final String name = getConverterClassname( clazz.getName(),
destination.getName() );
if( name == null )
{
continue;
}
// Choose the more specialised source class
if( match == null || match.isAssignableFrom( clazz ) )
{
match = clazz;
converterName = name;
}
else if( clazz.isAssignableFrom( clazz ) )
{
continue;
}
else
{
// Duplicate
final String message = REZ.getString( "ambiguous-converter.error" );
throw new ConverterException( message );
}
}
// TODO - should cache the (src, dest) -> converter mapping
if( match != null )
{
return converterName;
}
// Could not find a converter
final String message = REZ.getString( "no-converter.error" );
throw new ConverterException( message );
}
/**
* Retrieve name of ConverterInfo that describes converter that converts
* from source to destination.
*
* @param source the source classname
* @param destination the destination classname
* @return the className of converter or null if none available
*/
private String getConverterClassname( final String source, final String destination )
{
final HashMap map = (HashMap)m_mapping.get( source );
if( null == map )
{
return null;
}
return (String)map.get( destination );
}
}
}