/* Copyright (c) 2013-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: * Gabriel Roldan (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.DecoratingFeature; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.filter.identity.FeatureIdImpl; 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.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import org.opengis.filter.identity.FeatureId; import org.opengis.filter.sort.SortBy; class ForceTypeAndFidFeatureSource<T extends FeatureType, F extends Feature> extends ForwardingFeatureSource<T, F> { private T forceType; private String fidPrefix; private boolean forbidSorting; public ForceTypeAndFidFeatureSource(final FeatureSource<T, F> source, final T forceType, final String fidPrefix) { super(source); this.forceType = forceType; this.fidPrefix = fidPrefix; } /** * @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 T getSchema() { return forceType; } @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() { FeatureIterator<F> iterator = delegate.features(); return new FidPrefixRemovingIterator<F>(iterator, fidPrefix, (SimpleFeatureType) forceType); } @Override public T getSchema() { return forceType; } }; } private static class FidPrefixRemovingIterator<F extends Feature> extends ForwardingFeatureIterator<F> { private final String fidPrefix; private SimpleFeatureType forcedType; public FidPrefixRemovingIterator(final FeatureIterator<F> iterator, final String fidPrefix, SimpleFeatureType forcedType) { super(iterator); checkNotNull(fidPrefix); checkNotNull(forcedType); this.fidPrefix = fidPrefix; this.forcedType = forcedType; } @SuppressWarnings("unchecked") @Override public F next() { F next = super.next(); String fid = ((SimpleFeature) next).getID(); if (fid.startsWith(fidPrefix)) { fid = fid.substring(fidPrefix.length()); } return (F) new FidAndFtOverrideFeature((SimpleFeature) next, fid, forcedType); } } private static final class FidAndFtOverrideFeature extends DecoratingFeature { private String fid; private SimpleFeatureType featureType; public FidAndFtOverrideFeature(SimpleFeature delegate, String fid, SimpleFeatureType featureType) { super(delegate); this.fid = fid; this.featureType = featureType; } @Override public SimpleFeatureType getType() { return featureType; } @Override public String getID() { return fid; } @Override public FeatureId getIdentifier() { return new FeatureIdImpl(fid); } } }