From c3e97e6e7ef2567f4905e0813dd0b86892ec4d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Mantelet?= Date: Wed, 20 Mar 2019 14:07:25 +0100 Subject: [PATCH] [TAP] Add an optional feature to enable quick fix of input ADQL query on error: `fix_on_fail` in the configuration file. By default, this feature is disabled. _With 15cd594, this commit finishes the resolution of the GitHub issue #104 ._ --- src/tap/ADQLExecutor.java | 179 +- src/tap/ServiceConnection.java | 17 +- src/tap/TAPExecutionReport.java | 95 +- .../config/ConfigurableServiceConnection.java | 62 +- src/tap/config/TAPConfiguration.java | 13 +- src/tap/config/tap_configuration_file.html | 38 + src/tap/config/tap_full.properties | 1683 +++++++++-------- src/tap/config/tap_min.properties | 298 +-- src/tap/formatter/VOTableFormat.java | 7 + .../config/TestConfigurableTAPFactory.java | 5 + .../tap/formatter/ServiceConnection4Test.java | 5 + .../parameters/ServiceConnectionOfTest.java | 5 + 12 files changed, 1301 insertions(+), 1106 deletions(-) diff --git a/src/tap/ADQLExecutor.java b/src/tap/ADQLExecutor.java index c1327eb3..689a152a 100644 --- a/src/tap/ADQLExecutor.java +++ b/src/tap/ADQLExecutor.java @@ -2,21 +2,21 @@ /* * 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, see . - * - * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * + * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -49,7 +49,7 @@ /** *

Let process completely an ADQL query.

- * + * *

Thus, this class aims to apply the following actions (in the given order):

*
    *
  1. Upload the user tables, if any
  2. @@ -58,54 +58,54 @@ *
  3. Format and write the result
  4. *
  5. Drop all uploaded tables from the "database"
  6. *
- * + * *

Job execution mode

- * + * *

* 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. *

- * + * *

Input/Output formats

- * + * *

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. *

- * + * *

Executor customization

- * + * *

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)}). *

- * + * * @author Grégory Mantelet (CDS;ARI) - * @version 2.1 (04/2017) + * @version 2.3 (03/2019) */ public class ADQLExecutor { @@ -139,7 +139,7 @@ public class ADQLExecutor { /** * Build an {@link ADQLExecutor}. - * + * * @param service The description of the TAP service. */ public ADQLExecutor(final ServiceConnection service){ @@ -149,7 +149,7 @@ public ADQLExecutor(final ServiceConnection service){ /** * Get the logger used by this executor. - * + * * @return The used logger. */ public final TAPLog getLogger(){ @@ -158,12 +158,12 @@ public final TAPLog getLogger(){ /** *

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). *

- * + * * @return The execution report. */ public final TAPExecutionReport getExecReport(){ @@ -173,11 +173,11 @@ public final TAPExecutionReport getExecReport(){ /** *

Get the object to use in order to write the query result in the appropriate format * (either the asked one, or else VOTable).

- * + * * @return The appropriate result formatter to use. Can not be NULL! - * + * * @throws TAPException If no format corresponds to the asked one and if no default format (for VOTable) can be found. - * + * * @see ServiceConnection#getOutputFormat(String) */ protected OutputFormat getFormatter() throws TAPException{ @@ -196,19 +196,19 @@ protected OutputFormat getFormatter() throws TAPException{ /** *

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()}. *

- * + * * @param thread The asynchronous thread which asks the query processing. - * + * * @return The resulting execution report. - * + * * @throws UWSException If any error occurs while executing the ADQL query. * @throws InterruptedException If the job has been interrupted (by the user or a time-out). - * + * * @see #start() */ public final TAPExecutionReport start(final AsyncThread thread) throws UWSException, InterruptedException{ @@ -244,16 +244,16 @@ public final TAPExecutionReport start(final AsyncThread thread) throws UWSExcept /** *

Create the database connection required for the ADQL execution.

- * + * *

Note: This function has no effect if the DB connection already exists.

- * + * * @param jobID ID of the job which will be executed by this {@link ADQLExecutor}. * This ID will be the database connection ID. - * + * * @throws TAPException If the DB connection creation fails. - * + * * @see TAPFactory#getConnection(String) - * + * * @since 2.0 */ public final void initDBConnection(final String jobID) throws TAPException{ @@ -264,7 +264,7 @@ public final void initDBConnection(final String jobID) throws TAPException{ /** * Cancel the current SQL query execution or result set fetching if any is currently running. * If no such process is on going, this function has no effect. - * + * * @since 2.1 */ public final void cancelQuery(){ @@ -274,20 +274,20 @@ public final void cancelQuery(){ /** *

Start the synchronous processing of the ADQL query.

- * + * *

This function initialize the execution report and then call {@link #start()}.

- * + * * @param thread The synchronous thread which asks the query processing. * @param jobId ID of the corresponding job. * @param params All execution parameters (including the query to process). * @param response Object in which the result or the error must be written. - * + * * @return The resulting execution report. - * + * * @throws TAPException If any error occurs while executing the ADQL query. * @throws IOException If any error occurs while writing the result in the given {@link HttpServletResponse}. * @throws InterruptedException If the job has been interrupted (by the user or a time-out). - * + * * @see #start() */ public final TAPExecutionReport start(final Thread thread, final String jobId, final TAPParameters params, final HttpServletResponse response) throws TAPException, IOException, InterruptedException{ @@ -308,7 +308,7 @@ public final TAPExecutionReport start(final Thread thread, final String jobId, f /** *

Process the ADQL query.

- * + * *

This function calls the following function (in the same order):

*
    *
  1. {@link TAPFactory#getConnection(String)}
  2. @@ -319,16 +319,16 @@ public final TAPExecutionReport start(final Thread thread, final String jobId, f *
  3. {@link #dropUploadedTables()}
  4. *
  5. {@link TAPFactory#freeConnection(DBConnection)}
  6. *
- * + * *

* 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.

- * + * * @return The updated execution report. - * + * * @throws TAPException If any error occurs while executing the ADQL query. * @throws UWSException If any error occurs while executing the ADQL query. * @throws IOException If an error happens while writing the result in the specified {@link HttpServletResponse}. @@ -434,18 +434,18 @@ protected final TAPExecutionReport start() throws TAPException, UWSException, IO /** *

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). *

- * + * * @param progression ID of the starting step. - * + * * @see #endStep() */ private void startStep(final ExecutionProgression progression){ @@ -464,16 +464,16 @@ private void startStep(final ExecutionProgression progression){ /** *

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. *

- * + * * @see #startStep(ExecutionProgression) */ private void endStep(){ @@ -489,11 +489,11 @@ private void endStep(){ /** *

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. *

- * + * * @throws TAPException If any error occurs while reading the uploaded table * or while importing them in the database. */ @@ -510,23 +510,23 @@ private final void uploadTables() throws TAPException{ /** *

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. *

- * + * * @return The object representation of the ADQL query. - * + * * @throws ParseException If the given ADQL query can not be parsed or if the construction of the object representation has failed. * @throws InterruptedException If the thread has been interrupted. * @throws TAPException If the TAP factory is unable to create the ADQL factory or the query checker. @@ -551,7 +551,30 @@ protected ADQLQuery parseADQL() throws ParseException, InterruptedException, TAP parser.setQueryChecker(service.getFactory().createQueryChecker(uploadSchema)); // Parse the ADQL query: - ADQLQuery query = parser.parseQuery(tapParams.getQuery()); + ADQLQuery query = null; + // if the fixOnFail option is enabled... + if (service.fixOnFailEnabled()){ + try{ + // try parsing the query: + query = parser.parseQuery(tapParams.getQuery()); + }catch(ParseException pe){ + // if it fails... + // ...log the auto fix attempt: + logger.logTAP(LogLevel.INFO, report, "PARSING", "Parse attempt of the original input query failed! Trying auto-fix...", null); + // ...try fixing the query: + String fixedQuery = parser.tryQuickFix(tapParams.getQuery()); + // ...log the auto fixed query, if successful: + logger.logTAP(LogLevel.INFO, report, "PARSING", "Auto-fixed query: " + fixedQuery.replaceAll("(\t|\r?\n)+", " "), null); + // ...keep this fixed query in the exec report: + report.fixedQuery = fixedQuery; + // ...and finally try parsing it a last time: + query = parser.parseQuery(fixedQuery); + } + } + // if not enabled, parse immediately the query: + else{ + query = parser.parseQuery(tapParams.getQuery()); + } // Set or check the row limit: final int limit = query.getSelect().getLimit(); @@ -566,22 +589,22 @@ protected ADQLQuery parseADQL() throws ParseException, InterruptedException, TAP /** *

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. *

- * + * * @param adql The object representation of the ADQL query to execute. - * + * * @return The result of the query. - * + * * @throws InterruptedException If the thread has been interrupted. * @throws DBCancelledException If the inner DB connection has been canceled. * @throws TAPException If the {@link DBConnection} has failed to deal with the given ADQL query. - * + * * @see DBConnection#executeQuery(ADQLQuery) */ protected TableIterator executeADQL(final ADQLQuery adql) throws InterruptedException, DBCancelledException, TAPException{ @@ -617,21 +640,21 @@ protected TableIterator executeADQL(final ADQLQuery adql) throws InterruptedExce /** *

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. *

- * + * * @param queryResult The result of the query execution in database. - * + * * @throws InterruptedException If the thread has been interrupted. * @throws IOException If an error happens while writing the result in the {@link HttpServletResponse}. * That kind of error can be thrown only in synchronous mode. * In asynchronous, the error is stored as job error report and is never propagated. * @throws TAPException If an error occurs while getting the appropriate formatter or while formatting or writing (synchronous execution) the result. * @throws UWSException If an error occurs while getting the output stream or while writing (asynchronous execution) the result. - * + * * @see #writeResult(TableIterator, OutputFormat, OutputStream) */ protected final void writeResult(final TableIterator queryResult) throws InterruptedException, IOException, TAPException, UWSException{ @@ -707,18 +730,18 @@ protected final void writeResult(final TableIterator queryResult) throws Interru /** *

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. *

- * + * * @param queryResult Query result to format and to output. * @param formatter The object able to write the result in the appropriate format. * @param output The stream in which the result must be written. - * + * * @throws InterruptedException If the thread has been interrupted. * @throws IOException If there is an error while writing the result in the given stream. * @throws TAPException If there is an error while formatting the result. @@ -729,11 +752,11 @@ protected void writeResult(TableIterator queryResult, OutputFormat formatter, Ou /** *

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. *

- * + * * @throws TAPException If a grave error occurs. By default, no exception is thrown ; they are just logged. */ protected void dropUploadedTables() throws TAPException{ diff --git a/src/tap/ServiceConnection.java b/src/tap/ServiceConnection.java index 6545b5f3..e22e657f 100644 --- a/src/tap/ServiceConnection.java +++ b/src/tap/ServiceConnection.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with TAPLibrary. If not, see . * - * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -44,7 +44,7 @@ *

* * @author Grégory Mantelet (CDS;ARI) - * @version 2.3 (09/2018) + * @version 2.3 (03/2019) */ public interface ServiceConnection { @@ -744,4 +744,17 @@ public String toString(){ */ public int[] getFetchSize(); + /** + * [MANDATORY] + *

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, see . - * - * Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * + * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import tap.parameters.TAPParameters; -import adql.db.DBColumn; /** - *

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.

- * + * 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, see . * - * Copyright 2016-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2016-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE; import static tap.config.TAPConfiguration.DEFAULT_DIRECTORY_PER_USER; import static tap.config.TAPConfiguration.DEFAULT_EXECUTION_DURATION; +import static tap.config.TAPConfiguration.DEFAULT_FIX_ON_FAIL; import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES; import static tap.config.TAPConfiguration.DEFAULT_LOGGER; import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS; @@ -39,6 +40,7 @@ import static tap.config.TAPConfiguration.KEY_DIRECTORY_PER_USER; import static tap.config.TAPConfiguration.KEY_FILE_MANAGER; import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH; +import static tap.config.TAPConfiguration.KEY_FIX_ON_FAIL; import static tap.config.TAPConfiguration.KEY_GEOMETRIES; import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES; import static tap.config.TAPConfiguration.KEY_LOGGER; @@ -126,15 +128,17 @@ import uws.service.log.UWSLog.LogLevel; /** - *

Concrete 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 ArrayList outputFormats; /** Array of 2 integers: resp. default and maximum output limit. - * Each limit is expressed in a unit specified in the array {@link #outputLimitTypes}. */ + * Each limit is expressed in a unit specified in the array + * {@link #outputLimitTypes}. */ private int[] outputLimits = new int[]{ -1, -1 }; - /** Array of 2 limit units: resp. unit of the default output limit and unit of the maximum output limit. */ + /** Array of 2 limit units: resp. unit of the default output limit and unit + * of the maximum output limit. */ private LimitUnit[] outputLimitTypes = new LimitUnit[2]; /** Indicate whether the UPLOAD feature is enabled or not. */ @@ -201,20 +209,31 @@ public final class ConfigurableServiceConnection implements ServiceConnection { private UserIdentifier userIdentifier = null; /** List of all allowed coordinate systems. - * If NULL, all coord. sys. are allowed. If empty list, none is allowed. */ + * + * If NULL, all coord. sys. are allowed. If empty list, none is allowed. + * */ private ArrayList lstCoordSys = null; /** List of all allowed ADQL geometrical functions. - * If NULL, all geometries are allowed. If empty list, none is allowed. */ + * + * If NULL, all geometries are allowed. If empty list, none is allowed. + * */ private ArrayList geometries = null; private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)"; /** List of all known and allowed User Defined Functions. - * If NULL, any unknown function is allowed. If empty list, none is allowed. */ + * If NULL, any unknown function is allowed. If empty list, none is + * allowed. */ private Collection udfs = new ArrayList(0); + /** Indicate whether the input ADQL query should be automatically fixed + * if its parsing fails because of an incorrect tokenization. + * @since 2.3 */ + private boolean isFixOnFailEnabled = DEFAULT_FIX_ON_FAIL; + /** - * Create a TAP service description thanks to the given TAP configuration file. + * Create a TAP service description thanks to the given TAP configuration + * file. * * @param tapConfig The content of the TAP configuration file. * @@ -226,12 +245,15 @@ public ConfigurableServiceConnection(final Properties tapConfig) throws NullPoin } /** - * Create a TAP service description thanks to the given TAP configuration file. + * Create a TAP service description thanks to the given TAP configuration + * file. * * @param tapConfig The content of the TAP configuration file. - * @param webAppRootDir The directory of the Web Application running this TAP service. - * In this directory another directory may be created in order to store all TAP service files - * if none is specified in the given TAP configuration file. + * @param webAppRootDir The directory of the Web Application running this + * TAP service. In this directory another directory + * may be created in order to store all TAP service + * files if none is specified in the given TAP + * configuration file. * * @throws NullPointerException If the given properties set is NULL. * @throws TAPException If a property is wrong or missing. @@ -284,6 +306,7 @@ public ConfigurableServiceConnection(final Properties tapConfig, final String we initCoordSys(tapConfig); initADQLGeometries(tapConfig); initUDFs(tapConfig); + isFixOnFailEnabled = Boolean.parseBoolean(getProperty(tapConfig, KEY_FIX_ON_FAIL)); } /** @@ -1735,4 +1758,9 @@ public int[] getFetchSize(){ return fetchSize; } + @Override + public boolean fixOnFailEnabled(){ + return isFixOnFailEnabled; + } + } diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java index fa350036..b8eeeeef 100644 --- a/src/tap/config/TAPConfiguration.java +++ b/src/tap/config/TAPConfiguration.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with TAPLibrary. If not, see . * - * Copyright 2015-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2015-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -41,7 +41,7 @@ *

* * @author Grégory Mantelet (CDS;ARI) - * @version 2.3 (11/2018) + * @version 2.3 (03/2019) * @since 2.0 */ public final class TAPConfiguration { @@ -172,6 +172,15 @@ public final class TAPConfiguration { public final static String KEY_ASYNC_FETCH_SIZE = "async_fetch_size"; /** Default value of the property {@link #KEY_ASYNC_FETCH_SIZE}: {@value #DEFAULT_ASYNC_FETCH_SIZE}. */ public final static int DEFAULT_ASYNC_FETCH_SIZE = 10000; + /** Name/Key of the property specifying whether the fixOnFail option is + * enabled or not. This option lets automatically fix the input ADQL query + * if its tokenization fails. + * @since 2.3 */ + public final static String KEY_FIX_ON_FAIL = "fix_on_fail"; + /** Default value of the property {@link #KEY_FIX_ON_FAIL}: + * {@value #DEFAULT_FIX_ON_FAIL}. + * @since 2.3 */ + public final static boolean DEFAULT_FIX_ON_FAIL = false; /** Name/Key of the property specifying the name of the DataSource into the JDNI. */ public final static String KEY_DATASOURCE_JNDI_NAME = "datasource_jndi_name"; /** Name/Key of the property specifying the full class name of the JDBC driver. diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html index a5fedc46..65e54ebb 100644 --- a/src/tap/config/tap_configuration_file.html +++ b/src/tap/config/tap_configuration_file.html @@ -212,6 +212,44 @@

TAP Configuration File

  • 10000 (default)
  • 0 (wait for the the whole result)
  • 1000000
+ + fix_on_fail + + boolean + +

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

+ +
  • false (default)
  • true
+ ⤷ JNDI datasource (only if database_access=jndi) diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties index f6a410f1..a80320fb 100644 --- a/src/tap/config/tap_full.properties +++ b/src/tap/config/tap_full.properties @@ -1,825 +1,858 @@ -################################################################################ -# FULL TAP CONFIGURATION FILE # -# # -# TAP Version: 2.3 # -# Date: 13 Nov. 2018 # -# 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 - -############################# -# 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 = +################################################################################ +# 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(""); + out.newLine(); + } + // Insert the definition of all used coordinate systems: HashSet insertedCoosys = new HashSet(10); for(DBColumn col : execReport.resultingColumns){ diff --git a/test/tap/config/TestConfigurableTAPFactory.java b/test/tap/config/TestConfigurableTAPFactory.java index eeb81002..e015f236 100644 --- a/test/tap/config/TestConfigurableTAPFactory.java +++ b/test/tap/config/TestConfigurableTAPFactory.java @@ -520,6 +520,11 @@ public int getNbMaxAsyncJobs(){ public int[] getFetchSize(){ return null; } + + @Override + public boolean fixOnFailEnabled(){ + return false; + } } } diff --git a/test/tap/formatter/ServiceConnection4Test.java b/test/tap/formatter/ServiceConnection4Test.java index 97f6065c..8ec8487b 100644 --- a/test/tap/formatter/ServiceConnection4Test.java +++ b/test/tap/formatter/ServiceConnection4Test.java @@ -153,4 +153,9 @@ public int[] getFetchSize(){ return null; } + @Override + public boolean fixOnFailEnabled(){ + return false; + } + } \ No newline at end of file diff --git a/test/tap/parameters/ServiceConnectionOfTest.java b/test/tap/parameters/ServiceConnectionOfTest.java index 4a82f6bc..e886b3f8 100644 --- a/test/tap/parameters/ServiceConnectionOfTest.java +++ b/test/tap/parameters/ServiceConnectionOfTest.java @@ -174,4 +174,9 @@ public int[] getFetchSize(){ return null; } + @Override + public boolean fixOnFailEnabled(){ + return false; + } + } \ No newline at end of file