/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2010-2011, 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.complex.config; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.Set; import static org.junit.Assert.assertEquals; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureSource; import org.geotools.data.Query; import org.geotools.data.complex.AppSchemaDataAccess; import org.geotools.data.complex.AppSchemaDataAccessRegistry; import org.geotools.data.complex.FeatureTypeMapping; import org.geotools.test.AppSchemaTestSupport; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.opengis.feature.Feature; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; /** * This is a test for AppSchemaDataAccessConfigurator on file-based datastores, including shapefiles * and *.properties files. * * @author Tara Athan * @author Ben Caradoc-Davies (CSIRO Earth Science and Resource Engineering) * * * @source $URL$ */ public class AppSchemaFileDataTest extends AppSchemaTestSupport { /** * The resource path containing the source data for testing. */ private static final String testData = "/test-data/"; /** * The temporary directory where tests are run. */ private static final File testDir = new File("target/test/" + AppSchemaFileDataTest.class.getSimpleName()); /** * Create the test directory. * * @see junit.framework.TestCase#setUp() */ @Before public void setUp() throws IOException { FileUtils.deleteDirectory(testDir); // copy all the test data into the test directory copyTestData("ArchSite.xsd", testDir); copyTestData("ArchSiteNillable.xml", testDir); copyTestData("AppSchemaFileDataTest.xml", testDir); copyTestData("PointFeatureGeomPropertyfile.properties", new File(testDir, "directory")); } /** * Remove the test directory. * * @see junit.framework.TestCase#tearDown() */ @After public void tearDown() throws IOException { FileUtils.deleteDirectory(testDir); AppSchemaDataAccessRegistry.unregisterAndDisposeAll(); } /** * Copy a file from the test-data directory to another directory. * * @param baseFileName * base filename (without any path) of the file to be copied * @param destDir * destination filename * @throws IOException */ private static void copyTestData(String baseFileName, File destDir) throws IOException { destDir.mkdirs(); FileUtils.copyFileToDirectory( DataUtilities.urlToFile(AppSchemaFileDataTest.class.getResource(testData + baseFileName)), destDir); } /** * Return the path to a file in the test directory. * * @param baseFileName * file name without any path * @return */ private static String getTestDirPath(String baseFileName) { return (new File(testDir, baseFileName)).getPath(); } /** * Test the AppSchemaDataAccessConfigurator.buildMappings method with shapefiles, using a * relative paths to the data */ @Test public void testShapeMappings() throws Exception { String mappingFileNameRelativeShape = "ArchSiteNillable.xml"; AppSchemaDataAccess dSRelative = null; try { // create the DataAccess based on shapefile configured with a relative path dSRelative = buildDataAccess(mappingFileNameRelativeShape); // there should be a single target feature in this data access assertEquals(1, dSRelative.getNames().size()); // there should be 25 features in this data access assertEquals(25, countFeatures(dSRelative)); } finally { if (dSRelative != null) { dSRelative.dispose(); } } } /** * Test the AppSchemaDataAccessConfigurator.buildMappings method with shapefiles, using an * absolute path to the data. */ @Test public void testShapeMappingsAbsolute() throws Exception { String mappingFileNameRelativeShape = "ArchSiteNillable.xml"; String configFilePathRelativeShape = getTestDirPath(mappingFileNameRelativeShape); String mappingFileNameAbsoluteShape = "ArchSiteAbsolute.xml"; String configFilePathAbsoluteShape = getTestDirPath(mappingFileNameAbsoluteShape); AppSchemaDataAccess dSAbsolute = null; try { // now lets test a mapping file with an absolute path to the shapefile // because we don't know the absolute path in advance, we must create the mapping file copyRelativeToAbsolute(configFilePathRelativeShape, configFilePathAbsoluteShape); // create the DataAccess based on shapefile configured with a absolute path dSAbsolute = buildDataAccess(mappingFileNameAbsoluteShape); // there should be a single target feature in this data access assertEquals(1, dSAbsolute.getNames().size()); // there should be 25 features in this data access assertEquals(25, countFeatures(dSAbsolute)); } finally { if (dSAbsolute != null) { dSAbsolute.dispose(); } } } /** * Test the AppSchemaDataAccessConfigurator.buildMappings method with *.properties files using a * relative and paths to the data just to be sure we didn't break these while we were playing * around with shapefiles. */ @Test public void testPropertiesMappings() throws Exception { String mappingFileNameRelativeProperties = "AppSchemaFileDataTest.xml"; AppSchemaDataAccess dSRelative = null; try { // create the DataAccess based on properties file configured with a relative path dSRelative = buildDataAccess(mappingFileNameRelativeProperties); // there should be a single target feature in this data access assertEquals(1, dSRelative.getNames().size()); // there should be 2 features in this data access assertEquals(2, countFeatures(dSRelative)); } finally { if (dSRelative != null) { dSRelative.dispose(); } } } /** * Test the AppSchemaDataAccessConfigurator.buildMappings method with *.properties files using * an absolute path to the data just to be sure we didn't break these while we were playing * around with shapefiles. */ @Test public void testPropertiesMappingsAbsolute() throws Exception { String mappingFileNameRelativeProperties = "AppSchemaFileDataTest.xml"; String configFilePathRelativeProperties = getTestDirPath(mappingFileNameRelativeProperties); String mappingFileNameAbsoluteProperties = "AppSchemaFileDataTestAbsolute.xml"; String configFilePathAbsoluteProperties = getTestDirPath(mappingFileNameAbsoluteProperties); AppSchemaDataAccess dSAbsolute = null; try { // now let's test a mapping file with an absolute path to the properties file // because we don't know the absolute path in advance, we must create the mapping file copyRelativeToAbsolute(configFilePathRelativeProperties, configFilePathAbsoluteProperties); // create the DataAccess based on properties file configured with a absolute path dSAbsolute = buildDataAccess(mappingFileNameAbsoluteProperties); // there should be a single target feature in this data access assertEquals(1, dSAbsolute.getNames().size()); // there should be 2 features in this data access assertEquals(2, countFeatures(dSAbsolute)); } finally { if (dSAbsolute != null) { dSAbsolute.dispose(); } } } private int countFeatures(AppSchemaDataAccess dS) throws Exception { // we need the feature type in order to query for the number of features Name[] dSNameArray = dS.getTypeNames(); String testType = dSNameArray[0].toString(); FeatureSource<FeatureType, Feature> featureSource = dS .getFeatureSourceByName(dSNameArray[0]); int numFeatures = featureSource.getCount(new Query(testType)); return numFeatures; } private AppSchemaDataAccess buildDataAccess(String mappingsFileName) throws Exception { // generate the path to a mappings-file in the resources directory String configFilePath = extendFilename(testDir.getPath(), mappingsFileName); URL configFileUrl = DataUtilities.fileToURL(new File(configFilePath)); // parse the mappings-file XMLConfigDigester configReader = new XMLConfigDigester(); AppSchemaDataAccessDTO config = configReader.parse(configFileUrl); // generate the set of mappings needed to build the application-schema datastore Set<FeatureTypeMapping> mappings; mappings = AppSchemaDataAccessConfigurator.buildMappings(config); AppSchemaDataAccess datastore = new AppSchemaDataAccess(mappings); return datastore; } /** * copies a mapping file and changes some parameters to test absolute paths to data files * * @param filePathIn * the original mapping file * @param filePathOut * the new mapping file * @return * @throws Exception */ private String copyRelativeToAbsolute(String filePathIn, String filePathOut) throws Exception { BufferedReader reader = null; PrintWriter writer = null; String relativePath; String absolutePath = null; try { reader = new BufferedReader(new FileReader(filePathIn)); writer = new PrintWriter(new FileWriter(filePathOut)); String line; while ((line = reader.readLine()) != null) { // change the file path from relative to absolute if (line.trim().startsWith("<value>file:")) { relativePath = line.split("<value>file:|</value>")[1]; String resolvedPath = extendFilename(testDir.getPath(), relativePath); absolutePath = (new File(resolvedPath)).getAbsolutePath(); line = line.replace(relativePath, absolutePath); } // in shapefile test, chosen target feature doesn't allow null entry, so we'll take // the conditional out if (line.trim().startsWith("<OCQL>")) { line = line.replace("if_then_else(equalTo(CAT_DESC, 'No Name'), " + "Expression.Nil , CAT_DESC)", "CAT_DESC"); } writer.println(line); } } finally { if (reader != null) { reader.close(); } if (writer != null) { writer.close(); } } return absolutePath; } /** * extends a base filename with a path relative to the base filename * * @param baseFilename * may be absolute, or relative to the current directory * @param relativePath * must be relative to the base file name * @return an absolute, normalized filename * @throws RuntimeException * if the base filename and relative path are incompatible */ private String extendFilename(String baseFilename, String relativePath) throws RuntimeException { baseFilename = new File(baseFilename).getAbsolutePath(); String extendedFilename = FilenameUtils.concat(baseFilename, relativePath); if (extendedFilename == null) { throw new RuntimeException("Relative path to datastore is incompatible with the " + "base path - check double dot steps."); } return extendedFilename; } }