Commit 7bd91a1c authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[UWS,TAP] Fix the configuration file for the UPLOAD feature.

The property `upload_default_db_limit` has been deprecated. Indeed, in the
current state of the TAP protocol, this makes no sense: the user can not change
the limit size (in bytes or rows) for uploaded tables.

The property `upload_max_file_size` has been deprecated. It is actually
duplicated: `upload_max_db_limit`, if expressed in bytes already lets put a
limit on the maximum size of an uploaded table/file.

The property `upload_max_request_size` has been added. It lets set a maximum
size for a whole HTTP Multipart Request. By default it is set to 250MB.

The default value of `upload_max_db_size` is now 1 million rows.

The UPLOAD feature is still disabled by default (i.e. `upload_enabled=false`).
parent 02a4a7f5
Loading
Loading
Loading
Loading
+209 −156
Original line number Diff line number Diff line
@@ -16,13 +16,14 @@ package tap;
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 */

import java.util.Collection;
import java.util.Iterator;

import adql.db.FunctionDef;
import tap.db.DBConnection;
import tap.formatter.OutputFormat;
import tap.log.DefaultTAPLog;
@@ -31,19 +32,19 @@ import tap.metadata.TAPMetadata;
import uws.service.UserIdentifier;
import uws.service.file.LocalUWSFileManager;
import uws.service.file.UWSFileManager;
import adql.db.FunctionDef;

/**
 * <p>Description and parameters list of a TAP service.</p>
 * Description and parameters list of a TAP service.
 *
 * <p>
 * 	Through this object, it is possible to configure the different limits and formats,
 * 	but also to list all available tables and columns, to declare geometry features as all allowed user defined functions
 * 	and to say where log and other kinds of files must be stored.
 * 	Through this object, it is possible to configure the different limits and
 * 	formats, but also to list all available tables and columns, to declare
 * 	geometry features as well as all allowed user defined functions and to say
 * 	where log and other kinds of files must be stored.
 * </p>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (03/2015)
 * @version 2.3 (09/2018)
 */
public interface ServiceConnection {

@@ -103,14 +104,46 @@ public interface ServiceConnection {

		/**
		 * Compares the 2 given values (each one expressed in the given unit).
		 * Conversions are done internally in order to make a correct comparison between the 2 limits.
		 *
		 * <p>
		 * 	Conversions are done internally in order to make a correct
		 * 	comparison between the 2 limits.
		 * </p>
		 *
		 * @param leftLimit		Value/Limit of the comparison left part.
		 * @param leftUnit		Unit of the comparison left part value.
		 * @param rightLimit	Value/Limit of the comparison right part.
		 * @param rightUnit		Unit of the comparison right part value.
		 *
		 * @return the value 0 if x == y; a value less than 0 if x < y; and a value greater than 0 if x > y
		 * @return	the value 0 if x == y; a value less than 0 if x < y;
		 *        	and a value greater than 0 if x > y
		 *
		 * @throws TAPException If the two given units are not compatible.
		 *
		 * @see #compare(long, LimitUnit, long, LimitUnit)
		 *
		 * @since 1.1
		 */
		public static int compare(final int leftLimit, final LimitUnit leftUnit, final int rightLimit, final LimitUnit rightUnit) throws TAPException{
			return compare(leftLimit, leftUnit, rightLimit, rightUnit);
		}

		/**
		 * Compares the 2 given values (each one expressed in the given unit).
		 *
		 * <p>
		 * 	Conversions are done internally in order to make a correct
		 * 	comparison between the 2 limits.
		 * </p>
		 *
		 * @param leftLimit		Value/Limit of the comparison left part.
		 * @param leftUnit		Unit of the comparison left part value.
		 * @param rightLimit	Value/Limit of the comparison right part.
		 * @param rightUnit		Unit of the comparison right part value.
		 *
		 * @return	the value 0 if x == y;
		 *        	a value less than 0 if x < y;
		 *        	and a value greater than 0 if x > y
		 *
		 * @throws TAPException If the two given units are not compatible.
		 *
@@ -119,9 +152,9 @@ public interface ServiceConnection {
		 * @see Integer#compare(int, int)
		 * @see Long#compare(long, long)
		 *
		 * @since 1.1
		 * @since 2.3
		 */
		public static int compare(final int leftLimit, final LimitUnit leftUnit, final int rightLimit, final LimitUnit rightUnit) throws TAPException{
		public static int compare(final long leftLimit, final LimitUnit leftUnit, final long rightLimit, final LimitUnit rightUnit) throws TAPException{
			if (!leftUnit.isCompatibleWith(rightUnit))
				throw new TAPException("Limit units (" + leftUnit + " and " + rightUnit + ") are not compatible!");

@@ -365,13 +398,16 @@ public interface ServiceConnection {

	/**
	 * <i><b>[MANDATORY]</b></i>
	 * <p>This function let enable or disable the upload capability of this TAP service.</p>
	 * <p>This function lets enable or disable the upload capability of this TAP
	 * service.</p>
	 *
	 * <p><i>Note:
	 * 	If the upload is disabled, the request is aborted and an HTTP-400 error is thrown each time some tables are uploaded.
	 * 	If the upload is disabled, the request is aborted and an HTTP-400 error
	 * 	is thrown each time some tables are uploaded.
	 * </i></p>
	 *
	 * @return	<i>true</i> to enable the upload capability, <i>false</i> to disable it.
	 * @return	<i>true</i> to enable the upload capability,
	 *        	<i>false</i> to disable it.
	 */
	public boolean uploadEnabled();

@@ -389,47 +425,67 @@ public interface ServiceConnection {
	 * 	<li><b>Exactly 2 values or a NULL object is expected here.</b></li>
	 * 	<li><b>If NULL</b>, the upload limit is not limited and uploads could be
	 * 	    theoretically unlimited.</li>
	 * 	<li><b>If not NULL</b>, the 2 values must correspond to the default upload limit
	 * 	    and the maximum upload limit.</li>
	 * 	<li><b>The default value</b> is used inform the user about the server wishes.</li>
	 * 	<li><b>The maximum value</b> is used to really limit the upload limit.</li>
	 * 	<li><b>The structure of the object</b> returned by this function MUST be the same as the object returned by {@link #getUploadLimitType()}.
	 * 	    Particularly, the type given by the N-th item of {@link #getUploadLimitType()} must correspond to the N-th limit returned by this function.</li>
	 * 	<li><b>The default value</b> MUST be less or equals the maximum value.</li>
	 * 	<li><b>Both values must be positive</b>. If a negative value is given it will be interpreted as "no limit".</li>
	 * 	<li><b>If not NULL</b>, the 2 values must correspond to the default
	 * 	    upload limit and the maximum upload limit.</li>
	 * 	<li><b>The default value</b> is used to inform the user about the server
	 * 	    wishes. <i><b>In this version of TAPLib, this value is never used,
	 * 		whatever is its value.</b> It is defined here only in case the
	 * 		TAP protocol evolves and allow a such default value for UPLOAD
	 * 		limits.</i></li>
	 * 	<li><b>The maximum value</b> is used to really limit the upload
	 * 	    limit.</li>
	 * 	<li><b>The structure of the object</b> returned by this function MUST be
	 * 	    the same as the object returned by {@link #getUploadLimitType()}.
	 * 	    Particularly, the type given by the N-th item of
	 * 	    {@link #getUploadLimitType()} must correspond to the N-th limit
	 * 	    returned by this function.</li>
	 * 	<li><b>The default value</b> MUST be less or equals the maximum
	 * 	    value.</li>
	 * 	<li><b>Both values must be positive</b>. If a negative value is given it
	 * 	    will be interpreted as "no limit".</li>
	 * </ul>
	 *
	 * <p><i><b>Important note:</b>
	 * 	To save performances, it is recommended to use BYTES limit rather than in rows. Indeed, the bytes limit can be taken
	 * 	into account at directly when reading the bytes of the request, on the contrary of the rows limit which
	 * 	requires to parse the uploaded tables.
	 * 	To save performances, it is recommended to use BYTES limit rather than
	 * 	in rows. Indeed, the bytes limit can be taken into account at directly
	 * 	when reading the bytes of the request, on the contrary of the rows limit
	 * 	which requires to parse the uploaded tables.
	 * </i></p>
	 *
	 * @return	NULL if no limit must be set, or a two-items array ([0]: default value, [1]: maximum value).
	 * @return	NULL if no limit must be set,
	 *        	or a two-items array ([0]: default value, [1]: maximum value).
	 *
	 * @see #getUploadLimitType()
	 */
	public int[] getUploadLimit();
	public long[] getUploadLimit();

	/**
	 * <i>[OPTIONAL]</i>
	 * <p>Get the type of each upload limit set by this service connection (and accessible with {@link #getUploadLimit()}).</p>
	 * <p>Get the type of each upload limit set by this service connection (and
	 * accessible with {@link #getUploadLimit()}).</p>
	 *
	 * <p><b>Important notes:</b></p>
	 * <ul>
	 * 	<li><b>Exactly 2 values or a NULL object is expected here.</b></li>
	 * 	<li><b>If NULL</b>, the upload limit will be considered as expressed in ROWS.</li>
	 * 	<li><b>The structure of the object</b> returned by this function MUST be the same as the object returned by {@link #getUploadLimit()}.
	 * 	    Particularly, the type given by the N-th item of this function must correspond to the N-th limit returned by {@link #getUploadLimit()}.</li>
	 * 	<li><b>If NULL</b>, the upload limit will be considered as expressed in
	 * 	    ROWS.</li>
	 * 	<li><b>The structure of the object</b> returned by this function MUST be
	 * 	    the same as the object returned by {@link #getUploadLimit()}.
	 * 	    Particularly, the type given by the N-th item of this function must
	 * 	    correspond to the N-th limit returned by {@link #getUploadLimit()}.
	 * 	</li>
	 * </ul>
	 *
	 * <p><i><b>Important note:</b>
	 * 	To save performances, it is recommended to use BYTES limit rather than in rows. Indeed, the bytes limit can be taken
	 * 	into account at directly when reading the bytes of the request, on the contrary of the rows limit which
	 * 	requires to parse the uploaded tables.
	 * 	To save performances, it is recommended to use BYTES limit rather than
	 * 	in rows. Indeed, the bytes limit can be taken into account at directly
	 * 	when reading the bytes of the request, on the contrary of the rows limit
	 * 	which requires to parse the uploaded tables.
	 * </i></p>
	 *
	 * @return	NULL if limits should be expressed in ROWS, or a two-items array ([0]: type of getUploadLimit()[0], [1]: type of getUploadLimit()[1]). 
	 * @return	NULL if limits should be expressed in ROWS,
	 *        	or a two-items array ([0]: type of getUploadLimit()[0],
	 *        	[1]: type of getUploadLimit()[1]).
	 *
	 * @see #getUploadLimit()
	 */
@@ -437,22 +493,19 @@ public interface ServiceConnection {

	/**
	 * <i>[OPTIONAL]</i>
	 * <p>Get the maximum size of the whole set of all tables uploaded in one request.
	 * This size is expressed in bytes.</p>
	 * <p>Get the maximum size of the whole set of all tables uploaded in one
	 * request. This size is expressed in bytes.</p>
	 *
	 * <p><b>IMPORTANT 1:
	 * 	This value is always used when the upload capability is enabled.
	 * </b></p>
	 * 
	 * <p><b>IMPORTANT 2:
	 * 	The value returned by this function MUST always be positive.
	 * 	A zero or negative value will throw an exception later while
	 * 	reading parameters in a request with some uploaded tables.
	 * </b></p>
	 * <p><i><b>NOTE:</b>
	 * 	This value can be negative. In such case, there will be no limit on the
	 * 	size of an HTTP request.
	 * </i></p>
	 *
	 * @return	A positive (&gt;0) value corresponding to the maximum number of bytes of all uploaded tables sent in one request.
	 * @return	A positive value (&gt;0) corresponding to the maximum number of
	 *        	bytes of all uploaded tables sent in one request.
	 *        	A negative value (&le;0) means "unlimited".
	 */
	public int getMaxUploadSize();
	public long getMaxUploadSize();

	/**
	 * <i><b>[MANDATORY]</b></i>
+13 −5
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ package tap;
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 */

@@ -29,6 +29,7 @@ import adql.parser.ADQLParser;
import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;
import adql.query.ADQLQuery;
import tap.ServiceConnection.LimitUnit;
import tap.db.DBConnection;
import tap.metadata.TAPSchema;
import tap.parameters.TAPParameters;
@@ -63,7 +64,7 @@ import uws.service.request.RequestParser;
 * </ul>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.2 (09/2017)
 * @version 2.3 (09/2018)
 */
public abstract class TAPFactory implements UWSFactory {

@@ -485,7 +486,14 @@ public abstract class TAPFactory implements UWSFactory {

	@Override
	public RequestParser createRequestParser(final UWSFileManager fileManager) throws UWSException{
		return new TAPRequestParser(fileManager);
		/* Fetch the maximum size for each uploaded file:
		 * ....only if set to a positive value and expressed in bytes. */
		long maxFileSize = -1;
		if (service.getUploadLimit() != null && service.getUploadLimit().length >= 2 && service.getUploadLimit()[1] > 0 && service.getUploadLimitType() != null && service.getUploadLimitType().length == service.getUploadLimit().length && service.getUploadLimitType()[1] != LimitUnit.rows){
			maxFileSize = service.getUploadLimit()[1] * service.getUploadLimitType()[1].bytesFactor();
		}
		// Finally create the appropriate RequestParser:
		return new TAPRequestParser(fileManager, service.uploadEnabled(), maxFileSize, service.getMaxUploadSize());
	}

}
+69 −31
Original line number Diff line number Diff line
@@ -44,18 +44,18 @@ import uws.service.request.UploadFile;
 * </ul>
 *
 * <p>
 * 	The request body size is limited for the multipart. If you want to change
 * 	this limit, you MUST do it for each of these parsers, setting the following
 * 	static attributes: {@link MultipartParser#SIZE_LIMIT}.
 * 	The request body size is limited for the multipart. You can change these
 * 	limits with the constructor
 * 	{@link #TAPRequestParser(UWSFileManager, boolean, long, long)}
 * </p>
 *
 * <p><i>Note:
 * 	If you want to change the support other request parsing, you will have to
 * 	write your own {@link RequestParser} implementation.
 * 	If you want to support other request parsing, you have to write your own
 * 	{@link RequestParser} implementation.
 * </i></p>
 *
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 2.1 (06/2017)
 * @author Gr&eacute;gory Mantelet (ARI;CDS)
 * @version 2.3 (09/2018)
 * @since 2.0
 */
public class TAPRequestParser implements RequestParser {
@@ -76,6 +76,20 @@ public class TAPRequestParser implements RequestParser {
	 * only when needed, by calling the function {@link #getMultipartParser()}. */
	private RequestParser multipartParser = null;

	/** Indicates whether this parser should allow uploaded files.
	 * @since 2.3 */
	private final boolean allowUpload;

	/** Maximum size of a single uploaded file.
	 * <p><i><b>Note:</b> If negative (&le;0), "unlimited".</i></p>
	 * @since 2.3 */
	private final long maxFileSize;

	/** Maximum size of a whole HTTP Multipart Request.
	 * <p><i><b>Note:</b> If negative (&le;0), "unlimited".</i></p>
	 * @since 2.3 */
	private final long maxMultipartSize;

	/**
	 * Build a {@link RequestParser} able to choose the most appropriate
	 * {@link RequestParser} in function of the request content-type.
@@ -84,9 +98,32 @@ public class TAPRequestParser implements RequestParser {
	 *                   	eventual upload. <b>MUST NOT be NULL</b>
	 */
	public TAPRequestParser(final UWSFileManager fileManager){
		this(fileManager, true, -1, -1);
	}

	/**
	 * Build a {@link RequestParser} able to choose the most appropriate
	 * {@link RequestParser} in function of the request content-type.
	 *
	 * @param fileManager		The file manager to use in order to store any
	 *                   		eventual upload. <b>MUST NOT be NULL</b>
	 * @param uploadEnabled		<code>true</code> to support UPLOADs,
	 *                     		<code>false</code> otherwise (i.e. all Multipart
	 *                     		requests with files will be rejected).
	 * @param maxFileSize		Maximum size for a single uploaded file.
	 *                   		<i>A negative value means "no limit".</i>
	 * @param maxRequestSize	Maximum size for a whole Multipart HTTP Request.
	 *                   		<i>A negative value means "no limit".</i>
	 *
	 * @since 2.3
	 */
	public TAPRequestParser(final UWSFileManager fileManager, final boolean uploadEnabled, final long maxFileSize, final long maxRequestSize){
		if (fileManager == null)
			throw new NullPointerException("Missing file manager => can not create a TAPRequestParser!");
		this.fileManager = fileManager;
		this.allowUpload = uploadEnabled;
		this.maxFileSize = maxFileSize;
		this.maxMultipartSize = maxRequestSize;
	}

	@Override
@@ -155,7 +192,7 @@ public class TAPRequestParser implements RequestParser {
	 *        	requests. <i>Never NULL</i>
	 */
	private synchronized final RequestParser getMultipartParser(){
		return (multipartParser != null) ? multipartParser : (multipartParser = new MultipartParser(fileManager){
		return (multipartParser != null) ? multipartParser : (multipartParser = new MultipartParser(allowUpload, fileManager, maxFileSize, maxMultipartSize) {
			@Override
			protected void consumeParameter(String name, Object value, final Map<String, Object> allParams){
				// Modify the value if it is an UPLOAD parameter:
@@ -167,7 +204,8 @@ public class TAPRequestParser implements RequestParser {
					else if (name.equals(TAPJob.PARAM_UPLOAD) && value instanceof UploadFile){
						try{
							((UploadFile)value).deleteFile();
						}catch(IOException ioe){}
						}catch(IOException ioe){
						}
						return;
					}
					// use the same case for the parameter name:
+155 −49

File changed.

Preview size limit exceeded, changes collapsed.

+110 −22
Original line number Diff line number Diff line
@@ -31,13 +31,17 @@ import tap.TAPFactory;
import tap.backup.DefaultTAPBackupManager;

/**
 * <p>Utility class gathering tool functions and properties' names useful to deal with a TAP configuration file.</p>
 * Utility class gathering tool functions and properties' names useful to
 * deal with a TAP configuration file.
 *
 * <p><i>This class implements the Design Pattern "Utility": no instance of this class can be created, it can not be extended,
 * and it must be used only thanks to its static classes and attributes.</i></p>
 * <p><i>
 * 	This class implements the Design Pattern "Utility": no instance of this
 * 	class can be created, it can not be extended, and it must be used only
 * 	thanks to its static classes and attributes.
 * </i></p>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.3 (07/2018)
 * @version 2.3 (09/2018)
 * @since 2.0
 */
public final class TAPConfiguration {
@@ -234,17 +238,42 @@ public final class TAPConfiguration {
	public final static String KEY_SERVICE_DESCRIPTION = "service_description";

	/* UPLOAD KEYS */
	/** Name/Key of the property indicating whether the UPLOAD feature must be enabled or not.
	 * By default, this feature is disabled. */
	/** 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";
	/** Name/Key of the property specifying the default limit (in rows or bytes) on the uploaded VOTable(s). */
	/** Name/Key of the property specifying the default limit (in rows or bytes)
	 * on the uploaded VOTable(s).
	 * @deprecated	Since 2.3, use the property {@value #KEY_MAX_UPLOAD_LIMIT}
	 *            	instead. */
	@Deprecated
	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). */
	/** 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";
	/** Name/Key of the property specifying the maximum size of all VOTable(s) uploaded in a query. */
	/** Default value of the property {@value #KEY_MAX_UPLOAD_LIMIT} =
	 * {@value #DEFAULT_MAX_UPLOAD_LIMIT}.
	 * @since 2.3 */
	public final static String DEFAULT_MAX_UPLOAD_LIMIT = "1000000r";
	/** Name/Key of the property specifying the maximum size of all VOTable(s)
	 * uploaded in a query.
	 * @deprecated	Since 2.3, use the property {@value #KEY_MAX_UPLOAD_LIMIT}
	 *            	and {@value #KEY_MAX_REQUEST_LIMIT} instead. */
	@Deprecated
	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}.  */
	/** Default value of the property {@value #KEY_UPLOAD_MAX_FILE_SIZE} =
	 * {@value #DEFAULT_UPLOAD_MAX_FILE_SIZE}.
	 * @deprecated	Since 2.3, use the property {@value #KEY_MAX_UPLOAD_LIMIT}
	 *            	and {@value #KEY_MAX_REQUEST_LIMIT} instead. */
	@Deprecated
	public final static int DEFAULT_UPLOAD_MAX_FILE_SIZE = Integer.MAX_VALUE;
	/** Name/Key of the property specifying the maximum size of a whole HTTP
	 * Multipart Request.
	 * @since 2.3 */
	public final static String KEY_UPLOAD_MAX_REQUEST_SIZE = "upload_max_request_size";
	/** Default value of the property {@value #KEY_UPLOAD_MAX_REQUEST_SIZE} =
	 * {@value #DEFAULT_UPLOAD_MAX_REQUEST_SIZE}.
	 * @since 2.3 */
	public final static int DEFAULT_UPLOAD_MAX_REQUEST_SIZE = 250 * 1024 * 1024;

	/* OUTPUT KEYS */
	/** Name/Key of the property specifying the list of all result output formats to support.
@@ -525,41 +554,97 @@ public final class TAPConfiguration {
	}

	/**
	 * <p>Lets parsing a limit (for output, upload, ...) with its numeric value and its unit.</p>
	 * Lets parsing a limit (for output, upload, ...) with its numeric value
	 * and its unit.
	 *
	 * <p>
	 * 	Here is the expected syntax: num_val[unit].
	 * 	Where unit is optional and should be one of the following values: r or R, B, kB, MB, GB.
	 * 	If the unit is not specified, it is set by default to ROWS.
	 * 	Where unit is optional and should be one of the following values:
	 * 	r or R, B, kB, MB, GB. If the unit is not specified, it is set by
	 * 	default to ROWS.
	 * </p>
	 * <p><i>Note: If the value is strictly less than 0 (whatever is the unit), the returned value will be -1.</i></p>
	 *
	 * @param value				Property value (must follow the limit syntax: num_val[unit] ; ex: 20kB or 2000 (for 2000 rows)).
	 * <p><i>Note:
	 * 	If the value is strictly less than 0 (whatever is the unit), the
	 * 	returned value will be -1.
	 * </i></p>
	 *
	 * @param value				Property value (must follow the limit syntax:
	 *             				num_val[unit] ; ex: 20kB or 2000
	 *             				(for 2000 rows)).
	 * @param propertyName		Name of the property which specify the limit.
	 * @param areBytesAllowed	Tells whether the unit BYTES is allowed. If not and a BYTES unit is encountered, then an exception is thrown.
	 * @param areBytesAllowed	Tells whether the unit BYTES is allowed. If not
	 *                       	and a BYTES unit is encountered, then an
	 *                       	exception is thrown.
	 *
	 * @return	An array with always 2 items:
	 *        	[0]=numeric value (of type Integer),
	 *        	[1]=unit (of type {@link LimitUnit}).
	 *
	 * @return	An array with always 2 items: [0]=numeric value (of type Integer), [1]=unit (of type {@link LimitUnit}).
	 * @throws TAPException	If the syntax is incorrect
	 *                     	or if a not allowed unit has been used.
	 *
	 * @throws TAPException	If the syntax is incorrect or if a not allowed unit has been used.
	 * @see #parseLimit(String, String, boolean, boolean)
	 */
	public final static Object[] parseLimit(String value, final String propertyName, final boolean areBytesAllowed) throws TAPException{
		return parseLimit(value, propertyName, areBytesAllowed, false);
	}

	/**
	 * Lets parsing a limit (for output, upload, ...) with its numeric value
	 * and its unit.
	 *
	 * <p>
	 * 	Here is the expected syntax: num_val[unit].
	 * 	Where unit is optional and should be one of the following values:
	 * 	r or R, B, kB, MB, GB. If the unit is not specified, it is set by
	 * 	default to ROWS.
	 * </p>
	 *
	 * <p><i>Note:
	 * 	If the value is strictly less than 0 (whatever is the unit), the
	 * 	returned value will be -1.
	 * </i></p>
	 *
	 * @param value				Property value (must follow the limit syntax:
	 *             				num_val[unit] ; ex: 20kB or 2000
	 *             				(for 2000 rows)).
	 * @param propertyName		Name of the property which specify the limit.
	 * @param areBytesAllowed	Tells whether the unit BYTES is allowed. If not
	 *                       	and a BYTES unit is encountered, then an
	 *                       	exception is thrown.
	 * @param longValue			<code>true</code> to get the limit as a long,
	 *                 			<code>false</code> to get it as an int.
	 *
	 * @return	An array with always 2 items:
	 *        	[0]=numeric value (of type Integer or Long in function of the
	 *        	    parameter longValue),
	 *        	[1]=unit (of type {@link LimitUnit}).
	 *
	 * @throws TAPException	If the syntax is incorrect
	 *                     	or if a not allowed unit has been used.
	 *
	 * @since 2.3
	 */
	public final static Object[] parseLimit(String value, final String propertyName, final boolean areBytesAllowed, final boolean longValue) throws TAPException{
		// Remove any whitespace inside or outside the numeric value and its unit:
		if (value != null)
			value = value.replaceAll("\\s", "");

		// If empty value, return an infinite limit:
		if (value == null || value.length() == 0)
			return new Object[]{ -1, LimitUnit.rows };
			return (longValue ? new Object[]{ new Long(-1L), LimitUnit.rows } : new Object[]{ new Integer(-1), LimitUnit.rows });

		// A. Parse the string from the end in order to extract the unit part.
		//    The final step of the loop is the extraction of the numeric value, when the first digit is encountered.
		int numValue = -1;
		long numValue = -1;
		LimitUnit unit;
		StringBuffer buf = new StringBuffer();
		for(int i = value.length() - 1; i >= 0; i--){
			// if a digit, extract the numeric value:
			if (value.charAt(i) >= '0' && value.charAt(i) <= '9'){
				try{
					numValue = Integer.parseInt(value.substring(0, i + 1));
					numValue = Long.parseLong(value.substring(0, i + 1));
					break;
				}catch(NumberFormatException nfe){
					throw new TAPException("Integer expected for the property " + propertyName + " for the substring \"" + value.substring(0, i + 1) + "\" of the whole value: \"" + value + "\"!");
@@ -615,7 +700,10 @@ public final class TAPConfiguration {
			}
		}

		return new Object[]{ ((numValue < 0) ? -1 : numValue), unit };
		if (numValue < 0)
			return (longValue ? new Object[]{ new Long(-1L), unit } : new Object[]{ new Integer(-1), unit });
		else
			return (longValue ? new Object[]{ new Long(numValue), unit } : new Object[]{ new Integer((int)numValue), unit });
	}

}
Loading