package tap.config;
/*
* 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
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}. *
* * @author Grégory Mantelet (ARI) * @version 2.1 (02/2018) * @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). */ private TAPLog logger; /** 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. */ private final TAPMetadata metadata; /** Name of the organization/person providing the TAP service. */ private final String providerName; /** Description of the TAP service. */ private final String serviceDescription; /** 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."; /** Maximum number of asynchronous jobs that can run simultaneously. */ private int maxAsyncJobs = DEFAULT_MAX_ASYNC_JOBS; /** Array of 2 integers: resp. default and maximum execution duration. * Both duration are expressed in milliseconds. */ private int[] executionDuration = new int[2]; /** Array of 2 integers: resp. default and maximum retention period. * Both period are expressed in seconds. */ private int[] retentionPeriod = new int[2]; /** List of all available output formatters. */ private final ArrayListResolve the given file name/path.
* ** If not an absolute path, 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). *
* * @param filePath 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 ParseException If the given file path is a URI/URL. */ protected static final File getFile(final String filePath, final String webAppRootPath, final String propertyName) throws TAPException{ if (filePath == null) return null; else if (filePath.matches(".*:.*")) throw new TAPException("Incorrect file path for the property \"" + propertyName + "\": \"" + filePath + "\"! URI/URLs are not expected here."); File f = new File(filePath); if (f.isAbsolute()) return f; 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. * * @throws TAPException If no instance of the specified custom logger can * be created. */ private void initLogger(final Properties tapConfig) throws TAPException{ // Create the logger: String propValue = getProperty(tapConfig, KEY_LOGGER); if (propValue == null || propValue.trim().equalsIgnoreCase(DEFAULT_LOGGER)) logger = new DefaultTAPLog(fileManager); else logger = newInstance(propValue, KEY_LOGGER, TAPLog.class, new Class>[]{UWSFileManager.class}, new Object[]{fileManager}); StringBuffer buf = new StringBuffer("Logger initialized"); // Set the minimum log level: propValue = getProperty(tapConfig, KEY_MIN_LOG_LEVEL); if (propValue != null){ try{ ((DefaultTAPLog)logger).setMinLogLevel(LogLevel.valueOf(propValue.toUpperCase())); }catch(IllegalArgumentException iae){} } buf.append(" (minimum log level: ").append(((DefaultTAPLog)logger).getMinLogLevel()); // Set the log rotation period, if any: if (fileManager instanceof LocalUWSFileManager){ propValue = getProperty(tapConfig, KEY_LOG_ROTATION); if (propValue != null) ((LocalUWSFileManager)fileManager).setLogRotationFreq(propValue); buf.append(", log rotation: ").append(((LocalUWSFileManager)fileManager).getLogRotationFreq()); } // Log the successful initialization with set parameters: buf.append(")."); logger.info(buf.toString()); } /** *Initialize the {@link TAPFactory} to use.
* ** The built factory is either a {@link ConfigurableTAPFactory} instance (by default) or * an instance of the class specified in the TAP configuration file. *
* * @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{ String propValue = getProperty(tapConfig, KEY_TAP_FACTORY); if (propValue == null) tapFactory = new ConfigurableTAPFactory(this, tapConfig); else if (hasConstructor(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class>[]{ServiceConnection.class,Properties.class})) tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class>[]{ServiceConnection.class,Properties.class}, new Object[]{this,tapConfig}); else 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. * This directory may be used if a relative path is given for an XML metadata file. * * @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{ // Get the fetching method to use: String metaFetchType = getProperty(tapConfig, KEY_METADATA); if (metaFetchType == null) throw new TAPException("The property \"" + KEY_METADATA + "\" is missing! It is required to create a TAP Service. Three possible values: " + VALUE_XML + " (to get metadata from a TableSet XML document), " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA) or the name (between {}) of a class extending TAPMetadata. Only " + VALUE_XML + " and " + VALUE_DB + " can be followed by the path of a class extending TAPMetadata."); // Extract a custom class suffix if any for XML and DB options: String customMetaClass = null; if (metaFetchType.toLowerCase().matches("(" + VALUE_XML + "|" + VALUE_DB + ").*")){ int indSep = metaFetchType.toLowerCase().startsWith(VALUE_XML) ? 3 : 2; customMetaClass = metaFetchType.substring(indSep).trim(); metaFetchType = metaFetchType.substring(0, indSep); if (customMetaClass.length() == 0) customMetaClass = null; else if (!isClassName(customMetaClass)) throw new TAPException("Unexpected string after the fetching method \"" + metaFetchType + "\": \"" + customMetaClass + "\"! The full name of a class extending TAPMetadata was expected. If it is a class name, then it must be specified between {}."); } TAPMetadata metadata = null; // GET METADATA FROM XML & UPDATE THE DATABASE (schema TAP_SCHEMA only): if (metaFetchType.equalsIgnoreCase(VALUE_XML)){ // Get the XML file path: String xmlFilePath = getProperty(tapConfig, KEY_METADATA_FILE); if (xmlFilePath == null) throw new TAPException("The property \"" + KEY_METADATA_FILE + "\" is missing! According to the property \"" + KEY_METADATA + "\", metadata must be fetched from an XML document. The local file path of it MUST be provided using the property \"" + KEY_METADATA_FILE + "\"."); // Parse the XML document and build the corresponding metadata: try{ metadata = (new TableSetParser()).parse(getFile(xmlFilePath, webAppRootDir, KEY_METADATA_FILE)); }catch(IOException ioe){ throw new TAPException("A grave error occurred while reading/parsing the TableSet XML document: \"" + xmlFilePath + "\"!", ioe); } // Update the database: DBConnection conn = null; try{ conn = tapFactory.getConnection("SET_TAP_SCHEMA"); conn.setTAPSchema(metadata); }finally{ if (conn != null) tapFactory.freeConnection(conn); } } // GET METADATA FROM DATABASE (schema TAP_SCHEMA): else if (metaFetchType.equalsIgnoreCase(VALUE_DB)){ DBConnection conn = null; try{ // get a db connection: conn = tapFactory.getConnection("GET_TAP_SCHEMA"); // fetch and set the ADQL<->DB mapping for all standard TAP_SCHEMA items: if (conn instanceof JDBCConnection){ HashMapInitialize the list of all output format that the TAP service must support.
* ** 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. *
* * @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{ // Fetch the value of the property for additional output formats: String formats = getProperty(tapConfig, KEY_OUTPUT_FORMATS); // SPECIAL VALUE "ALL": if (formats == null || formats.equalsIgnoreCase(VALUE_ALL)){ outputFormats.add(new VOTableFormat(this, DataFormat.BINARY)); outputFormats.add(new VOTableFormat(this, DataFormat.BINARY2)); outputFormats.add(new VOTableFormat(this, DataFormat.TABLEDATA)); outputFormats.add(new VOTableFormat(this, DataFormat.FITS)); outputFormats.add(new FITSFormat(this)); outputFormats.add(new JSONFormat(this)); outputFormats.add(new SVFormat(this, ",", true)); outputFormats.add(new SVFormat(this, "\t", true)); outputFormats.add(new TextFormat(this)); outputFormats.add(new HTMLFormat(this)); return; } // LIST OF FORMATS: // Since it is a comma separated list of output formats, a loop will parse this list comma by comma: String f; int indexSep, indexLPar, indexRPar; boolean hasVotableFormat = false; while(formats != null && formats.length() > 0){ // Get a format item from the list: indexSep = formats.indexOf(','); // if a comma is after a left parenthesis indexLPar = formats.indexOf('('); if (indexSep > 0 && indexLPar > 0 && indexSep > indexLPar){ indexRPar = formats.indexOf(')', indexLPar); if (indexRPar > 0) indexSep = formats.indexOf(',', indexRPar); else throw new TAPException("Missing right parenthesis in: \"" + formats + "\"!"); } // no comma => only one format if (indexSep < 0){ f = formats; formats = null; } // comma at the first position => empty list item => go to the next item else if (indexSep == 0){ formats = formats.substring(1).trim(); continue; } // else => get the first format item, and then remove it from the list for the next iteration else{ f = formats.substring(0, indexSep).trim(); formats = formats.substring(indexSep + 1).trim(); } // Identify the format and append it to the output format list of the service: // FITS if (f.equalsIgnoreCase(VALUE_FITS)) outputFormats.add(new FITSFormat(this)); // JSON else if (f.equalsIgnoreCase(VALUE_JSON)) outputFormats.add(new JSONFormat(this)); // HTML else if (f.equalsIgnoreCase(VALUE_HTML)) outputFormats.add(new HTMLFormat(this)); // TEXT else if (f.equalsIgnoreCase(VALUE_TEXT)) outputFormats.add(new TextFormat(this)); // CSV else if (f.equalsIgnoreCase(VALUE_CSV)) outputFormats.add(new SVFormat(this, ",", true)); // TSV else if (f.equalsIgnoreCase(VALUE_TSV)) outputFormats.add(new SVFormat(this, "\t", true)); // any SV (separated value) format else if (f.toLowerCase().startsWith(VALUE_SV)){ // get the separator: int endSep = f.indexOf(')'); if (VALUE_SV.length() < f.length() && f.charAt(VALUE_SV.length()) == '(' && endSep > VALUE_SV.length() + 1){ String separator = f.substring(VALUE_SV.length() + 1, f.length() - 1); // get the MIME type and its alias, if any of them is provided: String mimeType = null, shortMimeType = null; if (endSep + 1 < f.length() && f.charAt(endSep + 1) == ':'){ int endMime = f.indexOf(':', endSep + 2); if (endMime < 0) mimeType = f.substring(endSep + 2, f.length()); else if (endMime > 0){ mimeType = f.substring(endSep + 2, endMime); shortMimeType = f.substring(endMime + 1); } } // add the defined SV(...) format: outputFormats.add(new SVFormat(this, separator, true, mimeType, shortMimeType)); }else throw new TAPException("Missing separator char/string for the SV output format: \"" + f + "\"!"); } // VOTABLE else if (f.toLowerCase().startsWith(VALUE_VOTABLE) || f.toLowerCase().startsWith(VALUE_VOT)){ // Parse the format: VOTableFormat votFormat = parseVOTableFormat(f); // Add the VOTable format: outputFormats.add(votFormat); // Determine whether the MIME type is the VOTable expected one: if (votFormat.getShortMimeType().equals("votable") || votFormat.getMimeType().equals("votable")) hasVotableFormat = true; } // custom OutputFormat else if (isClassName(f)) outputFormats.add(TAPConfiguration.newInstance(f, KEY_OUTPUT_FORMATS, OutputFormat.class, new Class>[]{ServiceConnection.class}, new Object[]{this})); // unknown format else throw new TAPException("Unknown output format: " + f); } // Add by default VOTable format if none is specified: if (!hasVotableFormat) outputFormats.add(new VOTableFormat(this)); } /** *Parse the given VOTable format specification.
* *This specification is expected to be an item of the property {@link TAPConfiguration#KEY_OUTPUT_FORMATS}.
* * @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{ DataFormat serialization = null; VOTableVersion votVersion = null; String mimeType = null, shortMimeType = null; // Get the parameters, if any: int beginSep = propValue.indexOf('('); if (beginSep > 0){ int endSep = propValue.indexOf(')'); if (endSep <= beginSep) throw new TAPException("Wrong output format specification syntax in: \"" + propValue + "\"! A VOTable parameters list must end with ')'."); // split the parameters: String[] params = propValue.substring(beginSep + 1, endSep).split(","); if (params.length > 2) throw new TAPException("Wrong number of parameters for the output format VOTable: \"" + propValue + "\"! Only two parameters may be provided: serialization and version."); else if (params.length >= 1){ // resolve the serialization format: params[0] = params[0].trim().toLowerCase(); if (params[0].length() == 0 || params[0].equals("b") || params[0].equals("binary")) serialization = DataFormat.BINARY; else if (params[0].equals("b2") || params[0].equals("binary2")) serialization = DataFormat.BINARY2; else if (params[0].equals("td") || params[0].equals("tabledata")) serialization = DataFormat.TABLEDATA; else if (params[0].equals("fits")) serialization = DataFormat.FITS; else throw new TAPException("Unsupported VOTable serialization: \"" + params[0] + "\"! Accepted values: 'binary' (or 'b'), 'binary2' (or 'b2'), 'tabledata' (or 'td') and 'fits'."); // resolve the version: if (params.length == 2){ params[1] = params[1].trim(); if (params[1].equals("1.0") || params[1].equalsIgnoreCase("v1.0")) votVersion = VOTableVersion.V10; else if (params[1].equals("1.1") || params[1].equalsIgnoreCase("v1.1")) votVersion = VOTableVersion.V11; else if (params[1].equals("1.2") || params[1].equalsIgnoreCase("v1.2")) votVersion = VOTableVersion.V12; else if (params[1].equals("1.3") || params[1].equalsIgnoreCase("v1.3")) votVersion = VOTableVersion.V13; else throw new TAPException("Unsupported VOTable version: \"" + params[1] + "\"! Accepted values: '1.0' (or 'v1.0'), '1.1' (or 'v1.1'), '1.2' (or 'v1.2') and '1.3' (or 'v1.3')."); } } } // Get the MIME type and its alias, if any: beginSep = propValue.indexOf(':'); if (beginSep > 0){ int endSep = propValue.indexOf(':', beginSep + 1); if (endSep < 0) endSep = propValue.length(); // extract the MIME type, if any: mimeType = propValue.substring(beginSep + 1, endSep).trim(); if (mimeType.length() == 0) mimeType = null; // extract the short MIME type, if any: if (endSep < propValue.length()){ beginSep = endSep; endSep = propValue.indexOf(':', beginSep + 1); if (endSep >= 0) throw new TAPException("Wrong output format specification syntax in: \"" + propValue + "\"! After a MIME type and a short MIME type, no more information is expected."); else endSep = propValue.length(); shortMimeType = propValue.substring(beginSep + 1, endSep).trim(); if (shortMimeType.length() == 0) shortMimeType = null; } } // Create the VOTable format: VOTableFormat votFormat = new VOTableFormat(this, serialization, votVersion); votFormat.setMimeType(mimeType, shortMimeType); 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{ 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 setDefaultOutputLimit((Integer)limit[0]); 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 setMaxOutputLimit((Integer)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{ fetchSize = new int[2]; // Set the fetch size for asynchronous queries: String propVal = getProperty(tapConfig, KEY_ASYNC_FETCH_SIZE); if (propVal == null) fetchSize[0] = DEFAULT_ASYNC_FETCH_SIZE; else{ try{ fetchSize[0] = Integer.parseInt(propVal); if (fetchSize[0] < 0) fetchSize[0] = 0; }catch(NumberFormatException nfe){ throw new TAPException("Integer expected for the property " + KEY_ASYNC_FETCH_SIZE + ": \"" + propVal + "\"!"); } } // Set the fetch size for synchronous queries: propVal = getProperty(tapConfig, KEY_SYNC_FETCH_SIZE); if (propVal == null) fetchSize[1] = DEFAULT_SYNC_FETCH_SIZE; else{ try{ fetchSize[1] = Integer.parseInt(propVal); if (fetchSize[1] < 0) fetchSize[1] = 0; }catch(NumberFormatException nfe){ throw new TAPException("Integer expected for the property " + KEY_SYNC_FETCH_SIZE + ": \"" + propVal + "\"!"); } } } /** * 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{ Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_UPLOAD_LIMIT), KEY_DEFAULT_UPLOAD_LIMIT, true); uploadLimitTypes[0] = (LimitUnit)limit[1]; setDefaultUploadLimit((Integer)limit[0]); limit = parseLimit(getProperty(tapConfig, KEY_MAX_UPLOAD_LIMIT), KEY_MAX_UPLOAD_LIMIT, true); if (!((LimitUnit)limit[1]).isCompatibleWith(uploadLimitTypes[0])) 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 uploadLimitTypes[1] = (LimitUnit)limit[1]; setMaxUploadLimit((Integer)limit[0]); } /** * 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{ String propValue = getProperty(tapConfig, KEY_UPLOAD_MAX_FILE_SIZE); // If a value is specified... if (propValue != null){ // ...parse the value: Object[] limit = parseLimit(propValue, KEY_UPLOAD_MAX_FILE_SIZE, true); if (((Integer)limit[0]).intValue() <= 0) limit[0] = new Integer(TAPConfiguration.DEFAULT_UPLOAD_MAX_FILE_SIZE); // ...check that the unit is correct (bytes): if (!LimitUnit.bytes.isCompatibleWith((LimitUnit)limit[1])) throw new TAPException("The maximum upload file size " + KEY_UPLOAD_MAX_FILE_SIZE + " (here: " + propValue + ") can not be expressed in a unit different from bytes (B, kB, MB, GB)!"); // ...set the max file size: int value = (int)((Integer)limit[0] * ((LimitUnit)limit[1]).bytesFactor()); setMaxUploadSize(value); } } /** * 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{ // Get the property value: String propValue = getProperty(tapConfig, KEY_USER_IDENTIFIER); if (propValue != null) 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{ // Get the property value: String propValue = getProperty(tapConfig, KEY_COORD_SYS); // NO VALUE => ALL COORD SYS ALLOWED! if (propValue == null) lstCoordSys = null; // "NONE" => ALL COORD SYS FORBIDDEN (= no coordinate system expression is allowed)! else if (propValue.equalsIgnoreCase(VALUE_NONE)) lstCoordSys = new ArrayListSet the default retention period.
* *This period is set by default if the user did not specify one before the execution of his query.
* *Important note: * 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. *
* * @param period New default retention period (in seconds). * * @return true if the given retention period has been successfully set, false otherwise. */ public boolean setDefaultRetentionPeriod(final int period){ if ((retentionPeriod[1] <= 0) || (period > 0 && period <= retentionPeriod[1])){ retentionPeriod[0] = period; return true; }else return false; } /** *Set the maximum retention period.
* *This period limits the default retention period and the retention period specified by a user.
* *Important note: * 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. *
* * @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 public int[] getExecutionDuration(){ return executionDuration; } /** *Set the default execution duration.
* *This duration is set by default if the user did not specify one before the execution of his query.
* *Important note: * 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. *
* * @param duration New default execution duration (in milliseconds). * * @return true if the given execution duration has been successfully set, false otherwise. */ public boolean setDefaultExecutionDuration(final int duration){ if ((executionDuration[1] <= 0) || (duration > 0 && duration <= executionDuration[1])){ executionDuration[0] = duration; return true; }else return false; } /** *Set the maximum execution duration.
* *This duration limits the default execution duration and the execution duration specified by a user.
* *Important note: * 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. *
* * @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 public IteratorAdd the given {@link OutputFormat} in the list of output formats supported by the TAP service.
* *Warning: * No verification is done in order to avoid duplicated output formats in the list. * NULL objects are merely ignored silently. *
* * @param newOutputFormat New output format. */ public void addOutputFormat(final OutputFormat 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 true if the specified format has been found and successfully removed from the list, * false otherwise. */ public boolean removeOutputFormat(final String mimeOrAlias){ OutputFormat of = getOutputFormat(mimeOrAlias); if (of != null) return outputFormats.remove(of); else return false; } @Override public int[] getOutputLimit(){ return outputLimits; } /** *Set the default output limit.
* *This limit is set by default if the user did not specify one before the execution of his query.
* *Important note: * 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. *
* * @param limit New default output limit (in number of rows). * * @return true if the given output limit has been successfully set, false otherwise. */ public boolean setDefaultOutputLimit(final int limit){ if ((outputLimits[1] <= 0) || (limit > 0 && limit <= outputLimits[1])){ outputLimits[0] = limit; return true; }else return false; } /** *Set the maximum output limit.
* *This output limit limits the default output limit and the output limit specified by a user.
* *Important note: * 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. *
* * @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 public final LimitUnit[] getOutputLimitType(){ return new LimitUnit[]{LimitUnit.rows,LimitUnit.rows}; } @Override public CollectionSet the default upload limit.
* *Important note: * 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. *
* * @param limit New default upload limit. * * @return true if the given upload limit has been successfully set, false otherwise. */ public boolean setDefaultUploadLimit(final int limit){ try{ if ((uploadLimits[1] <= 0) || (limit > 0 && LimitUnit.compare(limit, uploadLimitTypes[0], uploadLimits[1], uploadLimitTypes[1]) <= 0)){ uploadLimits[0] = limit; return true; } }catch(TAPException e){} return false; } /** *Set the maximum upload limit.
* *This upload limit limits the default upload limit.
* *Important note: * 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. *
* * @param limit New maximum upload limit. */ public void setMaxUploadLimit(final int limit){ try{ // Decrease the default output limit if it will be bigger than the new maximum output limit: if (limit > 0 && (uploadLimits[0] <= 0 || LimitUnit.compare(limit, uploadLimitTypes[1], uploadLimits[0], uploadLimitTypes[0]) < 0)) uploadLimits[0] = limit; // Set the new maximum output limit: uploadLimits[1] = limit; }catch(TAPException e){} } @Override public int getMaxUploadSize(){ return maxUploadSize; } /** *Set the maximum size of a VOTable files set that can be uploaded in once.
* *Warning: * This size can not be negative or 0. If the given value is in this case, nothing will be done * and false 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). *
* * @param maxSize New maximum size (in bytes). * * @return true if the size has been successfully set, false otherwise. */ public boolean setMaxUploadSize(final int maxSize){ // No "unlimited" value possible there: if (maxSize <= 0) return false; // Otherwise, set the maximum upload file size: maxUploadSize = maxSize; return true; } @Override public int getNbMaxAsyncJobs(){ return maxAsyncJobs; } @Override public UserIdentifier getUserIdentifier(){ return userIdentifier; } @Override public TAPMetadata getTAPMetadata(){ return metadata; } @Override public Collection