From 5509a898926d548e77f5de97b2a9efada12ed70a Mon Sep 17 00:00:00 2001 From: ebocher Date: Fri, 13 Jan 2023 11:04:35 +0100 Subject: [PATCH 1/2] Start to link H2GIS GT module to GeoScript --- pom.xml | 5 + .../workspace/DatabaseExtensionModule.groovy | 183 +++++++++++++++ .../groovy/geoscript/workspace/H2GIS.groovy | 212 ++++++++++++++++++ ...rg.codehaus.groovy.runtime.ExtensionModule | 2 +- .../geoscript/workspace/H2GISTest.groovy | 96 ++++++++ 5 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy create mode 100644 src/main/groovy/geoscript/workspace/H2GIS.groovy create mode 100644 src/test/groovy/geoscript/workspace/H2GISTest.groovy diff --git a/pom.xml b/pom.xml index d08a5f2a..6f7ff649 100755 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,11 @@ gt-jdbc-postgis ${gt.version} + + org.geotools.jdbc + gt-jdbc-h2gis + ${gt.version} + org.geotools.jdbc gt-jdbc-h2 diff --git a/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy b/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy new file mode 100644 index 00000000..65f84033 --- /dev/null +++ b/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy @@ -0,0 +1,183 @@ +package geoscript.workspace + +import org.apache.commons.lang3.StringUtils +import org.H2GIS.functions.io.utility.IOMethods +import org.geotools.util.logging.Logging +import java.sql.SQLException +import java.util.logging.Logger + +/** + * A Groovy Extension Module that adds static methods to some Database drivers. + * @author Erwan Bocher (CNRS) + */ +class DatabaseExtensionModule { + /** + * The Logger + */ + private static final Logger LOGGER = Logging.getLogger("geoscript.workspace.DatabaseExtensionModule") + + private static IOMethods ioMethods = null; + + /** + * Create a dynamic link from a file to a H2GIS database. + * + * @param sql connection to the database. + * @param path The path of the file. + * @param table The name of the table created to store the file. + * @param delete True to delete the table if exists. Default to true. + * @throws java.sql.SQLException Exception throw on database error. + */ + static String linkedFile(H2GIS h2GIS, String path, String table, boolean delete = false) throws SQLException { + return IOMethods.linkedFile(h2GIS.getDataSource().getConnection(), path, table, delete) + } + + /** + * Create a dynamic link from a file to a H2GIS database. + * + * @param sql connection to the database. + * @param path The path of the file. + * @param table The name of the table created to store the file. + * @param delete True to delete the table if exists. Default to true. + * @throws java.sql.SQLException Exception throw on database error. + */ + static String linkedFile(H2GIS h2GIS, String path, boolean delete = false) throws SQLException { + File pathFile = new File(path) + String fileName = pathFile.name + String name = fileName.substring(0, fileName.lastIndexOf('.')) + return linkedFile(h2GIS, path, StringUtils.deleteWhitespace(name), delete) + } + + + /** + * Save a table into a file + * @param database + * @param tableName + * @param filePath + * @param delete + * @return + */ + static boolean save(Database database, String tableName, String filePath, boolean delete = false) { + if (database instanceof H2GIS || database instanceof PostGIS) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.warning("No connection, cannot save."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + ioMethods.exportToFile(con, tableName, filePath, null, delete); + return true; + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath); + } + } + LOGGER.warning("Unsuported method for this Database ") + return false; + } + + /** + * Save a table into a file + * @param database + * @param tableName + * @param filePath + * @param delete + * @return + */ + static boolean save(Database database, String tableName, String filePath, String encoding) { + if (database instanceof H2GIS || database instanceof PostGIS) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot save."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + ioMethods.exportToFile(con, tableName, filePath, encoding, false); + return true; + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath); + } + } + LOGGER.warning("Unsuported method for this Database ") + return false; + } + + /** + * Load a file to the database + * @param database + * @param filePath + * @param encoding + * @param delete + * @return + */ + static String load(Database database, String filePath, + boolean delete = false) { + File pathFile = new File(filePath) + String fileName = pathFile.name + String name = fileName.substring(0, fileName.lastIndexOf('.')) + return load(database, filePath, StringUtils.deleteWhitespace(name), null, delete) + } + + + /** + * Load a file to the database + * @param database + * @param filePath + * @param tableName + * @param encoding + * @param delete + * @return + */ + static String load(Database database, String filePath, String tableName) { + return load(database, filePath, tableName, null, + false) + } + + /** + * Load a file to the database + * @param database + * @param filePath + * @param tableName + * @param encoding + * @param delete + * @return + */ + static String load(Database database, String filePath, String tableName, + delete) { + return load(database, filePath, tableName, null, + delete) + } + + /** + * Load a file to the database + * @param database + * @param filePath + * @param tableName + * @param encoding + * @param delete + * @return + */ + static String load(Database database, String filePath, String tableName, String encoding, + boolean delete = false) { + if (database instanceof H2GIS || database instanceof PostGIS) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot load the file $filePath."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + return ioMethods.importFile(con, filePath, tableName, encoding, delete) + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath); + } + } + return null + } +} diff --git a/src/main/groovy/geoscript/workspace/H2GIS.groovy b/src/main/groovy/geoscript/workspace/H2GIS.groovy new file mode 100644 index 00000000..7788db01 --- /dev/null +++ b/src/main/groovy/geoscript/workspace/H2GIS.groovy @@ -0,0 +1,212 @@ +package geoscript.workspace + +import org.geotools.data.DataStore +import org.geotools.jdbc.JDBCDataStore +import org.geotools.jdbc.JDBCDataStoreFactory +import org.geotools.util.logging.Logging +import org.h2gis.geotools.H2GISDataStoreFactory + +import java.sql.Connection +import java.sql.SQLException +import java.util.logging.Logger + +/** + * A H2GIS Workspace connects to a spatially enabled H2GIS database. + *

+ * H2GIS H2GIS = new H2GIS("acme", "target/H2GIS")
+ * Layer layer = H2GIS.create('widgets',[new Field("geom", "Point"), new Field("name", "String")])
+ * layer.add([new Point(1,1), "one"])
+ * layer.add([new Point(2,2), "two"])
+ * layer.add([new Point(3,3), "three"])
+ * 

+ * @author Jared Erickson + * @author Erwan Bocher (CNRS) + */ +class H2GIS extends Database { + + + /** + * The Logger + */ + private static final Logger LOGGER = Logging.getLogger("geoscript.workspace.H2GIS"); + + /** + * Create a new H2GIS Workspace with a name and directory + * @param name The name of the database + * @param dir The File containing the database + */ + H2GIS(String name, File dir) { + super(createDataStore(name, dir)) + } + + /** + * Create a new H2GIS Workspace with a name and directory + * @param name The name of the database + * @param dir The File containing the database + */ + H2GIS(String name, String dir) { + this(name, new File(dir).absoluteFile) + } + + + /** + * Create a new H2GIS Workspace from a database file + * @param file The H2 database file + */ + H2GIS(File file) { + this(file.name, file.parentFile) + } + + /** + * Create a new H2GIS Workspace with a name, host, port, schema, user, and password. + * @param database The database name + * @param host The host + * @param port The port + * @param schema The schema + * @param user The user name + * @param password The password + */ + H2GIS(String database, String host, String port, String schema, String user, String password) { + super(createDataStore(database, host, port, schema, user, password)) + } + + /** + * Create a new H2GIS Workspace + * @param options The named parameters + * + * @param database The database name (or JNDI reference name) + */ + H2GIS(Map options, String database) { + this(database, options.get("host", "localhost"), options.get("port", ""), options.get("schema"), + options.get("user", "sa"), options.get("password", "")) + } + + /** + * Create a new H2GIS Workspace + * + * @param database the name of the database + */ + H2GIS(String database) { + this(new File(database)) + } + + /** + * Create a new H2GIS Workspace from a GeoTools JDBCDataStore + * @param ds The GeoTools JDBCDataStore + */ + H2GIS(JDBCDataStore ds) { + super(ds) + } + + /** + * Get the format + * @return The workspace format name + */ + @Override + String getFormat() { + return "H2GIS" + } + + /** + * Load the H2GIS Network function in the current H2GIS DataSource. + * + * @return True if the functions have been successfully loaded, false otherwise. + */ + boolean addNetworkFunctions() { + Connection connection = getDataSource().getConnection(); + if (connection == null) { + LOGGER.error("Cannot load the H2GIS Network extension.\n"); + return false; + } + try { + NetworkFunctions.load(connection); + } catch (SQLException e) { + LOGGER.error("Cannot load the H2GIS Network extension.\n", e); + return false; + } + return true; + } + + /** + * Create a new H2GIS Workspace with a name and directory + */ + private static DataStore createDataStore(String name, File dir) { + HashMap params = new HashMap<>(); + params.put(JDBCDataStoreFactory.DATABASE.key, new File(dir, name).absolutePath) + params.put(JDBCDataStoreFactory.DBTYPE.key, "h2gis") + params.put(JDBCDataStoreFactory.FETCHSIZE.key, 100) + H2GISDataStoreFactory h2gisf = new H2GISDataStoreFactory() + h2gisf.createDataStore(params) + } + + /** + * Create a new H2GIS Workspace with a TCP connections + */ + private static DataStore createDataStore(String database, String host, String port, String schema, String user, String password) { + Map params = new java.util.HashMap() + params.put("dbtype", "h2gis") + params.put(JDBCDataStoreFactory.USER.key, user) + params.put(JDBCDataStoreFactory.FETCHSIZE.key, 100); + params.put("database", database) + params.put("schema", schema) + params.put("host", host) + params.put("port", port) + params.put("user", user) + params.put("passwd", password) + def h2gisf = new H2GISDataStoreFactory() + h2gisf.createDataStore(params) + } + + /** + * The H2GIS WorkspaceFactory + */ + static class Factory extends WorkspaceFactory { + + @Override + Map getParametersFromString(String str) { + Map params = [:] + if (!str.contains("=") && str.endsWith(".mv.db")) { + params.put("dbtype", "H2GIS") + params.put("database", new File(str).absolutePath) + } else { + params = super.getParametersFromString(str) + } + params + } + + @Override + H2GIS create(String type, Map params) { + if (type.equalsIgnoreCase('H2GIS')) { + params['dbtype'] = 'H2GIS' + if (params.containsKey('file')) { + params['database'] = params['file'] + } + if (params['database'] instanceof File) { + params['database'] = (params['database'] as File).absolutePath + } + super.create(params) + } else { + null + } + } + + @Override + H2GIS create(DataStore dataStore) { + H2GIS h2GIS = null + if (dataStore instanceof org.geotools.jdbc.JDBCDataStore) { + def jdbcds = dataStore as org.geotools.jdbc.JDBCDataStore + if (jdbcds.dataStoreFactory instanceof org.h2gis.geotools.H2GISDataStoreFactory || + jdbcds.dataStoreFactory instanceof org.h2gis.geotools.H2GISJNDIDataStoreFactory) { + h2GIS = new H2GIS(dataStore) + } + } + h2GIS + } + } +} diff --git a/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule index ea2267f6..2a3b1b2b 100644 --- a/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule +++ b/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule @@ -1,4 +1,4 @@ moduleName = geoscript-groovy-module moduleVersion = 1.0 -extensionClasses = geoscript.geom.io.GeometryExtensionModule, geoscript.feature.io.FeatureExtensionModule, geoscript.layer.io.LayerExtensionModule, geoscript.layer.io.PyramidExtensionModule, geoscript.layer.WMSMapExtensionModule, geoscript.style.io.StyleExtensionModule +extensionClasses = geoscript.geom.io.GeometryExtensionModule, geoscript.feature.io.FeatureExtensionModule, geoscript.layer.io.LayerExtensionModule, geoscript.layer.io.PyramidExtensionModule, geoscript.layer.WMSMapExtensionModule, geoscript.style.io.StyleExtensionModule,geoscript.workspace.DatabaseExtensionModule staticExtensionClasses = geoscript.geom.io.StaticGeometryExtensionModule, geoscript.feature.io.StaticFeatureExtensionModule, geoscript.plot.ViewerExtensionModule, geoscript.layer.io.StaticPyramidExtensionModule, geoscript.style.io.StaticStyleExtensionModule \ No newline at end of file diff --git a/src/test/groovy/geoscript/workspace/H2GISTest.groovy b/src/test/groovy/geoscript/workspace/H2GISTest.groovy new file mode 100644 index 00000000..4623bf5c --- /dev/null +++ b/src/test/groovy/geoscript/workspace/H2GISTest.groovy @@ -0,0 +1,96 @@ +package geoscript.workspace + +import geoscript.feature.Field +import geoscript.geom.Point +import geoscript.layer.Layer +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +import static org.junit.jupiter.api.Assertions.* + +/** + * The H2 Workspace Unit Test + */ + +class H2GISTest { + @TempDir + File folder + + @Test void loadShapeFile() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + File file = new File(getClass().getClassLoader().getResource("states.shp").toURI()) + String tableName = h2gis.load(file.getAbsolutePath(), true) + println(tableName) + } + + @Test void remove() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + assertEquals "H2GIS", h2gis.format + // Add + Layer l = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(l) + l.add([new Point(1,1), "one"]) + l.add([new Point(2,2), "two"]) + l.add([new Point(3,3), "three"]) + assertEquals 3, l.count() + // Get + assertNotNull(h2gis.get("widgets")) + // Remove + h2gis.remove("widgets") + boolean exceptionThrown = false + try { + h2gis.get("widgets") + } catch (IOException ex) { + exceptionThrown = true + } + assertTrue(exceptionThrown) + h2gis.close() + } + + @Test void createFromPath() { + H2GIS h2gis = new H2GIS("./target/mydb") + assertEquals "H2GIS", h2gis.format + Layer l = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(l) + l.add([new Point(1,1), "one"]) + l.add([new Point(2,2), "two"]) + l.add([new Point(3,3), "three"]) + assertEquals 3, l.count() + h2gis.close() + } + + @Test void writeLinkShapeFile() { + H2GIS h2gis = new H2GIS("./target/mydb") + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + File outputFile = new File("./target/widgets.shp") + h2gis.save("widgets", outputFile.getAbsolutePath()) + def outputTable = h2gis.linkedFile(outputFile.getAbsolutePath(), true) + assertEquals(3, h2gis.get(outputTable).count) + h2gis.close() + } + + @Test void writeSaveLoadShapeFile() { + H2GIS h2gis = new H2GIS("./target/mydb") + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + File outputFile = new File("./target/widgets.shp") + h2gis.save("widgets", outputFile.getAbsolutePath()) + def outputTable = h2gis.load(outputFile.getAbsolutePath(), "\"test_imported\"") + assertEquals(3, h2gis.get("test_imported").count) + h2gis.close() + } + +} From aea8a6b657adff0fbe7f57b849a58b6452552e1c Mon Sep 17 00:00:00 2001 From: ebocher Date: Fri, 20 Jan 2023 12:32:15 +0100 Subject: [PATCH 2/2] Update H2GIS workspace - add new methods on H2GIS module - add new unit tests --- .../workspace/DatabaseExtensionModule.groovy | 183 ----------- .../H2GISDatabaseExtensionModule.groovy | 304 ++++++++++++++++++ ...rg.codehaus.groovy.runtime.ExtensionModule | 2 +- .../geoscript/workspace/H2GISTest.groovy | 152 ++++++++- 4 files changed, 445 insertions(+), 196 deletions(-) delete mode 100644 src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy create mode 100644 src/main/groovy/geoscript/workspace/H2GISDatabaseExtensionModule.groovy diff --git a/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy b/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy deleted file mode 100644 index 65f84033..00000000 --- a/src/main/groovy/geoscript/workspace/DatabaseExtensionModule.groovy +++ /dev/null @@ -1,183 +0,0 @@ -package geoscript.workspace - -import org.apache.commons.lang3.StringUtils -import org.H2GIS.functions.io.utility.IOMethods -import org.geotools.util.logging.Logging -import java.sql.SQLException -import java.util.logging.Logger - -/** - * A Groovy Extension Module that adds static methods to some Database drivers. - * @author Erwan Bocher (CNRS) - */ -class DatabaseExtensionModule { - /** - * The Logger - */ - private static final Logger LOGGER = Logging.getLogger("geoscript.workspace.DatabaseExtensionModule") - - private static IOMethods ioMethods = null; - - /** - * Create a dynamic link from a file to a H2GIS database. - * - * @param sql connection to the database. - * @param path The path of the file. - * @param table The name of the table created to store the file. - * @param delete True to delete the table if exists. Default to true. - * @throws java.sql.SQLException Exception throw on database error. - */ - static String linkedFile(H2GIS h2GIS, String path, String table, boolean delete = false) throws SQLException { - return IOMethods.linkedFile(h2GIS.getDataSource().getConnection(), path, table, delete) - } - - /** - * Create a dynamic link from a file to a H2GIS database. - * - * @param sql connection to the database. - * @param path The path of the file. - * @param table The name of the table created to store the file. - * @param delete True to delete the table if exists. Default to true. - * @throws java.sql.SQLException Exception throw on database error. - */ - static String linkedFile(H2GIS h2GIS, String path, boolean delete = false) throws SQLException { - File pathFile = new File(path) - String fileName = pathFile.name - String name = fileName.substring(0, fileName.lastIndexOf('.')) - return linkedFile(h2GIS, path, StringUtils.deleteWhitespace(name), delete) - } - - - /** - * Save a table into a file - * @param database - * @param tableName - * @param filePath - * @param delete - * @return - */ - static boolean save(Database database, String tableName, String filePath, boolean delete = false) { - if (database instanceof H2GIS || database instanceof PostGIS) { - def con = database.getDataSource().getConnection() - if (con == null) { - LOGGER.warning("No connection, cannot save."); - return false; - } - try { - if (ioMethods == null) { - ioMethods = new IOMethods(); - } - ioMethods.exportToFile(con, tableName, filePath, null, delete); - return true; - } catch (SQLException e) { - LOGGER.severe("Cannot import the file : " + filePath); - } - } - LOGGER.warning("Unsuported method for this Database ") - return false; - } - - /** - * Save a table into a file - * @param database - * @param tableName - * @param filePath - * @param delete - * @return - */ - static boolean save(Database database, String tableName, String filePath, String encoding) { - if (database instanceof H2GIS || database instanceof PostGIS) { - def con = database.getDataSource().getConnection() - if (con == null) { - LOGGER.severe("No connection, cannot save."); - return false; - } - try { - if (ioMethods == null) { - ioMethods = new IOMethods(); - } - ioMethods.exportToFile(con, tableName, filePath, encoding, false); - return true; - } catch (SQLException e) { - LOGGER.severe("Cannot import the file : " + filePath); - } - } - LOGGER.warning("Unsuported method for this Database ") - return false; - } - - /** - * Load a file to the database - * @param database - * @param filePath - * @param encoding - * @param delete - * @return - */ - static String load(Database database, String filePath, - boolean delete = false) { - File pathFile = new File(filePath) - String fileName = pathFile.name - String name = fileName.substring(0, fileName.lastIndexOf('.')) - return load(database, filePath, StringUtils.deleteWhitespace(name), null, delete) - } - - - /** - * Load a file to the database - * @param database - * @param filePath - * @param tableName - * @param encoding - * @param delete - * @return - */ - static String load(Database database, String filePath, String tableName) { - return load(database, filePath, tableName, null, - false) - } - - /** - * Load a file to the database - * @param database - * @param filePath - * @param tableName - * @param encoding - * @param delete - * @return - */ - static String load(Database database, String filePath, String tableName, - delete) { - return load(database, filePath, tableName, null, - delete) - } - - /** - * Load a file to the database - * @param database - * @param filePath - * @param tableName - * @param encoding - * @param delete - * @return - */ - static String load(Database database, String filePath, String tableName, String encoding, - boolean delete = false) { - if (database instanceof H2GIS || database instanceof PostGIS) { - def con = database.getDataSource().getConnection() - if (con == null) { - LOGGER.severe("No connection, cannot load the file $filePath."); - return false; - } - try { - if (ioMethods == null) { - ioMethods = new IOMethods(); - } - return ioMethods.importFile(con, filePath, tableName, encoding, delete) - } catch (SQLException e) { - LOGGER.severe("Cannot import the file : " + filePath); - } - } - return null - } -} diff --git a/src/main/groovy/geoscript/workspace/H2GISDatabaseExtensionModule.groovy b/src/main/groovy/geoscript/workspace/H2GISDatabaseExtensionModule.groovy new file mode 100644 index 00000000..5ac3a8fa --- /dev/null +++ b/src/main/groovy/geoscript/workspace/H2GISDatabaseExtensionModule.groovy @@ -0,0 +1,304 @@ +package geoscript.workspace + +import org.apache.commons.lang3.StringUtils +import org.geotools.util.logging.Logging +import org.h2gis.functions.io.utility.IOMethods + +import java.sql.SQLException +import java.util.logging.Logger + +/** + * A Groovy Extension Module that adds static methods to H2GIS workspace. + * @author Erwan Bocher (CNRS) + */ +class H2GISDatabaseExtensionModule { + /** + * The Logger + */ + private static final Logger LOGGER = Logging.getLogger("geoscript.workspace.H2GISDatabaseExtensionModule") + + private static IOMethods ioMethods = null; + + /** + * Create a dynamic link from a file to the H2GIS database. + * + * @param sql connection to the database. + * @param path The path of the file. + * @param table The name of the table created to store the file. + * @param delete True to delete the table if exists. Default to true. + * @throws java.sql.SQLException Exception throw on database error. + */ + static String link(H2GIS h2GIS, String path, String table, boolean delete = false) throws SQLException { + return IOMethods.linkedFile(h2GIS.getDataSource().getConnection(), path, table, delete) + } + + /** + * Create a dynamic link from a file to the H2GIS database. + * + * @param sql connection to the database. + * @param path The path of the file. + * @param table The name of the table created to store the file. + * @param delete True to delete the table if exists. Default to true. + * @throws java.sql.SQLException Exception throw on database error. + */ + static String link(H2GIS h2GIS, String path, boolean delete = false) throws SQLException { + File pathFile = new File(path) + String fileName = pathFile.name + String name = fileName.substring(0, fileName.lastIndexOf('.')) + return link(h2GIS, path, StringUtils.deleteWhitespace(name), delete) + } + + /** + * Link a table from an external database to a H2GIS database. + * Databases supported are H2 [H2GIS], PostgreSQL [PostGIS] + * Note : the jdb driver of the external database must be in the classpath + * + * @param sql connection to the database. + * @param path The path of the file. + * @param table The name of the table created to store the file. + * @param delete True to delete the table if exists. Default to true. + * @throws java.sql.SQLException Exception throw on database error. + */ + static String link(H2GIS h2GIS, String dbname, String host, String port, String user, String password, String schema = "", + String table, String newTable = "", boolean delete = false, + int batch_size = 100) throws SQLException { + def properties = [:] + properties.put("user", user) + properties.put("password": password) + def url = "jdbc:$host" + if (port) { + url += "/$port" + } + properties.put("url": "$url/$dbname") + def sourceTable = table + + if (schema) { + sourceTable = "(select * from $schema.$table)" + } + return IOMethods.linkedTable(h2GIS.getDataSource().getConnection(), properties, sourceTable, newTable ? newTable : table, delete, batch_size) + } + + /** + * Save a PostGIS table into a file + * @param database PostGIS database + * @param table the name of the table + * @param filePath the path of the file + * @param delete the file is exist + * @param encoding encode the file is supported + * @return true if success + */ + static boolean save(PostGIS database, String table, String filePath, boolean delete = false, String encoding = null) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot save.") + return false + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods() + } + ioMethods.exportToFile(con, "\"$table\"", filePath, encoding, delete) + return true; + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath) + } + return false; + } + + /** + * Save an H2GIS table into a file + * @param database PostGIS database + * @param table the name of the table + * @param filePath the path of the file + * @param delete the file is exist + * @param encoding encode the file is supported + * @return true if success + */ + static boolean save(H2GIS database, String table, String filePath, boolean delete = false, String encoding = null) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot save."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + ioMethods.exportToFile(con, "\"$table\"", filePath, encoding, delete) + return true; + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath) + } + return false; + } + + + /** + * Load a file to H2GIS database + * @param database H2GIS database + * @param filePath the input file path + * @param delete remove the table if exists + * @return the names of the created tables + */ + static String[] load(H2GIS database, String filePath, + boolean delete = false) { + File pathFile = new File(filePath) + String fileName = pathFile.name + String name = fileName.substring(0, fileName.lastIndexOf('.')) + return load(database, filePath, StringUtils.deleteWhitespace(name), null, delete) + } + + /** + * Load a file to PostGIS database + * @param database PostGIS database + * @param filePath the input file path + * @param delete remove the table if exists + * @return the names of the created tables + */ + static String[] load(PostGIS database, String filePath, + boolean delete = false) { + File pathFile = new File(filePath) + String fileName = pathFile.name + String name = fileName.substring(0, fileName.lastIndexOf('.')) + return load(database, filePath, StringUtils.deleteWhitespace(name), null, delete) + } + + /** + * Load a file to PostGIS database + * @param database PostGIS database + * @param filePath the input file path + * @param table a name for the created table + * @param encoding input file encoding if supported + * @param delete remove the table if exists + * @return the names of the created tables + */ + static String[] load(PostGIS database, String filePath, String table, String encoding = null, + boolean delete = false) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot load the file $filePath."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + return ioMethods.importFile(con, filePath, table, encoding, delete) + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath); + } + return null + } + + /** + * Load a file to H2GIS database + * @param database H2GIS database + * @param filePath the input file path + * @param table a name for the created table + * @param encoding input file encoding if supported + * @param delete remove the table if exists + * @return the names of the created tables + */ + static String[] load(H2GIS database, String filePath, String table, String encoding = null, + boolean delete = false) { + def con = database.getDataSource().getConnection() + if (con == null) { + LOGGER.severe("No connection, cannot load the file $filePath."); + return false; + } + try { + if (ioMethods == null) { + ioMethods = new IOMethods(); + } + return ioMethods.importFile(con, filePath, table, encoding, delete) + } catch (SQLException e) { + LOGGER.severe("Cannot import the file : " + filePath); + } + return null + } + + /** + * Load a table from an external database to H2GIS + * + * @param h2GIS database + * @param database destination database connection + * @param table the name of the table to export or a select query + * @param newTable target table name + * @param mode -1 delete the target table if exists and create a new table, + * 0 create a new table, 1 update the target table if exists + * @param batch_size batch size value before sending the data + * @return the name of the created table + */ + static String load(H2GIS h2GIS, Database database, String table, int mode = 0, int batch_size = 100) { + return IOMethods.exportToDataBase(database.getDataSource().getConnection(), + "\"$table\"", h2GIS.getDataSource().getConnection(), "\"$table\"", mode, batch_size) + } + /** + * Load a table from an external database to H2GIS + * + * @param h2GIS database + * @param database destination database connection + * @param table the name of the table to export or a select query + * @param newTable target table name + * @param mode -1 delete the target table if exists and create a new table, + * 0 create a new table, 1 update the target table if exists + * @param batch_size batch size value before sending the data + * @return the name of the created table + */ + static String load(H2GIS h2GIS, Database database, String table, String newTable , int mode = 0, int batch_size = 100) { + return IOMethods.exportToDataBase(database.getDataSource().getConnection(), + table, h2GIS.getDataSource().getConnection(), newTable ? newTable : table, mode, batch_size) + } + + + /** + * Save a table to an external database + * @param h2GIS database + * @param database destination database connection + * @param table the name of the table to export or a select query + * @param newTable target table name + * @param mode -1 delete the target table if exists and create a new table, + * 0 create a new table, 1 update the target table if exists + * @param batch_size batch size value before sending the data + * @return the name of the created table + */ + static String save(H2GIS h2GIS, Database database, String table, String newTable, boolean delete=false, int batch_size =100) { + //The save method support select when the user set the table with '(select * from mytable)' + if(!table.startsWith("(")){ + //Escapte the table name because it's not a query + table = "\"$table\"" + } + return IOMethods.exportToDataBase(h2GIS.getDataSource().getConnection(), + table, database.getDataSource().getConnection(), "\"$newTable\"", delete?-1:0, batch_size) + } + + /** + * Save a table to an external database + * @param h2GIS database + * @param database destination database connection + * @param table the name of the table to export + * @param newTable target table name + * @param delete true to delete the existing table + * @param batch_size batch size value before sending the data + * @return the name of the created table + */ + static String save(H2GIS h2GIS, Database database, String table, boolean delete=false, int batch_size =100) { + return IOMethods.exportToDataBase(h2GIS.getDataSource().getConnection(), + "\"$table\"", database.getDataSource().getConnection(), "\"$table\"", delete?-1:0, batch_size) + } + + /** + * Insert to an existing table stored in an external database + * @param h2GIS database + * @param database destination database connection + * @param table the name of the table to export + * @param newTable target table name + * @param batch_size batch size value before sending the data + * @return the name of the created table + */ + static String insert(H2GIS h2GIS, Database database, String table, int batch_size =100) { + return IOMethods.exportToDataBase(h2GIS.getDataSource().getConnection(), + "\"$table\"", database.getDataSource().getConnection(), "\"$table\"", 1, batch_size) + } + +} diff --git a/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule index 2a3b1b2b..b17c7af0 100644 --- a/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule +++ b/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule @@ -1,4 +1,4 @@ moduleName = geoscript-groovy-module moduleVersion = 1.0 -extensionClasses = geoscript.geom.io.GeometryExtensionModule, geoscript.feature.io.FeatureExtensionModule, geoscript.layer.io.LayerExtensionModule, geoscript.layer.io.PyramidExtensionModule, geoscript.layer.WMSMapExtensionModule, geoscript.style.io.StyleExtensionModule,geoscript.workspace.DatabaseExtensionModule +extensionClasses = geoscript.geom.io.GeometryExtensionModule, geoscript.feature.io.FeatureExtensionModule, geoscript.layer.io.LayerExtensionModule, geoscript.layer.io.PyramidExtensionModule, geoscript.layer.WMSMapExtensionModule, geoscript.style.io.StyleExtensionModule,geoscript.workspace.H2GISDatabaseExtensionModule staticExtensionClasses = geoscript.geom.io.StaticGeometryExtensionModule, geoscript.feature.io.StaticFeatureExtensionModule, geoscript.plot.ViewerExtensionModule, geoscript.layer.io.StaticPyramidExtensionModule, geoscript.style.io.StaticStyleExtensionModule \ No newline at end of file diff --git a/src/test/groovy/geoscript/workspace/H2GISTest.groovy b/src/test/groovy/geoscript/workspace/H2GISTest.groovy index 4623bf5c..810ce8cd 100644 --- a/src/test/groovy/geoscript/workspace/H2GISTest.groovy +++ b/src/test/groovy/geoscript/workspace/H2GISTest.groovy @@ -3,8 +3,15 @@ package geoscript.workspace import geoscript.feature.Field import geoscript.geom.Point import geoscript.layer.Layer +import geoscript.proj.Projection +import geoscript.render.Map +import geoscript.style.Fill +import geoscript.style.Stroke +import geoscript.style.Symbolizer +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir +import static geoscript.render.Draw.* import static org.junit.jupiter.api.Assertions.* @@ -19,8 +26,25 @@ class H2GISTest { @Test void loadShapeFile() { H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) File file = new File(getClass().getClassLoader().getResource("states.shp").toURI()) - String tableName = h2gis.load(file.getAbsolutePath(), true) - println(tableName) + def tableName = h2gis.load(file.getAbsolutePath(), true) + assertEquals("STATES", tableName[0]) + Layer layer = h2gis.get("STATES") + assertEquals(49, layer.getCount()) + def minMax = layer.minmax("SAMP_POP") + assertEquals 72696.0, minMax.min, 0.1 + assertEquals 3792553.0, minMax.max, 0.1 + } + + @Test void linkShapeFile() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + File file = new File(getClass().getClassLoader().getResource("states.shp").toURI()) + def tableName = h2gis.link(file.getAbsolutePath(), true) + assertEquals("states", tableName) + Layer layer = h2gis.get("STATES") + assertEquals(49, layer.getCount()) + def minMax = layer.minmax("SAMP_POP") + assertEquals 72696.0, minMax.min, 0.1 + assertEquals 3792553.0, minMax.max, 0.1 } @Test void remove() { @@ -48,7 +72,7 @@ class H2GISTest { } @Test void createFromPath() { - H2GIS h2gis = new H2GIS("./target/mydb") + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) assertEquals "H2GIS", h2gis.format Layer l = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) assertNotNull(l) @@ -60,7 +84,7 @@ class H2GISTest { } @Test void writeLinkShapeFile() { - H2GIS h2gis = new H2GIS("./target/mydb") + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) assertEquals "H2GIS", h2gis.format Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) @@ -69,15 +93,90 @@ class H2GISTest { layer.add([new Point(2,2), "two"]) layer.add([new Point(3,3), "three"]) assertEquals 3, layer.count() - File outputFile = new File("./target/widgets.shp") - h2gis.save("widgets", outputFile.getAbsolutePath()) - def outputTable = h2gis.linkedFile(outputFile.getAbsolutePath(), true) + File outputFile = new File(folder, "widgets.shp") + h2gis.save("widgets", outputFile.getAbsolutePath(), true) + def outputTable = h2gis.link(outputFile.getAbsolutePath(), true) assertEquals(3, h2gis.get(outputTable).count) h2gis.close() } @Test void writeSaveLoadShapeFile() { - H2GIS h2gis = new H2GIS("./target/mydb") + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + File outputFile = new File(folder, "widgets.shp") + h2gis.save(layer.getName(), outputFile.getAbsolutePath(), true) + def outputTable = h2gis.load(outputFile.getAbsolutePath(), "test_imported") + assertEquals(3, h2gis.get(outputTable[0]).count) + h2gis.close() + } + + @Test void loadFromDatabase() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + H2GIS h2gis_target = new H2GIS(new File(folder,"h2gis_target.db")) + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + h2gis_target.load(h2gis, layer.getName(), -1) + Layer target_Layer = h2gis_target.get(layer.getName()) + assertNotNull(target_Layer) + assertEquals 3, target_Layer.count() + h2gis.close() + h2gis_target.close() + } + + @Test void saveToDatabase() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + H2GIS h2gis_target = new H2GIS(new File(folder,"h2gis_target.db")) + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + h2gis.save(h2gis_target,layer.getName(), true) + Layer target_Layer = h2gis_target.get(layer.getName()) + assertNotNull(target_Layer) + assertEquals 3, target_Layer.count() + h2gis.close() + h2gis_target.close() + } + + @Test void saveQueryToDatabase() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + H2GIS h2gis_target = new H2GIS(new File(folder,"h2gis_target.db")) + h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) + assertEquals "H2GIS", h2gis.format + Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) + assertNotNull(layer) + layer.add([new Point(1,1), "one"]) + layer.add([new Point(2,2), "two"]) + layer.add([new Point(3,3), "three"]) + assertEquals 3, layer.count() + h2gis.save(h2gis_target,"(SELECT * FROM \"${layer.getName()}\" WHERE \"name\"= 'two')", "output_layer", true) + Layer target_Layer = h2gis_target.get("output_layer") + assertNotNull(target_Layer) + assertEquals 1, target_Layer.count() + h2gis.close() + h2gis_target.close() + } + + @Test void saveAndInsertToDatabase() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + H2GIS h2gis_target = new H2GIS(new File(folder,"h2gis_target.db")) h2gis.getSql().execute("drop table if exists \"widgets\"".toString()) assertEquals "H2GIS", h2gis.format Layer layer = h2gis.create('widgets',[new Field("geom", "Point"), new Field("name", "String")]) @@ -86,11 +185,40 @@ class H2GISTest { layer.add([new Point(2,2), "two"]) layer.add([new Point(3,3), "three"]) assertEquals 3, layer.count() - File outputFile = new File("./target/widgets.shp") - h2gis.save("widgets", outputFile.getAbsolutePath()) - def outputTable = h2gis.load(outputFile.getAbsolutePath(), "\"test_imported\"") - assertEquals(3, h2gis.get("test_imported").count) + h2gis.save(h2gis_target,layer.getName(), true) + Layer target_Layer = h2gis_target.get(layer.getName()) + assertNotNull(target_Layer) + assertEquals 3, target_Layer.count() + h2gis.insert(h2gis_target,layer.getName()) + target_Layer = h2gis_target.get(layer.getName()) + assertNotNull(target_Layer) + assertEquals 6, target_Layer.count() h2gis.close() + h2gis_target.close() } + @Disabled + //TODO the map is weel rendered but there is an error message on org.geotools.renderer.lite.StreamingRenderer getStyleQuery + @Test void drawLinkedShapeFile() { + H2GIS h2gis = new H2GIS(new File(folder,"h2gis.db")) + File file = new File(getClass().getClassLoader().getResource("states.shp").toURI()) + def tableName = h2gis.link(file.getAbsolutePath(), true) + assertEquals("states", tableName) + Layer layer = h2gis.get("STATES") + Symbolizer symbolizer = new Fill("gray") + new Stroke("#ffffff") + layer.setStyle(symbolizer) + layer.setProj(new Projection("EPSG:2927")) + Map map = new Map() + map.proj = new Projection("EPSG:2927") + map.addLayer(layer) + map.bounds = layer.bounds + def image = map.renderToImage() + assertNotNull(image) + + File out = new File(folder,"map.png") + javax.imageio.ImageIO.write(image, "png", out); + assertTrue(out.exists()) + map.close() + h2gis.close() + } }