/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.factory.FactoryCreator;
import org.geotools.factory.FactoryRegistry;
import org.geotools.factory.GeoTools;
import org.geotools.factory.Hints;
import org.geotools.resources.LazySet;
import org.geotools.util.logging.Logging;
/**
* Convenience class for converting an object from one type to an object of another.
*
* @author Justin Deoliveira, The Open Planning Project
* @since 2.4
*
*
* @source $URL$
*/
public final class Converters {
private static final Logger LOGGER = Logging.getLogger(Converters.class);
/**
* Cached list of converter factories
*/
static ConverterFactory[] factories;
/**
* The service registry for this manager.
* Will be initialized only when first needed.
*/
private static FactoryRegistry registry;
/**
* Returns the service registry. The registry will be created the first
* time this method is invoked.
*/
private static FactoryRegistry getServiceRegistry() {
assert Thread.holdsLock(Converters.class);
if (registry == null) {
registry = new FactoryCreator(Arrays.asList(new Class<?>[] {
ConverterFactory.class,}));
}
return registry;
}
private static Hints addDefaultHints(final Hints hints) {
final Hints completed = GeoTools.getDefaultHints();
if (hints != null) {
completed.add(hints);
}
return completed;
}
/**
* Returns a set of all available implementations for the {@link ConverterFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available ConverterFactory implementations.
*/
public static synchronized Set getConverterFactories(Hints hints) {
hints = addDefaultHints(hints);
return new LazySet(getServiceRegistry().getServiceProviders(
ConverterFactory.class, null, hints));
}
/**
* Returns a set of all available {@link ConverterFactory}'s which can handle
* convert from the source to destination class.
* <p>
* This method essentially returns all factories in which the following
* returns non null.
* <pre>
* factory.createConverter( source, target );
* </pre>
* </p>
*
* @since 2.5
*/
public static Set<ConverterFactory> getConverterFactories( Class source, Class target ) {
HashSet factories = new HashSet();
for (ConverterFactory factory : factories()) {
if ( factory.createConverter( source, target, null ) != null ) {
factories.add( factory );
}
}
return factories;
}
/**
* Convenience for {@link #convert(Object, Class, Hints)}
* @param source The object to convert.
* @param target The type of the converted value.
* @return The converted value as an instance of target, or <code>null</code> if a converter
* could not be found
* @since 2.4
*/
public static <T> T convert( Object source, Class<T> target ) {
return convert( source, target, null );
}
/**
* Converts an object of a particular type into an object of a differnt type.
* <p>
* This method uses the {@link ConverterFactory} extension point to find a converter capable
* of performing the conversion. The first converter found is the one used. Using this class
* there is no way to guarantee which converter will be used.
* </p>
* @param source The object to convert.
* @param target The type of the converted value.
* @param hints Any hints for the converter factory.
*
* @return The converted value as an instance of target, or <code>null</code> if a converter
* could not be found.
*
* @since 2.4
*/
public static <T> T convert( Object source, Class<T> target, Hints hints ) {
//can't convert null
if ( source == null )
return null;
// handle case of source being an instance of target up front
final Class sourceClass = source.getClass();
if (sourceClass == target || sourceClass.equals( target )
|| target.isAssignableFrom(sourceClass) ) {
return (T) source;
}
for (ConverterFactory factory : factories()) {
Converter converter = factory.createConverter( sourceClass, target, hints );
if ( converter != null ) {
try {
T converted = converter.convert( source, target );
if ( converted != null ) {
return converted;
}
} catch (Exception e) {
if(LOGGER.isLoggable(Level.FINER))
LOGGER.log(Level.FINER, "Error applying the converter " + converter.getClass() + " on (" + source + "," + target + ")", e);
}
}
}
//a couple of final tries
if ( String.class.equals( target ) ) {
return (T) source.toString();
}
return null;
}
/**
* Processed the {@link ConverterFactory} extension point.
*
* @return A collection of converter factories.
* @since 2.4
*/
static ConverterFactory[] factories() {
if(factories == null) {
Collection factoryCollection = getConverterFactories(GeoTools.getDefaultHints());
factories = (ConverterFactory[]) factoryCollection.toArray(new ConverterFactory[factoryCollection.size()]);
}
return factories;
}
}