/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2011, 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.vector.merge;
import com.vividsolutions.jts.geom.Geometry;
import java.util.HashMap;
import java.util.Map;
import org.opengis.feature.AttributeType;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.geometry.jts.JTSMapping;
import org.geotoolkit.processing.AbstractProcess;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.UnconvertibleObjectException;
import org.apache.sis.util.ObjectConverter;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.util.GenericName;
import org.opengis.feature.PropertyType;
import org.opengis.parameter.ParameterValueGroup;
import org.geotoolkit.feature.util.converter.SimpleConverter;
import org.apache.sis.feature.FeatureExt;
import org.apache.sis.internal.feature.AttributeConvention;
import static org.geotoolkit.processing.vector.merge.MergeDescriptor.*;
import static org.geotoolkit.parameter.Parameters.*;
/**
* Merge many FeatureCollection in one. The fist FeatureCollection found in the input Collection
* have his FeatureType preserved. The others will be adapted to this one.
*
* @author Quentin Boileau
*/
public class MergeProcess extends AbstractProcess {
/**
* Default constructor
*/
public MergeProcess(final ParameterValueGroup input) {
super(INSTANCE, input);
}
/**
* {@inheritDoc }
*/
@Override
protected void execute() {
final FeatureCollection[] inputFeaturesList = value(FEATURES_IN, inputParameters);
final FeatureCollection firstFC = inputFeaturesList[0];
final FeatureCollection resultFeatureList = new MergeFeatureCollection(inputFeaturesList,firstFC);
getOrCreate(FEATURE_OUT, outputParameters).setValue(resultFeatureList);
}
/**
* Create a new feature based on common attributes form the base FeatureType.
* @param feature
* @param newFeatureType
* @param conversionMap
* @return a feature
* @throws UnconvertibleObjectException
*/
static Feature mergeFeature(final Feature feature, final FeatureType newFeatureType, final Map<GenericName, ObjectConverter> conversionMap)
throws UnconvertibleObjectException
{
if (conversionMap == null) {
return feature;
}
final Feature mergedFeature = newFeatureType.newInstance();
FeatureExt.setId(mergedFeature, FeatureExt.getId(feature));
for (final Map.Entry<GenericName,ObjectConverter> entry : conversionMap.entrySet()) {
final String key = entry.getKey().toString();
if(entry.getValue() == null) {
mergedFeature.setPropertyValue(key, feature.getPropertyValue(key));
}else{
mergedFeature.setPropertyValue(key, entry.getValue().apply(feature.getPropertyValue(key)));
}
}
return mergedFeature;
}
/**
* Create a map between two FeatureType. Each entry of the map represents a shared attribute between
* two input FeatureType. The key contained the name of attribute and the value a ObjectConverter if the
* type between attributes is different.
* @param input
* @param toConvert
* @return map<Name, ObjectConverter>. Return null if input FeatureType are equals
* @throws UnconvertibleObjectException
*/
static Map<GenericName, ObjectConverter> createConversionMap (final FeatureType input, final FeatureType toConvert) throws UnconvertibleObjectException {
if(input.equals(toConvert)) {
return null;
}
final Map<GenericName, ObjectConverter> map = new HashMap<GenericName, ObjectConverter>();
for (final PropertyType toConvertDesc : toConvert.getProperties(true)) {
for(final PropertyType inputDesc : input.getProperties(true)) {
//same property name
if (toConvertDesc.getName().equals(inputDesc.getName()) &&
inputDesc instanceof AttributeType<?> && toConvertDesc instanceof AttributeType<?>)
{
final Class<?> inputClass = ((AttributeType<?>) inputDesc).getValueClass();
final Class<?> toConvertClass = ((AttributeType<?>) toConvertDesc).getValueClass();
if(toConvertClass.equals(inputClass)) {
//same name and same type
map.put(toConvertDesc.getName(), null);
}else{
//same name but different type
if (AttributeConvention.isGeometryAttribute(toConvertDesc)) {
map.put(toConvertDesc.getName(), new GeomConverter(toConvertClass, inputClass));
} else {
map.put(toConvertDesc.getName(), ObjectConverters.find(toConvertClass, inputClass));
}
}
}
}
}
return map;
}
/**
* Implementation of ObjectConverter for JTS Geometry using the MappingUtils class.
* This class is use to Convert from a JTS Geometry to an other giving an ObjectConverter object.
* @author Quentin Boileau
* @module
*/
private static class GeomConverter extends SimpleConverter {
private final Class sourceClass;
private final Class targetClass;
/**
* GeomConverter constructor
* @param source
* @param target
*/
public GeomConverter(final Class source, final Class target) {
sourceClass = source;
targetClass = target;
}
@Override
public Class getSourceClass() {
return sourceClass;
}
@Override
public Class getTargetClass() {
return targetClass;
}
@Override
public Object apply(final Object s) throws UnconvertibleObjectException {
return JTSMapping.convertType((Geometry)s, getTargetClass());
}
}
}