/*
* Copyright (c) 2015 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.io.jdbc.spatialite.internal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import org.sqlite.SQLiteConnection;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
/**
* Factory to create {@link SpatiaLiteSupport} instances matching the version of
* the connected database.
*
* @author Stefano Costa, GeoSolutions
*/
public class SpatiaLiteSupportFactory {
private static final ALogger log = ALoggerFactory.getLogger(AbstractSpatiaLiteSupport.class);
private static SpatiaLiteSupportFactory instance;
private final ConcurrentHashMap<String, SpatiaLiteSupport> cache;
private SpatiaLiteSupportFactory() {
cache = new ConcurrentHashMap<String, SpatiaLiteSupport>();
}
/**
* Return the singleton factory instance.
*
* @return the factory instance
*/
public static SpatiaLiteSupportFactory getInstance() {
if (instance == null) {
instance = new SpatiaLiteSupportFactory();
}
return instance;
}
/**
* Create a {@link SpatiaLiteSupport} instances matching the version of the
* connected database.
* <p>
* {@link SpatiaLiteSupport} instances are internally cached; the connection
* URL is used as cache key, so if the method is invoked multiple times
* providing connection objects pointing to the same physical DB, only one
* instance of {@link SpatiaLiteSupport} is created and re-used multiple
* times.
* </p>
*
* @param connection the DB connection
* @return the proper {@link SpatiaLiteSupport} instance
*/
public SpatiaLiteSupport createSpatiaLiteSupport(SQLiteConnection connection) {
String key = connection.url();
SpatiaLiteSupport support = cache.get(key);
if (support != null) {
return support;
}
int version = determineSpatiaLiteVersion(connection);
if (version == 3) {
support = new SpatiaLiteSupportVersion3();
}
else if (version == 4) {
support = new SpatiaLiteSupportVersion4();
}
else {
throw new IllegalStateException("Unable to determine SpatiaLite version");
}
cache.putIfAbsent(key, support);
return cache.get(key);
}
/**
* Determine SpatiaLite version parsing the structure of the
* <code>geometry_columns</code> table.
*
* @param connection the DB connection
* @return the version number
*/
private int determineSpatiaLiteVersion(SQLiteConnection connection) {
final String V3_GEOM_COL_NAME = "type";
final String V3_GEOM_COL_TYPE = "TEXT";
final String V4_GEOM_COL_NAME = "geometry_type";
final String V4_GEOM_COL_TYPE = "INTEGER";
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = connection.prepareStatement("PRAGMA table_info(\"geometry_columns\")");
rs = stmt.executeQuery();
while (rs.next()) {
String name = rs.getString("name");
String type = rs.getString("type");
if (name.equals(V3_GEOM_COL_NAME) && type.equals(V3_GEOM_COL_TYPE)) {
return 3;
}
else if (name.equals(V4_GEOM_COL_NAME) && type.equals(V4_GEOM_COL_TYPE)) {
return 4;
}
}
} catch (SQLException e) {
log.error("Error inspecting \"geometry_columns\" table", e);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// ignore
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// ignore
}
}
}
return -1;
}
}