Skip to content

Commit

Permalink
[TAP] Add an optional feature to enable quick fix of input ADQL query…
Browse files Browse the repository at this point in the history
… 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 ._
  • Loading branch information
gmantele committed Mar 20, 2019
1 parent 15cd594 commit c3e97e6
Show file tree
Hide file tree
Showing 12 changed files with 1,301 additions and 1,106 deletions.
179 changes: 101 additions & 78 deletions src/tap/ADQLExecutor.java

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions src/tap/ServiceConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* 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)
*/

Expand Down Expand Up @@ -44,7 +44,7 @@
* </p>
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.3 (09/2018)
* @version 2.3 (03/2019)
*/
public interface ServiceConnection {

Expand Down Expand Up @@ -744,4 +744,17 @@ public String toString(){
*/
public int[] getFetchSize();

/**
* <i><b>[MANDATORY]</b></i>
* <p>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.</p>
*
* @return <i>true</i> to allow automatic fix attempt in case of error,
* <i>false</i> to disable this option.
*
* @since 2.3
*/
public boolean fixOnFailEnabled();

}
95 changes: 62 additions & 33 deletions src/tap/TAPExecutionReport.java
Original file line number Diff line number Diff line change
@@ -1,71 +1,93 @@
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 <http://www.gnu.org/licenses/>.
*
* 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;

/**
* <p>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.</p>
*
* <p>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.</p>
*
* Report the execution (including the parsing and the output writing) of an
* ADQL query.
*
* <p>
* 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.
* </p>
*
* <p>
* 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.
* </p>
*
* @author Gr&eacute;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.
* <p>This field is set only if the option fix_on_fail is enabled in the TAP
* configuration and that a query has been fixed.</p>
* @since 2.3 */
public String fixedQuery = null;

/** List of all resulting columns. <i>Empty array, if not yet known.</i> */
public DBColumn[] resultingColumns = new DBColumn[0];

/** Total number of written rows.
* @since 2.0 */
public long nbRows = -1;

/** Duration of all execution steps. <i>For the moment only 4 steps (in the order): uploading, parsing, executing and writing.</i> */
protected final long[] durations = new long[]{-1,-1,-1,-1};
/** Duration of all execution steps. <i>For the moment only 4 steps (in the
* order): uploading, parsing, executing and writing.</i> */
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. <i>At the beginning or while executing, this field is always FALSE.</i> */
/** Indicate whether this job has ended successfully or not.
* <i>At the beginning or while executing, this field is always FALSE.</i> */
public boolean success = false;

/**
* Build an empty execution report.
*
* @param jobID ID of the job whose the execution must be described here.
* @param synchronous <i>true</i> if the job is synchronous, <i>false</i> 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 <i>true</i> if the job is synchronous,
* <i>false</i> 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;
Expand All @@ -74,14 +96,20 @@ public TAPExecutionReport(final String jobID, final boolean synchronous, final T
}

/**
* <p>Map the execution progression with an index inside the {@link #durations} array.</p>
*
* <p><i><b>Warning:</b> for the moment, only {@link ExecutionProgression#UPLOADING}, {@link ExecutionProgression#PARSING},
* {@link ExecutionProgression#EXECUTING_ADQL} and {@link ExecutionProgression#WRITING_RESULT} are managed.</i></p>
*
* Map the execution progression with an index inside the {@link #durations}
* array.
*
* <p><i><b>Warning:</b>
* for the moment, only {@link ExecutionProgression#UPLOADING},
* {@link ExecutionProgression#PARSING},
* {@link ExecutionProgression#EXECUTING_ADQL} and
* {@link ExecutionProgression#WRITING_RESULT} are managed.
* </i></p>
*
* @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){
Expand All @@ -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){
Expand All @@ -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.
*/
Expand Down
62 changes: 45 additions & 17 deletions src/tap/config/ConfigurableServiceConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* 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;
Expand All @@ -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;
Expand Down Expand Up @@ -126,26 +128,30 @@
import uws.service.log.UWSLog.LogLevel;

/**
* <p>Concrete implementation of {@link ServiceConnection}, fully parameterized with a TAP configuration file.</p>
* Concrete implementation of {@link ServiceConnection}, fully parameterized
* with a TAP configuration file.
*
* <p>
* 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}.
* </p>
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.3 (11/2018)
* @version 2.3 (03/2019)
* @since 2.0
*/
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. */
Expand Down Expand Up @@ -175,9 +181,11 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
private final ArrayList<OutputFormat> outputFormats;

/** Array of 2 integers: resp. default and maximum output limit.
* <em>Each limit is expressed in a unit specified in the array {@link #outputLimitTypes}.</em> */
* <em>Each limit is expressed in a unit specified in the array
* {@link #outputLimitTypes}.</em> */
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. */
Expand All @@ -201,20 +209,31 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
private UserIdentifier userIdentifier = null;

/** List of all allowed coordinate systems.
* <em>If NULL, all coord. sys. are allowed. If empty list, none is allowed.</em> */
* <em>
* If NULL, all coord. sys. are allowed. If empty list, none is allowed.
* </em> */
private ArrayList<String> lstCoordSys = null;

/** List of all allowed ADQL geometrical functions.
* <em>If NULL, all geometries are allowed. If empty list, none is allowed.</em> */
* <em>
* If NULL, all geometries are allowed. If empty list, none is allowed.
* </em> */
private ArrayList<String> 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.
* <em>If NULL, any unknown function is allowed. If empty list, none is allowed.</em> */
* <em>If NULL, any unknown function is allowed. If empty list, none is
* allowed.</em> */
private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(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.
*
Expand All @@ -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.
* <em>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.</em>
* @param webAppRootDir The directory of the Web Application running this
* TAP service. <em>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.</em>
*
* @throws NullPointerException If the given properties set is NULL.
* @throws TAPException If a property is wrong or missing.
Expand Down Expand Up @@ -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));
}

/**
Expand Down Expand Up @@ -1735,4 +1758,9 @@ public int[] getFetchSize(){
return fetchSize;
}

@Override
public boolean fixOnFailEnabled(){
return isFixOnFailEnabled;
}

}
13 changes: 11 additions & 2 deletions src/tap/config/TAPConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* 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)
*/

Expand All @@ -41,7 +41,7 @@
* </i></p>
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.3 (11/2018)
* @version 2.3 (03/2019)
* @since 2.0
*/
public final class TAPConfiguration {
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit c3e97e6

Please sign in to comment.