From 937227a0f315f3fb617838ade3777c4f9e4f688f Mon Sep 17 00:00:00 2001 From: gmantele <gmantele@ari.uni-heidelberg.de> Date: Mon, 9 Feb 2015 15:01:48 +0100 Subject: [PATCH] [TAP] Add metadata support in the configuration file. Two methods to get metadata: 1/ Parse an XML file implementing the schema TableSet, and then re-build TAP_SCHEMA in the database, 2/ Get metadata from the database schema TAP_SCHEMA. --- src/tap/config/DefaultServiceConnection.java | 73 +++++++++++- src/tap/config/DefaultTAPFactory.java | 6 +- src/tap/config/TAPConfiguration.java | 16 ++- src/tap/config/tap_configuration_file.html | 38 ++++++- src/tap/config/tap_full.properties | 30 +++-- src/tap/config/tap_min.properties | 31 +++--- test/tap/config/AllTests.java | 2 +- .../config/TestDefaultServiceConnection.java | 105 +++++++++++++++++- test/tap/config/TestDefaultTAPFactory.java | 17 ++- 9 files changed, 269 insertions(+), 49 deletions(-) diff --git a/src/tap/config/DefaultServiceConnection.java b/src/tap/config/DefaultServiceConnection.java index f2470d0..c6598a0 100644 --- a/src/tap/config/DefaultServiceConnection.java +++ b/src/tap/config/DefaultServiceConnection.java @@ -17,22 +17,27 @@ import static tap.config.TAPConfiguration.KEY_MAX_EXECUTION_DURATION; import static tap.config.TAPConfiguration.KEY_MAX_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_MAX_RETENTION_PERIOD; import static tap.config.TAPConfiguration.KEY_MAX_UPLOAD_LIMIT; +import static tap.config.TAPConfiguration.KEY_METADATA; +import static tap.config.TAPConfiguration.KEY_METADATA_FILE; import static tap.config.TAPConfiguration.KEY_OUTPUT_FORMATS; import static tap.config.TAPConfiguration.KEY_PROVIDER_NAME; import static tap.config.TAPConfiguration.KEY_SERVICE_DESCRIPTION; import static tap.config.TAPConfiguration.KEY_UPLOAD_ENABLED; import static tap.config.TAPConfiguration.KEY_UPLOAD_MAX_FILE_SIZE; import static tap.config.TAPConfiguration.VALUE_CSV; +import static tap.config.TAPConfiguration.VALUE_DB; import static tap.config.TAPConfiguration.VALUE_JSON; import static tap.config.TAPConfiguration.VALUE_LOCAL; import static tap.config.TAPConfiguration.VALUE_SV; import static tap.config.TAPConfiguration.VALUE_TSV; +import static tap.config.TAPConfiguration.VALUE_XML; import static tap.config.TAPConfiguration.fetchClass; import static tap.config.TAPConfiguration.getProperty; import static tap.config.TAPConfiguration.isClassPath; import static tap.config.TAPConfiguration.parseLimit; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -41,6 +46,7 @@ import java.util.Properties; import tap.ServiceConnection; import tap.TAPException; import tap.TAPFactory; +import tap.db.DBConnection; import tap.formatter.JSONFormat; import tap.formatter.OutputFormat; import tap.formatter.SVFormat; @@ -48,6 +54,7 @@ import tap.formatter.VOTableFormat; import tap.log.DefaultTAPLog; import tap.log.TAPLog; import tap.metadata.TAPMetadata; +import tap.metadata.TableSetParser; import uws.UWSException; import uws.service.UserIdentifier; import uws.service.file.LocalUWSFileManager; @@ -62,6 +69,8 @@ public final class DefaultServiceConnection implements ServiceConnection { private DefaultTAPFactory tapFactory; + private final TAPMetadata metadata; + private final String providerName; private final String serviceDescription; @@ -93,13 +102,16 @@ public final class DefaultServiceConnection implements ServiceConnection { // 3. BUILD THE TAP FACTORY: tapFactory = new DefaultTAPFactory(this, tapConfig); - // 4. SET ALL GENERAL SERVICE CONNECTION INFORMATION: + // 4. GET THE METADATA: + metadata = initMetadata(tapConfig); + + // 5. SET ALL GENERAL SERVICE CONNECTION INFORMATION: providerName = getProperty(tapConfig, KEY_PROVIDER_NAME); serviceDescription = getProperty(tapConfig, KEY_SERVICE_DESCRIPTION); initRetentionPeriod(tapConfig); initExecutionDuration(tapConfig); - // 5. CONFIGURE OUTPUT: + // 6. CONFIGURE OUTPUT: // default output format = VOTable: outputFormats = new ArrayList<OutputFormat>(1); outputFormats.add(new VOTableFormat(this)); @@ -108,7 +120,7 @@ public final class DefaultServiceConnection implements ServiceConnection { // set output limits: initOutputLimits(tapConfig); - // 6. CONFIGURE THE UPLOAD: + // 7. CONFIGURE THE UPLOAD: // is upload enabled ? isUploadEnabled = Boolean.parseBoolean(getProperty(tapConfig, KEY_UPLOAD_ENABLED)); // set upload limits: @@ -116,7 +128,7 @@ public final class DefaultServiceConnection implements ServiceConnection { // set the maximum upload file size: initMaxUploadSize(tapConfig); - // 7. MAKE THE SERVICE AVAILABLE: + // 8. MAKE THE SERVICE AVAILABLE: setAvailable(true, "TAP service available."); } @@ -168,6 +180,56 @@ public final class DefaultServiceConnection implements ServiceConnection { } } + private TAPMetadata initMetadata(final Properties tapConfig) throws TAPException{ + // Get the fetching method to use: + String metaFetchType = getProperty(tapConfig, KEY_METADATA); + if (metaFetchType == null) + throw new TAPException("The property \"" + KEY_METADATA + "\" is missing! It is required to create a TAP Service. Two possible values: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA)."); + + TAPMetadata metadata = null; + + // GET METADATA FROM XML & UPDATE THE DATABASE (schema TAP_SCHEMA only): + if (metaFetchType.equalsIgnoreCase(VALUE_XML)){ + // Get the XML file path: + String xmlFilePath = getProperty(tapConfig, KEY_METADATA_FILE); + if (xmlFilePath == null) + throw new TAPException("The property \"" + KEY_METADATA_FILE + "\" is missing! According to the property \"" + KEY_METADATA + "\", metadata must be fetched from an XML document. The local file path of it MUST be provided using the property \"" + KEY_METADATA_FILE + "\"."); + + // Parse the XML document and build the corresponding metadata: + try{ + metadata = (new TableSetParser()).parse(new File(xmlFilePath)); + }catch(IOException ioe){ + throw new TAPException("A grave error occurred while reading/parsing the TableSet XML document: \"" + xmlFilePath + "\"!", ioe); + } + + // Update the database: + DBConnection conn = null; + try{ + conn = tapFactory.getConnection("SET_TAP_SCHEMA"); + conn.setTAPSchema(metadata); + }finally{ + if (conn != null) + tapFactory.freeConnection(conn); + } + } + // GET METADATA FROM DATABASE (schema TAP_SCHEMA): + else if (metaFetchType.equalsIgnoreCase(VALUE_DB)){ + DBConnection conn = null; + try{ + conn = tapFactory.getConnection("GET_TAP_SCHEMA"); + metadata = conn.getTAPSchema(); + }finally{ + if (conn != null) + tapFactory.freeConnection(conn); + } + } + // INCORRECT VALUE => ERROR! + else + throw new TAPException("Unsupported value for the property \"" + KEY_METADATA + "\": \"" + metaFetchType + "\"! Only two values are allowed: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA)."); + + return metadata; + } + private void initRetentionPeriod(final Properties tapConfig){ retentionPeriod = new int[2]; @@ -550,8 +612,7 @@ public final class DefaultServiceConnection implements ServiceConnection { @Override public TAPMetadata getTAPMetadata(){ - // TODO GET METADATA - return null; + return metadata; } @Override diff --git a/src/tap/config/DefaultTAPFactory.java b/src/tap/config/DefaultTAPFactory.java index ee3e3d2..399c891 100644 --- a/src/tap/config/DefaultTAPFactory.java +++ b/src/tap/config/DefaultTAPFactory.java @@ -52,7 +52,7 @@ public final class DefaultTAPFactory extends AbstractTAPFactory { String dbUrl = getProperty(tapConfig, KEY_JDBC_URL); if (jdbcDriver == null){ if (dbUrl == null) - throw new TAPException("JDBC URL missing."); + throw new TAPException("The property \"" + KEY_JDBC_URL + "\" is missing!"); else if (!dbUrl.startsWith(JDBCConnection.JDBC_PREFIX + ":")) throw new TAPException("JDBC URL format incorrect! It MUST begins with " + JDBCConnection.JDBC_PREFIX + ":"); else{ @@ -70,8 +70,8 @@ public final class DefaultTAPFactory extends AbstractTAPFactory { /* 1. Set the ADQLTranslator to use in function of the sql_translator property */ String sqlTranslator = getProperty(tapConfig, KEY_SQL_TRANSLATOR); // case a.) no translator specified - if (sqlTranslator == null || sqlTranslator.isEmpty()) - throw new TAPException("No SQL translator specified !"); + if (sqlTranslator == null) + throw new TAPException("The property \"" + KEY_SQL_TRANSLATOR + "\" is missing! ADQL queries can not be translated without it. Allowed values: \"" + VALUE_POSTGRESQL + "\", \"" + VALUE_PGSPHERE + "\" or a class path of a class implementing SQLTranslator."); // case b.) PostgreSQL translator else if (sqlTranslator.equalsIgnoreCase(VALUE_POSTGRESQL)) diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java index 4c9debc..96f42fb 100644 --- a/src/tap/config/TAPConfiguration.java +++ b/src/tap/config/TAPConfiguration.java @@ -53,6 +53,12 @@ public final class TAPConfiguration { public final static String KEY_DB_USERNAME = "db_username"; public final static String KEY_DB_PASSWORD = "db_password"; + /* METADATA KEYS */ + public final static String KEY_METADATA = "metadata"; + public final static String VALUE_XML = "xml"; + public final static String VALUE_DB = "db"; + public final static String KEY_METADATA_FILE = "metadata_file"; + /* PROVIDER KEYS */ public final static String KEY_PROVIDER_NAME = "provider_name"; public final static String KEY_SERVICE_DESCRIPTION = "service_description"; @@ -74,9 +80,11 @@ public final class TAPConfiguration { public final static String KEY_MAX_OUTPUT_LIMIT = "output_max_limit"; /** - * Read the asked property from the given Properties object. - * - The returned property value is trimmed (no space at the beginning and at the end of the string). - * - If the value is empty (length=0), NULL is returned. + * <p>Read the asked property from the given Properties object.</p> + * <ul> + * <li>The returned property value is trimmed (no space at the beginning and at the end of the string).</li> + * <li>If the value is empty (length=0), NULL is returned.</li> + * </ul> * * @param prop List of property * @param key Property whose the value is requested. @@ -242,7 +250,7 @@ public final class TAPConfiguration { FileInputStream configFileStream = null; try{ - final File configFile = new File("src/ext/tap_min.properties"); + final File configFile = new File("src/tap/config/tap_min.properties"); configFileStream = new FileInputStream(configFile); Properties config = new Properties(); diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html index 30d3d6b..94954c4 100644 --- a/src/tap/config/tap_configuration_file.html +++ b/src/tap/config/tap_configuration_file.html @@ -161,6 +161,19 @@ <td></td> </tr> <tr class="mandatory"> + <td class="done">sql_translator</td> + <td>M</td> + <td>text</td> + <td> + <p>The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension.</p> + <p>The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator + (even if it does not have spatial features), by providing a path to a class (within brackets: {...}) that implements ADQLTranslator and which have at least an empty constructor.</p> + </td> + <td><ul><li>postgres</li><li>pgsphere</li><li>{apackage.MyADQLTranslator}</li></ul></td> + </tr> + + <tr><td colspan="5">Metadata</td></tr> + <!-- tr class="mandatory"> <td class="later">db_tables</td> <td>M</td> <td>text</td> @@ -171,17 +184,30 @@ This list is not mandatory, but if provided it must be within parenthesis and comma separated.</p> </td> <td>schema1.*, schema2.table1, table2, table3(col1, col2, col4, ...)</td> - </tr> + </tr --> <tr class="mandatory"> - <td class="done">sql_translator</td> + <td class="done">metadata</td> <td>M</td> <td>text</td> <td> - <p>The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension.</p> - <p>The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator - (even if it does not have spatial features), by providing a path to a class (within brackets: {...}) that implements ADQLTranslator and which have at least an empty constructor.</p> + <p>Define the way the library must get the list of all schemas, tables and columns to publish and all their metadata (e.g. utype, description, type, ...)</p> + <p>In its current state, the library proposes two methods:</p> + <ol> + <li>Parse a TableSet XML document and load its content into the database schema TAP_SCHEMA (note: this schema is first erased and rebuilt by the library).</li> + <li>Get all metadata from the database schema TAP_SCHEMA.</li> + </ol> </td> - <td><ul><li>postgres</li><li>pgsphere</li><li>{apackage.MyADQLTranslator}</li></ul></td> + <td><ul><li>xml</li><li>db</li></ul> + </tr> + <tr> + <td class="done">metadata_file</td> + <td></td> + <td>text</td> + <td> + <p><b>Mandatory if</b> the value of "metadata" is "xml".</p> + <p>Local file path to the TableSet XML document. This XML must implement the schema TableSet defined by <a href="http://www.ivoa.net/xml/VODataService/v1.1">VODataService</a>.</p> + </td> + <td>/home/foo/my_metadata.xml</td> </tr> <tr><td colspan="5">Files</td></tr> diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties index c12b283..886c6a2 100644 --- a/src/tap/config/tap_full.properties +++ b/src/tap/config/tap_full.properties @@ -2,7 +2,7 @@ # FULL TAP CONFIGURATION FILE # # # # TAP Version: 2.0 # -# Date: 27 Jan. 2015 # +# Date: 09 Feb. 2015 # # Author: Gregory Mantelet (ARI) # # # # See the TAP documentation for more details: ...TODO... # @@ -56,17 +56,6 @@ db_username = # Note: No password encryption can be done in this configuration file for the moment. db_password = -# [MANDATORY] -# List all tables that must be accessed thanks to this TAP Service. -# -# Table names must be separated by a comma. A table name may explicitly specify the schema (if not, the table will be considered as part of the "public" schema). -# -# For each table, you can restrict the list of columns that you to expose via the TAP Service. This list is not mandatory, but if provided it must be -# within parenthesis and comma separated. -# -# Example: schema1.*, schema2.table1, table2, table3(col1, col2, col4, ...) -db_tables = - # [MANDATORY] # The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension. # The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator @@ -75,6 +64,23 @@ db_tables = # Allowed values: postgres, pgsphere, a class path sql_translator = postgres +############ +# METADATA # +############ + +# [MANDATORY] +# Metadata fetching method. The value of this key defines the way the library will get the list of all schemas, tables and columns to publish and all their metadata (e.g. utype, description, type, ...) +# In its current state, the library proposes two methods: +# 1/ Parse a TableSet XML document and load its content into the database schema TAP_SCHEMA (note: this schema is first erased and rebuilt by the library). +# 2/ Get all metadata from the database schema TAP_SCHEMA. +# Allowed values: xml, db. +metadata = + +# [MANDATORY] +# Mandatory if the value of "metadata" is "xml". +# Local file path to the TableSet XML document. This XML must implement the schema TableSet defined by VODataService (http://www.ivoa.net/xml/VODataService/v1.1). +metadata_file = + ######### # FILES # ######### diff --git a/src/tap/config/tap_min.properties b/src/tap/config/tap_min.properties index 29de929..62dffb5 100644 --- a/src/tap/config/tap_min.properties +++ b/src/tap/config/tap_min.properties @@ -1,8 +1,8 @@ ########################################################## # MINIMUM TAP CONFIGURATION FILE # # # -# TAP Version: 1.1 # -# Date: 20 Nov. 2013 # +# TAP Version: 2.0 # +# Date: 09 Feb. 2015 # # Author: Gregory Mantelet (ARI) # # # # See the TAP documentation for more details: ...TODO... # @@ -30,17 +30,7 @@ db_user = # Mandatory if the password is not already provided in jdbc_url # Password used by db_username to access to the database. # Note: No password encryption can be done in this configuration file for the moment. -db_password = - -# List all tables that must be accessed thanks to this TAP Service. -# -# Table names must be separated by a comma. A table name may explicitly specify the schema (if not, the table will be considered as part of the "public" schema). -# -# For each table, you can restrict the list of columns that you to expose via the TAP Service. This list is not mandatory, but if provided it must be -# within parenthesis and comma separated. -# -# Example: schema1.*, schema2.table1, table2, table3(col1, col2, col4, ...) -db_tables = +db_password = # The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension. # The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator @@ -49,6 +39,21 @@ db_tables = # Allowed values: postgres, pgsphere, a class path sql_translator = postgres +############ +# METADATA # +############ + +# Metadata fetching method. The value of this key defines the way the library will get the list of all schemas, tables and columns to publish and all their metadata (e.g. utype, description, type, ...) +# In its current state, the library proposes two methods: +# 1/ Parse a TableSet XML document and load its content into the database schema TAP_SCHEMA (note: this schema is first erased and rebuilt by the library). +# 2/ Get all metadata from the database schema TAP_SCHEMA. +# Allowed values: xml, db. +metadata = + +# Mandatory if the value of "metadata" is "xml". +# Local file path to the TableSet XML document. This XML must implement the schema TableSet defined by VODataService (http://www.ivoa.net/xml/VODataService/v1.1). +metadata_file = + ######### # FILES # ######### diff --git a/test/tap/config/AllTests.java b/test/tap/config/AllTests.java index e3a5b98..dffc3cf 100644 --- a/test/tap/config/AllTests.java +++ b/test/tap/config/AllTests.java @@ -18,8 +18,8 @@ public class AllTests { validProp.setProperty("jdbc_driver", "org.postgresql.Driver"); validProp.setProperty("db_username", "gmantele"); validProp.setProperty("db_password", "pwd"); - validProp.setProperty("db_tables", ""); validProp.setProperty("sql_translator", "postgres"); + validProp.setProperty("metadata", "db"); validProp.setProperty("file_manager", "local"); validProp.setProperty("file_root_path", "bin/ext/test/tap"); return validProp; diff --git a/test/tap/config/TestDefaultServiceConnection.java b/test/tap/config/TestDefaultServiceConnection.java index 03465f7..fc0cd96 100644 --- a/test/tap/config/TestDefaultServiceConnection.java +++ b/test/tap/config/TestDefaultServiceConnection.java @@ -7,14 +7,19 @@ import static org.junit.Assert.fail; import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_FILE_MANAGER; import static tap.config.TAPConfiguration.KEY_MAX_OUTPUT_LIMIT; +import static tap.config.TAPConfiguration.KEY_METADATA; +import static tap.config.TAPConfiguration.KEY_METADATA_FILE; import static tap.config.TAPConfiguration.KEY_OUTPUT_FORMATS; import static tap.config.TAPConfiguration.VALUE_CSV; +import static tap.config.TAPConfiguration.VALUE_DB; import static tap.config.TAPConfiguration.VALUE_JSON; import static tap.config.TAPConfiguration.VALUE_LOCAL; import static tap.config.TAPConfiguration.VALUE_SV; import static tap.config.TAPConfiguration.VALUE_TSV; +import static tap.config.TAPConfiguration.VALUE_XML; import java.io.File; +import java.io.PrintWriter; import java.util.Properties; import org.junit.Before; @@ -28,10 +33,14 @@ import uws.service.file.LocalUWSFileManager; public class TestDefaultServiceConnection { + private final static String XML_FILE = "test/tap/config/tables.xml"; + private Properties validProp, noFmProp, fmClassPathProp, incorrectFmProp, - validFormatsProp, badSVFormat1Prop, badSVFormat2Prop, - unknownFormatProp, defaultOutputLimitProp, maxOutputLimitProp, - bothOutputLimitGoodProp, bothOutputLimitBadProp; + xmlMetaProp, missingMetaProp, missingMetaFileProp, wrongMetaProp, + wrongMetaFileProp, validFormatsProp, badSVFormat1Prop, + badSVFormat2Prop, unknownFormatProp, defaultOutputLimitProp, + maxOutputLimitProp, bothOutputLimitGoodProp, + bothOutputLimitBadProp; @Before public void setUp() throws Exception{ @@ -47,6 +56,24 @@ public class TestDefaultServiceConnection { incorrectFmProp = (Properties)validProp.clone(); incorrectFmProp.setProperty(KEY_FILE_MANAGER, "foo"); + xmlMetaProp = (Properties)validProp.clone(); + xmlMetaProp.setProperty(KEY_METADATA, VALUE_XML); + xmlMetaProp.setProperty(KEY_METADATA_FILE, XML_FILE); + + missingMetaProp = (Properties)validProp.clone(); + missingMetaProp.remove(KEY_METADATA); + + wrongMetaProp = (Properties)validProp.clone(); + wrongMetaProp.setProperty(KEY_METADATA, "foo"); + + wrongMetaFileProp = (Properties)validProp.clone(); + wrongMetaFileProp.setProperty(KEY_METADATA, VALUE_XML); + wrongMetaFileProp.setProperty(KEY_METADATA_FILE, "foo"); + + missingMetaFileProp = (Properties)validProp.clone(); + missingMetaFileProp.setProperty(KEY_METADATA, VALUE_XML); + missingMetaFileProp.remove(KEY_METADATA_FILE); + validFormatsProp = (Properties)validProp.clone(); validFormatsProp.setProperty(KEY_OUTPUT_FORMATS, VALUE_JSON + "," + VALUE_CSV + " , " + VALUE_TSV + ",, , " + VALUE_SV + "([])" + ", " + VALUE_SV + "(|):text/psv:psv" + ", " + VALUE_SV + "($)::test" + ", \t " + VALUE_SV + "(@):text/arobase:"); @@ -95,18 +122,89 @@ public class TestDefaultServiceConnection { @Test public void testDefaultServiceConnectionProperties(){ // Valid Configuration File: + PrintWriter writer = null; + int nbSchemas = -1, nbTables = -1; try{ + // build the ServiceConnection: ServiceConnection connection = new DefaultServiceConnection(validProp); + + // tests: + assertNotNull(connection.getLogger()); + assertNotNull(connection.getFileManager()); + assertNotNull(connection.getFactory()); + assertNotNull(connection.getTAPMetadata()); + assertTrue(connection.getTAPMetadata().getNbSchemas() >= 1); + assertTrue(connection.getTAPMetadata().getNbTables() >= 5); + assertTrue(connection.isAvailable()); + assertTrue(connection.getRetentionPeriod()[0] <= connection.getRetentionPeriod()[1]); + assertTrue(connection.getExecutionDuration()[0] <= connection.getExecutionDuration()[1]); + + // finally, save metadata in an XML file for the other tests: + writer = new PrintWriter(new File(XML_FILE)); + connection.getTAPMetadata().write(writer); + nbSchemas = connection.getTAPMetadata().getNbSchemas(); + nbTables = connection.getTAPMetadata().getNbTables(); + + }catch(Exception e){ + fail("This MUST have succeeded because the property file is valid! \nCaught exception: " + getPertinentMessage(e)); + }finally{ + if (writer != null) + writer.close(); + } + + // Valid XML metadata: + try{ + ServiceConnection connection = new DefaultServiceConnection(xmlMetaProp); assertNotNull(connection.getLogger()); assertNotNull(connection.getFileManager()); assertNotNull(connection.getFactory()); + assertNotNull(connection.getTAPMetadata()); + assertEquals(nbSchemas, connection.getTAPMetadata().getNbSchemas()); + assertEquals(nbTables, connection.getTAPMetadata().getNbTables()); assertTrue(connection.isAvailable()); assertTrue(connection.getRetentionPeriod()[0] <= connection.getRetentionPeriod()[1]); assertTrue(connection.getExecutionDuration()[0] <= connection.getExecutionDuration()[1]); }catch(Exception e){ + e.printStackTrace(); fail("This MUST have succeeded because the property file is valid! \nCaught exception: " + getPertinentMessage(e)); } + // Missing metadata property: + try{ + new DefaultServiceConnection(missingMetaProp); + fail("This MUST have failed because the property 'metadata' is missing!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "The property \"" + KEY_METADATA + "\" is missing! It is required to create a TAP Service. Two possible values: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA)."); + } + + // Missing metadata_file property: + try{ + new DefaultServiceConnection(missingMetaFileProp); + fail("This MUST have failed because the property 'metadata_file' is missing!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "The property \"" + KEY_METADATA_FILE + "\" is missing! According to the property \"" + KEY_METADATA + "\", metadata must be fetched from an XML document. The local file path of it MUST be provided using the property \"" + KEY_METADATA_FILE + "\"."); + } + + // Wrong metadata property: + try{ + new DefaultServiceConnection(wrongMetaProp); + fail("This MUST have failed because the property 'metadata' has a wrong value!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "Unsupported value for the property \"" + KEY_METADATA + "\": \"foo\"! Only two values are allowed: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA)."); + } + + // Wrong metadata_file property: + try{ + new DefaultServiceConnection(wrongMetaFileProp); + fail("This MUST have failed because the property 'metadata_file' has a wrong value!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "A grave error occurred while reading/parsing the TableSet XML document: \"foo\"!"); + } + // No File Manager: try{ new DefaultServiceConnection(noFmProp); @@ -122,6 +220,7 @@ public class TestDefaultServiceConnection { assertNotNull(connection.getLogger()); assertNotNull(connection.getFileManager()); assertNotNull(connection.getFactory()); + assertNotNull(connection.getTAPMetadata()); assertTrue(connection.isAvailable()); /* Retention periods and execution durations are different in this configuration file from the valid one (validProp). diff --git a/test/tap/config/TestDefaultTAPFactory.java b/test/tap/config/TestDefaultTAPFactory.java index 895d558..69d7eee 100644 --- a/test/tap/config/TestDefaultTAPFactory.java +++ b/test/tap/config/TestDefaultTAPFactory.java @@ -10,6 +10,8 @@ import static tap.config.TAPConfiguration.KEY_DB_USERNAME; import static tap.config.TAPConfiguration.KEY_JDBC_DRIVER; import static tap.config.TAPConfiguration.KEY_JDBC_URL; import static tap.config.TAPConfiguration.KEY_SQL_TRANSLATOR; +import static tap.config.TAPConfiguration.VALUE_PGSPHERE; +import static tap.config.TAPConfiguration.VALUE_POSTGRESQL; import java.io.File; import java.util.Collection; @@ -37,7 +39,8 @@ import adql.db.FunctionDef; public class TestDefaultTAPFactory { private Properties validProp, noJdbcProp1, noJdbcProp2, badJdbcProp, - badTranslatorProp, badDBNameProp, badUsernameProp, badPasswordProp; + missingTranslatorProp, badTranslatorProp, badDBNameProp, + badUsernameProp, badPasswordProp; private ServiceConnection serviceConnection = null; @@ -59,6 +62,9 @@ public class TestDefaultTAPFactory { badJdbcProp.setProperty(KEY_JDBC_DRIVER, "foo"); badJdbcProp.setProperty(KEY_JDBC_URL, "jdbc:foo:gmantele"); + missingTranslatorProp = (Properties)validProp.clone(); + missingTranslatorProp.remove(KEY_SQL_TRANSLATOR); + badTranslatorProp = (Properties)validProp.clone(); badTranslatorProp.setProperty(KEY_SQL_TRANSLATOR, "foo"); @@ -108,6 +114,15 @@ public class TestDefaultTAPFactory { assertTrue(ex.getMessage().matches("Impossible to find the JDBC driver \"[^\\\"]*\" !")); } + // Missing Translator: + try{ + new DefaultTAPFactory(serviceConnection, missingTranslatorProp); + fail("This MUST have failed because the provided SQL translator is missing!"); + }catch(Exception ex){ + assertEquals(TAPException.class, ex.getClass()); + assertTrue(ex.getMessage().matches("The property \"" + KEY_SQL_TRANSLATOR + "\" is missing! ADQL queries can not be translated without it. Allowed values: \"" + VALUE_POSTGRESQL + "\", \"" + VALUE_PGSPHERE + "\" or a class path of a class implementing SQLTranslator.")); + } + // Bad Translator: try{ new DefaultTAPFactory(serviceConnection, badTranslatorProp); -- GitLab