From eaf27c6cebc30c9b7ac48f4820b9ec7b825a9364 Mon Sep 17 00:00:00 2001 From: gmantele <gmantele@ari.uni-heidelberg.de> Date: Mon, 15 Dec 2014 16:24:58 +0100 Subject: [PATCH] [UWS,TAP] Add clean release of all resources (e.g. Threads, Timers, DB connections) allocated in a UWS and a TAP service. Small changes of the UWS API...but only if ExecutionManager, DestructionManager and UWS have been implemented by library users rather than using the default implementation. --- src/tap/AbstractTAPFactory.java | 1 + src/tap/ServiceConnection.java | 18 +++++++- src/tap/TAPFactory.java | 22 +++++++++- src/tap/resource/ASync.java | 3 +- src/tap/resource/TAP.java | 10 +++++ .../AbstractQueuedExecutionManager.java | 42 ++++++++++++++++++- .../manager/DefaultDestructionManager.java | 26 +++++++++--- .../job/manager/DefaultExecutionManager.java | 26 +++++++++++- src/uws/job/manager/DestructionManager.java | 20 ++++++--- src/uws/job/manager/ExecutionManager.java | 15 ++++++- src/uws/service/UWS.java | 27 ++++++++++++ src/uws/service/UWSService.java | 30 +++++++++++++ src/uws/service/UWSServlet.java | 33 +++++++++++++++ .../backup/DefaultUWSBackupManager.java | 6 +-- src/uws/service/log/DefaultUWSLog.java | 10 +++++ src/uws/service/log/UWSLog.java | 1 + test/tap/formatter/JSONFormatTest.java | 3 ++ test/tap/formatter/SVFormatTest.java | 3 ++ test/tap/formatter/TextFormatTest.java | 3 ++ test/tap/formatter/VOTableFormatTest.java | 3 ++ .../parameters/ServiceConnectionOfTest.java | 15 ++++++- 21 files changed, 295 insertions(+), 22 deletions(-) diff --git a/src/tap/AbstractTAPFactory.java b/src/tap/AbstractTAPFactory.java index 359b3cb..cc364a3 100644 --- a/src/tap/AbstractTAPFactory.java +++ b/src/tap/AbstractTAPFactory.java @@ -215,6 +215,7 @@ public abstract class AbstractTAPFactory extends TAPFactory { public UWSService createUWS() throws TAPException{ try{ UWSService uws = new UWSService(this, this.service.getFileManager(), this.service.getLogger()); + uws.setName("TAP/async"); uws.setErrorWriter(errorWriter); return uws; }catch(UWSException ue){ diff --git a/src/tap/ServiceConnection.java b/src/tap/ServiceConnection.java index 444df9d..37eddb2 100644 --- a/src/tap/ServiceConnection.java +++ b/src/tap/ServiceConnection.java @@ -91,7 +91,8 @@ public interface ServiceConnection { /** * <i><b>[MANDATORY]</b></i> - * <p>This function controls the state of the whole TAP service.</p> + * <p>This function tells whether the TAP service is available + * (that's to say, "able to execute requests" ; resources like /availability, /capabilities and /tables may still work).</p> * * <p> * A message explaining the current state of the TAP service could be provided thanks to {@link #getAvailability()}. @@ -111,6 +112,21 @@ public interface ServiceConnection { */ public String getAvailability(); + /** + * <i><b>[MANDATORY]</b></i> + * <p>This function sets the state of the whole TAP service. + * If true, all TAP resources will be able to execute resources. + * If false, /sync and /async won't answer any more to requests and a HTTP-503 (Service unavailable) + * error will be returned. + * </p> + * + * @param isAvailable <i>true</i> to enable all resources, <i>false</i> to forbid /sync and /async (all other resources will still be available). + * @param message A message describing the current state of the service. If NULL, a default message may be set by the library. + * + * @since 2.0 + */ + public void setAvailable(final boolean isAvailable, final String message); + /** * <i>[OPTIONAL]</i> * <p>Get the limit of the retention period.</p> diff --git a/src/tap/TAPFactory.java b/src/tap/TAPFactory.java index 49d3421..580e232 100644 --- a/src/tap/TAPFactory.java +++ b/src/tap/TAPFactory.java @@ -61,7 +61,7 @@ import adql.query.ADQLQuery; * </ul> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (11/2014) + * @version 2.0 (12/2014) */ public abstract class TAPFactory implements UWSFactory { @@ -90,7 +90,7 @@ public abstract class TAPFactory implements UWSFactory { * * @return The error writer to use. * - * @since 4.1 + * @since 2.0 */ public abstract ServiceErrorWriter getErrorWriter(); @@ -125,6 +125,8 @@ public abstract class TAPFactory implements UWSFactory { * @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. + * + * @since 2.0 */ public abstract DBConnection getConnection(final String jobID) throws TAPException; @@ -142,6 +144,8 @@ public abstract class TAPFactory implements UWSFactory { * </i></p> * * @param conn The connection to close. + * + * @since 2.0 */ public abstract void freeConnection(final DBConnection conn); @@ -163,9 +167,23 @@ public abstract class TAPFactory implements UWSFactory { * * @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>). + * + * @since 2.0 */ public abstract int countFreeConnections(); + /** + * <p>Destroy all resources (and particularly DB connections and JDBC driver) allocated in this factory.</p> + * + * <p><i>Note: + * This function is called when the TAP service is shutting down. + * After this call, the factory may not be able to provide any closed resources ; its behavior may be unpredictable. + * </i></p> + * + * @since 2.0 + */ + public abstract void destroy(); + /* *************** */ /* ADQL MANAGEMENT */ /* *************** */ diff --git a/src/tap/resource/ASync.java b/src/tap/resource/ASync.java index fd0e7cd..ccd94df 100644 --- a/src/tap/resource/ASync.java +++ b/src/tap/resource/ASync.java @@ -175,7 +175,8 @@ public class ASync implements TAPResource { @Override public void destroy(){ - ; + if (uws != null) + uws.destroy(); } @Override diff --git a/src/tap/resource/TAP.java b/src/tap/resource/TAP.java index 918f211..65ec8b0 100644 --- a/src/tap/resource/TAP.java +++ b/src/tap/resource/TAP.java @@ -154,8 +154,18 @@ public class TAP implements VOSIResource { * @see TAPResource#destroy() */ public void destroy(){ + // Set the availability to "false" and the reason to "The application server is stopping!": + service.setAvailable(false, "The application server is stopping!"); + + // Destroy all web resources: for(TAPResource res : resources.values()) res.destroy(); + + // Destroy also all resources allocated in the factory: + service.getFactory().destroy(); + + // Log the end: + getLogger().logTAP(LogLevel.INFO, this, "STOP", "TAP Service stopped!", null); } /** diff --git a/src/uws/job/manager/AbstractQueuedExecutionManager.java b/src/uws/job/manager/AbstractQueuedExecutionManager.java index 49a1d0b..3fa56c2 100644 --- a/src/uws/job/manager/AbstractQueuedExecutionManager.java +++ b/src/uws/job/manager/AbstractQueuedExecutionManager.java @@ -34,17 +34,25 @@ import uws.service.log.UWSLog.LogLevel; /** * <p>Abstract implementation of the interface {@link ExecutionManager} which lets managing an execution queue.</p> + * * <p> * When calling {@link #execute(UWSJob)}, ALL jobs are put into the list of queued jobs (so their phase is changed * to {@link ExecutionPhase#QUEUED}). A call to {@link #refresh()}, reads this list and tries to execute the first job of the list. * The function {@link #isReadyForExecution(UWSJob)} decides whether the first job of the queue can be executed NOW or not. * </p> + * * <p><i>Note: * The order of queued jobs is preserved: it is implemented by a FIFO queue. * </i></p> * + * <p><i>Note: + * After a call to {@link #stopAll()}, this manager is still able to execute new jobs. + * Except if it was not possible to stop them properly, stopped jobs could be executed again by calling + * afterwards {@link #execute(UWSJob)} with these jobs in parameter. + * </i></p> + * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (08/2014) + * @version 4.1 (12/2014) */ public abstract class AbstractQueuedExecutionManager implements ExecutionManager { @@ -237,4 +245,36 @@ public abstract class AbstractQueuedExecutionManager implements ExecutionManager refresh(); } } + + @Override + public final synchronized void stopAll(){ + // Set back all queued jobs to the PENDING phase: + for(UWSJob qj : queuedJobs){ + try{ + qj.setPhase(ExecutionPhase.PENDING, true); + }catch(UWSException ue){ + if (logger != null) + logger.logJob(LogLevel.WARNING, qj, "ABORT", "Can not set back the job to the PENDING phase.", ue); + } + } + + // Empty the queue: + queuedJobs.clear(); + + // Stop all running jobs and set them back to the PENDING phase: + for(UWSJob rj : runningJobs.values()){ + try{ + // Stop the job: + rj.abort(); + // Set its phase back to PENDING: + rj.setPhase(ExecutionPhase.PENDING, true); + }catch(UWSException ue){ + if (logger != null) + logger.logJob(LogLevel.WARNING, rj, "ABORT", "Can not stop the job nicely. The thread may continue to run until its end.", ue); + } + } + + // Empty the list of running jobs: + runningJobs.clear(); + } } diff --git a/src/uws/job/manager/DefaultDestructionManager.java b/src/uws/job/manager/DefaultDestructionManager.java index 24bff3e..8a0314c 100644 --- a/src/uws/job/manager/DefaultDestructionManager.java +++ b/src/uws/job/manager/DefaultDestructionManager.java @@ -16,11 +16,11 @@ package uws.job.manager; * 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 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 java.io.Serializable; - import java.util.Comparator; import java.util.Date; import java.util.Timer; @@ -34,19 +34,27 @@ import uws.job.UWSJob; * The default implementation of the {@link DestructionManager} interface. * Its goal is to manage the automatic destruction any given jobs. * </p> + * * <p> * Jobs can be added thanks to {@link #update(UWSJob)} and removed with {@link #remove(UWSJob)}. * All added jobs are stored in a {@link TreeSet} which sorts them by ascending destruction time. * The job which must be destroyed in first is used to start a timer. * This one will destroyed the job once its destruction time is reached. * </p> + * * <p> * The list of jobs to destroy is supposed to be updated each time the destruction time of a job is changed. This update works only if * the job knows its jobs list ({@link UWSJob#getJobList()} != null) and its jobs list has a destruction manager. * </p> * - * @author Grégory Mantelet (CDS) - * @version 05/2012 + * <p><i>Note: + * The {@link #stop()} function lets stop this manager to watch for destructions of job until {@link #refresh()} or + * {@link #update(UWSJob)} or {@link #remove(UWSJob)} is called. When stopped, the inner timer is canceled and set + * to NULL ; no more thread resources is used. + * </i></p> + * + * @author Grégory Mantelet (CDS;ARI) + * @version 4.1 (12/2014) */ public class DefaultDestructionManager implements DestructionManager { private static final long serialVersionUID = 1L; @@ -83,7 +91,8 @@ public class DefaultDestructionManager implements DestructionManager { /** * Stops the timer if running and set to <i>null</i> {@link #timDestruction}, {@link #currentDate} and {@link #currentJob}. */ - protected synchronized final void stop(){ + @Override + public synchronized final void stop(){ if (timDestruction != null) timDestruction.cancel(); timDestruction = null; @@ -111,18 +120,22 @@ public class DefaultDestructionManager implements DestructionManager { /** * <p>Returns <i>true</i> if {@link #currentDate} is different from <i>null</i>.</p> */ + @Override public final boolean isRunning(){ return currentDate != null; } + @Override public final Date getNextDestruction(){ return currentDate; } + @Override public final String getNextJobToDestroy(){ return (currentJob == null) ? null : currentJob.getJobId(); } + @Override public final int getNbJobsToDestroy(){ return jobsToDestroy.size() + (isRunning() ? 1 : 0); } @@ -147,6 +160,7 @@ public class DefaultDestructionManager implements DestructionManager { * @see #stop() * @see #destroyJob(UWSJob) */ + @Override public synchronized void refresh(){ // Finish the current timer if... if (isRunning()){ @@ -196,6 +210,7 @@ public class DefaultDestructionManager implements DestructionManager { * @see #destroyJob(UWSJob) * @see #refresh() */ + @Override public synchronized void update(UWSJob job){ if (job != null && job.getJobList() != null && job.getDestructionTime() != null){ if (job.getDestructionTime().before(new Date())) @@ -217,6 +232,7 @@ public class DefaultDestructionManager implements DestructionManager { * @see #stop() * @see #refresh() */ + @Override public synchronized void remove(UWSJob job){ if (job == null) return; diff --git a/src/uws/job/manager/DefaultExecutionManager.java b/src/uws/job/manager/DefaultExecutionManager.java index 333cbca..7049aaf 100644 --- a/src/uws/job/manager/DefaultExecutionManager.java +++ b/src/uws/job/manager/DefaultExecutionManager.java @@ -36,9 +36,15 @@ import uws.service.log.UWSLog.LogLevel; * * <p>This manager does not have a queue. That is to say that all jobs are always immediately starting. * Consequently this manager is just used to gather all running jobs.</p> + * + * <p><i>Note: + * After a call to {@link #stopAll()}, this manager is still able to execute new jobs. + * Except if it was not possible to stop them properly, stopped jobs could be executed again by calling + * afterwards {@link #execute(UWSJob)} with these jobs in parameter. + * </i></p> * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (08/2014) + * @version 4.1 (12/2014) */ public class DefaultExecutionManager implements ExecutionManager { @@ -147,4 +153,22 @@ public class DefaultExecutionManager implements ExecutionManager { if (jobToRemove != null) runningJobs.remove(jobToRemove.getJobId()); } + + @Override + public synchronized void stopAll(){ + // Stop all running jobs: + for(UWSJob rj : runningJobs.values()){ + try{ + // Stop the job: + rj.abort(); + // Set its phase back to PENDING: + rj.setPhase(ExecutionPhase.PENDING, true); + }catch(UWSException ue){ + if (logger != null) + logger.logJob(LogLevel.WARNING, rj, "ABORT", "Can not stop the job nicely. The thread may continue to run until its end.", ue); + } + } + // Empty the list of running jobs: + runningJobs.clear(); + } } diff --git a/src/uws/job/manager/DestructionManager.java b/src/uws/job/manager/DestructionManager.java index 5bb8906..022ecbc 100644 --- a/src/uws/job/manager/DestructionManager.java +++ b/src/uws/job/manager/DestructionManager.java @@ -16,16 +16,15 @@ package uws.job.manager; * 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 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 java.io.Serializable; - import java.util.Date; import uws.job.JobList; import uws.job.UWSJob; - import uws.service.UWS; /** @@ -50,8 +49,8 @@ import uws.service.UWS; * </i> * </p> * - * @author Grégory Mantelet (CDS) - * @version 05/2012 + * @author Grégory Mantelet (CDS;ARI) + * @version 4.1 (12/2014) * * @see DefaultDestructionManager */ @@ -114,4 +113,15 @@ public interface DestructionManager extends Serializable { * @param job The job to remove. */ public void remove(UWSJob job); + + /** + * <p>Stop watching the destruction of jobs.</p> + * + * <p><i>Note: + * A subsequent call to {@link #update(UWSJob)} may enable again this manager. + * </i></p> + * + * @since 4.1 + */ + public void stop(); } diff --git a/src/uws/job/manager/ExecutionManager.java b/src/uws/job/manager/ExecutionManager.java index f95bd62..e50d86d 100644 --- a/src/uws/job/manager/ExecutionManager.java +++ b/src/uws/job/manager/ExecutionManager.java @@ -36,7 +36,7 @@ import uws.job.UWSJob; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (08/2014) + * @version 4.1 (12/2014) */ public interface ExecutionManager { @@ -102,4 +102,17 @@ public interface ExecutionManager { * @param jobToRemove The job to remove. */ public void remove(final UWSJob jobToRemove); + + /** + * <p>Stop all running jobs. No more job, even the queued ones, must be executed after a call to this function. + * All stopped or aborted queued jobs should be set forcedly back to the PENDING status.</p> + * + * <p><i>Note: + * A call to {@link #execute(UWSJob)} would re-activate this manager. However jobs stopped or + * aborted using this function might not be starting again. These behaviors at implementation-dependent. + * </i></p> + * + * @since 4.1 + */ + public void stopAll(); } diff --git a/src/uws/service/UWS.java b/src/uws/service/UWS.java index ebd0689..9c545b2 100644 --- a/src/uws/service/UWS.java +++ b/src/uws/service/UWS.java @@ -58,6 +58,11 @@ import uws.service.request.UWSRequestParser; * the UWS and the servlet. * </p> * + * <p><b>IMPORTANT: + * All implementations of this interface should implement properly the function {@link #closeService()} and should call it + * when the JVM or the HTTP server application is closing. + * </b></p> + * * @author Grégory Mantelet (CDS;ARI) * @version 4.1 (12/2014) */ @@ -85,6 +90,28 @@ public interface UWS extends Iterable<JobList> { */ public String getDescription(); + /* ***************** */ + /* RESOURCES RELEASE */ + /* ***************** */ + + /** + * <p> + * End properly this UWS: jobs should be backuped (if this feature is enable), timers and threads should be stopped, + * open files and database connections should be closed, etc... + * In brief, this function should release all used resources. + * </p> + * + * <p><b>IMPORTANT: This function should be called only when the JVM or the Web Application Server is stopping.</b></p> + * + * <p><i>Note: + * A call to this function may prevent this instance of {@link UWS} to execute any subsequent HTTP request, or the behavior + * would be unpredictable. + * </i></p> + * + * @since 4.1 + */ + public void destroy(); + /* ******************* */ /* JOB LIST MANAGEMENT */ /* ******************* */ diff --git a/src/uws/service/UWSService.java b/src/uws/service/UWSService.java index a2b1e74..9867ef6 100644 --- a/src/uws/service/UWSService.java +++ b/src/uws/service/UWSService.java @@ -37,6 +37,7 @@ import uws.UWSException; import uws.UWSToolBox; import uws.job.ExecutionPhase; import uws.job.JobList; +import uws.job.JobThread; import uws.job.UWSJob; import uws.job.manager.DefaultExecutionManager; import uws.job.serializer.JSONSerializer; @@ -414,6 +415,35 @@ public class UWSService implements UWS { logger.logUWS(LogLevel.INFO, this, "INIT", "UWS successfully initialized.", null); } + @Override + public void destroy(){ + // Backup all jobs: + /* Jobs are backuped now so that running jobs are set back to the PENDING phase in the backup. + * Indeed, the "stopAll" operation of the ExecutionManager may fail and would set the phase to ERROR + * for the wrong reason. */ + if (backupManager != null){ + // save all jobs: + backupManager.setEnabled(true); + backupManager.saveAll(); + // stop the automatic backup, if there is one: + backupManager.setEnabled(false); + } + + // Stop all jobs and stop watching for the jobs' destruction: + for(JobList jl : mapJobLists.values()){ + jl.getExecutionManager().stopAll(); + jl.getDestructionManager().stop(); + } + + // Just in case that previous clean "stop"s did not work, try again an interruption for all running threads: + /* note: timers are not part of this ThreadGroup and so, they won't be affected by this function call. */ + JobThread.tg.interrupt(); + + // Log the service is stopped: + if (logger != null) + logger.logUWS(LogLevel.INFO, this, "STOP", "UWS Service \"" + getName() + "\" stopped!", null); + } + /* ************** */ /* LOG MANAGEMENT */ /* ************** */ diff --git a/src/uws/service/UWSServlet.java b/src/uws/service/UWSServlet.java index da9b7f5..e755f4e 100644 --- a/src/uws/service/UWSServlet.java +++ b/src/uws/service/UWSServlet.java @@ -47,6 +47,7 @@ import uws.UWSExceptionFactory; import uws.UWSToolBox; import uws.job.ErrorSummary; import uws.job.JobList; +import uws.job.JobThread; import uws.job.Result; import uws.job.UWSJob; import uws.job.parameters.DestructionTimeController; @@ -240,6 +241,38 @@ public abstract class UWSServlet extends HttpServlet implements UWS, UWSFactory public abstract void initUWS() throws UWSException; + @Override + public void destroy(){ + // Backup all jobs: + /* Jobs are backuped now so that running jobs are set back to the PENDING phase in the backup. + * Indeed, the "stopAll" operation of the ExecutionManager may fail and would set the phase to ERROR + * for the wrong reason. */ + if (backupManager != null){ + // save all jobs: + backupManager.setEnabled(true); + backupManager.saveAll(); + // stop the automatic backup, if there is one: + backupManager.setEnabled(false); + } + + // Stop all jobs and stop watching for the jobs' destruction: + for(JobList jl : mapJobLists.values()){ + jl.getExecutionManager().stopAll(); + jl.getDestructionManager().stop(); + } + + // Just in case that previous clean "stop"s did not work, try again an interruption for all running threads: + /* note: timers are not part of this ThreadGroup and so, they won't be affected by this function call. */ + JobThread.tg.interrupt(); + + // Log the service is stopped: + if (logger != null) + logger.logUWS(LogLevel.INFO, this, "STOP", "UWS Service \"" + getName() + "\" stopped!", null); + + // Default destroy function: + super.destroy(); + } + public UWSFileManager createFileManager() throws UWSException{ UWSFileManager fm = null; String rootPath = getServletConfig().getInitParameter("rootDirectory"); diff --git a/src/uws/service/backup/DefaultUWSBackupManager.java b/src/uws/service/backup/DefaultUWSBackupManager.java index 6b198bd..3081bed 100644 --- a/src/uws/service/backup/DefaultUWSBackupManager.java +++ b/src/uws/service/backup/DefaultUWSBackupManager.java @@ -401,7 +401,7 @@ public class DefaultUWSBackupManager implements UWSBackupManager { // Build the report and log it: int[] report = new int[]{nbSavedJobs,nbJobs,nbSavedOwners,nbOwners}; - getLogger().logUWS(LogLevel.INFO, report, "BACKUPED", "UWS backuped! (" + nbSavedJobs + "/" + nbJobs + " jobs backuped ; " + nbSavedOwners + "/" + nbOwners + " users backuped)", null); + getLogger().logUWS(LogLevel.INFO, report, "BACKUPED", "UWS Service \"" + uws.getName() + "\" backuped!", null); lastBackup = new Date(); @@ -465,7 +465,7 @@ public class DefaultUWSBackupManager implements UWSBackupManager { out.endObject(); // Log the "save" report: - getLogger().logUWS(LogLevel.INFO, saveReport, "BACKUPED", "UWS backuped! (" + saveReport[0] + "/" + saveReport[1] + " users backuped)", null); + getLogger().logUWS(LogLevel.INFO, saveReport, "BACKUPED", "UWS backuped!", null); lastBackup = new Date(); @@ -756,7 +756,7 @@ public class DefaultUWSBackupManager implements UWSBackupManager { // Build the restoration report and log it: int[] report = new int[]{nbRestoredJobs,nbJobs,nbRestoredUsers,nbUsers}; - getLogger().logUWS(LogLevel.INFO, report, "RESTORED", "UWS restored! (" + nbRestoredJobs + "/" + nbJobs + " jobs restored ; " + nbRestoredUsers + "/" + nbUsers + " users restored)", null); + getLogger().logUWS(LogLevel.INFO, report, "RESTORED", "UWS restored!", null); return report; } diff --git a/src/uws/service/log/DefaultUWSLog.java b/src/uws/service/log/DefaultUWSLog.java index a1ef8b7..cfaadb4 100644 --- a/src/uws/service/log/DefaultUWSLog.java +++ b/src/uws/service/log/DefaultUWSLog.java @@ -390,6 +390,16 @@ public class DefaultUWSLog implements UWSLog { @Override public void logUWS(LogLevel level, Object obj, String event, String message, Throwable error){ + // CASE "BACKUPED": Append to the message the backup report: + if (event != null && event.equalsIgnoreCase("BACKUPED") && obj != null && obj.getClass().getName().equals("[I")){ + int[] backupReport = (int[])obj; + message += "\t(" + backupReport[0] + "/" + backupReport[1] + " jobs backuped ; " + backupReport[2] + "/" + backupReport[3] + " users backuped)"; + }else if (event != null && event.equalsIgnoreCase("RESTORED") && obj != null && obj.getClass().getName().equals("[I")){ + int[] restoreReport = (int[])obj; + message += "\t(" + restoreReport[0] + "/" + restoreReport[1] + " jobs restored ; " + restoreReport[2] + "/" + restoreReport[3] + " users restored)"; + } + + // Log the message log(level, "UWS", event, null, message, error); } diff --git a/src/uws/service/log/UWSLog.java b/src/uws/service/log/UWSLog.java index c0771f6..94a901b 100644 --- a/src/uws/service/log/UWSLog.java +++ b/src/uws/service/log/UWSLog.java @@ -191,6 +191,7 @@ public interface UWSLog { * <li>RESTORED (with "obj" as an integer array of 4 items: nb of restored jobs, total nb of jobs, nb of restored users, total nb of users)</li> * <li>BACKUPED (with "obj" as an integer array of 4 items: nb of saved jobs, total nb of jobs, nb of saved users, total nb of users or with just 2 items (the two last ones))</li> * <li>FORMAT_ERROR (with a NULL "obj")</li> + * <li>STOP (with "obj" as an instance of {@link UWS})</li> * </ul> * * @param level Level of the log (info, warning, error, ...). <i>SHOULD NOT be NULL, but if NULL anyway, the level SHOULD be considered as INFO</i> diff --git a/test/tap/formatter/JSONFormatTest.java b/test/tap/formatter/JSONFormatTest.java index fee9143..c7cb393 100644 --- a/test/tap/formatter/JSONFormatTest.java +++ b/test/tap/formatter/JSONFormatTest.java @@ -264,6 +264,9 @@ public class JSONFormatTest { return -1; } + @Override + public void setAvailable(boolean isAvailable, String message){} + } } diff --git a/test/tap/formatter/SVFormatTest.java b/test/tap/formatter/SVFormatTest.java index d32b3dc..d523abf 100644 --- a/test/tap/formatter/SVFormatTest.java +++ b/test/tap/formatter/SVFormatTest.java @@ -258,6 +258,9 @@ public class SVFormatTest { return -1; } + @Override + public void setAvailable(boolean isAvailable, String message){} + } } diff --git a/test/tap/formatter/TextFormatTest.java b/test/tap/formatter/TextFormatTest.java index 97145b2..d6632da 100644 --- a/test/tap/formatter/TextFormatTest.java +++ b/test/tap/formatter/TextFormatTest.java @@ -258,6 +258,9 @@ public class TextFormatTest { return -1; } + @Override + public void setAvailable(boolean isAvailable, String message){} + } } diff --git a/test/tap/formatter/VOTableFormatTest.java b/test/tap/formatter/VOTableFormatTest.java index dca3751..d55200a 100644 --- a/test/tap/formatter/VOTableFormatTest.java +++ b/test/tap/formatter/VOTableFormatTest.java @@ -263,6 +263,9 @@ public class VOTableFormatTest { return -1; } + @Override + public void setAvailable(boolean isAvailable, String message){} + } } diff --git a/test/tap/parameters/ServiceConnectionOfTest.java b/test/tap/parameters/ServiceConnectionOfTest.java index 1d390ce..cb0d793 100644 --- a/test/tap/parameters/ServiceConnectionOfTest.java +++ b/test/tap/parameters/ServiceConnectionOfTest.java @@ -20,6 +20,8 @@ import adql.db.FunctionDef; public class ServiceConnectionOfTest implements ServiceConnection { + private boolean available = true; + private String availability = "TAP Service available!"; private int[] retentionPeriod = new int[]{-1,-1}; private int[] executionDuration = new int[]{(int)TAPJob.UNLIMITED_DURATION,(int)TAPJob.UNLIMITED_DURATION}; private int[] outputLimit = new int[]{TAPJob.UNLIMITED_MAX_REC,TAPJob.UNLIMITED_MAX_REC}; @@ -37,12 +39,21 @@ public class ServiceConnectionOfTest implements ServiceConnection { @Override public boolean isAvailable(){ - return true; + return available; + } + + @Override + public void setAvailable(boolean isAvailable, String message){ + available = isAvailable; + if (message != null) + availability = message; + else + availability = (isAvailable ? "TAP Service available!" : "TAP Service momentarily UNavailable!"); } @Override public String getAvailability(){ - return null; + return availability; } @Override -- GitLab