Commit f3954c71 authored by gmantele's avatar gmantele
Browse files

[UWS] Add 3 job destruction policies: ALWAYS_DELETE (default), ARCHIVE_ON_DATE

and ALWAYS_ARCHIVE.

When archiving a job, its former phase is stored in jobInfo under the name
'oldPhase' if no jobInfo is already set.

Archiving a job means that all input files and results are destroyed ; the
error summary and jobInfo (even if it is a file) are kept.

Each archive operation ends with a log message ; in ERROR if failed or in
INFO if successful.

This commit also includes the following things:

    - reformat on 80 characters width the Javadoc of all modified classes

	- fix a bug with the phase transitions: since it is not possible any more
	  to go from PENDING to EXECUTING directly, UWSJob.start(...) must first
	  ensure to be on QUEUED phase. This bug has also been fixed in TAPJob.
	  Similarly, before going into ARCHIVED phase the job must be set into
	  ABORTED phase if not already in a final phase.
parent 0467dbb1
Loading
Loading
Loading
Loading
+109 −54
Original line number Diff line number Diff line
@@ -53,42 +53,55 @@ import uws.service.log.UWSLog.LogLevel;
public class TAPJob extends UWSJob {
	private static final long serialVersionUID = 1L;

	/** Name of the standard TAP parameter which specifies the type of request to execute: "REQUEST". */
	/** Name of the standard TAP parameter which specifies the type of request
	 * to execute: "REQUEST". */
	public static final String PARAM_REQUEST = "request";
	/** REQUEST value meaning an ADQL query must be executed: "doQuery". */
	public static final String REQUEST_DO_QUERY = "doQuery";
	/** REQUEST value meaning VO service capabilities must be returned: "getCapabilities". */
	/** REQUEST value meaning VO service capabilities must be returned:
	 * "getCapabilities". */
	public static final String REQUEST_GET_CAPABILITIES = "getCapabilities";

	/** Name of the standard TAP parameter which specifies the query language: "LANG". <i>(only the ADQL language is supported by default in this version of the library)</i> */
	/** Name of the standard TAP parameter which specifies the query language:
	 * "LANG". <i>(only the ADQL language is supported by default in this
	 * version of the library)</i> */
	public static final String PARAM_LANGUAGE = "lang";
	/** LANG value meaning ADQL language: "ADQL". */
	public static final String LANG_ADQL = "ADQL";
	/** LANG value meaning PQL language: "PQL". <i>(this language is not supported in this version of the library)</i> */
	/** LANG value meaning PQL language: "PQL". <i>(this language is not
	 * supported in this version of the library)</i> */
	public static final String LANG_PQL = "PQL";

	/** Name of the standard TAP parameter which specifies the version of the TAP protocol that must be used: "VERSION". <i>(only the version 1.0 is supported in this version of the library)</i> */
	/** Name of the standard TAP parameter which specifies the version of the
	 * TAP protocol that must be used: "VERSION". <i>(only the version 1.0 is
	 * supported in this version of the library)</i> */
	public static final String PARAM_VERSION = "version";
	/** VERSION value meaning the version 1.0 of TAP: "1.0". */
	public static final String VERSION_1_0 = "1.0";

	/** Name of the standard TAP parameter which specifies the output format (format of a query result): "FORMAT". */
	/** Name of the standard TAP parameter which specifies the output format
	 * (format of a query result): "FORMAT". */
	public static final String PARAM_FORMAT = "format";
	/** FORMAT value meaning the VOTable format: "votable". */
	public static final String FORMAT_VOTABLE = "votable";

	/** Name of the standard TAP parameter which specifies the maximum number of rows that must be returned in the query result: "MAXREC". */
	/** Name of the standard TAP parameter which specifies the maximum number of
	 * rows that must be returned in the query result: "MAXREC". */
	public static final String PARAM_MAX_REC = "maxRec";
	/** Special MAXREC value meaning the number of output rows is not limited. */
	public static final int UNLIMITED_MAX_REC = -1;

	/** Name of the standard TAP parameter which specifies the query to execute: "QUERY". */
	/** Name of the standard TAP parameter which specifies the query to execute:
	 * "QUERY". */
	public static final String PARAM_QUERY = "query";

	/** Name of the standard TAP parameter which defines the tables to upload in the database for the query execution: "UPLOAD". */
	/** Name of the standard TAP parameter which defines the tables to upload in
	 * the database for the query execution: "UPLOAD". */
	public static final String PARAM_UPLOAD = "upload";

	/** Name of the library parameter which informs about a query execution progression: "PROGRESSION". <i>(this parameter is removed once the execution is finished)</i> */
	/** Name of the library parameter which informs about a query execution
	 * progression: "PROGRESSION". <i>(this parameter is removed once the
	 * execution is finished)</i> */
	public static final String PARAM_PROGRESSION = "progression";

	/** Internal query execution report. */
@@ -98,15 +111,20 @@ public class TAPJob extends UWSJob {
	protected final TAPParameters tapParams;

	/**
	 * <p>Build a pending TAP job with the given parameters.</p>
	 * Build a pending TAP job with the given parameters.
	 *
	 * <p><i><u>Note:</u> if the parameter {@link #PARAM_PHASE} (</i>phase<i>) is given with the value {@link #PHASE_RUN}
	 * the job execution starts immediately after the job has been added to a job list or after {@link #applyPhaseParam(JobOwner)} is called.</i></p>
	 * <p><i>Note:
	 * 	If the parameter {@link #PARAM_PHASE} (</i>phase<i>) is given with the
	 * 	value {@link #PHASE_RUN} the job execution starts immediately after the
	 * 	job has been added to a job list or after
	 * 	{@link #applyPhaseParam(JobOwner)} is called.
	 * </i></p>
	 *
	 * @param owner		User who owns this job. <i>MAY BE NULL</i>
	 * @param tapParams	Set of parameters.
	 *
	 * @throws TAPException	If one of the given parameters has a forbidden or wrong value.
	 * @throws TAPException	If one of the given parameters has a forbidden or
	 *                     	wrong value.
	 */
	public TAPJob(final JobOwner owner, final TAPParameters tapParams) throws TAPException{
		super(owner, tapParams);
@@ -115,18 +133,26 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Build a pending TAP job with the given parameters.
	 * The given HTTP request ID will be used as Job ID if not already used by another job.</p>
	 * Build a pending TAP job with the given parameters.
	 * The given HTTP request ID will be used as Job ID if not already used by
	 * another job.
	 *
	 * <p><i><u>Note:</u> if the parameter {@link #PARAM_PHASE} (</i>phase<i>) is given with the value {@link #PHASE_RUN}
	 * the job execution starts immediately after the job has been added to a job list or after {@link #applyPhaseParam(JobOwner)} is called.</i></p>
	 * <p><i>Note:
	 * 	If the parameter {@link #PARAM_PHASE} (</i>phase<i>) is given with the
	 * 	value {@link #PHASE_RUN} the job execution starts immediately after the
	 * 	job has been added to a job list or after
	 * 	{@link #applyPhaseParam(JobOwner)} is called.
	 * </i></p>
	 *
	 * @param owner		User who owns this job. <i>MAY BE NULL</i>
	 * @param tapParams	Set of parameters.
	 * @param requestID	ID of the HTTP request which has initiated the creation of this job.
	 *                 	<i>Note: if NULL, empty or already used, a job ID will be generated thanks to {@link #generateJobId()}.</i>
	 * @param requestID	ID of the HTTP request which has initiated the creation
	 *                 	of this job.
	 *                 	<i>Note: if NULL, empty or already used, a job ID will
	 *                 	be generated thanks to {@link #generateJobId()}.</i>
	 *
	 * @throws TAPException	If one of the given parameters has a forbidden or wrong value.
	 * @throws TAPException	If one of the given parameters has a forbidden or
	 *                     	wrong value.
	 *
	 * @since 2.1
	 */
@@ -138,11 +164,13 @@ public class TAPJob extends UWSJob {

	/**
	 * Restore a job in a state defined by the given parameters.
	 * The phase must be set separately with {@link #setPhase(uws.job.ExecutionPhase, boolean)},
	 * where the second parameter is true.
	 * The phase must be set separately with
	 * {@link #setPhase(uws.job.ExecutionPhase, boolean)}, where the second
	 * parameter is true.
	 *
	 * @param jobID			ID of the job.
	 * @param creationTime	Creation date/time of the job (SHOULD NOT BE NEGATIVE OR NULL).
	 * @param creationTime	Creation date/time of the job
	 *                    	(SHOULD NOT BE NEGATIVE OR NULL).
	 * @param owner			User who owns this job.
	 * @param params		Set of not-standard UWS parameters (i.e. what is
	 *              		called by {@link UWSJob} as additional parameters ;
@@ -169,7 +197,8 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * Get the object storing and managing the set of all (UWS and TAP) parameters.
	 * Get the object storing and managing the set of all (UWS and TAP)
	 * parameters.
	 *
	 * @return The object managing all job parameters.
	 */
@@ -178,7 +207,7 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the value of the REQUEST parameter.</p>
	 * Get the value of the REQUEST parameter.
	 *
	 * <p>This value must be {@value #REQUEST_DO_QUERY}.</p>
	 *
@@ -198,9 +227,12 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the value of the LANG parameter.</p>
	 * Get the value of the LANG parameter.
	 *
	 * <p>This value should always be {@value #LANG_ADQL} in this version of the library</p>
	 * <p>
	 * 	This value should always be {@value #LANG_ADQL} in this version of the
	 * 	library
	 * </p>
	 *
	 * @return	LANG value.
	 */
@@ -209,9 +241,12 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the value of the MAXREC parameter.</p>
	 * Get the value of the MAXREC parameter.
	 *
	 * <p>If this value is negative, it means the number of output rows is not limited.</p>
	 * <p>
	 * 	If this value is negative, it means the number of output rows is not
	 * 	limited.
	 * </p>
	 *
	 * @return	MAXREC value.
	 */
@@ -220,7 +255,8 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * Get the value of the QUERY parameter (i.e. the query, in the language returned by {@link #getLanguage()}, to execute).
	 * Get the value of the QUERY parameter (i.e. the query, in the language
	 * returned by {@link #getLanguage()}, to execute).
	 *
	 * @return	QUERY value.
	 */
@@ -229,9 +265,12 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the value of the VERSION parameter.</p>
	 * Get the value of the VERSION parameter.
	 *
	 * <p>This value should be {@value #VERSION_1_0} in this version of the library.</p>
	 * <p>
	 * 	This value should be {@value #VERSION_1_0} in this version of the
	 * 	library.
	 * </p>
	 *
	 * @return	VERSION value.
	 */
@@ -240,9 +279,12 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the value of the UPLOAD parameter.</p>
	 * Get the value of the UPLOAD parameter.
	 *
	 * <p>This value must be formatted as specified by the TAP standard (= a semicolon separated list of DALI uploads).</p>
	 * <p>
	 * 	This value must be formatted as specified by the TAP standard (= a
	 * 	semicolon separated list of DALI uploads).
	 * </p>
	 *
	 * @return	UPLOAD value.
	 */
@@ -251,7 +293,7 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the list of tables to upload in the database for the query execution.</p>
	 * Get the list of tables to upload in the database for the query execution.
	 *
	 * <p>The returned array is an interpretation of the UPLOAD parameter.</p>
	 *
@@ -262,12 +304,13 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Get the execution report.</p>
	 * Get the execution report.
	 *
	 * <p>
	 * 	This report is available only during or after the job execution.
	 * 	It tells in which step the execution is, and how long was the previous steps.
	 * 	It can also give more information about the number of resulting rows and columns.
	 * 	It tells in which step the execution is, and how long was the previous
	 * 	steps. It can also give more information about the number of resulting
	 * 	rows and columns.
	 * </p>
	 *
	 * @return The execReport.
@@ -277,16 +320,18 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Set the execution report.</p>
	 * Set the execution report.
	 *
	 * <p><b>IMPORTANT:
	 * 	This function can be called only if the job is running or is being restored, otherwise an exception would be thrown.
	 * 	It should not be used by implementors, but only by the internal library processing.
	 * 	This function can be called only if the job is running or is being
	 * 	restored, otherwise an exception would be thrown. It should not be used
	 * 	by implementors, but only by the internal library processing.
	 * </b></p>
	 *
	 * @param execReport	An execution report.
	 *
	 * @throws UWSException	If this job has never been restored and is not running.
	 * @throws UWSException	If this job has never been restored and is not
	 *                     	running.
	 */
	public final void setExecReport(final TAPExecutionReport execReport) throws UWSException{
		if (getRestorationDate() == null && (thread == null || thread.isFinished()))
@@ -295,11 +340,14 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Create the thread to use for the execution of this job.</p>
	 * Create the thread to use for the execution of this job.
	 *
	 * <p><i>Note: If the job already exists, this function does nothing.</i></p>
	 * <p><i>Note:
	 * 	If the job already exists, this function does nothing.
	 * </i></p>
	 *
	 * @throws NullPointerException	If the factory returned NULL rather than the asked {@link JobThread}.
	 * @throws NullPointerException	If the factory returned NULL rather than the
	 *                             	asked {@link JobThread}.
	 * @throws UWSException			If the thread creation fails.
	 *
	 * @see TAPFactory#createJobThread(UWSJob)
@@ -315,18 +363,23 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * <p>Check whether this job is able to start right now.</p>
	 * Check whether this job is able to start right now.
	 *
	 * <p>
	 * 	Basically, this function try to get a database connection. If none is available,
	 * 	then this job can not start and this function return FALSE. In all the other cases,
	 * 	TRUE is returned.
	 * 	Basically, this function try to get a database connection. If none is
	 * 	available, then this job can not start and this function return FALSE.
	 * 	In all the other cases, TRUE is returned.
	 * </p>
	 *
	 * <p><b>Warning:</b> This function will indirectly open and keep a database connection, so that the job can be started just after its call.
	 * If it turns out that the execution won't start just after this call, the DB connection should be closed in some way in order to save database resources.</i></p>
	 * <p><b>Warning:</b>
	 * 	This function will indirectly open and keep a database connection, so
	 * 	that the job can be started just after its call. If it turns out that
	 * 	the execution won't start just after this call, the DB connection should
	 * 	be closed in some way in order to save database resources.
	 * </p>
	 *
	 * @return	<i>true</i> if this job can start right now, <i>false</i> otherwise.
	 * @return	<i>true</i> if this job can start right now,
	 *        	<i>false</i> otherwise.
	 *
	 * @since 2.0
	 */
@@ -363,6 +416,7 @@ public class TAPJob extends UWSJob {
			}

			// Change the job phase:
			setPhase(ExecutionPhase.QUEUED);
			setPhase(ExecutionPhase.EXECUTING);

			// Set the start time:
@@ -403,7 +457,8 @@ public class TAPJob extends UWSJob {
	}

	/**
	 * This exception is thrown by a job execution when no database connection are available anymore.
	 * This exception is thrown by a job execution when no database connection
	 * are available anymore.
	 *
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 2.0 (02/2015)
+97 −0
Original line number Diff line number Diff line
package uws.job;

/*
 * This file is part of UWSLibrary.
 *
 * UWSLibrary 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.
 *
 * UWSLibrary 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 UWSLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2017 - Astronomisches Rechen Institut (ARI)
 */

import uws.job.user.JobOwner;

/**
 * Behavior to apply when a job destruction is asked.
 *
 * <p>
 * 	This policy must be set individually on {@link JobList} instances.
 * 	Thus, the jobs lists of a UWS service may have a different behavior when a
 * 	job destruction is required.
 * </p>
 *
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 4.3 (09/2017)
 * @since 4.3
 *
 * @since {@link JobList#destroyJob(String)}
 * @since {@link JobList#destroyJob(String, JobOwner)}
 */
public enum JobDestructionPolicy{
	/**
	 * <p><i><b>Default behavior in UWS-1.0 (and in UWSLibrary).</b></i></p>
	 *
	 * <p>
	 * 	Jobs are ALWAYS immediately destroyed and removed from the
	 * 	{@link JobList}.
	 * </p>
	 */
	ALWAYS_DELETE,
	/**
	 * <p><i><b>
	 * 	Behavior described in UWS-1.1 about the ARCHIVED phase.
	 * </b></i></p>
	 *
	 * <p>
	 * 	Jobs are archived when the destruction date is reached.
	 * </p>
	 *
	 * <p>
	 * 	The archived jobs are then still in the {@link JobList}
	 * 	but in the {@link ExecutionPhase#ARCHIVED} phase. An archived job is
	 * 	stopped and all its resources (uploads, results and threads) are freed.
	 * </p>
	 * <p>
	 * 	If the destruction date is yet not reached, the job is merely destroyed
	 * 	and removed from the {@link JobList}.
	 * </p>
	 * <p><i>Note:
	 * 	Destroying an archived job will definitely destroy it. Thus, the real
	 * 	destruction of a job may be done in 2 steps while using this policy.
	 * </i></p>
	 */
	ARCHIVE_ON_DATE,
	/**
	 * <p><i><b>
	 * 	Alternative behavior proposed by UWSLibrary (but never described in any
	 * 	UWS standard document).
	 * </b></i></p>
	 *
	 * <p>
	 * 	Jobs are ALWAYS immediately archived when a destruction is required
	 * 	(either because the destruction is reached or because of an explicit
	 * 	 action of the UWS client).
	 * </p>
	 *
	 * <p>
	 * 	The archived jobs are then still in the {@link JobList} but in the
	 * 	{@link ExecutionPhase#ARCHIVED} phase. An archived job is stopped and
	 * 	all its resources (uploads, results and threads) are freed.
	 * </p>
	 * <p><i>Note:
	 * 	Destroying an archived job will definitely destroy it. Thus, the real
	 * 	destruction of a job must be done in 2 steps while using this policy.
	 * </i></p>
	 */
	ALWAYS_ARCHIVE;
}
+473 −185

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -362,14 +362,16 @@ public class JobPhase implements Serializable {
	 *
	 * <p><i>Note:
	 * 	By default, it returns TRUE only if the current phase is
	 * 	{@link ExecutionPhase#EXECUTING EXECUTING}!
	 * 	{@link ExecutionPhase#EXECUTING EXECUTING} or
	 * 	{@link ExecutionPhase#SUSPENDED SUSPENDED} (since it is a phase that can
	 * 	happen only during execution)!
	 * </i></p>
	 *
	 * @return	<i>true</i> if the job is executing,
	 *        	<i>false</i> otherwise.
	 */
	public boolean isExecuting(){
		return phase == ExecutionPhase.EXECUTING;
		return phase == ExecutionPhase.EXECUTING || phase == ExecutionPhase.SUSPENDED;
	}

	@Override
+149 −33
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import uws.UWSException;
import uws.UWSExceptionFactory;
import uws.UWSToolBox;
import uws.job.jobInfo.JobInfo;
import uws.job.jobInfo.SingleValueJobInfo;
import uws.job.manager.ExecutionManager;
import uws.job.parameters.UWSParameters;
import uws.job.serializer.UWSSerializer;
@@ -1105,6 +1106,12 @@ public class UWSJob extends SerializableUWSObject {
	 * job can be updated (considering its current execution phase, see
	 * {@link JobPhase#isJobUpdatable()}).
	 *
	 * <p><i><b>Important note:</b>
	 * 	If the given parameter value is an {@link UploadFile} and that it is
	 * 	impossible to move it close to the job, this parameter will be removed.
	 * 	No error is thrown, but a warning message is logged.
	 * </i></p>
	 *
	 * @param paramName		The name of the parameter to add or to update.
	 * @param paramValue	The (new) value of the specified parameter.
	 *
@@ -1125,6 +1132,12 @@ public class UWSJob extends SerializableUWSObject {
	 * job can be updated (considering its current execution phase, see
	 * {@link JobPhase#isJobUpdatable()}).
	 *
	 * <p><i><b>Important note:</b>
	 * 	If the given parameter value is an {@link UploadFile} and that it is
	 * 	impossible to move it close to the job, this parameter will be removed.
	 * 	No error is thrown, but a warning message is logged.
	 * </i></p>
	 *
	 * @param paramName		The name of the parameter to add or to update.
	 * @param paramValue	The (new) value of the specified parameter.
	 * @param user			The user who asks for this update.
@@ -1145,19 +1158,21 @@ public class UWSJob extends SerializableUWSObject {
			// Set the parameter:
			inputParams.set(paramName, paramValue);

			// If it is a file or an array containing files, they must be moved in a location related to this job:
			// CASE DESTRUCTION_TIME: update the thread dedicated to the destruction:
			if (paramValue.equals(PARAM_DESTRUCTION_TIME)){
				if (myJobList != null)
					myJobList.updateDestruction(this);
			}
			// DEFAULT: test whether the parameter is a file, and if yes, move it in a location related to this job:
			else{
				if (paramValue != null && paramValue instanceof UploadFile){
					try{
				if (paramValue instanceof UploadFile)
						((UploadFile)paramValue).move(this);
				else if (paramValue.getClass().isArray()){
					for(Object o : (Object[])paramValue){
						if (o != null && o instanceof UploadFile)
							((UploadFile)o).move(this);
					}
				}
					}catch(IOException ioe){
						getLogger().logJob(LogLevel.WARNING, this, "MOVE_UPLOAD", "Can not move an uploaded file in the job \"" + jobId + "\"!", ioe);
				return false;
						inputParams.remove(paramName);
					}
				}
			}

			// Apply the retrieved phase:
@@ -1190,6 +1205,12 @@ public class UWSJob extends SerializableUWSObject {
	 * 		done.</li>
	 * </ul>
	 *
	 * <p><i><b>Important note:</b>
	 * 	If a given parameter value is an {@link UploadFile} and that it is
	 * 	impossible to move it close to the job, this parameter will be removed.
	 * 	No error is thrown, but a warning message is logged.
	 * </i></p>
	 *
	 * @param params	A list of parameters to add/update.
	 * @return	<i>true</i> if all the given parameters have been successfully
	 *        	added/updated,
@@ -1236,6 +1257,12 @@ public class UWSJob extends SerializableUWSObject {
	 * 		done.</li>
	 * </ul></p>
	 *
	 * <p><i><b>Important note:</b>
	 * 	If a given parameter value is an {@link UploadFile} and that it is
	 * 	impossible to move it close to the job, this parameter will be removed.
	 * 	No error is thrown, but a warning message is logged.
	 * </i></p>
	 *
	 * @param params	The UWS parameters to update.
	 * @param user		The user who asks for this update.
	 *
@@ -1585,6 +1612,7 @@ public class UWSJob extends SerializableUWSObject {
				throw new NullPointerException("Missing job work! The thread created by the factory is NULL => The job can't be executed!");

			// Change the job phase:
			setPhase(ExecutionPhase.QUEUED);
			setPhase(ExecutionPhase.EXECUTING);

			// Set the start time:
@@ -1796,19 +1824,93 @@ public class UWSJob extends SerializableUWSObject {
	}

	/**
	 * Stops the job if running, removes the job from the execution manager,
	 * stops the timer for the execution duration and may clear all files or any
	 * other resources associated to this job.
	 * Archive this job.
	 *
	 * <p>
	 * 	An archive job can not be executed any more. Threads, results and input
	 * 	files are destroyed but the description and the error summary of
	 * 	the job stay unchanged (except the execution phase which will then be
	 * 	{@link ExecutionPhase#ARCHIVED ARCHIVED}).
	 * </p>
	 *
	 * <p><i>Note:
	 * 	By default the job is aborted, the {@link UWSJob#thread} attribute is
	 * 	set to null, the timers are stopped and uploaded files, results and the
	 * 	error summary are deleted and the jobInfo is destroyed.
	 * 	The current phase is stored as job information (only if no JobInfo is
	 * 	already set) in order to satisfy the user curiosity (i.e. "in what
	 * 	phase was this job before being archived?").
	 * </i></p>
	 *
	 * @return	<code>true</code> if this job has been successfully archived,
	 *        	<code>false</code> otherwise.
	 *
	 * @throws UWSException	If any error occurs while clearing resources
	 *                     	or changing the phase of this job.
	 *
	 * @since 4.3
	 */
	public boolean archive(){
		/* Interrupt the corresponding thread
		 * and remove results and input files attached to this job: */
		clearResources(false);

		// Ensure this job is no longer in the destruction manager:
		if (getJobList() != null && getJobList().getDestructionManager() != null)
			getJobList().getDestructionManager().remove(this);

		// Change the phase:
		try{
			// store the current phase as additional JobInfo for user curiosity
			//  (only if no JobInfo is already set):
			if (getJobInfo() == null)
				setJobInfo(new SingleValueJobInfo("oldPhase", getPhase().toString()));
			// change phase:
			setPhase(ExecutionPhase.ARCHIVED);
			// log the success of the archiving operation:
			getLogger().logJob(LogLevel.INFO, this, "ARCHIVE", "Job successfully archived!", null);
			return true;
		}catch(UWSException ue){
			getLogger().logJob(LogLevel.ERROR, this, "ARCHIVE", "Impossible to change the phase of this job into ARCHIVED!", ue);
			return false;
		}
	}

	/**
	 * Stops the job if running, removes the job from the execution manager,
	 * stops the timer for the execution duration.
	 *
	 * <p>
	 * 	Besides, ALL files AND ANY other resources (e.g. thread) associated with
	 * 	this job are destroyed.
	 * </p>
	 *
	 * @see #clearResources(boolean)
	 */
	public void clearResources(){
		clearResources(true);
	}

	/**
	 * Stops the job if running, removes the job from the execution manager,
	 * stops the timer for the execution duration.
	 *
	 * <p>
	 * 	Besides, resources (e.g. thread) associated with this job are freed.
	 * 	Depending on the given parameter, all (<code>true</code>) or just input
	 * 	and result files (<code>false</code>) are destroyed.
	 * </p>
	 *
	 * @param fullClean	Indicate whether all resources or just some input and
	 *                 	result files must be freed.
	 *                  <code>true</code> to stop the job and delete everything
	 *                  (input files, results, jobInfos and error summary),
	 *                  or <code>false</code> to stop the job and delete only
	 *                  all input files and results but not the jobInfos, the
	 *                  error summary and the other parameters.
	 *
	 * @since 4.3
	 */
	public void clearResources(final boolean fullClean){
		// If still running, abort/stop the job:
		if (isRunning()){
		if (!phase.isFinished()){
			try{
				abort();
			}catch(UWSException e){
@@ -1829,25 +1931,38 @@ public class UWSJob extends SerializableUWSObject {
		while(files.hasNext()){
			upl = files.next();
			try{
				// delete the file:
				upl.deleteFile();
				// delete the internal reference to this input parameter:
				files.remove();
			}catch(IOException ioe){
				getLogger().logJob(LogLevel.ERROR, this, "CLEAR_RESOURCES", "Impossible to delete the file uploaded as parameter \"" + upl.paramName + "\" (" + upl.getLocation() + ") of the job \"" + jobId + "\"!", null);
			}
		}

		// Clear all results file:
		for(Result r : results.values()){
		Iterator<Result> itResults = getResults();
		Result r;
		while(itResults.hasNext()){
			r = itResults.next();
			try{
				// delete the file:
				getFileManager().deleteResult(r, this);
				// delete the internal reference to this result:
				itResults.remove();
			}catch(IOException ioe){
				getLogger().logJob(LogLevel.ERROR, this, "CLEAR_RESOURCES", "Impossible to delete the file associated with the result '" + r.getId() + "' of the job \"" + jobId + "\"!", ioe);
			}
		}

		if (!fullClean){
			// Clear the error file:
			if (errorSummary != null && errorSummary.hasDetail()){
				try{
					// delete the file associated with the error details:
					getFileManager().deleteError(errorSummary, this);
					// delete the error summary:
					errorSummary = null;
				}catch(IOException ioe){
					getLogger().logJob(LogLevel.ERROR, this, "CLEAR_RESOURCES", "Impossible to delete the file associated with the error '" + errorSummary.message + "' of the job \"" + jobId + "\"!", ioe);
				}
@@ -1861,8 +1976,9 @@ public class UWSJob extends SerializableUWSObject {
					getLogger().logJob(LogLevel.ERROR, this, "CLEAR_RESOURCES", "Impossible to destroy the additional information about the job \"" + jobId + "\"", ue);
				}
			}
		}

		getLogger().logJob(LogLevel.INFO, this, "CLEAR_RESOURCES", "Resources associated with the job \"" + getJobId() + "\" have been successfully freed.", null);
		getLogger().logJob(LogLevel.INFO, this, "CLEAR_RESOURCES", (fullClean ? "All resources" : "Threads and input and result files") + " associated with the job \"" + getJobId() + "\" have been successfully freed.", null);
	}

	/* ******************* */
Loading