Skip to content
Snippets Groups Projects
Commit 4283809b authored by gmantele's avatar gmantele
Browse files

[TAP] Add Javadoc for all TAP configuration file related classes + Improve the...

[TAP] Add Javadoc for all TAP configuration file related classes + Improve the function ConfigurableServiceConnection.getFile(...) + Set the default value of limits/durations/periods to the maximum value if the new maximum value is less than the current default value.
parent d801186a
No related branches found
No related tags found
No related merge requests found
...@@ -243,7 +243,7 @@ public interface ServiceConnection { ...@@ -243,7 +243,7 @@ public interface ServiceConnection {
/** /**
* <i>[OPTIONAL]</i> * <i>[OPTIONAL]</i>
* <p>Get the limit of the retention period.</p> * <p>Get the limit of the retention period (in seconds).</p>
* *
* <p> * <p>
* It is the maximum period while an asynchronous job can leave in the jobs list * It is the maximum period while an asynchronous job can leave in the jobs list
...@@ -269,7 +269,7 @@ public interface ServiceConnection { ...@@ -269,7 +269,7 @@ public interface ServiceConnection {
/** /**
* <i>[OPTIONAL]</i> * <i>[OPTIONAL]</i>
* <p>Get the limit of the job execution duration.</p> * <p>Get the limit of the job execution duration (in milliseconds).</p>
* *
* <p> * <p>
* It is the duration of a running job (including the query execution). * It is the duration of a running job (including the query execution).
......
...@@ -116,58 +116,115 @@ import adql.parser.ParseException; ...@@ -116,58 +116,115 @@ import adql.parser.ParseException;
import adql.query.operand.function.UserDefinedFunction; import adql.query.operand.function.UserDefinedFunction;
/** /**
* <p>Concrete implementation of {@link ServiceConnection}, fully parameterized with a TAP configuration file.</p>
* *
* <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}.
* </p>
* *
* @author Gr&eacute;gory Mantelet (ARI) * @author Gr&eacute;gory Mantelet (ARI)
* @version 2.0 (03/2015) * @version 2.0 (04/2015)
* @since 2.0
*/ */
public final class ConfigurableServiceConnection implements ServiceConnection { public final class ConfigurableServiceConnection implements ServiceConnection {
/** File manager to use in the TAP service. */
private UWSFileManager fileManager; 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). */
private TAPLog logger; private TAPLog logger;
/** Factory which can create different types of objects for the TAP service (e.g. database connection). */
private TAPFactory tapFactory; private TAPFactory tapFactory;
/** Object gathering all metadata of this TAP service. */
private final TAPMetadata metadata; private final TAPMetadata metadata;
/** Name of the organization/person providing the TAP service. */
private final String providerName; private final String providerName;
/** Description of the TAP service. */
private final String serviceDescription; private final String serviceDescription;
private boolean isAvailable = false; // the TAP service must be disabled until the end of its connection initialization /** Indicate whether the TAP service is available or not. */
private boolean isAvailable = false; // the TAP service must be disabled until the end of its connection initialization
/** Description of the available or unavailable state of the TAP service. */
private String availability = "TAP service not yet initialized."; private String availability = "TAP service not yet initialized.";
/** Maximum number of asynchronous jobs that can run simultaneously. */
private int maxAsyncJobs = DEFAULT_MAX_ASYNC_JOBS; private int maxAsyncJobs = DEFAULT_MAX_ASYNC_JOBS;
/** Array of 2 integers: resp. default and maximum execution duration.
* <em>Both duration are expressed in milliseconds.</em> */
private int[] executionDuration = new int[2]; private int[] executionDuration = new int[2];
/** Array of 2 integers: resp. default and maximum retention period.
* <em>Both period are expressed in seconds.</em> */
private int[] retentionPeriod = new int[2]; private int[] retentionPeriod = new int[2];
/** List of all available output formatters. */
private final ArrayList<OutputFormat> outputFormats; 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> */
private int[] outputLimits = new int[]{-1,-1}; 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. */
private LimitUnit[] outputLimitTypes = new LimitUnit[2]; private LimitUnit[] outputLimitTypes = new LimitUnit[2];
/** Indicate whether the UPLOAD feature is enabled or not. */
private boolean isUploadEnabled = false; private boolean isUploadEnabled = false;
/** Array of 2 integers: resp. default and maximum upload limit.
* <em>Each limit is expressed in a unit specified in the array {@link #uploadLimitTypes}.</em> */
private int[] uploadLimits = new int[]{-1,-1}; private int[] uploadLimits = new int[]{-1,-1};
/** Array of 2 limit units: resp. unit of the default upload limit and unit of the maximum upload limit. */
private LimitUnit[] uploadLimitTypes = new LimitUnit[2]; private LimitUnit[] uploadLimitTypes = new LimitUnit[2];
/** The maximum size of a set of uploaded files.
* <em>This size is expressed in bytes.</em> */
private int maxUploadSize = DEFAULT_UPLOAD_MAX_FILE_SIZE; private int maxUploadSize = DEFAULT_UPLOAD_MAX_FILE_SIZE;
/** Array of 2 integers: resp. default and maximum fetch size.
* <em>Both sizes are expressed in number of rows.</em> */
private int[] fetchSize = new int[]{DEFAULT_ASYNC_FETCH_SIZE,DEFAULT_SYNC_FETCH_SIZE}; private int[] fetchSize = new int[]{DEFAULT_ASYNC_FETCH_SIZE,DEFAULT_SYNC_FETCH_SIZE};
/** The method to use in order to identify a TAP user. */
private UserIdentifier userIdentifier = null; 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> */
private ArrayList<String> lstCoordSys = null; 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> */
private ArrayList<String> geometries = null; private ArrayList<String> geometries = null;
private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)"; 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> */
private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0); private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0);
public ConfigurableServiceConnection(final Properties tapConfig) throws NullPointerException, TAPException, UWSException{ /**
* Create a TAP service description thanks to the given TAP configuration file.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws NullPointerException If the given properties set is NULL.
* @throws TAPException If a property is wrong or missing.
*/
public ConfigurableServiceConnection(final Properties tapConfig) throws NullPointerException, TAPException{
this(tapConfig, null); this(tapConfig, null);
} }
public ConfigurableServiceConnection(final Properties tapConfig, final String webAppRootDir) throws NullPointerException, TAPException, UWSException{ /**
* 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>
*
* @throws NullPointerException If the given properties set is NULL.
* @throws TAPException If a property is wrong or missing.
*/
public ConfigurableServiceConnection(final Properties tapConfig, final String webAppRootDir) throws NullPointerException, TAPException{
if (tapConfig == null) if (tapConfig == null)
throw new NullPointerException("Missing TAP properties! "); throw new NullPointerException("Missing TAP properties! ");
...@@ -217,6 +274,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -217,6 +274,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
initUDFs(tapConfig); initUDFs(tapConfig);
} }
/**
* Initialize the management of TAP service files using 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>This directory may be used only to search the root TAP directory
* if specified with a relative path in the TAP configuration file.</em>
*
* @throws TAPException If a property is wrong or missing, or if an error occurs while creating the file manager.
*/
private void initFileManager(final Properties tapConfig, final String webAppRootDir) throws TAPException{ private void initFileManager(final Properties tapConfig, final String webAppRootDir) throws TAPException{
// Read the desired file manager: // Read the desired file manager:
String fileManagerType = getProperty(tapConfig, KEY_FILE_MANAGER); String fileManagerType = getProperty(tapConfig, KEY_FILE_MANAGER);
...@@ -253,23 +320,52 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -253,23 +320,52 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
fileManager = newInstance(fileManagerType, KEY_FILE_MANAGER, UWSFileManager.class, new Class<?>[]{Properties.class}, new Object[]{tapConfig}); fileManager = newInstance(fileManagerType, KEY_FILE_MANAGER, UWSFileManager.class, new Class<?>[]{Properties.class}, new Object[]{tapConfig});
} }
/**
* <p>Resolve the given file name/path.</p>
*
* <p>Only the URI protocol "file:" is allowed. If the protocol is different a {@link TAPException} is thrown.</p>
*
* <p>
* If not an absolute URI, the given path may be either relative or absolute. A relative path is always considered
* as relative from the Web Application directory (supposed to be given in 2nd parameter).
* </p>
*
* @param filePath URI/Path/Name of the file to get.
* @param webAppRootPath Web Application directory local path.
* @param propertyName Name of the property which gives the given file path.
*
* @return The specified File instance.
*
* @throws TAPException If the given URI is malformed or if the used URI scheme is different from "file:".
*/
protected static final File getFile(final String filePath, final String webAppRootPath, final String propertyName) throws TAPException{ protected static final File getFile(final String filePath, final String webAppRootPath, final String propertyName) throws TAPException{
if (filePath == null) if (filePath == null)
return null; return null;
else if (filePath.startsWith("file:"))
try{ try{
return new File(new URI(filePath)); URI uri = new URI(filePath);
}catch(URISyntaxException e){ if (uri.isAbsolute()){
throw new TAPException("Incorrect file URI for the property \"" + propertyName + "\": \"" + filePath + "\"! Bad syntax for the given file URI.", e); if (uri.getScheme().equalsIgnoreCase("file"))
return new File(uri);
else
throw new TAPException("Incorrect file URI for the property \"" + propertyName + "\": \"" + filePath + "\"! Only URI with the protocol \"file:\" are allowed.");
}else{
File f = new File(filePath);
if (f.isAbsolute())
return f;
else
return new File(webAppRootPath, filePath);
} }
else if (filePath.startsWith("/")) }catch(URISyntaxException use){
return new File(filePath); throw new TAPException("Incorrect file URI for the property \"" + propertyName + "\": \"" + filePath + "\"! Bad syntax for the given file URI.", use);
else if (filePath.matches("[a-zA-Z]+:.*")) }
throw new TAPException("Incorrect file URI for the property \"" + propertyName + "\": \"" + filePath + "\"! Only URI with the protocol \"file:\" are allowed.");
else
return new File(webAppRootPath, filePath);
} }
/**
* Initialize the TAP logger with the given TAP configuration file.
*
* @param tapConfig The content of the TAP configuration file.
*/
private void initLogger(final Properties tapConfig){ private void initLogger(final Properties tapConfig){
// Create the logger: // Create the logger:
logger = new DefaultTAPLog(fileManager); logger = new DefaultTAPLog(fileManager);
...@@ -298,6 +394,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -298,6 +394,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
logger.info(buf.toString()); logger.info(buf.toString());
} }
/**
* <p>Initialize the {@link TAPFactory} to use.</p>
*
* <p>
* The built factory is either a {@link ConfigurableTAPFactory} instance (by default) or
* an instance of the class specified in the TAP configuration file.
* </p>
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If an error occurs while building the specified {@link TAPFactory}.
*
* @see ConfigurableTAPFactory
*/
private void initFactory(final Properties tapConfig) throws TAPException{ private void initFactory(final Properties tapConfig) throws TAPException{
String propValue = getProperty(tapConfig, KEY_TAP_FACTORY); String propValue = getProperty(tapConfig, KEY_TAP_FACTORY);
if (propValue == null) if (propValue == null)
...@@ -306,6 +416,21 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -306,6 +416,21 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class}, new Object[]{this}); tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class}, new Object[]{this});
} }
/**
* Initialize the TAP metadata (i.e. database schemas, tables and columns and their attached metadata).
*
* @param tapConfig The content of the TAP configuration file.
* @param webAppRootDir Web Application directory local path.
* <em>This directory may be used if a relative path is given for an XML metadata file.</em>
*
* @return The extracted TAP metadata.
*
* @throws TAPException If some TAP configuration file properties are wrong or missing,
* or if an error has occurred while extracting the metadata from the database or the XML file.
*
* @see DBConnection#getTAPSchema()
* @see TableSetParser
*/
private TAPMetadata initMetadata(final Properties tapConfig, final String webAppRootDir) throws TAPException{ private TAPMetadata initMetadata(final Properties tapConfig, final String webAppRootDir) throws TAPException{
// Get the fetching method to use: // Get the fetching method to use:
String metaFetchType = getProperty(tapConfig, KEY_METADATA); String metaFetchType = getProperty(tapConfig, KEY_METADATA);
...@@ -402,6 +527,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -402,6 +527,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return metadata; return metadata;
} }
/**
* Initialize the maximum number of asynchronous jobs.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration property is wrong.
*/
private void initMaxAsyncJobs(final Properties tapConfig) throws TAPException{ private void initMaxAsyncJobs(final Properties tapConfig) throws TAPException{
// Get the property value: // Get the property value:
String propValue = getProperty(tapConfig, KEY_MAX_ASYNC_JOBS); String propValue = getProperty(tapConfig, KEY_MAX_ASYNC_JOBS);
...@@ -413,6 +545,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -413,6 +545,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
} }
} }
/**
* Initialize the default and maximum retention period.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initRetentionPeriod(final Properties tapConfig) throws TAPException{ private void initRetentionPeriod(final Properties tapConfig) throws TAPException{
retentionPeriod = new int[2]; retentionPeriod = new int[2];
...@@ -438,6 +577,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -438,6 +577,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
retentionPeriod[0] = retentionPeriod[1]; retentionPeriod[0] = retentionPeriod[1];
} }
/**
* Initialize the default and maximum execution duration.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initExecutionDuration(final Properties tapConfig) throws TAPException{ private void initExecutionDuration(final Properties tapConfig) throws TAPException{
executionDuration = new int[2]; executionDuration = new int[2];
...@@ -463,6 +609,19 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -463,6 +609,19 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
executionDuration[0] = executionDuration[1]; executionDuration[0] = executionDuration[1];
} }
/**
* <p>Initialize the list of all output format that the TAP service must support.</p>
*
* <p>
* This function ensures that at least one VOTable format is part of the returned list,
* even if none has been specified in the TAP configuration file. Indeed, the VOTable format is the only
* format required for a TAP service.
* </p>
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void addOutputFormats(final Properties tapConfig) throws TAPException{ private void addOutputFormats(final Properties tapConfig) throws TAPException{
// Fetch the value of the property for additional output formats: // Fetch the value of the property for additional output formats:
String formats = getProperty(tapConfig, KEY_OUTPUT_FORMATS); String formats = getProperty(tapConfig, KEY_OUTPUT_FORMATS);
...@@ -581,6 +740,18 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -581,6 +740,18 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
outputFormats.add(new VOTableFormat(this)); outputFormats.add(new VOTableFormat(this));
} }
/**
* <p>Parse the given VOTable format specification.</p>
*
* <p>This specification is expected to be an item of the property {@link TAPConfiguration#KEY_OUTPUT_FORMATS}.</p>
*
* @param propValue A single VOTable format specification.
*
* @return The corresponding configured {@link VOTableFormat} instance.
*
* @throws TAPException If the syntax of the given specification is incorrect,
* or if the specified VOTable version or serialization does not exist.
*/
private VOTableFormat parseVOTableFormat(final String propValue) throws TAPException{ private VOTableFormat parseVOTableFormat(final String propValue) throws TAPException{
DataFormat serialization = null; DataFormat serialization = null;
VOTableVersion votVersion = null; VOTableVersion votVersion = null;
...@@ -657,6 +828,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -657,6 +828,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return votFormat; return votFormat;
} }
/**
* Initialize the default and maximum output limits.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initOutputLimits(final Properties tapConfig) throws TAPException{ private void initOutputLimits(final Properties tapConfig) throws TAPException{
Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false); Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false);
outputLimitTypes[0] = (LimitUnit)limit[1]; // it should be "rows" since the parameter areBytesAllowed of parseLimit =false outputLimitTypes[0] = (LimitUnit)limit[1]; // it should be "rows" since the parameter areBytesAllowed of parseLimit =false
...@@ -664,11 +842,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -664,11 +842,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
limit = parseLimit(getProperty(tapConfig, KEY_MAX_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false); limit = parseLimit(getProperty(tapConfig, KEY_MAX_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false);
outputLimitTypes[1] = (LimitUnit)limit[1]; // it should be "rows" since the parameter areBytesAllowed of parseLimit =false outputLimitTypes[1] = (LimitUnit)limit[1]; // it should be "rows" since the parameter areBytesAllowed of parseLimit =false
setMaxOutputLimit((Integer)limit[0]);
if (!setMaxOutputLimit((Integer)limit[0]))
throw new TAPException("The default output limit (here: " + outputLimits[0] + ") MUST be less or equal to the maximum output limit (here: " + limit[0] + ")!");
} }
/**
* Initialize the fetch size for the synchronous and for the asynchronous resources.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initFetchSize(final Properties tapConfig) throws TAPException{ private void initFetchSize(final Properties tapConfig) throws TAPException{
fetchSize = new int[2]; fetchSize = new int[2];
...@@ -701,6 +884,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -701,6 +884,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
} }
} }
/**
* Initialize the default and maximum upload limits.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initUploadLimits(final Properties tapConfig) throws TAPException{ private void initUploadLimits(final Properties tapConfig) throws TAPException{
Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_UPLOAD_LIMIT), KEY_DEFAULT_UPLOAD_LIMIT, true); Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_UPLOAD_LIMIT), KEY_DEFAULT_UPLOAD_LIMIT, true);
uploadLimitTypes[0] = (LimitUnit)limit[1]; uploadLimitTypes[0] = (LimitUnit)limit[1];
...@@ -711,11 +901,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -711,11 +901,16 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
throw new TAPException("The default upload limit (in " + uploadLimitTypes[0] + ") and the maximum upload limit (in " + limit[1] + ") MUST be expressed in the same unit!"); throw new TAPException("The default upload limit (in " + uploadLimitTypes[0] + ") and the maximum upload limit (in " + limit[1] + ") MUST be expressed in the same unit!");
else else
uploadLimitTypes[1] = (LimitUnit)limit[1]; uploadLimitTypes[1] = (LimitUnit)limit[1];
setMaxUploadLimit((Integer)limit[0]);
if (!setMaxUploadLimit((Integer)limit[0]))
throw new TAPException("The default upload limit (here: " + getProperty(tapConfig, KEY_DEFAULT_UPLOAD_LIMIT) + ") MUST be less or equal to the maximum upload limit (here: " + getProperty(tapConfig, KEY_MAX_UPLOAD_LIMIT) + ")!");
} }
/**
* Initialize the maximum size (in bytes) of a VOTable files set upload.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration property is wrong.
*/
private void initMaxUploadSize(final Properties tapConfig) throws TAPException{ private void initMaxUploadSize(final Properties tapConfig) throws TAPException{
String propValue = getProperty(tapConfig, KEY_UPLOAD_MAX_FILE_SIZE); String propValue = getProperty(tapConfig, KEY_UPLOAD_MAX_FILE_SIZE);
// If a value is specified... // If a value is specified...
...@@ -733,6 +928,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -733,6 +928,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
} }
} }
/**
* Initialize the TAP user identification method.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration property is wrong.
*/
private void initUserIdentifier(final Properties tapConfig) throws TAPException{ private void initUserIdentifier(final Properties tapConfig) throws TAPException{
// Get the property value: // Get the property value:
String propValue = getProperty(tapConfig, KEY_USER_IDENTIFIER); String propValue = getProperty(tapConfig, KEY_USER_IDENTIFIER);
...@@ -740,6 +942,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -740,6 +942,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
userIdentifier = newInstance(propValue, KEY_USER_IDENTIFIER, UserIdentifier.class); userIdentifier = newInstance(propValue, KEY_USER_IDENTIFIER, UserIdentifier.class);
} }
/**
* Initialize the list of all allowed coordinate systems.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initCoordSys(final Properties tapConfig) throws TAPException{ private void initCoordSys(final Properties tapConfig) throws TAPException{
// Get the property value: // Get the property value:
String propValue = getProperty(tapConfig, KEY_COORD_SYS); String propValue = getProperty(tapConfig, KEY_COORD_SYS);
...@@ -791,6 +1000,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -791,6 +1000,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
} }
} }
/**
* Initialize the list of all allowed ADQL geometrical functions.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initADQLGeometries(final Properties tapConfig) throws TAPException{ private void initADQLGeometries(final Properties tapConfig) throws TAPException{
// Get the property value: // Get the property value:
String propValue = getProperty(tapConfig, KEY_GEOMETRIES); String propValue = getProperty(tapConfig, KEY_GEOMETRIES);
...@@ -839,6 +1055,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -839,6 +1055,13 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
} }
} }
/**
* Initialize the list of all known and allowed User Defined Functions.
*
* @param tapConfig The content of the TAP configuration file.
*
* @throws TAPException If the corresponding TAP configuration properties are wrong.
*/
private void initUDFs(final Properties tapConfig) throws TAPException{ private void initUDFs(final Properties tapConfig) throws TAPException{
// Get the property value: // Get the property value:
String propValue = getProperty(tapConfig, KEY_UDFS); String propValue = getProperty(tapConfig, KEY_UDFS);
...@@ -1023,6 +1246,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1023,6 +1246,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return retentionPeriod; return retentionPeriod;
} }
/**
* <p>Set the default retention period.</p>
*
* <p>This period is set by default if the user did not specify one before the execution of his query.</p>
*
* <p><em><b>Important note:</b>
* This function will apply the given retention period only if legal compared to the currently set maximum value.
* In other words, if the given value is less or equals to the current maximum retention period.
* </em></p>
*
* @param period New default retention period (in seconds).
*
* @return <i>true</i> if the given retention period has been successfully set, <i>false</i> otherwise.
*/
public boolean setDefaultRetentionPeriod(final int period){ public boolean setDefaultRetentionPeriod(final int period){
if ((retentionPeriod[1] <= 0) || (period > 0 && period <= retentionPeriod[1])){ if ((retentionPeriod[1] <= 0) || (period > 0 && period <= retentionPeriod[1])){
retentionPeriod[0] = period; retentionPeriod[0] = period;
...@@ -1031,12 +1268,25 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1031,12 +1268,25 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return false; return false;
} }
public boolean setMaxRetentionPeriod(final int period){ /**
if (period <= 0 || (retentionPeriod[0] > 0 && period >= retentionPeriod[0])){ * <p>Set the maximum retention period.</p>
retentionPeriod[1] = period; *
return true; * <p>This period limits the default retention period and the retention period specified by a user.</p>
}else *
return false; * <p><em><b>Important note:</b>
* This function may reduce the default retention period if the current default retention period is bigger
* to the new maximum retention period. In a such case, the default retention period is set to the
* new maximum retention period.
* </em></p>
*
* @param period New maximum retention period (in seconds).
*/
public void setMaxRetentionPeriod(final int period){
// Decrease the default retention period if it will be bigger than the new maximum retention period:
if (period > 0 && (retentionPeriod[0] <= 0 || period < retentionPeriod[0]))
retentionPeriod[0] = period;
// Set the new maximum retention period:
retentionPeriod[1] = period;
} }
@Override @Override
...@@ -1044,20 +1294,47 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1044,20 +1294,47 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return executionDuration; return executionDuration;
} }
public boolean setDefaultExecutionDuration(final int period){ /**
if ((executionDuration[1] <= 0) || (period > 0 && period <= executionDuration[1])){ * <p>Set the default execution duration.</p>
executionDuration[0] = period; *
* <p>This duration is set by default if the user did not specify one before the execution of his query.</p>
*
* <p><em><b>Important note:</b>
* This function will apply the given execution duration only if legal compared to the currently set maximum value.
* In other words, if the given value is less or equals to the current maximum execution duration.
* </em></p>
*
* @param duration New default execution duration (in milliseconds).
*
* @return <i>true</i> if the given execution duration has been successfully set, <i>false</i> otherwise.
*/
public boolean setDefaultExecutionDuration(final int duration){
if ((executionDuration[1] <= 0) || (duration > 0 && duration <= executionDuration[1])){
executionDuration[0] = duration;
return true; return true;
}else }else
return false; return false;
} }
public boolean setMaxExecutionDuration(final int period){ /**
if (period <= 0 || (executionDuration[0] > 0 && period >= executionDuration[0])){ * <p>Set the maximum execution duration.</p>
executionDuration[1] = period; *
return true; * <p>This duration limits the default execution duration and the execution duration specified by a user.</p>
}else *
return false; * <p><em><b>Important note:</b>
* This function may reduce the default execution duration if the current default execution duration is bigger
* to the new maximum execution duration. In a such case, the default execution duration is set to the
* new maximum execution duration.
* </em></p>
*
* @param duration New maximum execution duration (in milliseconds).
*/
public void setMaxExecutionDuration(final int duration){
// Decrease the default execution duration if it will be bigger than the new maximum execution duration:
if (duration > 0 && (executionDuration[0] <= 0 || duration < executionDuration[0]))
executionDuration[0] = duration;
// Set the new maximum execution duration:
executionDuration[1] = duration;
} }
@Override @Override
...@@ -1077,10 +1354,29 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1077,10 +1354,29 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return null; return null;
} }
/**
* <p>Add the given {@link OutputFormat} in the list of output formats supported by the TAP service.</p>
*
* <p><b>Warning:
* No verification is done in order to avoid duplicated output formats in the list.
* NULL objects are merely ignored silently.
* </b></p>
*
* @param newOutputFormat New output format.
*/
public void addOutputFormat(final OutputFormat newOutputFormat){ public void addOutputFormat(final OutputFormat newOutputFormat){
outputFormats.add(newOutputFormat); if (newOutputFormat != null)
outputFormats.add(newOutputFormat);
} }
/**
* Remove the specified output format.
*
* @param mimeOrAlias Full or short MIME type of the output format to remove.
*
* @return <i>true</i> if the specified format has been found and successfully removed from the list,
* <i>false</i> otherwise.
*/
public boolean removeOutputFormat(final String mimeOrAlias){ public boolean removeOutputFormat(final String mimeOrAlias){
OutputFormat of = getOutputFormat(mimeOrAlias); OutputFormat of = getOutputFormat(mimeOrAlias);
if (of != null) if (of != null)
...@@ -1094,6 +1390,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1094,6 +1390,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return outputLimits; return outputLimits;
} }
/**
* <p>Set the default output limit.</p>
*
* <p>This limit is set by default if the user did not specify one before the execution of his query.</p>
*
* <p><em><b>Important note:</b>
* This function will apply the given output limit only if legal compared to the currently set maximum value.
* In other words, if the given value is less or equals to the current maximum output limit.
* </em></p>
*
* @param limit New default output limit (in number of rows).
*
* @return <i>true</i> if the given output limit has been successfully set, <i>false</i> otherwise.
*/
public boolean setDefaultOutputLimit(final int limit){ public boolean setDefaultOutputLimit(final int limit){
if ((outputLimits[1] <= 0) || (limit > 0 && limit <= outputLimits[1])){ if ((outputLimits[1] <= 0) || (limit > 0 && limit <= outputLimits[1])){
outputLimits[0] = limit; outputLimits[0] = limit;
...@@ -1102,13 +1412,25 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1102,13 +1412,25 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return false; return false;
} }
public boolean setMaxOutputLimit(final int limit){ /**
if (limit > 0 && outputLimits[0] > 0 && limit < outputLimits[0]) * <p>Set the maximum output limit.</p>
return false; *
else{ * <p>This output limit limits the default output limit and the output limit specified by a user.</p>
outputLimits[1] = limit; *
return true; * <p><em><b>Important note:</b>
} * This function may reduce the default output limit if the current default output limit is bigger
* to the new maximum output limit. In a such case, the default output limit is set to the
* new maximum output limit.
* </em></p>
*
* @param limit New maximum output limit (in number of rows).
*/
public void setMaxOutputLimit(final int limit){
// Decrease the default output limit if it will be bigger than the new maximum output limit:
if (limit > 0 && (outputLimits[0] <= 0 || limit < outputLimits[0]))
outputLimits[0] = limit;
// Set the new maximum output limit:
outputLimits[1] = limit;
} }
@Override @Override
...@@ -1155,11 +1477,28 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1155,11 +1477,28 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return uploadLimitTypes; return uploadLimitTypes;
} }
/**
* Set the unit of the upload limit.
*
* @param type Unit of upload limit (rows or bytes).
*/
public void setUploadLimitType(final LimitUnit type){ public void setUploadLimitType(final LimitUnit type){
if (type != null) if (type != null)
uploadLimitTypes = new LimitUnit[]{type,type}; uploadLimitTypes = new LimitUnit[]{type,type};
} }
/**
* <p>Set the default upload limit.</p>
*
* <p><em><b>Important note:</b>
* This function will apply the given upload limit only if legal compared to the currently set maximum value.
* In other words, if the given value is less or equals to the current maximum upload limit.
* </em></p>
*
* @param limit New default upload limit.
*
* @return <i>true</i> if the given upload limit has been successfully set, <i>false</i> otherwise.
*/
public boolean setDefaultUploadLimit(final int limit){ public boolean setDefaultUploadLimit(final int limit){
try{ try{
if ((uploadLimits[1] <= 0) || (limit > 0 && LimitUnit.compare(limit, uploadLimitTypes[0], uploadLimits[1], uploadLimitTypes[1]) <= 0)){ if ((uploadLimits[1] <= 0) || (limit > 0 && LimitUnit.compare(limit, uploadLimitTypes[0], uploadLimits[1], uploadLimitTypes[1]) <= 0)){
...@@ -1170,17 +1509,27 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1170,17 +1509,27 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return false; return false;
} }
public boolean setMaxUploadLimit(final int limit){ /**
* <p>Set the maximum upload limit.</p>
*
* <p>This upload limit limits the default upload limit.</p>
*
* <p><em><b>Important note:</b>
* This function may reduce the default upload limit if the current default upload limit is bigger
* to the new maximum upload limit. In a such case, the default upload limit is set to the
* new maximum upload limit.
* </em></p>
*
* @param limit New maximum upload limit.
*/
public void setMaxUploadLimit(final int limit){
try{ try{
if (limit > 0 && uploadLimits[0] > 0 && LimitUnit.compare(limit, uploadLimitTypes[1], uploadLimits[0], uploadLimitTypes[0]) < 0) // Decrease the default output limit if it will be bigger than the new maximum output limit:
return false; if (limit > 0 && (uploadLimits[0] <= 0 || LimitUnit.compare(limit, uploadLimitTypes[1], uploadLimits[0], uploadLimitTypes[0]) < 0))
else{ uploadLimits[0] = limit;
uploadLimits[1] = limit; // Set the new maximum output limit:
return true; uploadLimits[1] = limit;
} }catch(TAPException e){}
}catch(TAPException e){
return false;
}
} }
@Override @Override
...@@ -1188,6 +1537,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection { ...@@ -1188,6 +1537,20 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
return maxUploadSize; return maxUploadSize;
} }
/**
* <p>Set the maximum size of a VOTable files set that can be uploaded in once.</p>
*
* <p><b>Warning:
* This size can not be negative or 0. If the given value is in this case, nothing will be done
* and <i>false</i> will be returned.
* On the contrary to the other limits, no "unlimited" limit is possible here ; only the
* maximum value can be set (i.e. maximum positive integer value).
* </b></p>
*
* @param maxSize New maximum size (in bytes).
*
* @return <i>true</i> if the size has been successfully set, <i>false</i> otherwise.
*/
public boolean setMaxUploadSize(final int maxSize){ public boolean setMaxUploadSize(final int maxSize){
// No "unlimited" value possible there: // No "unlimited" value possible there:
if (maxSize <= 0) if (maxSize <= 0)
......
...@@ -52,6 +52,7 @@ import javax.sql.DataSource; ...@@ -52,6 +52,7 @@ import javax.sql.DataSource;
import tap.AbstractTAPFactory; import tap.AbstractTAPFactory;
import tap.ServiceConnection; import tap.ServiceConnection;
import tap.TAPException; import tap.TAPException;
import tap.TAPFactory;
import tap.backup.DefaultTAPBackupManager; import tap.backup.DefaultTAPBackupManager;
import tap.db.DBConnection; import tap.db.DBConnection;
import tap.db.JDBCConnection; import tap.db.JDBCConnection;
...@@ -64,25 +65,59 @@ import adql.translator.PgSphereTranslator; ...@@ -64,25 +65,59 @@ import adql.translator.PgSphereTranslator;
import adql.translator.PostgreSQLTranslator; import adql.translator.PostgreSQLTranslator;
/** /**
* <p>Concrete implementation of a {@link TAPFactory} which is parameterized by a TAP configuration file.</p>
* *
* <p>
* All abstract or NULL-implemented methods/functions left by {@link AbstractTAPFactory} are implemented using values
* of a TAP configuration file. The concerned methods are: {@link #getConnection(String)}, {@link #freeConnection(DBConnection)},
* {@link #destroy()}, {@link #createADQLTranslator()} and {@link #createUWSBackupManager(UWSService)}.
* </p>
* *
* @author Gr&eacute;gory Mantelet (ARI) * @author Gr&eacute;gory Mantelet (ARI)
* @version 2.0 (04/2015) * @version 2.0 (04/2015)
* @since 2.0
*/ */
public final class ConfigurableTAPFactory extends AbstractTAPFactory { public final class ConfigurableTAPFactory extends AbstractTAPFactory {
/* ADQL to SQL translation: */
/** The {@link JDBCTranslator} to use when a ADQL query must be executed in the database.
* This translator is also used to convert ADQL types into database types. */
private Class<? extends JDBCTranslator> translator; private Class<? extends JDBCTranslator> translator;
/* JNDI DB access: */
/** The {@link DataSource} to use in order to access the database.
* <em>This attribute is actually used only if the chosen database access method is JNDI.</em> */
private final DataSource datasource; private final DataSource datasource;
/* Simple JDBC access: */
/** Classpath of the JDBC driver to use in order to access the database.
* <em>This attribute is actually used only if the chosen database access method is JDBC.</em> */
private final String driverPath; private final String driverPath;
/** JDBC URL of the database to access.
* <em>This attribute is actually used only if the chosen database access method is JDBC.</em> */
private final String dbUrl; private final String dbUrl;
/** Name of the database user to use in order to access the database.
* <em>This attribute is actually used only if the chosen database access method is JDBC.</em> */
private final String dbUser; private final String dbUser;
/** Password of the database user to use in order to access the database.
* <em>This attribute is actually used only if the chosen database access method is JDBC.</em> */
private final String dbPassword; private final String dbPassword;
/* UWS's jobs backup: */
/** Indicate whether the jobs must be backuped gathered by user or just all mixed together. */
private boolean backupByUser; private boolean backupByUser;
/** Frequency at which the jobs must be backuped. */
private long backupFrequency; private long backupFrequency;
/**
* Build a {@link TAPFactory} using the given TAP service description and TAP configuration file.
*
* @param service The TAP service description.
* @param tapConfig The TAP configuration file containing particularly information about the database access.
*
* @throws NullPointerException If one of the parameter is NULL.
* @throws TAPException If some properties of the TAP configuration file are wrong.
*/
public ConfigurableTAPFactory(ServiceConnection service, final Properties tapConfig) throws NullPointerException, TAPException{ public ConfigurableTAPFactory(ServiceConnection service, final Properties tapConfig) throws NullPointerException, TAPException{
super(service); super(service);
......
...@@ -47,14 +47,22 @@ import tap.resource.TAP; ...@@ -47,14 +47,22 @@ import tap.resource.TAP;
import tap.resource.TAPResource; import tap.resource.TAPResource;
/** /**
* <p>HTTP servlet fully configured with a TAP configuration file.</p>
* *
* <p>
* This configuration file may be specified in the initial parameter named {@value TAPConfiguration#TAP_CONF_PARAMETER}
* of this servlet inside the WEB-INF/web.xml file. If none is specified, the file {@value TAPConfiguration#DEFAULT_TAP_CONF_FILE}
* will be searched inside the directories of the classpath, and inside WEB-INF and META-INF.
* </p>
* *
* @author Gr&eacute;gory Mantelet (ARI) * @author Gr&eacute;gory Mantelet (ARI)
* @version 2.0 (03/2015) * @version 2.0 (04/2015)
* @since 2.0
*/ */
public class ConfigurableTAPServlet extends HttpServlet { public class ConfigurableTAPServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** TAP object representing the TAP service. */
private TAP tap = null; private TAP tap = null;
@Override @Override
...@@ -171,6 +179,16 @@ public class ConfigurableTAPServlet extends HttpServlet { ...@@ -171,6 +179,16 @@ public class ConfigurableTAPServlet extends HttpServlet {
serviceConn.setAvailable(true, "TAP service available."); serviceConn.setAvailable(true, "TAP service available.");
} }
/**
* Search the given file name/path in the directories of the classpath, then inside WEB-INF and finally inside META-INF.
*
* @param filePath A file name/path.
* @param config Servlet configuration (containing also the context class loader - link with the servlet classpath).
*
* @return The input stream toward the specified file, or NULL if no file can be found.
*
* @since 2.0
*/
protected final InputStream searchFile(String filePath, final ServletConfig config){ protected final InputStream searchFile(String filePath, final ServletConfig config){
InputStream input = null; InputStream input = null;
...@@ -207,8 +225,6 @@ public class ConfigurableTAPServlet extends HttpServlet { ...@@ -207,8 +225,6 @@ public class ConfigurableTAPServlet extends HttpServlet {
try{ try{
tap.executeRequest(req, resp); tap.executeRequest(req, resp);
}catch(Throwable t){ }catch(Throwable t){
System.err.println("Request aborted !");
t.printStackTrace(System.err);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getMessage()); resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getMessage());
} }
}else }else
......
...@@ -26,6 +26,7 @@ import java.util.Properties; ...@@ -26,6 +26,7 @@ import java.util.Properties;
import tap.ServiceConnection.LimitUnit; import tap.ServiceConnection.LimitUnit;
import tap.TAPException; import tap.TAPException;
import tap.TAPFactory;
import tap.backup.DefaultTAPBackupManager; import tap.backup.DefaultTAPBackupManager;
/** /**
...@@ -105,27 +106,53 @@ public final class TAPConfiguration { ...@@ -105,27 +106,53 @@ public final class TAPConfiguration {
public final static boolean DEFAULT_BACKUP_BY_USER = false; public final static boolean DEFAULT_BACKUP_BY_USER = false;
/* ASYNCHRONOUS JOBS */ /* ASYNCHRONOUS JOBS */
/** Name/Key of the property specifying the maximum number of asynchronous jobs that can run simultaneously.
* A negative or null value means "no limit". */
public final static String KEY_MAX_ASYNC_JOBS = "max_async_jobs"; public final static String KEY_MAX_ASYNC_JOBS = "max_async_jobs";
/** Default value of the property {@link #KEY_MAX_ASYNC_JOBS}: {@value #DEFAULT_MAX_ASYNC_JOBS}. */
public final static int DEFAULT_MAX_ASYNC_JOBS = 0; public final static int DEFAULT_MAX_ASYNC_JOBS = 0;
/* EXECUTION DURATION */ /* EXECUTION DURATION */
/** Name/Key of the property specifying the default execution duration (in milliseconds) set automatically to a job
* if none has been specified by the user. */
public final static String KEY_DEFAULT_EXECUTION_DURATION = "default_execution_duration"; public final static String KEY_DEFAULT_EXECUTION_DURATION = "default_execution_duration";
/** Name/Key of the property specifying the maximum execution duration (in milliseconds) that can be set on a job. */
public final static String KEY_MAX_EXECUTION_DURATION = "max_execution_duration"; public final static String KEY_MAX_EXECUTION_DURATION = "max_execution_duration";
/** Default value of the property {@link #KEY_DEFAULT_EXECUTION_DURATION} and {@link #KEY_MAX_EXECUTION_DURATION}: {@value #DEFAULT_EXECUTION_DURATION}. */
public final static int DEFAULT_EXECUTION_DURATION = 0; public final static int DEFAULT_EXECUTION_DURATION = 0;
/* DATABASE KEYS */ /* DATABASE KEYS */
/** Name/Key of the property specifying the database access method to use. */
public final static String KEY_DATABASE_ACCESS = "database_access"; public final static String KEY_DATABASE_ACCESS = "database_access";
/** Value of the property {@link #KEY_DATABASE_ACCESS} to select the simple JDBC method. */
public final static String VALUE_JDBC = "jdbc"; public final static String VALUE_JDBC = "jdbc";
/** Value of the property {@link #KEY_DATABASE_ACCESS} to access the database using a DataSource stored in JNDI. */
public final static String VALUE_JNDI = "jndi"; public final static String VALUE_JNDI = "jndi";
/** Name/Key of the property specifying the ADQL to SQL translator to use. */
public final static String KEY_SQL_TRANSLATOR = "sql_translator"; public final static String KEY_SQL_TRANSLATOR = "sql_translator";
/** Value of the property {@link #KEY_SQL_TRANSLATOR} to select a PostgreSQL translator (no support for geometrical functions). */
public final static String VALUE_POSTGRESQL = "postgres"; public final static String VALUE_POSTGRESQL = "postgres";
/** Value of the property {@link #KEY_SQL_TRANSLATOR} to select a PgSphere translator. */
public final static String VALUE_PGSPHERE = "pgsphere"; public final static String VALUE_PGSPHERE = "pgsphere";
/** Name/Key of the property specifying by how many rows the library should fetch a query result from the database.
* This is the fetch size for to apply for synchronous queries. */
public final static String KEY_SYNC_FETCH_SIZE = "sync_fetch_size"; public final static String KEY_SYNC_FETCH_SIZE = "sync_fetch_size";
/** Default value of the property {@link #KEY_SYNC_FETCH_SIZE}: {@value #DEFAULT_SYNC_FETCH_SIZE}. */
public final static int DEFAULT_SYNC_FETCH_SIZE = 10000; public final static int DEFAULT_SYNC_FETCH_SIZE = 10000;
/** Name/Key of the property specifying by how many rows the library should fetch a query result from the database.
* This is the fetch size for to apply for asynchronous queries. */
public final static String KEY_ASYNC_FETCH_SIZE = "async_fetch_size"; 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 = 100000; public final static int DEFAULT_ASYNC_FETCH_SIZE = 100000;
/** 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"; 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.
* Alternatively, a shortcut the most known JDBC drivers can be used. The list of these drivers is stored
* in {@link #VALUE_JDBC_DRIVERS}. */
public final static String KEY_JDBC_DRIVER = "jdbc_driver"; public final static String KEY_JDBC_DRIVER = "jdbc_driver";
/** List of the most known JDBC drivers. For the moment this list contains 4 drivers:
* oracle ("oracle.jdbc.OracleDriver"), postgresql ("org.postgresql.Driver"), mysql ("com.mysql.jdbc.Driver")
* and sqlite ("org.sqlite.JDBC"). */
public final static HashMap<String,String> VALUE_JDBC_DRIVERS = new HashMap<String,String>(4); public final static HashMap<String,String> VALUE_JDBC_DRIVERS = new HashMap<String,String>(4);
static{ static{
VALUE_JDBC_DRIVERS.put("oracle", "oracle.jdbc.OracleDriver"); VALUE_JDBC_DRIVERS.put("oracle", "oracle.jdbc.OracleDriver");
...@@ -133,60 +160,116 @@ public final class TAPConfiguration { ...@@ -133,60 +160,116 @@ public final class TAPConfiguration {
VALUE_JDBC_DRIVERS.put("mysql", "com.mysql.jdbc.Driver"); VALUE_JDBC_DRIVERS.put("mysql", "com.mysql.jdbc.Driver");
VALUE_JDBC_DRIVERS.put("sqlite", "org.sqlite.JDBC"); VALUE_JDBC_DRIVERS.put("sqlite", "org.sqlite.JDBC");
} }
/** Name/Key of the property specifying the JDBC URL of the database to access. */
public final static String KEY_JDBC_URL = "jdbc_url"; public final static String KEY_JDBC_URL = "jdbc_url";
/** Name/Key of the property specifying the database user name to use to access the database. */
public final static String KEY_DB_USERNAME = "db_username"; public final static String KEY_DB_USERNAME = "db_username";
/** Name/Key of the property specifying the password of the database user. */
public final static String KEY_DB_PASSWORD = "db_password"; public final static String KEY_DB_PASSWORD = "db_password";
/* METADATA KEYS */ /* METADATA KEYS */
/** Name/Key of the property specifying where the list of schemas, tables and columns and their respective metadata
* is provided. */
public final static String KEY_METADATA = "metadata"; public final static String KEY_METADATA = "metadata";
/** Value of the property {@link #KEY_METADATA} which indicates that metadata are provided in an XML file, whose the
* local path is given by the property {@link #KEY_METADATA_FILE}. */
public final static String VALUE_XML = "xml"; public final static String VALUE_XML = "xml";
/** Value of the property {@link #KEY_METADATA} which indicates that metadata are already in the TAP_SCHEMA of the database. */
public final static String VALUE_DB = "db"; public final static String VALUE_DB = "db";
/** Name/Key of the property specifying the local file path of the XML file containing the TAP metadata to load. */
public final static String KEY_METADATA_FILE = "metadata_file"; public final static String KEY_METADATA_FILE = "metadata_file";
/* HOME PAGE KEY */ /* HOME PAGE KEY */
/** Name/Key of the property specifying the TAP home page to use.
* It can be a file, a URL or a class. If null, the default TAP home page of the library is used.
* By default the default library home page is used. */
public final static String KEY_HOME_PAGE = "home_page"; public final static String KEY_HOME_PAGE = "home_page";
/** Name/Key of the property specifying the MIME type of the set home page.
* By default, "text/html" is set. */
public final static String KEY_HOME_PAGE_MIME_TYPE = "home_page_mime_type"; public final static String KEY_HOME_PAGE_MIME_TYPE = "home_page_mime_type";
/* PROVIDER KEYS */ /* PROVIDER KEYS */
/** Name/Key of the property specifying the name of the organization/person providing the TAP service. */
public final static String KEY_PROVIDER_NAME = "provider_name"; public final static String KEY_PROVIDER_NAME = "provider_name";
/** Name/Key of the property specifying the description of the TAP service. */
public final static String KEY_SERVICE_DESCRIPTION = "service_description"; public final static String KEY_SERVICE_DESCRIPTION = "service_description";
/* UPLOAD KEYS */ /* UPLOAD KEYS */
/** Name/Key of the property indicating whether the UPLOAD feature must be enabled or not.
* By default, this feature is disabled. */
public final static String KEY_UPLOAD_ENABLED = "upload_enabled"; public final static String KEY_UPLOAD_ENABLED = "upload_enabled";
/** Name/Key of the property specifying the default limit (in rows or bytes) on the uploaded VOTable(s). */
public final static String KEY_DEFAULT_UPLOAD_LIMIT = "upload_default_db_limit"; public final static String KEY_DEFAULT_UPLOAD_LIMIT = "upload_default_db_limit";
/** Name/Key of the property specifying the maximum limit (in rows or bytes) on the uploaded VOTable(s). */
public final static String KEY_MAX_UPLOAD_LIMIT = "upload_max_db_limit"; public final static String KEY_MAX_UPLOAD_LIMIT = "upload_max_db_limit";
/** Name/Key of the property specifying the maximum size of all VOTable(s) uploaded in a query. */
public final static String KEY_UPLOAD_MAX_FILE_SIZE = "upload_max_file_size"; public final static String KEY_UPLOAD_MAX_FILE_SIZE = "upload_max_file_size";
/** Default value of the property {@link #KEY_UPLOAD_MAX_FILE_SIZE}: {@value #DEFAULT_UPLOAD_MAX_FILE_SIZE}. */
public final static int DEFAULT_UPLOAD_MAX_FILE_SIZE = Integer.MAX_VALUE; public final static int DEFAULT_UPLOAD_MAX_FILE_SIZE = Integer.MAX_VALUE;
/* OUTPUT KEYS */ /* OUTPUT KEYS */
/** Name/Key of the property specifying the list of all result output formats to support.
* By default all formats provided by the library are allowed. */
public final static String KEY_OUTPUT_FORMATS = "output_formats"; public final static String KEY_OUTPUT_FORMATS = "output_formats";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select all formats that the library can provide. */
public final static String VALUE_ALL = "ALL"; public final static String VALUE_ALL = "ALL";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a VOTable format.
* The format can be parameterized with the VOTable version and serialization. */
public final static String VALUE_VOTABLE = "votable"; public final static String VALUE_VOTABLE = "votable";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a VOTable format.
* The format can be parameterized with the VOTable version and serialization.
* <em>This value is just an alias of {@link #VALUE_VOTABLE}.</em> */
public final static String VALUE_VOT = "vot"; public final static String VALUE_VOT = "vot";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a FITS format. */
public final static String VALUE_FITS = "fits"; public final static String VALUE_FITS = "fits";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a JSON format. */
public final static String VALUE_JSON = "json"; public final static String VALUE_JSON = "json";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select an HTML format. */
public final static String VALUE_HTML = "html"; public final static String VALUE_HTML = "html";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a human-readable table. */
public final static String VALUE_TEXT = "text"; public final static String VALUE_TEXT = "text";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a CSV format. */
public final static String VALUE_CSV = "csv"; public final static String VALUE_CSV = "csv";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a TSV format. */
public final static String VALUE_TSV = "tsv"; public final static String VALUE_TSV = "tsv";
/** Value of the property {@link #KEY_OUTPUT_FORMATS} which select a Separated-Value format.
* <em>This value must be parameterized with the separator to use.</em> */
public final static String VALUE_SV = "sv"; public final static String VALUE_SV = "sv";
/** Name/Key of the property specifying the number of result rows that should be returned if none is specified by the user. */
public final static String KEY_DEFAULT_OUTPUT_LIMIT = "output_default_limit"; public final static String KEY_DEFAULT_OUTPUT_LIMIT = "output_default_limit";
/** Name/Key of the property specifying the maximum number of result rows that can be returned by the TAP service. */
public final static String KEY_MAX_OUTPUT_LIMIT = "output_max_limit"; public final static String KEY_MAX_OUTPUT_LIMIT = "output_max_limit";
/* USER IDENTIFICATION */ /* USER IDENTIFICATION */
/** Name/Key of the property specifying the user identification method to use.
* None is implemented by the library, so a class must be provided as value of this property. */
public final static String KEY_USER_IDENTIFIER = "user_identifier"; public final static String KEY_USER_IDENTIFIER = "user_identifier";
/* ADQL RESTRICTIONS */ /* ADQL RESTRICTIONS */
/** Name/Key of the property specifying the list of all allowed coordinate systems that can be used in ADQL queries.
* By default, all are allowed, but no conversion is done by the library. */
public final static String KEY_COORD_SYS = "coordinate_systems"; public final static String KEY_COORD_SYS = "coordinate_systems";
/** Name/Key of the property specifying the list of all ADQL geometrical function that can be used in ADQL queries.
* By default, all are allowed. */
public final static String KEY_GEOMETRIES = "geometries"; public final static String KEY_GEOMETRIES = "geometries";
/** Value of {@link #KEY_COORD_SYS} and {@link #KEY_GEOMETRIES} that forbid all possible values. */
public final static String VALUE_NONE = "NONE"; public final static String VALUE_NONE = "NONE";
/** Name/Key of the property that lets declare all User Defined Functions that must be allowed in ADQL queries.
* By default, all unknown functions are rejected. This default behavior can be totally reversed by using the
* value {@link #VALUE_ANY} */
public final static String KEY_UDFS = "udfs"; public final static String KEY_UDFS = "udfs";
/** Value of {@link #KEY_UDFS} allowing any unknown function in ADQL queries. Those functions will be considered as UDFs
* and will be translated into SQL exactly as they are written in ADQL. */
public final static String VALUE_ANY = "ANY"; public final static String VALUE_ANY = "ANY";
/* ADDITIONAL TAP RESOURCES */ /* ADDITIONAL TAP RESOURCES */
/** Name/Key of the property specifying a list of resources to add to the TAP service (e.g. a ADQL query validator).
* By default, this list if empty ; only the default TAP resources exist. */
public final static String KEY_ADD_TAP_RESOURCES = "additional_resources"; public final static String KEY_ADD_TAP_RESOURCES = "additional_resources";
/* CUSTOM FACTORY */ /* CUSTOM FACTORY */
/** Name/Key of the property specifying the {@link TAPFactory} class to use instead of the default {@link ConfigurableTAPFactory}.
* <em>Setting a value to this property could disable several properties of the TAP configuration file.</em> */
public final static String KEY_TAP_FACTORY = "tap_factory"; public final static String KEY_TAP_FACTORY = "tap_factory";
/** No instance of this class should be created. */ /** No instance of this class should be created. */
......
...@@ -714,10 +714,10 @@ public class TestConfigurableServiceConnection { ...@@ -714,10 +714,10 @@ public class TestConfigurableServiceConnection {
// Test with only a set maximum output limit: // Test with only a set maximum output limit:
try{ try{
ServiceConnection connection = new ConfigurableServiceConnection(maxOutputLimitProp); ServiceConnection connection = new ConfigurableServiceConnection(maxOutputLimitProp);
assertEquals(connection.getOutputLimit()[0], -1); assertEquals(1000, connection.getOutputLimit()[0]);
assertEquals(connection.getOutputLimit()[1], 1000); assertEquals(1000, connection.getOutputLimit()[1]);
assertEquals(connection.getOutputLimitType()[0], LimitUnit.rows); assertEquals(LimitUnit.rows, connection.getOutputLimitType()[0]);
assertEquals(connection.getOutputLimitType()[1], LimitUnit.rows); assertEquals(LimitUnit.rows, connection.getOutputLimitType()[1]);
}catch(Exception e){ }catch(Exception e){
fail("This MUST have succeeded because setting only the maximum output limit is valid! \nCaught exception: " + getPertinentMessage(e)); fail("This MUST have succeeded because setting only the maximum output limit is valid! \nCaught exception: " + getPertinentMessage(e));
} }
...@@ -734,12 +734,15 @@ public class TestConfigurableServiceConnection { ...@@ -734,12 +734,15 @@ public class TestConfigurableServiceConnection {
} }
// Test with both a default and a maximum output limits BUT where default > max: // Test with both a default and a maximum output limits BUT where default > max:
/* In a such case, the default value is set silently to the maximum one. */
try{ try{
new ConfigurableServiceConnection(bothOutputLimitBadProp); ServiceConnection connection = new ConfigurableServiceConnection(bothOutputLimitBadProp);
fail("This MUST have failed because the default output limit is greater than the maximum one!"); assertEquals(100, connection.getOutputLimit()[1]);
assertEquals(connection.getOutputLimit()[1], connection.getOutputLimit()[0]);
assertEquals(LimitUnit.rows, connection.getOutputLimitType()[1]);
assertEquals(connection.getOutputLimitType()[1], connection.getOutputLimitType()[0]);
}catch(Exception e){ }catch(Exception e){
assertEquals(TAPException.class, e.getClass()); fail("This MUST have succeeded because the default output limit is set automatically to the maximum one if bigger! \nCaught exception: " + getPertinentMessage(e));
assertEquals("The default output limit (here: 1000) MUST be less or equal to the maximum output limit (here: 100)!", e.getMessage());
} }
// Test with a not integer sync. fetch size: // Test with a not integer sync. fetch size:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment