Commit 9aa13889 authored by gmantele's avatar gmantele
Browse files

[TAP,UWS] Fix a problem with the format of the error details returned by the...

[TAP,UWS] Fix a problem with the format of the error details returned by the parameter .../error/details. In TAP a VOTable document is expected, but a text/plain description was returned (default behavior in the UWS lib.). Now, a ServiceErrorWriter is used to format the error details correctly.
parent 6a448b36
Loading
Loading
Loading
Loading
+32 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;

import tap.db.DBConnection;
import tap.error.DefaultTAPErrorWriter;
import tap.metadata.TAPMetadata;
import tap.metadata.TAPSchema;
import tap.metadata.TAPTable;
@@ -40,6 +41,7 @@ import uws.job.Result;
import uws.job.user.JobOwner;
import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import uws.service.error.ServiceErrorWriter;
import adql.db.DBChecker;
import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;
@@ -50,10 +52,12 @@ import adql.query.ADQLQuery;
 * Only the functions related with the database connection stay abstract.
 * 
 * @author Grégory Mantelet (CDS;ARI)
 * @version 2.0 (08/2014)
 * @version 2.0 (09/2014)
 */
public abstract class AbstractTAPFactory extends TAPFactory {

	protected final ServiceErrorWriter errorWriter;

	/**
	 * Build a basic TAPFactory.
	 * Nothing is done except setting the service connection.
@@ -62,10 +66,33 @@ public abstract class AbstractTAPFactory extends TAPFactory {
	 * 
	 * @throws NullPointerException	If the given {@link ServiceConnection} is NULL.
	 * 
	 * @see {@link TAPFactory#TAPFactory(ServiceConnection)}
	 * @see AbstractTAPFactory#AbstractTAPFactory(ServiceConnection, ServiceErrorWriter)
	 */
	protected AbstractTAPFactory(ServiceConnection service) throws NullPointerException{
		this(service, new DefaultTAPErrorWriter(service));
	}

	/**
	 * <p>Build a basic TAPFactory.
	 * Nothing is done except setting the service connection and the given error writer.</p>
	 * 
	 * <p>Then the error writer will be used when creating a UWS service and a job thread.</p>
	 * 
	 * @param service		Configuration of the TAP service. <i>MUST NOT be NULL</i>
	 * @param errorWriter	Object to use to format and write the errors for the user.
	 * 
	 * @throws NullPointerException	If the given {@link ServiceConnection} is NULL.
	 * 
	 * @see {@link TAPFactory#TAPFactory(ServiceConnection)}
	 */
	protected AbstractTAPFactory(final ServiceConnection service, final ServiceErrorWriter errorWriter) throws NullPointerException{
		super(service);
		this.errorWriter = errorWriter;
	}

	@Override
	public final ServiceErrorWriter getErrorWriter(){
		return errorWriter;
	}

	/* *************** */
@@ -192,7 +219,9 @@ public abstract class AbstractTAPFactory extends TAPFactory {
	 */
	@Override
	public UWSService createUWS() throws TAPException{
		return new UWSService(this, this.service.getFileManager(), this.service.getLogger());
		UWSService uws = new UWSService(this, this.service.getFileManager(), this.service.getLogger());
		uws.setErrorWriter(errorWriter);
		return uws;
	}

	/**
+26 −3
Original line number Diff line number Diff line
@@ -16,18 +16,36 @@ 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)
 */

import uws.UWSException;
import uws.job.JobThread;
import uws.service.error.ServiceErrorWriter;

/**
 * Thread in charge of a TAP job execution.
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (09/2014)
 */
public class AsyncThread extends JobThread {

	/** The only object which knows how to execute an ADQL query. */
	protected final ADQLExecutor executor;

	public AsyncThread(TAPJob j, ADQLExecutor executor) throws UWSException{
		super(j, "Execute the ADQL query of the TAP request " + j.getJobId());
	/**
	 * Build a TAP asynchronous job execution.
	 * 
	 * @param j				Description of the job to execute.
	 * @param executor		The object to use for the ADQL execution itself.
	 * @param errorWriter	The object to use to format and to write an execution error for the user.
	 * 
	 * @throws NullPointerException	If the job parameter is missing.
	 */
	public AsyncThread(final TAPJob j, final ADQLExecutor executor, final ServiceErrorWriter errorWriter) throws NullPointerException{
		super(j, "Execute the ADQL query of the TAP request " + j.getJobId(), errorWriter);
		this.executor = executor;
	}

@@ -46,6 +64,11 @@ public class AsyncThread extends JobThread {
		}
	}

	/**
	 * Get the description of the job that this thread is executing.
	 * 
	 * @return	The executed job.
	 */
	public final TAPJob getTAPJob(){
		return (TAPJob)job;
	}
+14 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import uws.job.user.JobOwner;
import uws.service.AbstractUWSFactory;
import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import uws.service.error.ServiceErrorWriter;
import adql.parser.ADQLQueryFactory;
import adql.parser.QueryChecker;
import adql.query.ADQLQuery;
@@ -80,6 +81,17 @@ public abstract class TAPFactory extends AbstractUWSFactory {
		this.service = service;
	}

	/**
	 * <p>Get the object to use when an error must be formatted and written to the user.</p>
	 * 
	 * <p>This formatted error will be either written in an HTTP response or in a job error summary.</p>
	 * 
	 * @return	The error writer to use.
	 * 
	 * @since 4.1
	 */
	public abstract ServiceErrorWriter getErrorWriter();

	/* ******************* */
	/* DATABASE CONNECTION */
	/* ******************* */
@@ -343,7 +355,7 @@ public abstract class TAPFactory extends AbstractUWSFactory {
	 * <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
	 * 	This function is definitely implemented here and can not be overridden. The processing of
	 * 	an ADQL query must always be the same in a TAP service ; it is completely done by {@link AsyncThread}.
	 * </p>
	 * 
@@ -353,7 +365,7 @@ public abstract class TAPFactory extends AbstractUWSFactory {
	@Override
	public final JobThread createJobThread(final UWSJob job) throws UWSException{
		try{
			return new AsyncThread((TAPJob)job, createADQLExecutor());
			return new AsyncThread((TAPJob)job, createADQLExecutor(), getErrorWriter());
		}catch(TAPException te){
			throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, te, "Impossible to create an AsyncThread !");
		}
+36 −1
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ package tap.error;
 */

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
@@ -32,7 +34,9 @@ import tap.formatter.VOTableFormat;
import tap.log.DefaultTAPLog;
import tap.log.TAPLog;
import uws.UWSException;
import uws.job.ErrorSummary;
import uws.job.ErrorType;
import uws.job.UWSJob;
import uws.job.user.JobOwner;
import uws.service.error.DefaultUWSErrorWriter;
import uws.service.error.ServiceErrorWriter;
@@ -125,7 +129,7 @@ public class DefaultTAPErrorWriter implements ServiceErrorWriter {
		response.setStatus((httpErrorCode <= 0) ? 500 : httpErrorCode);

		// Set the MIME type of the answer (XML for a VOTable document):
		response.setContentType("text/xml");
		response.setContentType("application/xml");

		// List any additional information useful to report to the user:
		HashMap<String,String> addInfos = new HashMap<String,String>();
@@ -142,4 +146,35 @@ public class DefaultTAPErrorWriter implements ServiceErrorWriter {
		formatter.writeError(message, addInfos, response.getWriter());
	}

	@Override
	public void writeError(Throwable t, ErrorSummary error, UWSJob job, OutputStream output) throws IOException{
		// Get the error message:
		String message;
		if (error != null && error.getMessage() != null)
			message = error.getMessage();
		else if (t != null)
			message = (t.getMessage() == null) ? t.getClass().getName() : t.getMessage();
		else
			message = "{NO MESSAGE}";

		// List any additional information useful to report to the user:
		HashMap<String,String> addInfos = new HashMap<String,String>();
		if (job != null){
			addInfos.put("JOB_ID", job.getJobId());
			if (job.getOwner() != null)
				addInfos.put("USER", job.getOwner().getID() + ((job.getOwner().getPseudo() == null) ? "" : " (" + job.getOwner().getPseudo() + ")"));
		}
		if (error != null && error.getType() != null)
			addInfos.put("ERROR_TYPE", error.getType().toString());
		addInfos.put("ACTION", "EXECUTING");

		// Format the error in VOTable and write the document in the given HTTP response:
		formatter.writeError(message, addInfos, new PrintWriter(output));
	}

	@Override
	public String getErrorDetailsMIMEType(){
		return "application/xml";
	}

}
+0 −1
Original line number Diff line number Diff line
@@ -111,7 +111,6 @@ public class TAP implements VOSIResource {

		res = new ASync(service);
		resources.put(res.getName(), res);
		getUWS().setErrorWriter(errorWriter);

		TAPMetadata metadata = service.getTAPMetadata();
		if (metadata != null)
Loading