/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.importer; import java.util.NoSuchElementException; import org.geoserver.importer.job.ProgressMonitor; import org.geoserver.importer.transform.VectorTransformChain; import org.geotools.data.DataStore; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.collection.DecoratingFeatureCollection; import org.geotools.feature.collection.DecoratingFeatureIterator; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.opengis.feature.Feature; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import com.vividsolutions.jts.geom.Geometry; /** * FeatureCollection that does two things required by the importer; a) provide cancel functionality b) Do some FeatureType Transforming * * This class is simply wraps the FeatureIterator with two iterators wrappers that provide the above functionality. */ class ImportTransformFeatureCollection extends DecoratingFeatureCollection { ProgressMonitor monitor; FeatureDataConverter featureDataConverter; FeatureType resultingFT; VectorTransformChain vectorTransformChain; ImportTask task; DataStore dataStoreDestination; public ImportTransformFeatureCollection(FeatureCollection fc, FeatureDataConverter featureDataConverter, FeatureType resultingFT, VectorTransformChain vectorTransformChain, ImportTask task, DataStore dataStoreDestination) { super(fc); this.monitor = task.progress(); this.featureDataConverter = featureDataConverter; this.resultingFT = resultingFT; this.vectorTransformChain = vectorTransformChain; this.task = task; this.dataStoreDestination = dataStoreDestination; } @Override public FeatureIterator features() { FeatureIterator fi = super.features(); return new TransformingFeatureIterator(new CancelableFeatureIterator(fi, monitor), resultingFT, featureDataConverter, vectorTransformChain, task, dataStoreDestination); } /** * Simple FeatureIterator that does some transforming of the features. * * The emulates the behavior of the Importer's low-level feature transformation. */ private class TransformingFeatureIterator extends DecoratingFeatureIterator { SimpleFeatureBuilder featureBuilder; FeatureDataConverter featureDataConverter; VectorTransformChain vectorTransformChain; ImportTask task; DataStore dataStore; int cnt = 0; public TransformingFeatureIterator(FeatureIterator fi, FeatureType resultingFT, FeatureDataConverter featureDataConverter, VectorTransformChain vectorTransformChain, ImportTask task, DataStore dataStore) { super(fi); this.featureBuilder = new SimpleFeatureBuilder((SimpleFeatureType) resultingFT); this.featureDataConverter = featureDataConverter; this.vectorTransformChain = vectorTransformChain; this.task = task; this.dataStore = dataStore; } @Override public Feature next() throws NoSuchElementException { // the xform could produce null features - we eat them while (super.hasNext()) { Feature result = attemptNext(); if (result != null) { return result; } } throw new NoSuchElementException(); } /* for details, see the low-level api version in the Importer */ private Feature attemptNext() { SimpleFeature input = (SimpleFeature) super.next(); SimpleFeature result = featureBuilder.buildFeature(null); featureDataConverter.convert(input, result); // @hack #45678 - mask empty geometry or postgis will complain Geometry geom = (Geometry) result.getDefaultGeometry(); if (geom != null && geom.isEmpty()) { result.setDefaultGeometry(null); } try { result = vectorTransformChain.inline(task, dataStore, input, result); } catch (Exception e) { throw new RuntimeException(e); } task.setNumberProcessed(++cnt); return result; } } /** * Simple FeatureIterator that will handle canceling. If the monitor cancels, the iterator will say there are no more elementss (hasNext() will be * false) */ private class CancelableFeatureIterator extends DecoratingFeatureIterator { ProgressMonitor monitor; public CancelableFeatureIterator(FeatureIterator fi, ProgressMonitor monitor) { super(fi); this.monitor = monitor; } /** * if cancelled, then report no more features */ @Override public boolean hasNext() { if (monitor.isCanceled()) { return false; } return super.hasNext(); } } }