/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008-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.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Query;
import org.geotools.data.store.ContentEntry;
import org.geotools.data.store.ContentFeatureStore;
import org.geotools.data.store.ContentState;
import org.geotools.factory.Hints;
import org.geotools.filter.identity.FeatureIdImpl;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
/**
* Inserts features in the database. Buffers the insertions until BUFFER_SIZE is reached or
* the writer is closed.
*
* @source $URL$
*/
public class JDBCInsertFeatureWriter extends JDBCFeatureReader implements FeatureWriter<SimpleFeatureType, SimpleFeature> {
/**
* Grouping elements together in order to have a decent batch size.
*/
private final ResultSetFeature[] buffer;
private int curBufferPos = 0;
public JDBCInsertFeatureWriter(String sql, Connection cx,
JDBCFeatureSource featureSource, Query query) throws SQLException, IOException {
super(sql, cx, featureSource, featureSource.getSchema(), query);
md = rs.getMetaData();
buffer = new ResultSetFeature[dataStore.getBatchInsertSize()];
}
public JDBCInsertFeatureWriter(PreparedStatement ps, Connection cx, JDBCFeatureSource featureSource, Query query)
throws SQLException, IOException {
super( ps, cx, featureSource, featureSource.getSchema(), query );
md = rs.getMetaData();
buffer = new ResultSetFeature[dataStore.getBatchInsertSize()];
}
public JDBCInsertFeatureWriter(JDBCUpdateFeatureWriter other) throws IOException {
super(other);
buffer = new ResultSetFeature[dataStore.getBatchInsertSize()];
}
private ResultSetFeature getOrCreateRSF() throws IOException {
ResultSetFeature result = buffer[curBufferPos];
if (result == null) {
try {
result = new ResultSetFeature(rs, cx);
buffer[curBufferPos] = result;
} catch (SQLException e) {
throw new IOException(e);
}
}
return result;
}
public boolean hasNext() throws IOException {
return false;
}
public SimpleFeature next() throws IOException {
//init, setting id to null explicity since the feature is yet to be
// inserted
ResultSetFeature rsf = getOrCreateRSF();
rsf.init(null);
return rsf;
}
public void remove() throws IOException {
//noop
}
public void write() throws IOException {
if (++curBufferPos >= buffer.length) {
//buffer full => do the inserts
flush();
}
}
@Override
protected void cleanup() throws IOException {
try {
flush();
} finally {
for (int i = 0; i < buffer.length; i++) {
if (buffer[i] == null) {
break;
}
buffer[i].close();
buffer[i] = null;
}
super.cleanup();
}
}
private void flush() throws IOException {
if(curBufferPos == 0) {
return;
}
try {
//do the insert
Collection<ResultSetFeature> features =
Arrays.asList(Arrays.copyOfRange(buffer, 0, curBufferPos));
dataStore.insert(features, featureType, st.getConnection());
for (ResultSetFeature cur : features) {
//the datastore sets as userData, grab it and update the fid
final String fid = (String) cur.getUserData().get("fid");
cur.setID(fid);
final SimpleFeature orig =(SimpleFeature)cur.getUserData().
get(ContentFeatureStore.ORIGINAL_FEATURE_KEY);
if (orig != null) {
((FeatureIdImpl)orig.getIdentifier()).setID(fid);
orig.getUserData().putAll(cur.getUserData());
orig.getUserData().remove(ContentFeatureStore.ORIGINAL_FEATURE_KEY);
}
final ContentEntry entry = featureSource.getEntry();
final ContentState state = entry.getState(this.tx);
state.fireFeatureAdded(featureSource, cur);
}
} catch (SQLException e) {
throw new IOException(e);
} finally {
curBufferPos = 0;
}
}
public void close() throws IOException {
try {
flush();
} finally {
super.close();
}
}
}