From c3e97e6e7ef2567f4905e0813dd0b86892ec4d90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gr=C3=A9gory=20Mantelet?=
Let process completely an ADQL query. Thus, this class aims to apply the following actions (in the given order):
* This executor is able to process queries coming from a synchronous job (the result must be written directly in the HTTP response)
* and from an asynchronous job (the result must be written, generally, in a file). Two start(...) functions let deal with
* the differences between the two job execution modes: {@link #start(AsyncThread)} for asynchronous jobs
* and {@link #start(Thread, String, TAPParameters, HttpServletResponse)} for synchronous jobs.
* Uploaded tables must be provided in VOTable format.
* Query results must be formatted in the format specified by the user in the job parameters. A corresponding formatter ({@link OutputFormat})
* is asked to the description of the TAP service ({@link ServiceConnection}). If none can be found, VOTable will be chosen by default.
* It is totally possible to customize some parts of the ADQL query processing. However, the main algorithm must remain the same and is implemented
* by {@link #start()}. This function is final, like {@link #start(AsyncThread)} and {@link #start(Thread, String, TAPParameters, HttpServletResponse)},
* which are just preparing the execution for {@link #start()} in function of the job execution mode (asynchronous or synchronous).
* Note:
* {@link #start()} is using the Template Method Design Pattern: it defines the skeleton/algorithm of the processing, and defers some steps
* to other functions.
*
* So, you are able to customize almost all individual steps of the ADQL query processing: {@link #parseADQL()}, {@link #executeADQL(ADQLQuery)} and
* {@link #writeResult(TableIterator, OutputFormat, OutputStream)}.
* Note:
* Note that the formatting of the result is done by an OutputFormat and that the executor is just calling the appropriate function of the formatter.
*
* There is no way in this executor to customize the upload. However, it does not mean it can not be customized.
* Indeed you can do it easily by extending {@link Uploader} and by providing the new class inside your {@link TAPFactory} implementation
* (see {@link TAPFactory#createUploader(DBConnection)}).
* Get the report of the query execution. It helps indicating the execution progression and the duration of each step. Note:
* Before starting the execution (= before the call of a "start(...)" function), this function will return NULL.
* It is set when the query processing starts and remains not NULL after that (even when the execution is finished).
* Get the object to use in order to write the query result in the appropriate format
* (either the asked one, or else VOTable). Start the asynchronous processing of the ADQL query.
* This function initialize the execution report, get the execution parameters (including the query to process)
* and then call {@link #start()}.
* Create the database connection required for the ADQL execution. Note: This function has no effect if the DB connection already exists. Start the synchronous processing of the ADQL query. This function initialize the execution report and then call {@link #start()}. Process the ADQL query. This function calls the following function (in the same order):
* The execution report is updated gradually. Besides a job parameter - progression - is set at each step of the process in order to
* notify the user of the progression of the query execution. This parameter is removed at the end of the execution if it is successful.
* The "interrupted" flag of the associated thread is often tested so that stopping the execution as soon as possible. Memorize the time at which the step starts, the step ID and update the job parameter "progression"
* (to notify the user about the progression of the query processing). Note:
* If for some reason the job parameter "progression" can not be updated, no error will be thrown. A WARNING message
* will be just written in the log.
* Note:
* This function is designed to work with {@link #endStep()}, which must be called after it, when the step is finished (successfully or not).
* Set the duration of the current step in the execution report. Note:
* The start time and the ID of the step are then forgotten.
* Note:
* This function is designed to work with {@link #startStep(ExecutionProgression)}, which must be called before it, when the step is starting.
* It marks the end of a step.
* Create in the "database" all tables uploaded by the user (only for this specific query execution). Note:
* Obviously, nothing is done if no table has been uploaded.
* Parse the ADQL query provided in the parameters by the user. The query factory and the query checker are got from the TAP factory.
* The configuration of this TAP service list all allowed coordinate systems. These are got here and provided to the query checker
* in order to ensure the coordinate systems used in the query are in this list.
*
* The row limit specified in the ADQL query (with TOP) is checked and adjusted (if needed). Indeed, this limit
* can not exceed MAXREC given in parameter and the maximum value specified in the configuration of this TAP service.
* In the case no row limit is specified in the query or the given value is greater than MAXREC, (MAXREC+1) is used by default.
* The "+1" aims to detect overflows.
* Execute in "database" the given object representation of an ADQL query. By default, this function is just calling {@link DBConnection#executeQuery(ADQLQuery)} and then it returns the value returned by this call. Note:
* An INFO message is logged at the end of the query execution in order to report the result status (success or error)
* and the execution duration.
* Write the given query result into the appropriate format in the appropriate output
* (HTTP response for a synchronous execution, otherwise a file or any output provided by UWS). This function prepare the output in function of the execution type (synchronous or asynchronous).
* Once prepared, the result, the output and the formatter to use are given to {@link #writeResult(TableIterator, OutputFormat, OutputStream)}
* which will really process the result formatting and writing.
* Format and write the given result in the given output with the given formatter. By default, this function is just calling {@link OutputFormat#writeResult(TableIterator, OutputStream, TAPExecutionReport, Thread)}. Note:
* {@link OutputFormat#writeResult(TableIterator, OutputStream, TAPExecutionReport, Thread)} is often testing the "interrupted" flag of the
* thread in order to stop as fast as possible if the user has cancelled the job or if the thread has been interrupted for another reason.
* Drop all tables uploaded by the user from the database. Note:
* By default, if an error occurs while dropping a table from the database, the error will just be logged ; it won't be thrown/propagated.
*
*
- *
+ *
* Job execution mode
- *
+ *
* Input/Output formats
- *
+ *
* Executor customization
- *
+ *
*
*
- *
+ *
*
This function tells whether TAP-Lib should automatically try to fix a + * query whose parsing failed because of a token error. After this fix + * attempt the query is parsed again for a last time.
+ * + * @return true to allow automatic fix attempt in case of error, + * false to disable this option. + * + * @since 2.3 + */ + public boolean fixOnFailEnabled(); + } diff --git a/src/tap/TAPExecutionReport.java b/src/tap/TAPExecutionReport.java index fe2733f0..5e4db034 100644 --- a/src/tap/TAPExecutionReport.java +++ b/src/tap/TAPExecutionReport.java @@ -1,49 +1,66 @@ package tap; +import adql.db.DBColumn; + /* * This file is part of TAPLibrary. - * + * * TAPLibrary 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, either version 3 of the License, or * (at your option) any later version. - * + * * TAPLibrary 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. - * + * * You should have received a copy of the GNU Lesser General Public License * along with TAPLibrary. If not, seeReport the execution (including the parsing and the output writing) of an ADQL query. - * It gives information on the job parameters, the job ID, whether it is a synchronous task or not, times of each execution step (uploading, parsing, executing and writing), - * the resulting columns and the success or not of the execution.
- * - *This report is completely filled by {@link ADQLExecutor}, and aims to be used/read only at the end of the job or when it is definitely finished.
- * + * Report the execution (including the parsing and the output writing) of an + * ADQL query. + * + *+ * It gives information on the job parameters, the job ID, whether it is a + * synchronous task or not, times of each execution step (uploading, parsing, + * executing and writing), the resulting columns and the success or not of the + * execution. + *
+ * + *+ * This report is completely filled by {@link ADQLExecutor}, and aims to be + * used/read only at the end of the job or when it is definitely finished. + *
+ * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (04/2015) + * @version 2.3 (03/2019) */ public class TAPExecutionReport { /** ID of the job whose the execution is reported here. */ public final String jobID; - /** Indicate whether this execution is done in a synchronous or asynchronous job. */ + /** Indicate whether this execution is done in a synchronous or asynchronous + * job. */ public final boolean synchronous; /** List of all parameters provided in the user request. */ public final TAPParameters parameters; + /** Input ADQL query after an automatic fix by TAP-Lib. + *This field is set only if the option fix_on_fail is enabled in the TAP + * configuration and that a query has been fixed.
+ * @since 2.3 */ + public String fixedQuery = null; + /** List of all resulting columns. Empty array, if not yet known. */ public DBColumn[] resultingColumns = new DBColumn[0]; @@ -51,21 +68,26 @@ public class TAPExecutionReport { * @since 2.0 */ public long nbRows = -1; - /** Duration of all execution steps. For the moment only 4 steps (in the order): uploading, parsing, executing and writing. */ - protected final long[] durations = new long[]{-1,-1,-1,-1}; + /** Duration of all execution steps. For the moment only 4 steps (in the + * order): uploading, parsing, executing and writing. */ + protected final long[] durations = new long[]{ -1, -1, -1, -1 }; /** Total duration of the job execution. */ protected long totalDuration = -1; - /** Indicate whether this job has ended successfully or not. At the beginning or while executing, this field is always FALSE. */ + /** Indicate whether this job has ended successfully or not. + * At the beginning or while executing, this field is always FALSE. */ public boolean success = false; /** * Build an empty execution report. - * - * @param jobID ID of the job whose the execution must be described here. - * @param synchronous true if the job is synchronous, false otherwise. - * @param params List of all parameters provided by the user for the execution. + * + * @param jobID ID of the job whose the execution must be described + * here. + * @param synchronous true if the job is synchronous, + * false otherwise. + * @param params List of all parameters provided by the user for the + * execution. */ public TAPExecutionReport(final String jobID, final boolean synchronous, final TAPParameters params){ this.jobID = jobID; @@ -74,14 +96,20 @@ public TAPExecutionReport(final String jobID, final boolean synchronous, final T } /** - *Map the execution progression with an index inside the {@link #durations} array.
- * - *Warning: for the moment, only {@link ExecutionProgression#UPLOADING}, {@link ExecutionProgression#PARSING}, - * {@link ExecutionProgression#EXECUTING_ADQL} and {@link ExecutionProgression#WRITING_RESULT} are managed.
- * + * Map the execution progression with an index inside the {@link #durations} + * array. + * + *Warning: + * for the moment, only {@link ExecutionProgression#UPLOADING}, + * {@link ExecutionProgression#PARSING}, + * {@link ExecutionProgression#EXECUTING_ADQL} and + * {@link ExecutionProgression#WRITING_RESULT} are managed. + *
+ * * @param tapProgression Execution progression. - * - * @return Index in the array {@link #durations}, or -1 if the given execution progression is not managed. + * + * @return Index in the array {@link #durations}, + * or -1 if the given execution progression is not managed. */ protected int getIndexDuration(final ExecutionProgression tapProgression){ switch(tapProgression){ @@ -100,11 +128,12 @@ protected int getIndexDuration(final ExecutionProgression tapProgression){ /** * Get the duration corresponding to the given job execution step. - * + * * @param tapStep Job execution step. - * - * @return The corresponding duration (in ms), or -1 if this step has not been (yet) processed. - * + * + * @return The corresponding duration (in ms), or -1 if this step has not + * been (yet) processed. + * * @see #getIndexDuration(ExecutionProgression) */ public final long getDuration(final ExecutionProgression tapStep){ @@ -117,7 +146,7 @@ public final long getDuration(final ExecutionProgression tapStep){ /** * Set the duration corresponding to the given execution step. - * + * * @param tapStep Job execution step. * @param duration Duration (in ms) of the given execution step. */ diff --git a/src/tap/config/ConfigurableServiceConnection.java b/src/tap/config/ConfigurableServiceConnection.java index 09e2ce7d..f9213925 100644 --- a/src/tap/config/ConfigurableServiceConnection.java +++ b/src/tap/config/ConfigurableServiceConnection.java @@ -16,13 +16,14 @@ * You should have received a copy of the GNU Lesser General Public License * along with TAPLibrary. If not, seeConcrete implementation of {@link ServiceConnection}, fully parameterized with a TAP configuration file.
+ * Concrete implementation of {@link ServiceConnection}, fully parameterized + * with a TAP configuration file. * *- * Every aspects of the TAP service are configured here. This instance is also creating the {@link TAPFactory} using the - * TAP configuration file thanks to the implementation {@link ConfigurableTAPFactory}. + * Every aspects of the TAP service are configured here. This instance is also + * creating the {@link TAPFactory} using the TAP configuration file thanks to + * the implementation {@link ConfigurableTAPFactory}. *
* * @author Grégory Mantelet (CDS;ARI) - * @version 2.3 (11/2018) + * @version 2.3 (03/2019) * @since 2.0 */ public final class ConfigurableServiceConnection implements ServiceConnection { @@ -142,10 +146,12 @@ public final class ConfigurableServiceConnection implements ServiceConnection { /** File manager to use in the TAP service. */ private UWSFileManager fileManager; - /** Object to use in the TAP service in order to log different types of messages (e.g. DEBUG, INFO, WARNING, ERROR, FATAL). */ + /** Object to use in the TAP service in order to log different types of + * messages (e.g. DEBUG, INFO, WARNING, ERROR, FATAL). */ private TAPLog logger; - /** Factory which can create different types of objects for the TAP service (e.g. database connection). */ + /** Factory which can create different types of objects for the TAP service + * (e.g. database connection). */ private TAPFactory tapFactory; /** Object gathering all metadata of this TAP service. */ @@ -175,9 +181,11 @@ public final class ConfigurableServiceConnection implements ServiceConnection { private final ArrayListIf enabled, this option lets automatically try fixing a query whose parsing + failed because of a token error. This is particularly useful in the following + cases:
+_RAJ2000
, 2mass
)distance
, point
, min
)public
, date
, year
, user
)In all these cases, the name/identifier/alias will be surrounded between
+ double quotes if the option fix_on_fail
is enabled.
This feature is also able to fix some incorrect Unicode characters + (e.g. LaTeX alternatives for underscores, spaces and double/single quotes, + copy-pasted from a PDF into a TAP query field).
+Warning: + since this option alters the query provided by the query, it is + possible that, after fix attempt, the query parses and runs but might + generate an output different from what was expected. So, if this + option is enabled, it should made be clear to the user that the TAP + server might alter the query to make it work. +
+Note:
+ when an input query is fixed and run successfully, the fixed ADQL query
+ is reported in an INFO element named QUERY_AFTER_AUTO_FIX
inside the
+ output VOTable.
+
Default: fix_on_fail=false
/examples
endpoint by specifying an
-# XHTML-RDFa document listing TAP query examples using the syntax specified by
-# TAPNotes 1.0 DALI 1.0.
-#
-# 3 different kinds of value are accepted:
-# * nothing (default): no /examples endpoint.
-# * name or relative path of a file: this method MUST be chosen if the
-# endpoint content is a JSP file. This file MUST be inside the directory
-# WebContent of your web application.
-# * URI starting with file://: in this method the local file pointed by the
-# URI will be merely returned when the endpoint will be requested.
-# * a URL: here, a redirection toward this URL will be made at each request
-# on the endpoint
-#
-# If you want a custom /examples endpoint (i.e. you do not)
-# want to forward/redirect to a file/URL), you can create a class which
-# implements TAPResource AND VOSIResource. The function getName() must return
-# "examples". Then, just append the classpath to the property
-# "additional_resources" of the TAP configuration file.
-#
-# By default, the TAP service does not have any /examples
endpoint.
-examples =
-
-# [OPTIONAL]
-# Comma-separated list of additional TAP resources/end-point.
-#
-# By default, the following standard TAP resources are already existing: /sync,
-# /async, /tables, /capabilities and /availability. With this property, you can
-# add a custom resource to your TAP service (e.g. /adqlValidator, /admin).
-#
-# Each item of the list MUST be the name of a class implementing
-# tap.resource.TAPResource. This class MUST have at least one constructor with
-# exactly one parameter of type tap.resource.TAP.
-#
-# The string returned by tap.resource.TAPResource.getName() will be the
-# resource name, following the root TAP service URL (e.g. if getName() returns
-# "foo", then its access URL will "{tapRoot}/foo"). Then, it is possible to
-# replace TAP resources already existing by using the same name (e.g. if
-# getName() returns "sync", the /sync resource won't be anymore the default Sync
-# resource of this library but your new resource).
-#
-# By default, this list is empty ; only the standard TAP resources exist.
-additional_resources =
-
-######################
-# CUSTOM TAP_FACTORY #
-######################
-
-# [OPTIONAL]
-# Class to use in replacement of the default TAPFactory.
-#
-# This property must be a class name (given between {...}). It must reference an
-# implementation of TAPFactory. This implementation must have at least one
-# constructor with exactly one parameter of type ServiceConnection.
-#
-# It is recommended to extend an existing implementation such as:
-# tap.AbstractTAPFactory or tap.config.ConfigurableTAPFactory.
-#
-# By default, the default TAPFactory (tap.config.ConfigurableTAPFactory) is used
-# and may use all properties related to the backup management, the database
-# access, the TAP_SCHEMA mapping and the ADQL translation.
-tap_factory =
+################################################################################
+# FULL TAP CONFIGURATION FILE #
+# #
+# TAP Version: 2.3 #
+# Date: 20 March. 2019 #
+# Author: Gregory Mantelet (CDS;ARI) #
+# #
+################################################################################
+
+###########
+# GENERAL #
+###########
+
+# [OPTIONAL]
+# This property lets set a custom home page.
+#
+# 4 different kinds of value are accepted:
+# * nothing (default): the default home page provided by the library (just
+# a simple HTML page displaying a list of all available
+# TAP resources).
+# * name or relative path of a file: this method MUST be chosen if the new
+# home page is a JSP file. This file MUST
+# be inside the directory WebContent of
+# your web application.
+# * a URI starting with file://: in this method the local file pointed by
+# the URI will be merely returned when the
+# home page will be requested.
+# * a URL: here, a redirection toward this URL will be made at each request
+# on the home page
+# * a class name: the class name of an extension of tap.resource.HomePage
+# which must replace the default home page resource. This
+# class MUST have at least one constructor with exactly one
+# parameter not NULL of type tap.resource.TAP.
+home_page =
+
+# [OPTIONAL]
+# MIME type of the service home page.
+#
+# This property is used only if the specified "home_page" is a local file path
+# (i.e. if "home_page=file://...").
+#
+# If no value is provided "text/html" will be set by default.
+#
+# Default: text/html
+home_page_mime_type =
+
+############
+# PROVIDER #
+############
+
+# [OPTIONAL]
+# Name of the provider of the TAP Service.
+provider_name = CDS
+
+# [OPTIONAL]
+# Description of the TAP Service.
+service_description = My TAP Service is so amazing! You should use it with your favorite TAP client.
+
+############
+# DATABASE #
+############
+
+# [MANDATORY]
+# Method to use in order to create database connections.
+#
+# Only two values are supported:
+# * jndi: database connections will be supplied by a Datasource whose the
+# JNDI name must be given. This method may propose connection
+# pooling in function of the datasource configuration.
+# * jdbc: the library will create itself connections when they will be
+# needed thanks to the below JDBC parameters. This method does not
+# propose any connection pooling.
+#
+# Allowed values: jndi, jdbc.
+database_access =
+
+# [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 (no spatial extension),
+# PostgreSQL+PgSphere, SQLServer (no spatial extension), MySQL (no spatial
+# extension) and H2 (no spatial extension) for the moment. But you can provide
+# your own SQL translator (even if it does not have spatial features), by
+# providing the name of a class (within brackets: {...}) that implements
+# ADQLTranslator (for instance: {apackage.MyADQLTranslator}) and which have at
+# least an empty constructor.
+#
+# Allowed values: postgres, pgsphere, sqlserver, mysql, h2, a class name
+sql_translator = postgres
+
+# [OPTIONAL]
+# Size of result blocks to fetch from the database when a ADQL query is executed
+# in Synchronous mode.
+#
+# Rather than fetching a query result in a whole, it may be possible to specify
+# to the database that results may be retrieved by blocks whose the size can be
+# specified with this property. If supported by the DBMS and the JDBC driver,
+# this feature may help sparing memory and avoid too much waiting time from the
+# TAP /sync users (and thus, avoiding some HTTP client timeouts).
+#
+# A negative or null value means that the default value of the JDBC driver will
+# be used. Generally, it means that the database must wait to have collected all
+# data before sending them to the library.
+#
+# Default: sync_fetch_size=10000
+sync_fetch_size = 1000
+
+# [OPTIONAL]
+# Size of result blocks to fetch from the database when an ADQL query is
+# executed in Asynchronous mode.
+#
+# Rather than fetching a query result in a whole, it may be possible to specify
+# to the database that results may be retrieved by blocks whose the size can be
+# specified with this property. If supported by the DBMS and the JDBC driver,
+# this feature may help sparing memory.
+#
+# A negative or null value means that the default value of the JDBC driver will
+# be used. Generally, it means that the database must wait to have collected all
+# data before sending them to the library.
+#
+# Default: async_fetch_size=100000
+async_fetch_size = 10000
+
+# [OPTIONAL]
+# If enabled, this option lets automatically try fixing a query whose parsing
+# failed because of a token error. This is particularly useful in the following
+# cases:
+#
+# - when a column/table identifier/alias has an incorrect syntax
+# (e.g. `_RAJ2000`, `2mass`)
+# - if the name of an ADQL function is used as a column/table identifier/alias
+# (e.g. `distance`, `point`, `min`)
+# - if the name of a reserved SQL keyword is used as a column/table
+# identifier/alias
+# (e.g. `public`, `date`, `year`, `user`)
+#
+# In all these cases, the name/identifier/alias will be surrounded between
+# double quotes if the option `fix_on_fail` is enabled.
+#
+# This feature is also able to fix some incorrect Unicode characters
+# (e.g. LaTeX alternatives for underscores, spaces and double/single quotes,
+# copy-pasted from a PDF into a TAP query field).
+#
+# Warning: since this option alters the query provided by the query, it is
+# possible that, after fix attempt, the query parses and runs but might
+# generate an output different from what was expected. So, if this
+# option is enabled, it should made be clear to the user that the TAP
+# server might alter the query to make it work.
+#
+# Note: when an input query is fixed and run successfully, the fixed ADQL query
+# is reported in an INFO element named `QUERY_AFTER_AUTO_FIX` inside the
+# output VOTable.
+#
+# Default: fix_on_fail=false
+fix_on_fail = false
+
+#############################
+# IF DATABASE ACCESS = JNDI #
+#############################
+
+# [MANDATORY]
+# JNDI name of the datasource pointing toward the database to use.
+# It should be defined in the web application (e.g. in the META-INF/context.xml
+# file in tomcat).
+datasource_jndi_name =
+
+#############################
+# IF DATABASE ACCESS = JDBC #
+#############################
+
+# [MANDATORY]
+# JDBC driver URL pointing toward the database to use.
+#
+# Note: The username, password or other parameters may be included in it, but
+# in this case, the corresponding properties should leave empty or not
+# provided at all.
+jdbc_url =
+
+# [OPTIONAL]
+# JDBC driver path.
+#
+# By default, it is guessed in function of the database name provided in the
+# jdbc_url property. It MUST be provided if another DBMS is used or if the
+# JDBC driver path does not match the following ones:
+# * Oracle : oracle.jdbc.OracleDriver
+# * PostgreSQL: org.postgresql.Driver
+# * MySQL : com.mysql.jdbc.Driver
+# * SQLite : org.sqlite.JDBC
+# * H2 : org.h2.Driver
+#jdbc_driver =
+
+# [MANDATORY]
+# [Mandatory if the username is not already provided in jdbc_url]
+#
+# Username used to access to the database.
+db_username =
+
+# [MANDATORY]
+# [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 =
+
+############
+# 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 three 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.
+# 3/ Build yourself the metadata of your service by creating an extension of
+# tap.metadata.TAPMetadata. This extension must have either an empty
+# constructor or a constructor with exactly 3 parameters of type
+# UWSFileManager, TAPFactory and TAPLog ; if both constructor are
+# provided, only the one with parameters will be used.
+#
+# For the two first methods, it is also possible to specify an extension of
+# tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created
+# using the specified methods (i.e. XML tableset or TAP_SCHEMA). In this way, it
+# is possible to get the "default" metadata from an XML file or the database
+# and then add/remove/modify some of them, or to change the output of the
+# 'tables' resource. The extension of tap.metadata.TAPMetadata must have at
+# least one constructor with the following parameters: (TAPMetadata) or
+# (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
+#
+# Allowed values: xml, xml {myTAPMetadata}, db, db {myTAPMetadata}
+# or a full class name (between {}).
+metadata =
+
+# [MANDATORY]
+# [Mandatory if the value of "metadata" is "xml".]
+#
+# Local file path to the TableSet XML document.
+#
+# The XML document must implement the schema TableSet defined by VODataService.
+# The file path must be either an absolute local file path or a file path
+# relative to WebContent (i.e. the web application directory in which there are
+# WEB-INF and META-INF).
+metadata_file =
+
+# [OPTIONAL]
+# [ONLY USED IF metadata = db]
+#
+# Mapping between TAP_SCHEMA ADQL names and their names in the database.
+#
+# Any property named exactly (case sensitive) like TAP_SCHEMA items will be
+# considered as a mapping between its ADQL name and its DB name.
+#
+# Examples: "TAP_SCHEMA = TAP_SCHEMA2"
+# or "TAP_SCHEMA.columns.column_name = name"
+#
+# The property value MUST be NOT qualified. Just the item name is required.
+# The value will be used as provided (with the same case).
+#
+# Note:
+# The column dbName in the database TAP_SCHEMA declaring the standard
+# TAP_SCHEMA entries (e.g. TAP_SCHEMA.schemas.dbName) is now ignored. Thus,
+# only the mapping defined here, in the configuration file, is taken into
+# account.
+#
+# TAP_SCHEMA =
+
+#########
+# FILES #
+#########
+
+# [MANDATORY]
+# Type of the file manager.
+#
+# Accepted values are: local (to manage files on the local system). You can also
+# add another way to manage files by providing the name (within brackets: {...})
+# of a class implementing TAPFileManager and having at least one constructor
+# with only a java.util.Properties parameter.
+#
+# Allowed values: local, a class name.
+file_manager = local
+
+# [MANDATORY]
+# Local file path of the directory in which all TAP files (logs, errors, job
+# results, backup, ...) must be.
+#
+# The file path must be either an absolute local directory path or a directory
+# path relative to WebContent (i.e. the web application directory in which there
+# are WEB-INF and META-INF).
+file_root_path =
+
+# [OPTIONAL]
+# Tells whether a directory should be created for each user.
+#
+# If yes, the user directory will be named with the user ID. In this directory,
+# there will be error files, job results and it may be the backup file of the
+# user.
+#
+# Allowed values: true (default), false.
+directory_per_user = true
+
+# [OPTIONAL]
+# Tells whether user directories must be grouped.
+#
+# If yes, directories are grouped by the first letter found in the user ID.
+#
+# Allowed values: true (default), false.
+group_user_dir = true
+
+# [OPTIONAL]
+# The default period (in seconds) to keep query results.
+#
+# The prefix "default" means here that this value is put by default by the TAP
+# Service if the client does not provide a value for it.
+#
+# The default period MUST be less or equals to the maximum retention period. If
+# this rule is not respected, the default retention period is set immediately to
+# the maximum retention period.
+#
+# A negative or null value means there is no restriction on the default
+# retention period: job results will be kept forever. Float values are not
+# allowed.
+#
+# Default: 0 (results kept forever).
+default_retention_period = 0
+
+# [OPTIONAL]
+# The maximum period (in seconds) to keep query results.
+#
+# The prefix "max" means here that the client can not set a retention period
+# greater than this one.
+#
+# The maximum period MUST be greater or equals to the default retention period.
+# If this rule is not respected, the default retention period is set immediately
+# to the maximum retention period.
+#
+# A negative or null value means there is no restriction on the maximum
+# retention period: the job results will be kept forever. Float values are not
+# allowed.
+#
+# Default: 0 (results kept forever).
+max_retention_period = 0
+
+#############
+# LOG FILES #
+#############
+
+# [OPTIONAL]
+# Logging method to use.
+#
+# Only two possibilities are already implemented.
+#
+# * default: default logger provided by the library. Any logged message
+# will be appended in the file 'service.log' inside the root
+# directory of this service (cf property 'file_root_path').
+#
+# * slf4j: wrapper for SLF4J (https://www.slf4j.org). All log messages will
+# be forwarded to SLF4J. It is up to the implementor to add the
+# suitable JAR files in the Java class-path. Exactly two JAR files
+# are expected by SLF4J to work as expected:
+# - slf4j-api-{version}.jar (the main API)
+# - and the slf4j-{binding}-{version}.jar.
+# Depending on the chosen SLF4J binding, you may also add another
+# JAR file (e.g. Log4J, LogBack, ...) in the Java class-path.
+# A configuration file might also be needed. There, it will be
+# possible to configure the the following loggers:
+# - "tap.service" (general/root purpose log),
+# - "tap.service.UWS" (UWS actions),
+# - "tap.service.HTTP" (HTTP requests and responses),
+# - "tap.service.JOB" (UWS's jobs actions),
+# - "tap.service.THREAD" (job's thread actions),
+# - "tap.service.TAP" (TAP actions)
+# - and "tap.service.DB" (DB actions).
+#
+# * {...}: a custom logger. A class name MUST be provided
+# (between {...}). The specified class must reference
+# an implementation of tap.log.TAPLog. This implementation
+# must have at least one constructor with a single parameter of
+# type uws.service.file.UWSFileManager.
+#
+# Default: 'default' (i.e. tap.log.DefaultTAPLog)
+logger =
+
+# [OPTIONAL]
+# Minimum level that a message must have in order to be logged by the default
+# logger.
+#
+# 5 possible values:
+# * DEBUG: every messages are logged.
+# * INFO: every messages EXCEPT DEBUG are logged.
+# * WARNING: every messages EXCEPT DEBUG and INFO are logged.
+# * ERROR: only ERROR and FATAL messages are logged.
+# * FATAL: only FATAL messages are logged.
+#
+# Note: this property is ignored if `logger != default`.
+#
+# Default: DEBUG (every messages are logged)
+min_log_level =
+
+# [OPTIONAL]
+# Frequency of the log file rotation performed by the default logger.
+# That's to say, logs will be written in a new file after this period. This
+# avoid having too big log files. Old log files are renamed so that highlighting
+# its logging period.
+#
+# The frequency string must respect the following syntax:
+# 'D' hh mm: daily schedule at hh:mm
+# 'W' dd hh mm: weekly schedule at the given day of the week
+# (1:sunday, 2:monday, ..., 7:saturday) at hh:mm
+# 'M' dd hh mm: monthly schedule at the given day of the month at hh:mm
+# 'h' mm: hourly schedule at the given minute
+# 'm': scheduled every minute (for completness :-))
+#
+# Where: hh = integer between 0 and 23,
+# mm = integer between 0 and 59,
+# dd (for 'W') = integer between 1 and 7
+# (1:sunday, 2:monday, ..., 7:saturday),
+# dd (for 'M') = integer between 1 and 31.
+#
+# Warning: The frequency type is case sensitive! Then you should particularly
+# pay attention at the case when using the frequency types 'M'
+# (monthly) and 'm' (every minute).
+#
+# Note 1: this property is ignored if the file manager is not any more an
+# extension of uws.service.file.LocalUWSFileManager.
+#
+# Note 2: this property is ignored if `logger != default`.
+#
+# Default: D 0 0 (daily at midnight)
+log_rotation =
+
+##############
+# UWS_BACKUP #
+##############
+
+# [OPTIONAL]
+# Frequency at which the UWS service (that's to say, all its users and jobs)
+# must be backuped.
+#
+# Allowed values: never (no backup will never be done ; default), user_action
+# (each time a user does a writing action, like creating or
+# execution a job), a time (must be positive and not null) in
+# milliseconds.
+#
+# The value user_action can be used ONLY IF backup_by_user=true.
+#
+# Default: never
+backup_frequency = never
+
+# [OPTIONAL]
+# Tells whether the backup must be one file for every user (false), or one file
+# for each user (true). This second option should be chosen if your TAP Service
+# is organizing its files by user directories ; see the property
+# directory_per_user.
+#
+# This option can be enabled ONLY IF a user identification method is provided ;
+# see property user_identifier.
+#
+# Default: false
+backup_by_user = false
+
+#####################
+# ASYNCHRONOUS JOBS #
+#####################
+
+# [OPTIONAL]
+# Maximum number of asynchronous jobs that can run simultaneously.
+#
+# A negative or null value means there is no restriction on the number of
+# running asynchronous jobs.
+#
+# Default: there is no restriction => max_async_jobs=0.
+max_async_jobs = 0
+
+###################
+# QUERY_EXECUTION #
+###################
+
+# [OPTIONAL]
+# Default time (in milliseconds) for query execution.
+#
+# The prefix "default" means here that the execution duration will be this one
+# if the client does not set one.
+#
+# The default duration MUST be less or equals to the maximum execution duration.
+# If this rule is not respected, the default execution duration is set
+# immediately to the maximum execution duration.
+#
+# A negative or null value means there is no restriction on the default
+# execution duration: the execution could never end. Float values are not
+# allowed.
+#
+# Default: there is no restriction => default_execution_duration=0.
+default_execution_duration = 0
+
+# [OPTIONAL]
+# Maximum time (in milliseconds) for query execution.
+#
+# The prefix "max" means here that the client can not set a time greater than
+# this one.
+#
+# The maximum duration MUST be greater or equals to the default execution
+# duration. If this rule is not respected, the default execution duration is set
+# immediately to the maximum execution duration.
+#
+# A negative or null value means there is no restriction on the maximum
+# execution duration: the execution could never end. Float values are not
+# allowed.
+#
+# Default: there is no restriction => max_execution_duration=0.
+max_execution_duration = 0
+
+##########
+# OUTPUT #
+##########
+
+# [OPTIONAL]
+# Comma separated list of output formats for query results.
+#
+# Allowed values are: votable (or 'vot'), fits, text, csv, tsv, json and html.
+#
+# The VOTable format may be more detailed with the following syntax:
+# (serialization,version):mime_type:short_mime_type.
+# The MIME type part and the parameters part may be omitted
+# (e.g. votable:application/xml:votable , votable(td,1.3)]).
+# Empty string values are allowed for each values (e.g. votable():: ,
+# votable(td)::votable).
+#
+# The default VOTable format (i.e. serialization and version) is the one defined
+# with the short form `votable`. It is be default set to
+# `vot(binary,1.3)::votable` (see the special value `ALL` below). To change it
+# just define a VOTable format with the short form `votable`.
+#
+# It is also possible to define a custom Separated Value format, different from
+# CSV and TSV, thanks to the following syntax:
+# sv(separator):mime_type:short_mime_type. On the contrary to the VOTable
+# syntax, the parameter (i.e. separator) MUST BE provided. The MIME type part
+# may be omitted ; then the MIME type will be set by default to text/plain.
+#
+# There is finally a last possible value: a class name of a class implementing
+# OutputFormat and having at least one constructor with exactly one parameter of
+# type tap.ServiceConnection.
+#
+# The special value "ALL" will select all formats provided by the library. It is
+# equivalent to the following:
+# output_formats = vot(binary,1.3)::votable, vot(td,1.3)::votable/td,
+# vot(binary,1.3)::votable/b, vot(binary2,1.3)::votable/b2,
+# vot(fits,1.3)::votable/fits, fits, csv, tsv, text, html,
+# json
+#
+# Default: ALL
+output_formats = ALL
+
+# [OPTIONAL]
+# Default limit for the result output.
+#
+# The prefix "default" means here that this value will be set if the client does
+# not provide one.
+#
+# This limit can be expressed in only one unit: rows.
+#
+# A negative value means there is no restriction on this limit. Float values are
+# not allowed.
+#
+# Obviously this limit MUST be less or equal than output_max_limit.
+#
+# Default: there is no restriction: output_default_limit=-1
+output_default_limit = -1
+
+# [OPTIONAL]
+# Maximum limit for the result output. The prefix "max" means here that the
+# client can not set a limit greater than this one.
+#
+# This limit can be expressed in only one unit: rows.
+#
+# A negative value means there is no restriction on this limit. Float values are
+# not allowed.
+#
+# Obviously this limit MUST be greater or equal than output_default_limit.
+#
+# Default: there is no restriction => output_max_limit=-1
+output_max_limit = -1
+
+##########
+# UPLOAD #
+##########
+
+# [OPTIONAL]
+# Tells whether the Upload must be enabled.
+#
+# If enabled, files can be uploaded in the file_root_path, the corresponding
+# tables can be added inside the UPLOAD_SCHEMA of the database, queried and then
+# deleted.
+#
+# NOTE: Before being stored in the directory file_root_path, it is first
+# uploaded in the temporary directory (defined in the JVM ; generally
+# `/tmp` on Unix system and `c:\temp` ; it can be changed at start of the
+# JVM with the property `java.io.tmpdir`). When the upload is complete,
+# the file is finally moved in file_root_path.
+#
+# Allowed values: true, false (default).
+upload_enabled = false
+
+# [OPTIONAL]
+# Maximum limit for the number of uploaded records that can be inserted inside
+# the database.
+#
+# This limit can be expressed with 2 types: rows or bytes. For rows, you just
+# have to suffix the value by a "r" (upper- or lower-case), with nothing (by
+# default, nothing will mean "rows"). For bytes, you have to suffix the numeric
+# value by "b", "kb", "Mb" or "Gb". Here, unit is case sensitive (except for the
+# last character: "b"). No other storage unit is allowed.
+#
+# A negative value means there is no restriction on this limit. Float values are
+# not allowed.
+#
+# IMPORTANT NOTE: the specified limit will be checked at a different step of
+# a query processing in function of its unit.
+# If expressed in bytes, the file size will be checked when
+# uploading the file on disk. Thus, when the uploading file
+# starts to exceed the set limit, it will be no longer uploaded
+# and the whole request will be immediately rejected.
+# On the contrary, if the limit is expressed in rows, it will
+# be tested only when ingesting the whole uploaded file
+# (whatever is its size) in the database ; so, after it has been
+# uploaded. As soon as, the rows insertion in the database
+# exceeds the limit, the query is rejected.
+# Consequently, a very huge file could potentially be
+# completely uploaded before being rejected if this property is
+# expressed in rows. Then, it is very important to set the
+# property `upload_max_request_size` limiting the size of a
+# whole HTTP request in order to better preserve your machine
+# from running out of disk space.
+#
+# Default: upload_max_db_limit=1000000r (i.e. 1 million rows)
+upload_max_db_limit = 1000000r
+
+
+# [OPTIONAL]
+# Maximum allowed size for a whole HTTP multipart request (i.e. request with
+# uploads).
+#
+# This limit MUST be expressed in bytes. Thus, you have to suffix the numeric
+# value by "B", "kB", "MB" or "GB". Here, unit is case sensitive. No other
+# storage unit is allowed.
+#
+# A negative value means there is no restriction on this limit. Float values are
+# not allowed.
+#
+# Warning: It is highly recommended to set this property in order to prevent
+# exceeding the disk storage space/quota (especially if
+# `upload_max_db_limit` is not set or is set in rows).
+#
+# Default: upload_max_request_size=250MB
+upload_max_request_size = 250MB
+
+# [OPTIONAL ; DEPRECATED since v2.3]
+# Default limit for the number of uploaded records that can be inserted inside
+# the database.
+#
+# This property is DEPRECATED. You should use `upload_max_db_limit` instead.
+# If it is set anyway, its value will be used as value for
+# `upload_max_db_limit` ONLY IF this latter is not set.
+#
+# Default: upload_default_db_limit=-1 (i.e. unlimited)
+upload_default_db_limit = -1
+
+# [OPTIONAL ; DEPRECATED since v2.3]
+# Maximum allowed size for the uploaded file.
+#
+# This property is DEPRECATED. You should use `upload_max_db_limit` with a value
+# expressed in bytes if you wanted to limit the size of each uploaded file, or
+# `upload_max_request_size` if your goal was to limit the input HTTP request
+# size. If it is set anyway, its value will be used as value for
+# `upload_max_request_size` ONLY IF this latter is not set.
+#
+# Default: upload_max_file_size=-1 (i.e. unlimited)
+upload_max_file_size = -1
+
+#######################
+# USER IDENTIFICATION #
+#######################
+
+# [OPTIONAL]
+# Class to use in order to identify a user of the TAP service.
+#
+# The same instance of this class will be used for every request sent to the
+# service.
+#
+# The value of this property MUST be a class name (with brackets: {...}) of a
+# class implementing the interface uws.service.UserIdentifier. This class MUST
+# have one of its constructors with no parameter.
+#
+# Default: no identification is performed => all users are then anonymous and
+# their jobs can be seen by everybody.
+user_identifier =
+
+######################
+# COORDINATE SYSTEMS #
+######################
+
+# [OPTIONAL]
+# Comma-separated list of all allowed coordinate systems.
+#
+# Each item of the list be a kind of regular expression respecting the following
+# syntax: Frame RefPos Flavor. In other words, it must be a string of exactly 3
+# parts. Each of this part is a single value, a list of allowed values
+# or a * meaning all values. A list of values must be indicated between
+# parenthesis and values must be separated by a pipe.
+#
+# Allowed values for Frame are: ICRS, FK4, FK5, J2000, ECLIPTIC, GALACTIC
+# and UNKNOWNFRAME.
+# Allowed values for RefPos are: BARYCENTER, GEOCENTER, HELIOCENTER, LSR,
+# TOPOCENTER, RELOCATABLE and UNKNOWNREFPOS.
+# Allowed values for Flavor are: CARTESIAN2, CARTESIAN3 and SPHERICAL2.
+#
+# If the special value NONE is given instead of a list of allowed coordinate
+# systems, no coordinate system will be allowed. And if the list is empty, any
+# coordinate system will be allowed.
+#
+# By default, any coordinate system is allowed.
+coordinate_systems =
+
+##############
+# GEOMETRIES #
+##############
+
+# [OPTIONAL]
+# Comma-separated list of all allowed geometries.
+#
+# Each item of the list must be the name (whatever is the case) of an ADQL
+# geometrical function (e.g. INTERSECTS, COORDSYS, POINT) to allow.
+# If the list is empty (no item), all functions are allowed. And if the special
+# value NONE is given, no ADQL function will be allowed.
+#
+# Default: all ADQL geometrical functions are allowed.
+geometries =
+
+#################################
+# USER DEFINED FUNCTIONS (UDFs) #
+#################################
+
+# [OPTIONAL]
+# Comma-separated list of all allowed UDFs (User Defined Functions).
+#
+# Each item of the list must have the following syntax: [fct_signature],
+# [fct_signature, className] or [fct_signature, className, description].
+# fct_function is the function signature. Its syntax is the same as in
+# TAPRegExt. className is the name of a class extending UserDefinedFunction.
+# An instance of this class will replace any reference of a UDF written in an
+# ADQL function with the associated signature. A class name must be specified if
+# the function to represent has a signature (and more particularly a name)
+# different in ADQL and in SQL. description is the human description of the
+# function to be displayed in the /capabilities of the TAP service. It must be
+# written between double quotes.
+#
+# Example: udfs = [ivo_healpix_index(hpxOrder integer, ra double, dec double)
+# -> bigint, {adql.query.operand.function.healpix.HealpixIndex}
+# , "Compute the index of the \"Healpix cell\" containing the
+# specified position at the given Healpix order."],
+# [trim(txt String) -> String],
+# [newFct(x double)->double, {apackage.MyNewFunction}],
+# [random() -> DOUBLE,,"Generate a random number."]
+#
+# If the list is empty (no item), all unknown functions are forbidden. And if
+# the special value ANY is given, any unknown function is allowed ; consequently
+# the unknown ADQL functions will be translated into SQL as they are in ADQL.
+#
+# Default: no unknown function is allowed.
+udfs =
+
+########################
+# ADDITIONAL RESOURCES #
+########################
+
+# [OPTIONAL]
+# URL of the XSLT stylesheet to link with the XML output of /capabilities.
+#
+# By default, no XSLT stylesheet is defined.
+capabilities_stylesheet =
+
+# [OPTIONAL]
+# URL of the XSLT stylesheet to link with the XML output of /tables.
+#
+# By default, no XSLT stylesheet is defined.
+tables_stylesheet =
+
+# [OPTIONAL]
+# This property lets add an /examples
endpoint by specifying an
+# XHTML-RDFa document listing TAP query examples using the syntax specified by
+# TAPNotes 1.0 DALI 1.0.
+#
+# 3 different kinds of value are accepted:
+# * nothing (default): no /examples endpoint.
+# * name or relative path of a file: this method MUST be chosen if the
+# endpoint content is a JSP file. This file MUST be inside the directory
+# WebContent of your web application.
+# * URI starting with file://: in this method the local file pointed by the
+# URI will be merely returned when the endpoint will be requested.
+# * a URL: here, a redirection toward this URL will be made at each request
+# on the endpoint
+#
+# If you want a custom /examples endpoint (i.e. you do not)
+# want to forward/redirect to a file/URL), you can create a class which
+# implements TAPResource AND VOSIResource. The function getName() must return
+# "examples". Then, just append the classpath to the property
+# "additional_resources" of the TAP configuration file.
+#
+# By default, the TAP service does not have any /examples
endpoint.
+examples =
+
+# [OPTIONAL]
+# Comma-separated list of additional TAP resources/end-point.
+#
+# By default, the following standard TAP resources are already existing: /sync,
+# /async, /tables, /capabilities and /availability. With this property, you can
+# add a custom resource to your TAP service (e.g. /adqlValidator, /admin).
+#
+# Each item of the list MUST be the name of a class implementing
+# tap.resource.TAPResource. This class MUST have at least one constructor with
+# exactly one parameter of type tap.resource.TAP.
+#
+# The string returned by tap.resource.TAPResource.getName() will be the
+# resource name, following the root TAP service URL (e.g. if getName() returns
+# "foo", then its access URL will "{tapRoot}/foo"). Then, it is possible to
+# replace TAP resources already existing by using the same name (e.g. if
+# getName() returns "sync", the /sync resource won't be anymore the default Sync
+# resource of this library but your new resource).
+#
+# By default, this list is empty ; only the standard TAP resources exist.
+additional_resources =
+
+######################
+# CUSTOM TAP_FACTORY #
+######################
+
+# [OPTIONAL]
+# Class to use in replacement of the default TAPFactory.
+#
+# This property must be a class name (given between {...}). It must reference an
+# implementation of TAPFactory. This implementation must have at least one
+# constructor with exactly one parameter of type ServiceConnection.
+#
+# It is recommended to extend an existing implementation such as:
+# tap.AbstractTAPFactory or tap.config.ConfigurableTAPFactory.
+#
+# By default, the default TAPFactory (tap.config.ConfigurableTAPFactory) is used
+# and may use all properties related to the backup management, the database
+# access, the TAP_SCHEMA mapping and the ADQL translation.
+tap_factory =
diff --git a/src/tap/config/tap_min.properties b/src/tap/config/tap_min.properties
index 26d4d6a2..08e0f115 100644
--- a/src/tap/config/tap_min.properties
+++ b/src/tap/config/tap_min.properties
@@ -1,149 +1,149 @@
-################################################################################
-# MINIMUM TAP CONFIGURATION FILE #
-# #
-# TAP Version: 2.1 #
-# Date: 22 Feb. 2018 #
-# Author: Gregory Mantelet (ARI) #
-# #
-################################################################################
-
-############
-# DATABASE #
-############
-
-# Method to use in order to create database connections.
-#
-# Only two values are supported:
-# * jndi: database connections will be supplied by a Datasource whose the
-# JNDI name must be given. This method may propose connection
-# pooling in function of the datasource configuration.
-# * jdbc: the library will create itself connections when they will be
-# needed thanks to the below JDBC parameters. This method does not
-# propose any connection pooling.
-#
-# Allowed values: jndi, jdbc.
-database_access =
-
-# 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 (no spatial extension),
-# PostgreSQL+PgSphere, SQLServer (no spatial extension) and MySQL (no spatial
-# extension) for the moment. But you can provide your own SQL translator (even
-# if it does not have spatial features), by providing the name of a class
-# (within brackets: {...}) that implements ADQLTranslator (for instance:
-# {apackage.MyADQLTranslator}) and which have at least an empty constructor.
-#
-# Allowed values: postgres, pgsphere, sqlserver, mysql, a class name
-sql_translator = postgres
-
-#############################
-# IF DATABASE ACCESS = JNDI #
-#############################
-
-# JNDI name of the datasource pointing toward the database to use.
-# It should be defined in the web application (e.g. in the META-INF/context.xml
-# file in tomcat).
-datasource_jndi_name =
-
-#############################
-# IF DATABASE ACCESS = JDBC #
-#############################
-
-# JDBC driver URL pointing toward the database to use.
-#
-# Note: The username, password or other parameters may be included in it, but
-# in this case, the corresponding properties should leave empty or not
-# provided at all.
-jdbc_url =
-
-# JDBC driver path.
-#
-# By default, it is guessed in function of the database name provided in the
-# jdbc_url property. It MUST be provided if another DBMS is used or if the
-# JDBC driver path does not match the following ones:
-# * Oracle : oracle.jdbc.OracleDriver
-# * PostgreSQL: org.postgresql.Driver
-# * MySQL : com.mysql.jdbc.Driver
-# * SQLite : org.sqlite.JDBC
-# * H2 : org.h2.Driver
-jdbc_driver =
-
-# [Mandatory if the username is not already provided in jdbc_url]
-#
-# Username used to access to the database.
-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 =
-
-############
-# 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 three 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.
-# 3/ Build yourself the metadata of your service by creating an extension of
-# tap.metadata.TAPMetadata. This extension must have either an empty
-# constructor or a constructor with exactly 3 parameters of type
-# UWSFileManager, TAPFactory and TAPLog ; if both constructor are
-# provided, only the one with parameters will be used.
-#
-# For the two first methods, it is also possible to specify an extension of
-# tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created
-# using the specified methods (i.e. XML tableset or TAP_SCHEMA). In this way, it
-# is possible to get the "default" metadata from an XML file or the database
-# and then add/remove/modify some of them, or to change the output of the
-# 'tables' resource. The extension of tap.metadata.TAPMetadata must have at
-# least one constructor with the following parameters: (TAPMetadata) or
-# (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
-#
-# Allowed values: xml, xml {myTAPMetadata}, db, db {myTAPMetadata}
-# or a full class name (between {}).
-metadata =
-
-# [Mandatory if the value of "metadata" is "xml".]
-#
-# Local file path to the TableSet XML document.
-#
-# The XML document must implement the schema TableSet defined by VODataService.
-# The file path must be either an absolute local file path or a file path
-# relative to WebContent (i.e. the web application directory in which there are
-# WEB-INF and META-INF).
-metadata_file =
-
-#########
-# FILES #
-#########
-
-# Type of the file manager.
-#
-# Accepted values are: local (to manage files on the local system). You can also
-# add another way to manage files by providing the name (within brackets: {...})
-# of a class implementing TAPFileManager and having at least one constructor
-# with only a java.util.Properties parameter.
-#
-# Allowed values: local, a class name.
-file_manager = local
-
-# Local file path of the directory in which all TAP files (logs, errors, job
-# results, backup, ...) must be.
-#
-# The file path must be either an absolute local directory path or a directory
-# path relative to WebContent (i.e. the web application directory in which there
-# are WEB-INF and META-INF).
-file_root_path =
+################################################################################
+# MINIMUM TAP CONFIGURATION FILE #
+# #
+# TAP Version: 2.1 #
+# Date: 22 Feb. 2018 #
+# Author: Gregory Mantelet (ARI) #
+# #
+################################################################################
+
+############
+# DATABASE #
+############
+
+# Method to use in order to create database connections.
+#
+# Only two values are supported:
+# * jndi: database connections will be supplied by a Datasource whose the
+# JNDI name must be given. This method may propose connection
+# pooling in function of the datasource configuration.
+# * jdbc: the library will create itself connections when they will be
+# needed thanks to the below JDBC parameters. This method does not
+# propose any connection pooling.
+#
+# Allowed values: jndi, jdbc.
+database_access =
+
+# 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 (no spatial extension),
+# PostgreSQL+PgSphere, SQLServer (no spatial extension) and MySQL (no spatial
+# extension) for the moment. But you can provide your own SQL translator (even
+# if it does not have spatial features), by providing the name of a class
+# (within brackets: {...}) that implements ADQLTranslator (for instance:
+# {apackage.MyADQLTranslator}) and which have at least an empty constructor.
+#
+# Allowed values: postgres, pgsphere, sqlserver, mysql, a class name
+sql_translator = postgres
+
+#############################
+# IF DATABASE ACCESS = JNDI #
+#############################
+
+# JNDI name of the datasource pointing toward the database to use.
+# It should be defined in the web application (e.g. in the META-INF/context.xml
+# file in tomcat).
+datasource_jndi_name =
+
+#############################
+# IF DATABASE ACCESS = JDBC #
+#############################
+
+# JDBC driver URL pointing toward the database to use.
+#
+# Note: The username, password or other parameters may be included in it, but
+# in this case, the corresponding properties should leave empty or not
+# provided at all.
+jdbc_url =
+
+# JDBC driver path.
+#
+# By default, it is guessed in function of the database name provided in the
+# jdbc_url property. It MUST be provided if another DBMS is used or if the
+# JDBC driver path does not match the following ones:
+# * Oracle : oracle.jdbc.OracleDriver
+# * PostgreSQL: org.postgresql.Driver
+# * MySQL : com.mysql.jdbc.Driver
+# * SQLite : org.sqlite.JDBC
+# * H2 : org.h2.Driver
+jdbc_driver =
+
+# [Mandatory if the username is not already provided in jdbc_url]
+#
+# Username used to access to the database.
+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 =
+
+############
+# 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 three 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.
+# 3/ Build yourself the metadata of your service by creating an extension of
+# tap.metadata.TAPMetadata. This extension must have either an empty
+# constructor or a constructor with exactly 3 parameters of type
+# UWSFileManager, TAPFactory and TAPLog ; if both constructor are
+# provided, only the one with parameters will be used.
+#
+# For the two first methods, it is also possible to specify an extension of
+# tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created
+# using the specified methods (i.e. XML tableset or TAP_SCHEMA). In this way, it
+# is possible to get the "default" metadata from an XML file or the database
+# and then add/remove/modify some of them, or to change the output of the
+# 'tables' resource. The extension of tap.metadata.TAPMetadata must have at
+# least one constructor with the following parameters: (TAPMetadata) or
+# (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
+#
+# Allowed values: xml, xml {myTAPMetadata}, db, db {myTAPMetadata}
+# or a full class name (between {}).
+metadata =
+
+# [Mandatory if the value of "metadata" is "xml".]
+#
+# Local file path to the TableSet XML document.
+#
+# The XML document must implement the schema TableSet defined by VODataService.
+# The file path must be either an absolute local file path or a file path
+# relative to WebContent (i.e. the web application directory in which there are
+# WEB-INF and META-INF).
+metadata_file =
+
+#########
+# FILES #
+#########
+
+# Type of the file manager.
+#
+# Accepted values are: local (to manage files on the local system). You can also
+# add another way to manage files by providing the name (within brackets: {...})
+# of a class implementing TAPFileManager and having at least one constructor
+# with only a java.util.Properties parameter.
+#
+# Allowed values: local, a class name.
+file_manager = local
+
+# Local file path of the directory in which all TAP files (logs, errors, job
+# results, backup, ...) must be.
+#
+# The file path must be either an absolute local directory path or a directory
+# path relative to WebContent (i.e. the web application directory in which there
+# are WEB-INF and META-INF).
+file_root_path =
diff --git a/src/tap/formatter/VOTableFormat.java b/src/tap/formatter/VOTableFormat.java
index c641a6f9..c870007a 100644
--- a/src/tap/formatter/VOTableFormat.java
+++ b/src/tap/formatter/VOTableFormat.java
@@ -415,6 +415,13 @@ protected void writeHeader(final VOTableVersion votVersion, final TAPExecutionRe
out.newLine();
}
+ // Append the fixed ADQL query, if any: [OPTIONAL]
+ String fixedQuery = execReport.fixedQuery;
+ if (adqlQuery != null){
+ out.write("