/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2015, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.data.geobuf; import org.geotools.data.DataStore; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureWriter; import org.geotools.data.Query; import org.geotools.data.store.ContentState; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; public class GeobufFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> { private ContentState state; private File temp; private Geobuf.Data.Builder dataBuilder; private Geobuf.Data.FeatureCollection.Builder featureCollectionBuilder; private GeobufFeatureReader delegate; private boolean appending = false; private SimpleFeature currentFeature; private int nextRow = 0; private GeobufFeature geobufFeature; private File file; public GeobufFeatureWriter(ContentState state, Query query, int precision, int dimension) throws IOException { this.state = state; String typeName = query.getTypeName(); DataStore dataStore = state.getEntry().getDataStore(); if (dataStore instanceof GeobufDirectoryDataStore) { this.file = ((GeobufDirectoryDataStore)dataStore).getDataStore(typeName).getFile(); } else { this.file = ((GeobufDataStore) dataStore).getFile(); } File directory = file.getParentFile(); this.temp = File.createTempFile(typeName + System.currentTimeMillis(), "geobuf", directory); this.dataBuilder = Geobuf.Data.newBuilder(); GeobufFeatureType geobufFeatureType = new GeobufFeatureType(); geobufFeatureType.encode(state.getFeatureType(), dataBuilder); dataBuilder.build().writeTo(new FileOutputStream(this.temp)); this.featureCollectionBuilder = Geobuf.Data.FeatureCollection.newBuilder(); this.geobufFeature = new GeobufFeature(new GeobufGeometry(precision, dimension)); this.delegate = new GeobufFeatureReader(state, query, precision, dimension); } @Override public SimpleFeatureType getFeatureType() { return state.getFeatureType(); } @Override public SimpleFeature next() throws IOException { if (dataBuilder == null) { throw new IOException("FeatureWriter has been closed"); } if (this.currentFeature != null) { this.write(); } try { if (!appending) { if (delegate.hasNext()) { this.currentFeature = delegate.next(); return this.currentFeature; } else { this.appending = true; } } SimpleFeatureType featureType = state.getFeatureType(); String fid = featureType.getTypeName() + "." + nextRow; Object values[] = DataUtilities.defaultValues(featureType); this.currentFeature = SimpleFeatureBuilder.build(featureType, values, fid); return this.currentFeature; } catch (IllegalArgumentException invalid) { throw new IOException("Unable to create feature:" + invalid.getMessage(), invalid); } } @Override public void remove() throws IOException { this.currentFeature = null; } @Override public void write() throws IOException { if (this.currentFeature == null) { return; } featureCollectionBuilder.addFeatures(geobufFeature.encode(currentFeature)); nextRow++; this.currentFeature = null; } @Override public boolean hasNext() throws IOException { if (dataBuilder == null) { return false; } if (this.appending) { return false; } return delegate.hasNext(); } @Override public void close() throws IOException { if (dataBuilder == null) { throw new IOException("Writer alread closed"); } if (this.currentFeature != null) { this.write(); } while (hasNext()) { next(); write(); } dataBuilder.setFeatureCollection(featureCollectionBuilder.build()); Geobuf.Data data = dataBuilder.build(); data.writeTo(new FileOutputStream(temp)); dataBuilder = null; if (delegate != null) { this.delegate.close(); this.delegate = null; } Files.copy(temp.toPath(), this.file.toPath(), StandardCopyOption.REPLACE_EXISTING); temp.delete(); } }