Commit cc2462d6 authored by gmantele's avatar gmantele
Browse files

[TAP] Remove all generic types + Delete specific (for ResultSet) output...

[TAP] Remove all generic types + Delete specific (for ResultSet) output formatters + Modify the main output formatter
parent e323573f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
/ADQLParser.java
/ADQLParserConstants.java
/ADQLParserTokenManager.java
+75 −117
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-2013 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2012-2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institute (ARI)
 */

@@ -26,6 +26,7 @@ import java.sql.SQLException;

import javax.servlet.http.HttpServletResponse;

import tap.data.TableIterator;
import tap.db.DBConnection;
import tap.db.DBException;
import tap.formatter.OutputFormat;
@@ -42,20 +43,17 @@ import adql.parser.ADQLQueryFactory;
import adql.parser.ParseException;
import adql.parser.QueryChecker;
import adql.query.ADQLQuery;
import adql.translator.ADQLTranslator;
import adql.translator.TranslationException;

/**
 * 
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
 * @version 1.1 (12/2013)
 * 
 * @param <R>
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (07/2014)
 */
public class ADQLExecutor< R > {
public class ADQLExecutor {

	protected final ServiceConnection<R> service;
	protected final ServiceConnection service;
	protected final TAPLog logger;

	protected Thread thread;
@@ -63,10 +61,10 @@ public class ADQLExecutor< R > {
	protected HttpServletResponse response;
	protected TAPExecutionReport report;

	private DBConnection<R> dbConn = null;
	private DBConnection dbConn = null;
	protected TAPSchema uploadSchema = null;

	public ADQLExecutor(final ServiceConnection<R> service){
	public ADQLExecutor(final ServiceConnection service){
		this.service = service;
		this.logger = service.getLogger();
	}
@@ -79,76 +77,21 @@ public class ADQLExecutor< R > {
		return report;
	}

	public boolean hasUploadedTables(){
		return (uploadSchema != null) && (uploadSchema.getNbTables() > 0);
	}

	protected final DBConnection<R> getDBConnection() throws TAPException{
		return (dbConn != null) ? dbConn : (dbConn = service.getFactory().createDBConnection((report != null) ? report.jobID : null));
	}

	public final void closeDBConnection() throws TAPException{
		if (dbConn != null){
			dbConn.close();
			dbConn = null;
		}
	}

	private final void uploadTables() throws TAPException{
		TableLoader[] tables = tapParams.getTableLoaders();
		if (tables.length > 0){
			logger.info("JOB " + report.jobID + "\tLoading uploaded tables (" + tables.length + ")...");
			long start = System.currentTimeMillis();
			try{
				/* TODO Problem with the DBConnection! One is created here for the Uploader (and dbConn is set) and closed by its uploadTables function (but dbConn is not set to null).
				 * Ideally, the connection should not be close, or at least dbConn should be set to null just after. */
				uploadSchema = service.getFactory().createUploader(getDBConnection()).upload(tables);
			}finally{
				TAPParameters.deleteUploadedTables(tables);
				report.setDuration(ExecutionProgression.UPLOADING, System.currentTimeMillis() - start);
			}
		}

	}

	private final R executeADQL() throws ParseException, InterruptedException, TranslationException, SQLException, TAPException, UWSException{
		long start;

		tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.PARSING);
		start = System.currentTimeMillis();
		ADQLQuery adql = parseADQL();
		report.setDuration(ExecutionProgression.PARSING, System.currentTimeMillis() - start);

		if (thread.isInterrupted())
			throw new InterruptedException();

		report.resultingColumns = adql.getResultingColumns();

		final int limit = adql.getSelect().getLimit();
		final Integer maxRec = tapParams.getMaxRec();
		if (maxRec != null && maxRec > -1){
			if (limit <= -1 || limit > maxRec)
				adql.getSelect().setLimit(maxRec + 1);
		}

		tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.TRANSLATING);
		start = System.currentTimeMillis();
		String sqlQuery = translateADQL(adql);
		report.setDuration(ExecutionProgression.TRANSLATING, System.currentTimeMillis() - start);
		report.sqlTranslation = sqlQuery;

		if (thread.isInterrupted())
			throw new InterruptedException();
	protected OutputFormat getFormatter() throws TAPException{
		// Search for the corresponding formatter:
		String format = tapParams.getFormat();
		OutputFormat formatter = service.getOutputFormat((format == null) ? "votable" : format);
		if (format != null && formatter == null)
			formatter = service.getOutputFormat("votable");

		tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.EXECUTING_SQL);
		start = System.currentTimeMillis();
		R result = executeQuery(sqlQuery, adql);
		report.setDuration(ExecutionProgression.EXECUTING_SQL, System.currentTimeMillis() - start);
		// Format the result:
		if (formatter == null)
			throw new TAPException("Impossible to format the query result: no formatter has been found for the given MIME type \"" + format + "\" and for the default MIME type \"votable\" (short form) !");

		return result;
		return formatter;
	}

	public final TAPExecutionReport start(final AsyncThread<R> thread) throws TAPException, UWSException, InterruptedException, ParseException, TranslationException, SQLException{
	public final TAPExecutionReport start(final AsyncThread thread) throws UWSException, InterruptedException{
		if (this.thread != null || this.report != null)
			throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, "This ADQLExecutor has already been executed !");

@@ -162,7 +105,7 @@ public class ADQLExecutor< R > {
		return start();
	}

	public final TAPExecutionReport start(final Thread thread, final String jobId, final TAPParameters params, final HttpServletResponse response) throws TAPException, UWSException, InterruptedException, ParseException, TranslationException, SQLException{
	public final TAPExecutionReport start(final Thread thread, final String jobId, final TAPParameters params, final HttpServletResponse response) throws TAPException, InterruptedException{
		if (this.thread != null || this.report != null)
			throw new TAPException("This ADQLExecutor has already been executed !");

@@ -177,7 +120,10 @@ public class ADQLExecutor< R > {
	protected final TAPExecutionReport start() throws TAPException, UWSException, InterruptedException, ParseException, TranslationException, SQLException{
		long start = System.currentTimeMillis();
		try{
			// Upload tables if needed:
			// Get a "database" connection:
			dbConn = service.getFactory().createDBConnection(report.jobID);

			// 1. UPLOAD TABLES, if needed:
			if (tapParams != null && tapParams.getTableLoaders() != null && tapParams.getTableLoaders().length > 0){
				tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.UPLOADING);
				uploadTables();
@@ -186,18 +132,24 @@ public class ADQLExecutor< R > {
			if (thread.isInterrupted())
				throw new InterruptedException();

			// Parse, translate in SQL and execute the ADQL query:
			R queryResult = executeADQL();
			if (queryResult == null || thread.isInterrupted())
			// 2. PARSE THE ADQL QUERY:
			tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.PARSING);
			ADQLQuery adqlQuery = parseADQL();

			if (adqlQuery == null || thread.isInterrupted())
				throw new InterruptedException();

			// Write the result:
			// 3. EXECUTE THE ADQL QUERY:
			tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.EXECUTING_ADQL);
			TableIterator queryResult = executeADQL(adqlQuery);

			// 4. WRITE RESULT:
			tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.WRITING_RESULT);
			writeResult(queryResult);

			// Report the COMPLETED status:
			logger.info("JOB " + report.jobID + " COMPLETED");
			tapParams.set(TAPJob.PARAM_PROGRESSION, ExecutionProgression.FINISHED);

			report.success = true;

			return report;
@@ -211,7 +163,10 @@ public class ADQLExecutor< R > {
				logger.error("JOB " + report.jobID + "\tCan not drop uploaded tables !", e);
			}
			try{
				closeDBConnection();
				if (dbConn != null){
					dbConn.close();
					dbConn = null;
				}
			}catch(TAPException e){
				logger.error("JOB " + report.jobID + "\tCan not close the DB connection !", e);
			}
@@ -220,7 +175,27 @@ public class ADQLExecutor< R > {
		}
	}

	private final void uploadTables() throws TAPException{
		// Fetch the tables to upload:
		TableLoader[] tables = tapParams.getTableLoaders();

		// Upload them, if needed:
		if (tables.length > 0){
			logger.info("JOB " + report.jobID + "\tLoading uploaded tables (" + tables.length + ")...");
			long start = System.currentTimeMillis();
			try{
				/* TODO Problem with the DBConnection! One is created here for the Uploader (and dbConn is set) and closed by its uploadTables function (but dbConn is not set to null).
				 * Ideally, the connection should not be close, or at least dbConn should be set to null just after. */
				uploadSchema = service.getFactory().createUploader(dbConn).upload(tables);
			}finally{
				TAPParameters.deleteUploadedTables(tables);
				report.setDuration(ExecutionProgression.UPLOADING, System.currentTimeMillis() - start);
			}
		}
	}

	protected ADQLQuery parseADQL() throws ParseException, InterruptedException, TAPException{
		long start = System.currentTimeMillis();
		ADQLQueryFactory queryFactory = service.getFactory().createQueryFactory();
		QueryChecker queryChecker = service.getFactory().createQueryChecker(uploadSchema);
		ADQLParser parser;
@@ -230,22 +205,21 @@ public class ADQLExecutor< R > {
			parser = new ADQLParser(queryChecker, queryFactory);
		parser.setCoordinateSystems(service.getCoordinateSystems());
		parser.setDebug(false);
		//logger.info("Job "+report.jobID+" - 1/5 Parsing ADQL....");
		return parser.parseQuery(tapParams.getQuery());
		ADQLQuery query = parser.parseQuery(tapParams.getQuery());
		final int limit = query.getSelect().getLimit();
		final Integer maxRec = tapParams.getMaxRec();
		if (maxRec != null && maxRec > -1){
			if (limit <= -1 || limit > maxRec)
				query.getSelect().setLimit(maxRec + 1);
		}

	protected String translateADQL(ADQLQuery query) throws TranslationException, InterruptedException, TAPException{
		ADQLTranslator translator = service.getFactory().createADQLTranslator();
		//logger.info("Job "+report.jobID+" - 2/5 Translating ADQL...");
		return translator.translate(query);
		report.setDuration(ExecutionProgression.PARSING, System.currentTimeMillis() - start);
		report.resultingColumns = query.getResultingColumns();
		return query;
	}

	protected R executeQuery(String sql, ADQLQuery adql) throws SQLException, InterruptedException, TAPException{
		//logger.info("Job "+report.jobID+" - 3/5 Creating DBConnection....");
		DBConnection<R> dbConn = getDBConnection();
		//logger.info("Job "+report.jobID+" - 4/5 Executing query...\n"+sql);
	protected TableIterator executeADQL(ADQLQuery adql) throws SQLException, InterruptedException, TAPException{
		final long startTime = System.currentTimeMillis();
		R result = dbConn.executeQuery(sql, adql);
		TableIterator result = dbConn.executeQuery(adql);
		if (result == null)
			logger.info("JOB " + report.jobID + " - QUERY ABORTED AFTER " + (System.currentTimeMillis() - startTime) + " MS !");
		else
@@ -253,22 +227,8 @@ public class ADQLExecutor< R > {
		return result;
	}

	protected OutputFormat<R> getFormatter() throws TAPException{
		// Search for the corresponding formatter:
		String format = tapParams.getFormat();
		OutputFormat<R> formatter = service.getOutputFormat((format == null) ? "votable" : format);
		if (format != null && formatter == null)
			formatter = service.getOutputFormat("votable");

		// Format the result:
		if (formatter == null)
			throw new TAPException("Impossible to format the query result: no formatter has been found for the given MIME type \"" + format + "\" and for the default MIME type \"votable\" (short form) !");

		return formatter;
	}

	protected final void writeResult(R queryResult) throws InterruptedException, TAPException, UWSException{
		OutputFormat<R> formatter = getFormatter();
	protected final void writeResult(TableIterator queryResult) throws InterruptedException, TAPException, UWSException{
		OutputFormat formatter = getFormatter();

		// Synchronous case:
		if (response != null){
@@ -300,7 +260,7 @@ public class ADQLExecutor< R > {
		}
	}

	protected void writeResult(R queryResult, OutputFormat<R> formatter, OutputStream output) throws InterruptedException, TAPException{
	protected void writeResult(TableIterator queryResult, OutputFormat formatter, OutputStream output) throws InterruptedException, TAPException{
		//logger.info("Job "+report.jobID+" - 5/5 Writing result file...");
		formatter.writeResult(queryResult, output, report, thread);
	}
@@ -308,15 +268,13 @@ public class ADQLExecutor< R > {
	protected void dropUploadedTables() throws TAPException{
		if (uploadSchema != null){
			// Drop all uploaded tables:
			DBConnection<R> dbConn = getDBConnection();
			for(TAPTable t : uploadSchema){
				try{
					dbConn.dropTable(t);
					dbConn.dropUploadedTable(t.getDBName());
				}catch(DBException dbe){
					logger.error("JOB " + report.jobID + "\tCan not drop the table \"" + t.getDBName() + "\" (in adql \"" + t.getADQLName() + "\") from the database !", dbe);
				}
			}
			closeDBConnection();
		}
	}

+9 −13
Original line number Diff line number Diff line
@@ -32,33 +32,27 @@ import tap.metadata.TAPMetadata;
import tap.metadata.TAPSchema;
import tap.metadata.TAPTable;
import tap.parameters.TAPParameters;

import tap.upload.Uploader;

import uws.UWSException;

import uws.job.ErrorSummary;
import uws.job.JobThread;
import uws.job.Result;
import uws.job.UWSJob;

import uws.job.parameters.UWSParameters;
import uws.job.user.JobOwner;

import uws.service.AbstractUWSFactory;
import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import adql.db.DBChecker;
import adql.db.DBTable;

import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;

public abstract class AbstractTAPFactory< R > extends AbstractUWSFactory implements TAPFactory<R> {
public abstract class AbstractTAPFactory extends AbstractUWSFactory implements TAPFactory {

	protected final ServiceConnection<R> service;
	protected final ServiceConnection service;

	protected AbstractTAPFactory(ServiceConnection<R> service) throws NullPointerException{
	protected AbstractTAPFactory(ServiceConnection service) throws NullPointerException{
		if (service == null)
			throw new NullPointerException("Can not create a TAPFactory without a ServiceConnection instance !");

@@ -102,14 +96,15 @@ public abstract class AbstractTAPFactory< R > extends AbstractUWSFactory impleme
	@Override
	public final JobThread createJobThread(final UWSJob job) throws UWSException{
		try{
			return new AsyncThread<R>((TAPJob)job, createADQLExecutor());
			return new AsyncThread((TAPJob)job, createADQLExecutor());
		}catch(TAPException te){
			throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, te, "Impossible to create an AsyncThread !");
		}
	}

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

	/**
@@ -155,7 +150,8 @@ public abstract class AbstractTAPFactory< R > extends AbstractUWSFactory impleme
		return new DBChecker(tables);
	}

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

+5 −6
Original line number Diff line number Diff line
@@ -19,17 +19,16 @@ package tap;
 * Copyright 2012 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 */

import adql.parser.ParseException;
import adql.translator.TranslationException;
import uws.UWSException;

import uws.job.JobThread;
import adql.parser.ParseException;
import adql.translator.TranslationException;

public class AsyncThread< R > extends JobThread {
public class AsyncThread extends JobThread {

	protected final ADQLExecutor<R> executor;
	protected final ADQLExecutor executor;

	public AsyncThread(TAPJob j, ADQLExecutor<R> executor) throws UWSException{
	public AsyncThread(TAPJob j, ADQLExecutor executor) throws UWSException{
		super(j, "Execute the ADQL query of the TAP request " + j.getJobId());
		this.executor = executor;
	}
+9 −2
Original line number Diff line number Diff line
@@ -16,9 +16,16 @@ 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 * Copyright 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 */

/**
 * Let describe the current status of a job execution.
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (07/2014)
 */
public enum ExecutionProgression{
	PENDING, UPLOADING, PARSING, TRANSLATING, EXECUTING_SQL, WRITING_RESULT, FINISHED;
	PENDING, UPLOADING, PARSING, EXECUTING_ADQL, WRITING_RESULT, FINISHED;
}
Loading