package mil.nga.giat.geowave.adapter.vector.ingest; import java.io.File; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.google.common.base.Predicate; import com.google.common.collect.Iterators; import mil.nga.giat.geowave.adapter.vector.AvroFeatureDataAdapter; import mil.nga.giat.geowave.adapter.vector.FeatureDataAdapter; import mil.nga.giat.geowave.adapter.vector.WholeFeatureDataAdapter; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.Persistable; import mil.nga.giat.geowave.core.ingest.GeoWaveData; import mil.nga.giat.geowave.core.ingest.avro.AvroFormatPlugin; import mil.nga.giat.geowave.core.ingest.hdfs.mapreduce.IngestFromHdfsPlugin; import mil.nga.giat.geowave.core.ingest.hdfs.mapreduce.IngestWithMapper; import mil.nga.giat.geowave.core.ingest.local.LocalFileIngestPlugin; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.CloseableIteratorWrapper; import mil.nga.giat.geowave.core.store.adapter.WritableDataAdapter; import mil.nga.giat.geowave.core.store.data.field.FieldVisibilityHandler; import mil.nga.giat.geowave.core.store.data.visibility.GlobalVisibilityHandler; import mil.nga.giat.geowave.core.store.index.CommonIndexValue; abstract public class AbstractSimpleFeatureIngestPlugin<I> implements LocalFileIngestPlugin<SimpleFeature>, IngestFromHdfsPlugin<I, SimpleFeature>, AvroFormatPlugin<I, SimpleFeature>, Persistable { protected CQLFilterOptionProvider filterOptionProvider = new CQLFilterOptionProvider(); protected FeatureSerializationOptionProvider serializationFormatOptionProvider = new FeatureSerializationOptionProvider(); protected TypeNameOptionProvider typeNameProvider = new TypeNameOptionProvider(); public void setFilterProvider( final CQLFilterOptionProvider filterOptionProvider ) { this.filterOptionProvider = filterOptionProvider; } public void setSerializationFormatProvider( final FeatureSerializationOptionProvider serializationFormatOptionProvider ) { this.serializationFormatOptionProvider = serializationFormatOptionProvider; } public void setTypeNameProvider( final TypeNameOptionProvider typeNameProvider ) { this.typeNameProvider = typeNameProvider; } @Override public byte[] toBinary() { final byte[] filterBinary = filterOptionProvider.toBinary(); final byte[] typeNameBinary = typeNameProvider.toBinary(); final ByteBuffer buf = ByteBuffer.allocate(filterBinary.length + typeNameBinary.length + 4); buf.putInt(filterBinary.length); buf.put(filterBinary); buf.put(typeNameBinary); return ArrayUtils.addAll( serializationFormatOptionProvider.toBinary(), buf.array()); } @Override public void fromBinary( final byte[] bytes ) { final byte[] otherBytes = new byte[bytes.length - 1]; System.arraycopy( bytes, 1, otherBytes, 0, otherBytes.length); final byte[] kryoBytes = new byte[] { bytes[0] }; final ByteBuffer buf = ByteBuffer.wrap(otherBytes); final int filterBinaryLength = buf.getInt(); final byte[] filterBinary = new byte[filterBinaryLength]; final byte[] typeNameBinary = new byte[otherBytes.length - filterBinaryLength - 4]; buf.get(filterBinary); buf.get(typeNameBinary); serializationFormatOptionProvider = new FeatureSerializationOptionProvider(); serializationFormatOptionProvider.fromBinary(kryoBytes); filterOptionProvider = new CQLFilterOptionProvider(); filterOptionProvider.fromBinary(filterBinary); typeNameProvider = new TypeNameOptionProvider(); typeNameProvider.fromBinary(typeNameBinary); } protected WritableDataAdapter<SimpleFeature> newAdapter( final SimpleFeatureType type, final FieldVisibilityHandler<SimpleFeature, Object> fieldVisiblityHandler ) { if (serializationFormatOptionProvider.isAvro()) { return new AvroFeatureDataAdapter( type); } return new FeatureDataAdapter( type, fieldVisiblityHandler); } abstract protected SimpleFeatureType[] getTypes(); @Override public WritableDataAdapter<SimpleFeature>[] getDataAdapters( final String globalVisibility ) { final FieldVisibilityHandler<SimpleFeature, Object> fieldVisiblityHandler = ((globalVisibility != null) && !globalVisibility .isEmpty()) ? new GlobalVisibilityHandler<SimpleFeature, Object>( globalVisibility) : null; final SimpleFeatureType[] types = getTypes(); final WritableDataAdapter<SimpleFeature>[] retVal = new WritableDataAdapter[types.length]; for (int i = 0; i < types.length; i++) { retVal[i] = newAdapter( types[i], fieldVisiblityHandler); } return retVal; } @Override public CloseableIterator<GeoWaveData<SimpleFeature>> toGeoWaveData( final File input, final Collection<ByteArrayId> primaryIndexIds, final String globalVisibility ) { final I[] hdfsObjects = toAvroObjects(input); final List<CloseableIterator<GeoWaveData<SimpleFeature>>> allData = new ArrayList<CloseableIterator<GeoWaveData<SimpleFeature>>>(); for (final I hdfsObject : hdfsObjects) { final CloseableIterator<GeoWaveData<SimpleFeature>> geowaveData = toGeoWaveDataInternal( hdfsObject, primaryIndexIds, globalVisibility); allData.add(wrapIteratorWithFilters(geowaveData)); } return new CloseableIterator.Wrapper<GeoWaveData<SimpleFeature>>( Iterators.concat(allData.iterator())); } protected CloseableIterator<GeoWaveData<SimpleFeature>> wrapIteratorWithFilters( final CloseableIterator<GeoWaveData<SimpleFeature>> geowaveData ) { final CQLFilterOptionProvider internalFilterProvider; if ((filterOptionProvider != null) && (filterOptionProvider.getCqlFilterString() != null) && !filterOptionProvider.getCqlFilterString().trim().isEmpty()) { internalFilterProvider = filterOptionProvider; } else { internalFilterProvider = null; } final TypeNameOptionProvider internalTypeNameProvider; if ((typeNameProvider != null) && (typeNameProvider.getTypeName() != null) && !typeNameProvider.getTypeName().trim().isEmpty()) { internalTypeNameProvider = typeNameProvider; } else { internalTypeNameProvider = null; } if ((internalFilterProvider != null) || (internalTypeNameProvider != null)) { final Iterator<GeoWaveData<SimpleFeature>> it = Iterators.filter( geowaveData, new Predicate<GeoWaveData<SimpleFeature>>() { @Override public boolean apply( final GeoWaveData<SimpleFeature> input ) { if ((internalTypeNameProvider != null) && !internalTypeNameProvider.typeNameMatches(input.getAdapterId().getString())) { return false; } if ((internalFilterProvider != null) && !internalFilterProvider.evaluate(input.getValue())) { return false; } return true; } }); return new CloseableIteratorWrapper<GeoWaveData<SimpleFeature>>( geowaveData, it); } return geowaveData; } abstract protected CloseableIterator<GeoWaveData<SimpleFeature>> toGeoWaveDataInternal( final I hdfsObject, final Collection<ByteArrayId> primaryIndexIds, final String globalVisibility ); abstract public static class AbstractIngestSimpleFeatureWithMapper<I> implements IngestWithMapper<I, SimpleFeature> { protected AbstractSimpleFeatureIngestPlugin<I> parentPlugin; public AbstractIngestSimpleFeatureWithMapper( final AbstractSimpleFeatureIngestPlugin<I> parentPlugin ) { this.parentPlugin = parentPlugin; } @Override public WritableDataAdapter<SimpleFeature>[] getDataAdapters( final String globalVisibility ) { return parentPlugin.getDataAdapters(globalVisibility); } @Override public CloseableIterator<GeoWaveData<SimpleFeature>> toGeoWaveData( final I input, final Collection<ByteArrayId> primaryIndexIds, final String globalVisibility ) { return parentPlugin.wrapIteratorWithFilters(parentPlugin.toGeoWaveDataInternal( input, primaryIndexIds, globalVisibility)); } @Override public byte[] toBinary() { return parentPlugin.toBinary(); } @Override public void fromBinary( final byte[] bytes ) { parentPlugin.fromBinary(bytes); } @Override public Class<? extends CommonIndexValue>[] getSupportedIndexableTypes() { return parentPlugin.getSupportedIndexableTypes(); } } }