/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, 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.postgis;
import java.sql.Connection;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import org.geotools.test.OnlineTestCase;
/**
* Online test fixture for registered function support.
*
* <p>
*
* The id of this test fixture and its subclasses is "postgis-regfunc". This test fixture requires
* PostGIS connection parameter entries like those listed below. The target should be a PostGIS
* database to which the user has write permission.
*
* <pre>
* host = HOSTNAME.example.com
* port = 5432
* schema = public
* database = DATABASE
* user = USER
* passwd = PASSWD
* skip.on.failure = false
* </pre>
*
* See {@link OnlineTestCase} for more about online test fixtures.
*
* @author Ben Caradoc-Davies, CSIRO Exploration and Mining
* @version $Id$
* @source $URL$
* @since 2.4
*/
public abstract class AbstractRegfuncPostgisOnlineTestCase extends OnlineTestCase {
/**
* The name of the test table in the database.
*/
public static final String TEST_TABLE_NAME = "regfunc_test_table";
/**
* The column in the test table used as its primary key.
*/
public static final String ID_COLUMN_NAME = "id";
/**
* The columns in the table that contains text describing the feature.
*/
public static final String DESCRIPTION_COLUMN_NAME = "description";
/**
* The description column for row with id 3.
*/
public static final String DESCRIPTION_FOR_ID_3 = "Basalt, tuff, and some lumpy bits.";
/**
* The description column for row with id 27.
*/
public static final String DESCRIPTION_FOR_ID_27 = "Sandstone, on top of basalt.";
/**
* The description column for row with id 41.
*/
public static final String DESCRIPTION_FOR_ID_41 = "Tuff, limestone, and rich creamy butter.";
/**
* The description column for row with id 93.
*/
public static final String DESCRIPTION_FOR_ID_93 = "Two pointy ones, a flat one, and a packet of gravel.";
/**
* Name of the test function created in the database.
*/
public static final String TEST_FUNCTION_NAME = "regfunc_test_function_contains_text";
/**
* SQL to create the test function created in the database.
*
* <p>
*
* This function determines whether the column named in the first argument contains the text
* given in the second argument, and returns 1 for true and 0 for false. The text comparison is
* case insensitive.
*/
/*
* Do not use $$ for function body quoting as not supported by JDBC driver. Use
* single-apostrophe instead. See comment at end of
* http://www.postgresql.org/docs/8.2/interactive/plpgsql-development-tips.html
*/
public static final String CREATE_FUNCTION_SQL = //
"-- Return 1 if s contains ss (case insensitive), else return 0\n" //
+ "CREATE FUNCTION " //
+ TEST_FUNCTION_NAME //
+ "(s text, ss text) RETURNS integer AS '\n" //
+ "BEGIN\n" //
+ " IF position(lower(ss) in lower(s) ) > 0\n" //
+ " THEN\n" //
+ " RETURN 1;\n" //
+ " ELSE\n" //
+ " RETURN 0;\n" //
+ " END IF;\n" //
+ "END;\n" + "' LANGUAGE plpgsql"; //
/**
* The test function returns 1 for true and 0 for false.
*
* <p>
*
* GeoSciML Testbed 3 implementers report Oracle does not support boolean datatype, so use cases
* implemented with filter functions that return these integers in place of boolean.
*
* @see https://www.seegrid.csiro.au/twiki/bin/view/CGIModel/TestBed3UseCase3AProfile
*/
public static final int TEST_FUNCTION_RETURN_TRUE = 1;
/**
* The data store under test.
*/
private RegfuncPostgisDataStore datastore;
/**
* Define the id for this fixture.
*
* @see org.geotools.test.OnlineTestCase#getFixtureId()
*/
protected String getFixtureId() {
return (String) RegfuncPostgisDataStoreFactory.DBTYPE.sample;
}
/**
* Create a PostGIS data store with registered function support, test table, and test function.
*
* @see org.geotools.test.OnlineTestCase#connect()
*/
protected void connect() throws Exception {
super.connect();
datastore = (RegfuncPostgisDataStore) new RegfuncPostgisDataStoreFactory()
.createDataStore(getParams());
createTable();
createFunction();
}
/**
* Read the data store configuration parameters from the fixture properties.
*
* @return data store configuration parameters
*/
public Map getParams() {
Map params = new HashMap();
params
.put(PostgisDataStoreFactory.DBTYPE.key,
RegfuncPostgisDataStoreFactory.DBTYPE.sample);
loadParam(params, PostgisDataStoreFactory.HOST.key);
loadParam(params, PostgisDataStoreFactory.PORT.key);
loadParam(params, PostgisDataStoreFactory.SCHEMA.key);
loadParam(params, PostgisDataStoreFactory.DATABASE.key);
loadParam(params, PostgisDataStoreFactory.USER.key);
loadParam(params, PostgisDataStoreFactory.PASSWD.key);
return params;
}
/**
* If fixture properties contains a given key, update the configuration parameters map with the
* corresponding value taken from the fixture properties, with the same key.
*
* @param params
* the parameter map used to configure a DataStore
* @param key
* the key for the value in both the properties and parameter map
*/
private void loadParam(Map params, String key) {
if (fixture.containsKey(key)) {
params.put(key, fixture.getProperty(key));
}
}
/**
* Remove test table and function, and disconnect.
*
* @see org.geotools.test.OnlineTestCase#disconnect()
*/
protected void disconnect() throws Exception {
dropTable();
dropFunction();
datastore.dispose();
datastore = null;
super.disconnect();
}
/**
* Get a JDBC Connection to the database.
*
* <p>
*
* Caller must <code>close<code> this resource.
*
* @return a JDBC connection
* @throws Exception
*/
public Connection getConnection() throws Exception {
return datastore.getDataSource().getConnection();
}
/**
* Create the test table in the database.
*
* @throws Exception
*/
public void createTable() throws Exception {
// first make sure no old test function present
dropTable();
// create the table
execute("CREATE TABLE " + TEST_TABLE_NAME + " (" + ID_COLUMN_NAME
+ " INTEGER PRIMARY KEY, " + DESCRIPTION_COLUMN_NAME + " VARCHAR(80))");
// insert the rows
populateTable();
}
/**
* Execute an SQL statement on the database.
*
* @param sql
* the test of the SQL statement (no trailing semicolon)
* @throws Exception
*/
public void execute(String sql) throws Exception {
Connection connection = null;
try {
connection = getConnection();
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(sql);
} finally {
if (statement != null) {
statement.close();
}
}
} finally {
if (connection != null) {
connection.close();
}
}
}
/**
* Insert the four test rows into the test table, in arbitrary order.
*
* @throws Exception
*/
private void populateTable() throws Exception {
insertRow(41, DESCRIPTION_FOR_ID_41);
insertRow(3, DESCRIPTION_FOR_ID_3);
insertRow(27, DESCRIPTION_FOR_ID_27);
insertRow(93, DESCRIPTION_FOR_ID_93);
}
/**
* Insert a row into the test table.
*
* @param id
* the key for this row
* @param description
* descriptive text
* @throws Exception
*/
private void insertRow(int id, String description) throws Exception {
execute("INSERT INTO " + TEST_TABLE_NAME + " (" + ID_COLUMN_NAME + ", "
+ DESCRIPTION_COLUMN_NAME + ") VALUES (" + id + ", '" + description + "')");
}
/**
* Create the test function in the database by executing SQL.
*
* @throws Exception
*/
public void createFunction() throws Exception {
// first make sure no old test function present
dropFunction();
execute(CREATE_FUNCTION_SQL);
}
/**
* Remove the test table from the database. Exceptions are ignored.
*/
public void dropTable() {
try {
execute("DROP TABLE " + TEST_TABLE_NAME);
} catch (Exception e) {
// ignore
}
}
/**
* Remove the test function from the database. Exceptions are ignored.
*/
public void dropFunction() {
try {
execute("DROP FUNCTION " + TEST_FUNCTION_NAME + "(text, text)");
} catch (Exception e) {
// ignore
}
}
}