Commit af33e445 authored by gmantele's avatar gmantele
Browse files

[TAP] Add Javadoc for TAPFactorys

parent f132fc44
Loading
Loading
Loading
Loading
+201 −20
Original line number Diff line number Diff line
@@ -20,13 +20,17 @@ package tap;
 *                       Astronomisches Rechen Institut (ARI)
 */

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import tap.db.DBConnection;
import tap.metadata.TAPMetadata;
import tap.metadata.TAPSchema;
import tap.metadata.TAPTable;
import tap.parameters.TAPParameters;
import tap.upload.Uploader;
@@ -39,18 +43,181 @@ import uws.service.backup.UWSBackupManager;
import adql.db.DBChecker;
import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;
import adql.query.ADQLQuery;

/**
 * Default implementation of most of the {@link TAPFactory} function.
 * Only the functions related with the database connection stay abstract.
 * 
 * @author Grégory Mantelet (ARI)
 * @version 2.0 (08/2014)
 */
public abstract class AbstractTAPFactory extends TAPFactory {

	/**
	 * Build a basic TAPFactory.
	 * Nothing is done except setting the service connection.
	 * 
	 * @param service	Configuration of the TAP service. <i>MUST NOT be NULL</i>
	 * 
	 * @throws NullPointerException	If the given {@link ServiceConnection} is NULL.
	 * 
	 * @see {@link TAPFactory#TAPFactory(ServiceConnection)}
	 */
	protected AbstractTAPFactory(ServiceConnection service) throws NullPointerException{
		super(service);
	}

	/* *************** */
	/* ADQL MANAGEMENT */
	/* *************** */

	/**
	 * <p><i>Note:
	 * 	Unless the standard implementation - {@link ADQLExecutor} - does not fit exactly your needs,
	 * 	it should not be necessary to extend this class and to extend this function (implemented here by default).
	 * </i></p>
	 * 
	 * @see tap.TAPFactory#createADQLExecutor()
	 */
	@Override
	public ADQLExecutor createADQLExecutor() throws TAPException{
		return new ADQLExecutor(service);
	}

	/**
	 * <p><i>Note:
	 * 	This function should be extended if you have customized the creation of any
	 * 	{@link ADQLQuery} part ; it could be the addition of one or several user defined function
	 * 	or the modification of any ADQL function or clause specific to your implementation.
	 * </i></p>
	 * 
	 * @see tap.TAPFactory#createQueryFactory()
	 */
	@Override
	public ADQLQueryFactory createQueryFactory() throws TAPException{
		return new ADQLQueryFactory();
	}

	/**
	 * <p>This implementation gathers all tables published in this TAP service and those uploaded
	 * by the user. Then it calls {@link #createQueryChecker(Collection)} with this list in order
	 * to create a query checked.
	 * </p>
	 * 
	 * <p><i>Note:
	 * 	This function can not be overrided, but {@link #createQueryChecker(Collection)} can be.
	 * </i></p>
	 * 
	 * @see tap.TAPFactory#createQueryChecker(tap.metadata.TAPSchema)
	 */
	@Override
	public final QueryChecker createQueryChecker(final TAPSchema uploadSchema) throws TAPException{
		// Get all tables published in this TAP service:
		TAPMetadata meta = service.getTAPMetadata();

		// Build a list in order to gather all these with the uploaded ones:
		ArrayList<TAPTable> tables = new ArrayList<TAPTable>(meta.getNbTables());

		// Add all tables published in TAP:
		Iterator<TAPTable> it = meta.getTables();
		while(it.hasNext())
			tables.add(it.next());

		// Add all tables uploaded by the user:
		if (uploadSchema != null){
			for(TAPTable table : uploadSchema)
				tables.add(table);
		}

		// Finally, create the query checker:
		return createQueryChecker(tables);
	}

	/**
	 * <p>Create an object able to check the consistency between the ADQL query and the database.
	 * That's to say, it checks whether the tables and columns used in the query really exist
	 * in the database.</p>
	 * 
	 * <p><i>Note:
	 * 	This implementation just create a {@link DBChecker} instance with the list given in parameter.
	 * </i></p>
	 * 
	 * @param tables	List of all available tables (and indirectly, columns).
	 * 
	 * @return	A new ADQL query checker.
	 * 
	 * @throws TAPException	If any error occurs while creating the query checker.
	 * 
	 * @see DBChecker
	 */
	protected QueryChecker createQueryChecker(final Collection<TAPTable> tables) throws TAPException{
		return new DBChecker(tables);
	}

	/* ****** */
	/* UPLOAD */
	/* ****** */

	/**
	 * <p>This implementation just create an {@link Uploader} instance with the given database connection.</p>
	 * 
	 * <p><i>Note:
	 * 	This function should be overrided if the way user tables are interpreted and then created into the database
	 * 	does not fit yours needs.
	 * </i></p>
	 * 
	 * @see tap.TAPFactory#createUploader(tap.db.DBConnection)
	 * 
	 * @see Uploader
	 */
	@Override
	public Uploader createUploader(final DBConnection dbConn) throws TAPException{
		return new Uploader(service, dbConn);
	}

	/* ************** */
	/* UWS MANAGEMENT */
	/* ************** */

	/**
	 * <p>This implementation just create a {@link UWSService} instance.</p>
	 * 
	 * <p><i>Note:
	 * 	This implementation is largely enough for a TAP service. It is not recommended to override
	 * 	this function.
	 * </i></p>
	 * 
	 * @see tap.TAPFactory#createUWS()
	 */
	@Override
	public UWSService createUWS() throws TAPException{
		return new UWSService(this, this.service.getFileManager(), this.service.getLogger());
	}

	/**
	 * <p>This implementation does not provided a backup manager.
	 * It means that no asynchronous job will be restored and backuped.</p>
	 * 
	 * <p>You must override this function if you want enable the backup feature.</p>
	 * 
	 * @see tap.TAPFactory#createUWSBackupManager(uws.service.UWSService)
	 */
	@Override
	public UWSBackupManager createUWSBackupManager(final UWSService uws) throws TAPException{
		return null;
	}

	/**
	 * <p>This implementation provides a basic {@link TAPJob} instance.</p>
	 * 
	 * <p>
	 * 	If you need to add or modify the behavior of some functions of a {@link TAPJob},
	 * 	you must override this function and return your own extension of {@link TAPJob}.
	 * </p>
	 * 
	 * @see tap.TAPFactory#createTAPJob(javax.servlet.http.HttpServletRequest, uws.job.user.JobOwner)
	 */
	@Override
	protected TAPJob createTAPJob(final HttpServletRequest request, final JobOwner owner) throws UWSException{
		try{
@@ -61,6 +228,16 @@ public abstract class AbstractTAPFactory extends TAPFactory {
		}
	}

	/**
	 * <p>This implementation provides a basic {@link TAPJob} instance.</p>
	 * 
	 * <p>
	 * 	If you need to add or modify the behavior of some functions of a {@link TAPJob},
	 * 	you must override this function and return your own extension of {@link TAPJob}.
	 * </p>
	 * 
	 * @see tap.TAPFactory#createTAPJob(javax.servlet.http.HttpServletRequest, uws.job.user.JobOwner)
	 */
	@Override
	protected TAPJob createTAPJob(final String jobId, final JobOwner owner, final TAPParameters params, final long quote, final long startTime, final long endTime, final List<Result> results, final ErrorSummary error) throws UWSException{
		try{
@@ -70,11 +247,18 @@ public abstract class AbstractTAPFactory extends TAPFactory {
		}
	}

	@Override
	public ADQLExecutor createADQLExecutor() throws TAPException{
		return new ADQLExecutor(service);
	}

	/**
	 * <p>This implementation extracts standard TAP parameters from the given request.</p>
	 * 
	 * <p>
	 * 	Non-standard TAP parameters are added in a map inside the returned {@link TAPParameters} object
	 * 	and are accessible with {@link TAPParameters#get(String)} and {@link TAPParameters#getAdditionalParameters()}.
	 * 	However, if you want to manage them in another way, you must extend {@link TAPParameters} and override
	 * 	this function in order to return an instance of your extension.
	 * </p>
	 * 
	 * @see tap.TAPFactory#createTAPParameters(javax.servlet.http.HttpServletRequest)
	 */
	@Override
	protected TAPParameters createTAPParameters(final HttpServletRequest request) throws UWSException{
		try{
@@ -84,6 +268,18 @@ public abstract class AbstractTAPFactory extends TAPFactory {
		}
	}

	/**
	 * <p>This implementation extracts standard TAP parameters from the given request.</p>
	 * 
	 * <p>
	 * 	Non-standard TAP parameters are added in a map inside the returned {@link TAPParameters} object
	 * 	and are accessible with {@link TAPParameters#get(String)} and {@link TAPParameters#getAdditionalParameters()}.
	 * 	However, if you want to manage them in another way, you must extend {@link TAPParameters} and override
	 * 	this function in order to return an instance of your extension.
	 * </p>
	 * 
	 * @see tap.TAPFactory#createTAPParameters(javax.servlet.http.HttpServletRequest)
	 */
	@Override
	protected TAPParameters createTAPParameters(final Map<String,Object> params) throws UWSException{
		try{
@@ -93,19 +289,4 @@ public abstract class AbstractTAPFactory extends TAPFactory {
		}
	}

	@Override
	public ADQLQueryFactory createQueryFactory() throws TAPException{
		return new ADQLQueryFactory();
	}

	@Override
	protected QueryChecker createQueryChecker(final Collection<TAPTable> tables) throws TAPException{
		return new DBChecker(tables);
	}

	@Override
	public Uploader createUploader(final DBConnection dbConn) throws TAPException{
		return new Uploader(service, dbConn);
	}

}
+309 −36
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ package tap;
 *                       Astronomisches Rechen Institut (ARI)
 */

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@@ -30,9 +27,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import tap.db.DBConnection;
import tap.metadata.TAPMetadata;
import tap.metadata.TAPSchema;
import tap.metadata.TAPTable;
import tap.parameters.TAPParameters;
import tap.upload.Uploader;
import uws.UWSException;
@@ -47,12 +42,37 @@ import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;
import adql.translator.ADQLTranslator;
import adql.query.ADQLQuery;

/**
 * <p>Let build essential objects of the TAP service.</p>
 * 
 * <p>Basically, it means answering to the following questions:</p>
 * <ul>
 * 	<li>how to connect to the database? <i>({@link DBConnection})</i></li>
 * 	<li>which UWS implementation (default implementation provided by default) to use? <i>({@link UWSService})</i></li>
 * 	<li>whether and how UWS/asynchronous jobs must be backuped and restored? <i>({@link UWSBackupManager})</i></li>
 * 	<li>how to create asynchronous jobs? <i>({@link TAPJob})</i></li>
 * 	<li>whether and how tables must be updated? <i>({@link Uploader})</i></li>
 * 	<li>how to check ADQL queries? <i>({@link QueryChecker})</i></li>
 * </ul>
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (08/2014)
 */
public abstract class TAPFactory extends AbstractUWSFactory {

	/** Connection to the TAP service ; it provides all important service configuration information. */
	protected final ServiceConnection service;

	/**
	 * Build a basic {@link TAPFactory}.
	 * Nothing is done except setting the service connection.
	 * 
	 * @param service	Configuration of the TAP service. <i>MUST NOT be NULL</i>
	 * 
	 * @throws NullPointerException	If the given {@link ServiceConnection} is NULL.
	 */
	protected TAPFactory(final ServiceConnection service) throws NullPointerException{
		if (service == null)
			throw new NullPointerException("Can not create a TAPFactory without a ServiceConnection instance !");
@@ -60,25 +80,192 @@ public abstract class TAPFactory extends AbstractUWSFactory {
		this.service = service;
	}

	public abstract ADQLTranslator createADQLTranslator() throws TAPException;

	protected abstract DBConnection createDBConnection() throws TAPException;
	/* ******************* */
	/* DATABASE CONNECTION */
	/* ******************* */

	/**
	 * <p>Get a free database connection.</p>
	 * 
	 * <p>
	 * 	<i>Free</i> means this connection is not currently in use and will be exclusively dedicated to the function/process/thread
	 * 	which has asked for it by calling this function.
	 * </p>
	 * 
	 * <p><i>Note:
	 * 	This function can create on the fly a new connection OR get a free one from a connection pool. Considering the
	 * 	creation time of a database connection, the second way is recommended.
	 * </i></p>
	 * 
	 * <p><b>IMPORTANT:</b>
	 * 	The returned connection MUST be freed after having used it.
	 * </p>
	 * 
	 * <p><i><b>WARNING:</b>
	 * 	Some implementation may free the connection automatically when not used for a specific time.
	 * 	So, do not forget to free the connection after use!
	 * </i></p>
	 * 
	 * @param jobID	ID of the job/thread/process which has asked for this connection. <i>note: The returned connection must then be identified thanks to this ID.</i>
	 * 
	 * @return	A new and free connection to the database. <b>MUST BE NOT NULL, or otherwise a TAPException should be returned.</b>
	 * 
	 * @throws TAPException	If there is any error while getting a free connection.
	 */
	public abstract DBConnection getConnection(final String jobID) throws TAPException;

	/**
	 * <p>Free the given connection.</p>
	 * 
	 * <p>
	 * 	This function is called by the TAP library when a job/thread does not need this connection any more. It aims
	 * 	to free resources associated to the given database connection.
	 * </p>
	 * 
	 * <p><i>Note:
	 * 	This function can just close definitely the connection OR give it back to a connection pool. The implementation is
	 * 	here totally free!
	 * </i></p>
	 * 
	 * @param conn	The connection to close.
	 */
	public abstract void freeConnection(final DBConnection conn);

	/**
	 * @return	<=0 in case of problem, >0 otherwise.
	 * <p>Count the number of connection not currently used and available on demand.</p>
	 * 
	 * <p>This function is called particularly by the queue manager in order to determine whether a job can start.
	 * It won't start if no connection is available.</p>
	 * 
	 * <p><i>Note:
	 * 	If the implementation of this factory creates connections on the fly, the value 1 (or bigger) must always be returned.
	 * 	However, if the connections are managed by a connection pool, the count value must be asked to it.
	 * </i></p>
	 * 
	 * <p><i>Note:
	 * 	In case of error when counting, a null or negative value must be returned. If the error must be
	 * 	reported, it is up to this function to log the error before returning a null or negative value.
	 * </i></p>
	 * 
	 * @return	The number of connections still available,
	 *        	or <=0 in case of problem (<i>note: in this case, the error must be logged in the implementation of this function</i>).
	 */
	public abstract int countFreeConnections();

	public UWSService createUWS() throws TAPException{
		return new UWSService(this, this.service.getFileManager(), this.service.getLogger());
	}
	/* *************** */
	/* ADQL MANAGEMENT */
	/* *************** */

	/**
	 * <p>Create the object able to execute an ADQL query and to write and to format its result.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}
	 * </i></p>
	 * 
	 * @return	An ADQL executor.
	 * 
	 * @throws TAPException	If any error occurs while creating an ADQL executor.
	 */
	public abstract ADQLExecutor createADQLExecutor() throws TAPException;

	/**
	 * <p>Create a factory able to build every part of an {@link ADQLQuery} object.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}
	 * </i></p> 
	 * 
	 * @return	An {@link ADQLQuery} factory.
	 * 
	 * @throws TAPException	If any error occurs while creating the factory.
	 */
	public abstract ADQLQueryFactory createQueryFactory() throws TAPException;

	/**
	 * <p>Create an object able to check the consistency between the ADQL query and the database.
	 * That's to say, it checks whether the tables and columns used in the query really exist
	 * in the database.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}
	 * </i></p>
	 * 
	 * @param uploadSchema	ADQL schema containing the description of all uploaded tables.
	 * 
	 * @return	A query checker.
	 * 
	 * @throws TAPException	If any error occurs while creating a query checker.
	 */
	public abstract QueryChecker createQueryChecker(final TAPSchema uploadSchema) throws TAPException;

	/* ****** */
	/* UPLOAD */
	/* ****** */

	/**
	 * <p>Create an object able to manage the creation of submitted user tables (in VOTable) into the database.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param dbConn	The database connection which has requested an {@link Uploader}.
	 * 
	 * @return	An {@link Uploader}.
	 * 
	 * @throws TAPException	If any error occurs while creating an {@link Uploader} instance.
	 */
	public abstract Uploader createUploader(final DBConnection dbConn) throws TAPException;

	/* ************** */
	/* UWS MANAGEMENT */
	/* ************** */

	/**
	 * <p>Create the object which will manage the asynchronous resource of the TAP service.
	 * This resource is a UWS service.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @return	A UWS service which will be the asynchronous resource of this TAP service.
	 * 
	 * @throws TAPException	If any error occurs while creating this UWS service.
	 */
	public abstract UWSService createUWS() throws TAPException;

	/**
	 * <p>Create the object which will manage the backup and restoration of all asynchronous jobs.</p>
	 * 
	 * <p><i>Note:
	 * 	This function may return NULL. If it does, asynchronous jobs won't be backuped.
	 * </i></p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param uws	The UWS service which has to be backuped and restored.
	 * 
	 * @return	The backup manager to use. <i>MAY be NULL</i>
	 * 
	 * @throws TAPException	If any error occurs while creating this backup manager.
	 */
	public abstract UWSBackupManager createUWSBackupManager(final UWSService uws) throws TAPException;

	/**
	 * <p>Creates a (PENDING) UWS job from the given HTTP request.</p>
	 * 
	 * <p>
	 * 	This implementation just call {@link #createTAPJob(HttpServletRequest, JobOwner)}
	 * 	with the given request, in order to ensure that the returned object is always a {@link TAPJob}.
	 * </p>
	 * 
	 * @see uws.service.AbstractUWSFactory#createJob(javax.servlet.http.HttpServletRequest, uws.job.user.JobOwner)
	 * @see #createTAPJob(HttpServletRequest, JobOwner)
	 */
	@Override
	public final UWSJob createJob(HttpServletRequest request, JobOwner owner) throws UWSException{
		if (!service.isAvailable())
@@ -87,8 +274,41 @@ public abstract class TAPFactory extends AbstractUWSFactory {
		return createTAPJob(request, owner);
	}

	/**
	 * <p>Create a PENDING asynchronous job from the given HTTP request.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param request	Request which contains all parameters needed to set correctly the asynchronous job to create.
	 * @param owner		The user which has requested the job creation.
	 * 
	 * @return	A new PENDING asynchronous job.
	 * 
	 * @throws UWSException	If any error occurs while reading the parameters in the request or while creating the job.
	 */
	protected abstract TAPJob createTAPJob(final HttpServletRequest request, final JobOwner owner) throws UWSException;

	/**
	 * <p>Creates a UWS job with the following attributes.</p>
	 * 
	 * <p>
	 * 	This implementation just call {@link #createTAPJob(String, JobOwner, TAPParameters, long, long, long, List, ErrorSummary)}
	 * 	with the given parameters, in order to ensure that the returned object is always a {@link TAPJob}.
	 * </p>
	 *
	 * <p><i>Note 1:
	 * 	This function is mainly used to restore a UWS job at the UWS initialization.
	 * </i></p>
	 * 
	 * <p><i>Note 2:
	 * 	The job phase is chosen automatically from the given job attributes (i.e. no endTime => PENDING, no result and no error => ABORTED, ...).
	 * </i></p>
	 * 
	 * @see uws.service.AbstractUWSFactory#createJob(java.lang.String, uws.job.user.JobOwner, uws.job.parameters.UWSParameters, long, long, long, java.util.List, uws.job.ErrorSummary)
	 * @see #createTAPJob(String, JobOwner, TAPParameters, long, long, long, List, ErrorSummary)
	 */
	@Override
	public final UWSJob createJob(String jobId, JobOwner owner, final UWSParameters params, long quote, long startTime, long endTime, List<Result> results, ErrorSummary error) throws UWSException{
		if (!service.isAvailable())
@@ -97,8 +317,39 @@ public abstract class TAPFactory extends AbstractUWSFactory {
		return createTAPJob(jobId, owner, (TAPParameters)params, quote, startTime, endTime, results, error);
	}

	/**
	 * <p>Create a PENDING asynchronous job with the given parameters.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided in {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param jobID			ID of the job (NOT NULL).
	 * @param owner			Owner of the job.
	 * @param params		List of all input job parameters.
	 * @param quote			Its quote (in seconds).
	 * @param startTime		Date/Time of the start of this job.
	 * @param endTime		Date/Time of the end of this job.
	 * @param results		All results of this job.
	 * @param error			The error which ended the job to create.
	 * 
	 * @return	A new PENDING asynchronous job.
	 * 
	 * @throws UWSException	If there is an error while creating the job.
	 */
	protected abstract TAPJob createTAPJob(final String jobId, final JobOwner owner, final TAPParameters params, final long quote, final long startTime, final long endTime, final List<Result> results, final ErrorSummary error) throws UWSException;

	/**
	 * <p>Create the thread which will execute the task described by the given UWSJob instance.</p>
	 * 
	 * <p>
	 * 	This function is definitely implemented here and can not be overrided. The processing of
	 * 	an ADQL query must always be the same in a TAP service ; it is completely done by {@link AsyncThread}.
	 * </p>
	 * 
	 * @see uws.service.UWSFactory#createJobThread(uws.job.UWSJob)
	 * @see AsyncThread
	 */
	@Override
	public final JobThread createJobThread(final UWSJob job) throws UWSException{
		try{
@@ -108,45 +359,67 @@ public abstract class TAPFactory extends AbstractUWSFactory {
		}
	}

	public abstract ADQLExecutor createADQLExecutor() throws TAPException;

	/**
	 * Extracts the parameters from the given request (multipart or not).
	 * This function is used only to set UWS parameters, not to create a TAP query (for that, see {@link TAPParameters}).
	 * <p>Extract the parameters from the given request (multipart or not).</p>
	 * 
	 * <p>
	 * 	This function is used only to create the set of parameters for a TAP job (synchronous or asynchronous).
	 * 	Thus, it just call {@link #createTAPParameters(HttpServletRequest)} with the given request, in order to ensure
	 * 	that the returned object is always a {@link TAPParameters}.
	 * </p>
	 * 
	 * @see uws.service.AbstractUWSFactory#extractParameters(javax.servlet.http.HttpServletRequest, uws.service.UWS)
	 * @see #createTAPParameters(HttpServletRequest)
	 */
	@Override
	public final UWSParameters createUWSParameters(HttpServletRequest request) throws UWSException{
		return createTAPParameters(request);
	}

	/**
	 * <p>Extract all the TAP parameters from the given HTTP request (multipart or not) and return them.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param request	The HTTP request containing the TAP parameters to extract.
	 * 
	 * @return	An object gathering all successfully extracted TAP parameters.
	 * 
	 * @throws UWSException	If any error occurs while extracting the parameters.
	 */
	protected abstract TAPParameters createTAPParameters(final HttpServletRequest request) throws UWSException;

	/**
	 * <p>Identify and gather all identified parameters of the given map inside a {@link TAPParameters} object.</p>
	 * 
	 * <p>
	 * 	This implementation just call {@link #createTAPParameters(Map)} with the given map, in order to ensure
	 * 	that the returned object is always a {@link TAPParameters}.
	 * </p>
	 * 
	 * @see uws.service.AbstractUWSFactory#createUWSParameters(java.util.Map)
	 * @see #createTAPParameters(Map)
	 */
	@Override
	public final UWSParameters createUWSParameters(Map<String,Object> params) throws UWSException{
		return createTAPParameters(params);
	}

	/**
	 * <p>Identify all TAP parameters and gather them inside a {@link TAPParameters} object.</p>
	 * 
	 * <p><i>Note:
	 * 	A default implementation is provided by {@link AbstractTAPFactory}.
	 * </i></p>
	 * 
	 * @param params	Map containing all parameters.
	 * 
	 * @return	An object gathering all successfully identified TAP parameters.
	 * 
	 * @throws UWSException	If any error occurs while creating the {@link TAPParameters} object.
	 */
	protected abstract TAPParameters createTAPParameters(final Map<String,Object> params) throws UWSException;

	public abstract ADQLQueryFactory createQueryFactory() throws TAPException;

	public final QueryChecker createQueryChecker(final TAPSchema uploadSchema) throws TAPException{
		TAPMetadata meta = service.getTAPMetadata();
		ArrayList<TAPTable> tables = new ArrayList<TAPTable>(meta.getNbTables());
		Iterator<TAPTable> it = meta.getTables();
		while(it.hasNext())
			tables.add(it.next());
		if (uploadSchema != null){
			for(TAPTable table : uploadSchema)
				tables.add(table);
		}
		return createQueryChecker(tables);
	}

	protected abstract QueryChecker createQueryChecker(final Collection<TAPTable> tables) throws TAPException;

	public abstract Uploader createUploader(final DBConnection dbConn) throws TAPException;

}