/* (c) 2014-16 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.test.onlineTest.setup; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.apache.commons.lang.StringUtils; import org.geotools.data.property.PropertyFeatureReader; import org.geotools.feature.IllegalAttributeException; import org.geotools.resources.Classes; import org.opengis.feature.Property; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.feature.type.GeometryType; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.filter.identity.FeatureId; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.WKTWriter; /** * Oracle data setup for app-schema-test with online mode. * * @author Rini Angreani (CSIRO Earth Science and Resource Engineering) */ @SuppressWarnings("deprecation") public class AppSchemaTestOracleSetup extends ReferenceDataOracleSetup { /** * Mapping file database parameters */ public static String DB_PARAMS = "<parameters>" // + "\n<Parameter>\n" // + "<name>dbtype</name>\n" // + "<value>Oracle</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" // + "<name>host</name>\n" // + "<value>${host}</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" // + "<name>port</name>\n" // + "<value>${port}</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" // + "<name>database</name>\n" // + "<value>${database}</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" // + "<name>user</name>\n" // + "<value>${user}</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" // + "<name>passwd</name>\n" // + "<value>${passwd}</value>" // + "\n</Parameter>" // + "\n<Parameter>\n" + "<name>Expose primary keys</name>" + "<value>true</value>" + "\n</Parameter>" // + "\n</parameters>"; // /** * Default WKT parser for non 3D tests. */ private static String DEFAULT_PARSER = "SDO_GEOMETRY"; private String sql; /** * Factory method with no 3D support. * * @param propertyFiles * Property file name and its parent directory map * @return This class instance. */ public static AppSchemaTestOracleSetup getInstance(Map<String, File> propertyFiles) throws Exception { return new AppSchemaTestOracleSetup(propertyFiles, false); } /** * Factory method with 3D enabled. * * @param propertyFiles Property file name and its parent directory map * @return This class instance. */ public static AppSchemaTestOracleSetup get3DInstance(Map<String, File> propertyFiles) throws Exception { return new AppSchemaTestOracleSetup(propertyFiles, true); } /** * Ensure the app-schema properties file is loaded with the database parameters. Also create corresponding tables on the database based on data * from properties files. * * @param propertyFiles Property file name and its feature type directory map * @param is3D True if this is a 3D test and needs a particular WKT parser */ public AppSchemaTestOracleSetup(Map<String, File> propertyFiles, boolean is3D) throws Exception { configureFixture(); String parser; if (is3D) { // use 3D parser // if SC4OUser is different from the database user, it will be specified // else, use the current database user String user = System.getProperty("SC4OUser"); if (user == null) { user = fixture.getProperty("user"); } parser = user + ".SC4O.ST_GeomFromEWKT"; } else { parser = DEFAULT_PARSER; // default wkt parser procedure, does not support 3D } createTables(propertyFiles, parser); } /** * Write SQL string to create tables in the test database based on the property files. * * @param propertyFiles * Property files from app-schema-test suite. * @param parser * The parser (WKT or an SC4O one for 3D tests) * @throws IllegalAttributeException * @throws NoSuchElementException * @throws IOException */ private void createTables(Map<String, File> propertyFiles, String parser) throws IllegalAttributeException, NoSuchElementException, IOException { StringBuffer buf = new StringBuffer(); StringBuffer spatialIndex = new StringBuffer(); // drop table procedure I copied from Victor's Oracle_Data_ref_set.sql buf .append("CREATE OR REPLACE PROCEDURE DROP_TABLE_OR_VIEW(TabName in Varchar2) IS ") .append("temp number:=0;") .append(" tes VARCHAR2 (200) := TabName;") .append(" drp_stmt VARCHAR2 (200):=null;") .append("BEGIN select count(*) into temp from user_tables where TABLE_NAME = tes;") .append("if temp = 1 then drp_stmt := 'Drop Table '||tes;") .append("EXECUTE IMMEDIATE drp_stmt;") // drop views too .append("else select count(*) into temp from user_views where VIEW_NAME = tes;") .append("if temp = 1 then drp_stmt := 'Drop VIEW '||tes;") .append("EXECUTE IMMEDIATE drp_stmt;end if;end if;") .append("EXCEPTION WHEN OTHERS THEN ") .append( "raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);") .append("END DROP_TABLE_OR_VIEW;\n"); for (String fileName : propertyFiles.keySet()) { File file = new File(propertyFiles.get(fileName), fileName); try ( PropertyFeatureReader reader = new PropertyFeatureReader("test", file ) ){ SimpleFeatureType schema = reader.getFeatureType(); String tableName = schema.getName().getLocalPart().toUpperCase(); // drop table if exists buf.append("CALL DROP_TABLE_OR_VIEW('").append(tableName).append("')\n"); // create the table buf.append("CREATE TABLE ").append(tableName).append("("); // + pkey int size = schema.getAttributeCount() + 1; String[] fieldNames = new String[size]; List<String> createParams = new ArrayList<String>(); int j = 0; String type; String field; int spatialIndexCounter = 0; for (PropertyDescriptor desc : schema.getDescriptors()) { field = desc.getName().toString().toUpperCase(); fieldNames[j] = field; if (desc instanceof GeometryDescriptor) { type = "SDO_GEOMETRY"; // Update spatial index int srid = getSrid(((GeometryType) desc.getType())); spatialIndex.append("DELETE FROM user_sdo_geom_metadata WHERE table_name = '") .append(tableName).append("'\n"); spatialIndex .append("Insert into user_sdo_geom_metadata ") .append("(TABLE_NAME,COLUMN_NAME,DIMINFO,SRID)") .append("values ('") .append(tableName) .append("','") .append(field) .append( "',MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',140.962,144.909,0.00001),") .append("MDSYS.SDO_DIM_ELEMENT('Y',-38.858,-33.98,0.00001)") .append( //support 3d index ((GeometryDescriptor) desc).getCoordinateReferenceSystem() != null && ((GeometryDescriptor) desc).getCoordinateReferenceSystem().getCoordinateSystem().getDimension() == 3 ? ", MDSYS.SDO_DIM_ELEMENT('Z',-100000, 100000, 1) )," : "),") .append(srid).append(")\n"); // ensure it's <= 30 characters to avoid Oracle exception String indexName = (tableName.length() <= 26 ? tableName : tableName.substring( 0, 26)) + "_IDX"; if (spatialIndexCounter > 0) { // to avoid duplicate index name when there are > 1 geometry in the same table indexName += spatialIndexCounter; } spatialIndex.append("CREATE INDEX \"").append(indexName).append("\" ON \"") .append(tableName).append("\"(\"").append(field).append("\") ").append( "INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\"\n"); spatialIndexCounter++; } else { type = Classes.getShortName(desc.getType().getBinding()); if (type.equalsIgnoreCase("String")) { type = "NVARCHAR2(250)"; } else if (type.equalsIgnoreCase("Double")) { type = "NUMBER"; } // etc. assign as required } createParams.add(field + " " + type); j++; } // Add numeric PK for sorting fieldNames[j] = "PKEY"; createParams.add("PKEY VARCHAR2(30)"); buf.append(StringUtils.join(createParams.iterator(), ", ")); buf.append(")\n"); buf.append("ALTER TABLE " + tableName + " ADD CONSTRAINT " + tableName + " PRIMARY KEY (PKEY)\n"); // then insert rows SimpleFeature feature; FeatureId id; while (reader.hasNext()) { buf.append("INSERT INTO ").append(tableName).append("("); feature = reader.next(); buf.append(StringUtils.join(fieldNames, ", ")); buf.append(") "); buf.append("VALUES ("); Collection<Property> properties = feature.getProperties(); String[] values = new String[size]; int valueIndex = 0; for (Property prop : properties) { Object value = prop.getValue(); if (value instanceof Geometry) { //use wkt writer to convert geometry to string, so third dimension can be supported if present. Geometry geom = (Geometry) value; value = new WKTWriter(geom.getCoordinate().z == Double.NaN? 2 : 3).write(geom); } if (value == null || value.toString().equalsIgnoreCase("null")) { values[valueIndex] = "null"; } else if (prop.getType() instanceof GeometryType) { int srid = getSrid(((GeometryType) prop.getType())); StringBuffer geomValue = new StringBuffer(parser + "('"); geomValue.append(value).append("'"); if (srid > -1) { // attach srid geomValue.append(", ").append(srid); } geomValue.append(")"); values[valueIndex] = geomValue.toString(); } else if (prop.getType().getBinding().getSimpleName().equalsIgnoreCase("DATE")) { values[valueIndex] = "TO_DATE('" + value + "', 'yyyy-MM-dd')"; } else { values[valueIndex] = "'" + value + "'"; } valueIndex++; } id = feature.getIdentifier(); // insert primary key values[valueIndex] = "'" + id.toString() + "'"; buf.append(StringUtils.join(values, ",")); buf.append(")\n"); } } buf.append(spatialIndex.toString()); spatialIndex.delete(0, spatialIndex.length()); if (buf.length() > 0) { this.sql = buf.toString(); } } } @Override protected void runSqlInsertScript() throws Exception { this.run(sql, false); } }