/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012-2013, Geomatys
*
* 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.geotoolkit.processing.chain.model.event;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.sis.util.ArgumentChecks;
import org.geotoolkit.processing.chain.model.ClassFull;
import org.apache.sis.util.ObjectConverter;
/**
* Used to find convertion possibilities from two objects.
*
* @author Johann Sorel (Geomatys)
*/
public class ConverterMatcher {
public static ConverterMatcher DEFAULT;
static {
DEFAULT = new ConverterMatcher(
new HashMap<ClassFull, List<ClassFull>>(),
new ArrayList<ObjectConverter>());
}
private final Map<ClassFull, List<ClassFull>> distantConverters;
private final Collection<ObjectConverter> localConverters;
public ConverterMatcher(Map<ClassFull, List<ClassFull>> distantConverters,
Collection<ObjectConverter> localConverters) {
ArgumentChecks.ensureNonNull("disntantConverters", distantConverters);
ArgumentChecks.ensureNonNull("localConverters", localConverters);
this.distantConverters = distantConverters;
this.localConverters = localConverters;
}
/**
*
* @param source : expect Class or ClassFullDto
* @param target : expect Class or ClassFullDto
* @return true is convertion is possible
* @throws IllegalArgumentException if source or targer is not an expected type
*/
public boolean canBeConverted(Object source, Object target) throws IllegalArgumentException{
if(source == null || target == null){
return false;
}
if(source instanceof Class && target instanceof Class){
return canBeConverted((Class)source, (Class)target);
}else if(source instanceof Class && target instanceof ClassFull){
return canBeConverted(new ClassFull((Class)source), (ClassFull)target);
}else if(source instanceof ClassFull && target instanceof Class){
return canBeConverted((ClassFull)source, new ClassFull((Class)target) );
}else if(source instanceof ClassFull && target instanceof ClassFull){
return canBeConverted((ClassFull)source, (ClassFull)target);
}
throw new IllegalArgumentException("Unexpected types : " + source +" ⇒ "+target);
}
private boolean canBeConverted(final Class source, final Class target){
//check natural possibilities
if(target.isAssignableFrom(source)){
//source is already the same or a subclass of target.
return true;
}
for(ObjectConverter oc : localConverters){
if(oc.getSourceClass().isAssignableFrom(source)
&& oc.getTargetClass().isAssignableFrom(target)){
return true;
}
}
return false;
}
private boolean canBeConverted(final ClassFull source, final ClassFull target){
//check natural possibilities
if(isAssignableFrom(source,target)){
//source is already the same or a subclass of target.
return true;
}
for(Entry<ClassFull, List<ClassFull>> entry : distantConverters.entrySet()){
if(isAssignableFrom(source,entry.getKey())){
for(ClassFull cfd : entry.getValue()){
if(isAssignableFrom(cfd, target)){
return true;
}
}
}
}
return false;
}
/**
* @return true if candidate is the same or a child class of reference.
*/
public static boolean isAssignableFrom(ClassFull candidate, ClassFull reference){
if(candidate.getName().equals(reference.getName())){
return true;
}
if(candidate.getClasses().contains(reference.getName())){
return true;
}
return false;
}
}