package mil.nga.giat.geowave.format.geotools.vector;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import mil.nga.giat.geowave.adapter.vector.FeatureDataAdapter;
import mil.nga.giat.geowave.adapter.vector.utils.SimpleFeatureUserDataConfigurationSet;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.ingest.GeoWaveData;
import mil.nga.giat.geowave.core.store.CloseableIterator;
import mil.nga.giat.geowave.core.store.adapter.WritableDataAdapter;
import mil.nga.giat.geowave.core.store.data.visibility.GlobalVisibilityHandler;
import mil.nga.giat.geowave.format.geotools.vector.RetypingVectorDataPlugin.RetypingVectorDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.geotools.data.DataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
/**
* This is a wrapper for a GeoTools SimpleFeatureCollection as a convenience to
* ingest it into GeoWave by translating a list of SimpleFeatureCollection to a
* closeable iterator of GeoWaveData
*/
public class SimpleFeatureGeoWaveWrapper implements
CloseableIterator<GeoWaveData<SimpleFeature>>
{
private final static Logger LOGGER = LoggerFactory.getLogger(SimpleFeatureGeoWaveWrapper.class);
private class InternalIterator implements
CloseableIterator<GeoWaveData<SimpleFeature>>
{
private final SimpleFeatureIterator featureIterator;
private final WritableDataAdapter<SimpleFeature> dataAdapter;
private RetypingVectorDataSource source = null;
private final Filter filter;
private SimpleFeatureBuilder builder = null;
private GeoWaveData<SimpleFeature> currentData = null;
public InternalIterator(
final SimpleFeatureCollection featureCollection,
final String visibility,
final Filter filter ) {
this.filter = filter;
featureIterator = featureCollection.features();
final SimpleFeatureType originalSchema = featureCollection.getSchema();
SimpleFeatureType retypedSchema = SimpleFeatureUserDataConfigurationSet.configureType(originalSchema);
if (retypingPlugin != null) {
source = retypingPlugin.getRetypingSource(originalSchema);
if (source != null) {
retypedSchema = source.getRetypedSimpleFeatureType();
builder = new SimpleFeatureBuilder(
retypedSchema);
}
}
if ((visibility == null) || visibility.isEmpty()) {
dataAdapter = new FeatureDataAdapter(
retypedSchema);
}
else {
dataAdapter = new FeatureDataAdapter(
retypedSchema,
new GlobalVisibilityHandler<SimpleFeature, Object>(
visibility));
}
}
@Override
public boolean hasNext() {
if (currentData == null) {
// return a flag indicating if we find more data that matches
// the filter, essentially peeking and caching the result
return nextData();
}
return true;
}
@Override
public GeoWaveData<SimpleFeature> next() {
if (currentData == null) {
// get the next data that matches the filter
nextData();
}
// return that data and set the current data to null
final GeoWaveData<SimpleFeature> retVal = currentData;
currentData = null;
return retVal;
}
private synchronized boolean nextData() {
SimpleFeature nextAcceptedFeature;
do {
if (!featureIterator.hasNext()) {
return false;
}
nextAcceptedFeature = featureIterator.next();
if (builder != null) {
nextAcceptedFeature = source.getRetypedSimpleFeature(
builder,
nextAcceptedFeature);
}
}
while (!filter.evaluate(nextAcceptedFeature));
currentData = new GeoWaveData<SimpleFeature>(
dataAdapter,
primaryIndexIds,
nextAcceptedFeature);
return true;
}
@Override
public void remove() {}
@Override
public void close()
throws IOException {
featureIterator.close();
}
}
private final List<SimpleFeatureCollection> featureCollections;
private final Collection<ByteArrayId> primaryIndexIds;
private InternalIterator currentIterator = null;
private final String visibility;
private final DataStore dataStore;
private final RetypingVectorDataPlugin retypingPlugin;
private final Filter filter;
public SimpleFeatureGeoWaveWrapper(
final List<SimpleFeatureCollection> featureCollections,
final Collection<ByteArrayId> primaryIndexIds,
final String visibility,
final DataStore dataStore,
final RetypingVectorDataPlugin retypingPlugin,
final Filter filter ) {
this.featureCollections = featureCollections;
this.visibility = visibility;
this.primaryIndexIds = primaryIndexIds;
this.dataStore = dataStore;
this.retypingPlugin = retypingPlugin;
this.filter = filter;
}
@Override
public boolean hasNext() {
if ((currentIterator == null) || !currentIterator.hasNext()) {
// return a flag indicating if we find another iterator that hasNext
return nextIterator();
}
// currentIterator has next
return true;
}
private synchronized boolean nextIterator() {
if (currentIterator != null) {
try {
currentIterator.close();
}
catch (final IOException e) {
LOGGER.warn(
"Cannot close feature iterator",
e);
}
}
final Iterator<SimpleFeatureCollection> it = featureCollections.iterator();
while (it.hasNext()) {
final SimpleFeatureCollection collection = it.next();
final InternalIterator featureIt = new InternalIterator(
collection,
visibility,
filter);
it.remove();
if (!featureIt.hasNext()) {
try {
featureIt.close();
}
catch (final IOException e) {
LOGGER.warn(
"Cannot close feature iterator",
e);
}
}
else {
currentIterator = featureIt;
return true;
}
}
return false;
}
@Override
public GeoWaveData<SimpleFeature> next() {
if ((currentIterator == null) || !currentIterator.hasNext()) {
if (nextIterator()) {
return currentIterator.next();
}
return null;
}
return currentIterator.next();
}
@Override
public void remove() {
if (currentIterator != null) {
// this isn't really implemented anyway and should not be called
currentIterator.remove();
}
}
@Override
public void close()
throws IOException {
if (currentIterator != null) {
currentIterator.close();
}
if (dataStore != null) {
dataStore.dispose();
}
}
}