/* Copyright (c) 2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Victor Olaya (Boundless) - initial implementation
*/
package org.locationtech.geogig.geotools.plumbing;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.QueryCapabilities;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.locationtech.geogig.api.data.ForwardingFeatureCollection;
import org.locationtech.geogig.api.data.ForwardingFeatureIterator;
import org.locationtech.geogig.api.data.ForwardingFeatureSource;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.sort.SortBy;
class FeatureTypeAdapterFeatureSource<T extends FeatureType, F extends Feature> extends
ForwardingFeatureSource<T, F> {
private T featureType;
private boolean forbidSorting;
public FeatureTypeAdapterFeatureSource(final FeatureSource<T, F> source, final T featureType) {
super(source);
this.featureType = featureType;
}
@Override
public T getSchema() {
return featureType;
}
/**
* @param forbidSorting flag for {@link #getQueryCapabilities()} to return false on
* isOffsetSupported() to work around malfunctioning geotools datastores from
*/
public void setForbidSorting(boolean forbidSorting) {
this.forbidSorting = forbidSorting;
}
@Override
public QueryCapabilities getQueryCapabilities() {
final QueryCapabilities capabilities = super.getQueryCapabilities();
if (!forbidSorting) {
return capabilities;
}
return new QueryCapabilities() {
@Override
public boolean isOffsetSupported() {
return false;
}
@Override
public boolean supportsSorting(SortBy[] sortAttributes) {
return false;
}
@Override
public boolean isReliableFIDSupported() {
return capabilities.isReliableFIDSupported();
}
@Override
public boolean isUseProvidedFIDSupported() {
return capabilities.isUseProvidedFIDSupported();
}
};
}
@Override
public FeatureCollection<T, F> getFeatures(Query query) throws IOException {
final FeatureCollection<T, F> features = super.getFeatures(query);
return new ForwardingFeatureCollection<T, F>(features) {
@Override
public FeatureIterator<F> features() {
if (delegate.getSchema().getDescriptors().size() != featureType.getDescriptors()
.size()) {
throw new GeoToolsOpException(
GeoToolsOpException.StatusCode.INCOMPATIBLE_FEATURE_TYPE);
}
GeometryDescriptor geomDescriptorOrg = delegate.getSchema().getGeometryDescriptor();
GeometryDescriptor geomDescriptorDest = featureType.getGeometryDescriptor();
if (!geomDescriptorOrg.getType().getBinding()
.equals(geomDescriptorDest.getType().getBinding())
|| !geomDescriptorOrg
.getType()
.getCoordinateReferenceSystem()
.equals(geomDescriptorDest.getType().getCoordinateReferenceSystem())) {
throw new GeoToolsOpException(
GeoToolsOpException.StatusCode.INCOMPATIBLE_FEATURE_TYPE);
}
FeatureIterator<F> iterator = delegate.features();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(
(SimpleFeatureType) featureType);
return new FeatureTypeConverterIterator<F>(iterator, (SimpleFeatureBuilder) builder);
}
@Override
public T getSchema() {
return featureType;
}
};
}
private static class FeatureTypeConverterIterator<F extends Feature> extends
ForwardingFeatureIterator<F> {
private SimpleFeatureBuilder builder;
public FeatureTypeConverterIterator(final FeatureIterator<F> iterator,
SimpleFeatureBuilder builder) {
super(iterator);
checkNotNull(builder);
this.builder = builder;
}
@SuppressWarnings("unchecked")
@Override
public F next() {
F next = super.next();
String fid = ((SimpleFeature) next).getID();
Name geometryAttributeName = builder.getFeatureType().getGeometryDescriptor().getName();
builder.set(geometryAttributeName, next.getDefaultGeometryProperty().getValue());
for (AttributeDescriptor attribute : builder.getFeatureType().getAttributeDescriptors()) {
Name name = attribute.getName();
if (!name.equals(geometryAttributeName)) {
Property property = next.getProperty(name);
if (property == null) {
throw new GeoToolsOpException(
GeoToolsOpException.StatusCode.INCOMPATIBLE_FEATURE_TYPE);
}
builder.set(name, next.getProperty(name).getValue());
}
}
return (F) builder.buildFeature(fid);
}
}
}