Skip to content
Snippets Groups Projects
Commit 3f246d19 authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[TAP,UWS] Fix backup restoration. When restoring upload only, the error message:

```
RESTORATION Incorrect JSON format for the serialization of an uploaded file!
Caused by a org.json.JSONException: JSONObject["length"] not a string.
[...]

RESTORATION Incorrect JSON format for the DALIUpload labelled "xxx" of the job "xxxxxxxxx": "xxxxxxxx" is not pointing a job parameter representing a file!
[...]

RESTORATION Unexpected error while restoring the UWS!
Caused by a java.lang.NullPointerException: Missing UploadFile! => Can not build a DaliUpload instance.
[...]
```

Now, in case of grave error while restoring backup files, it will be just
disabled, instead of preventing start-up of the TAP service.
In case of non-grave error while restoring a job or a user, the failed job or
error won't be restored and then the restoration process will go on with the
other jobs/users.
parent f83a6b75
No related branches found
No related tags found
No related merge requests found
......@@ -2,21 +2,21 @@ package tap.backup;
/*
* This file is part of TAPLibrary.
*
*
* TAPLibrary 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.
*
*
* TAPLibrary 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 TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
*
* Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
......@@ -42,84 +42,84 @@ import uws.service.request.UploadFile;
/**
* <p>Let backup all TAP asynchronous jobs.</p>
*
*
* <p><i>note: Basically the saved data are the same, but in addition some execution statistics are also added.</i></p>
*
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.0 (12/2014)
*
* @version 2.4 (01/2020)
*
* @see DefaultUWSBackupManager
*/
public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
/**
* Build a default TAP jobs backup manager.
*
*
* @param uws The UWS containing all the jobs to backup.
*
*
* @see DefaultUWSBackupManager#DefaultUWSBackupManager(UWS)
*/
public DefaultTAPBackupManager(UWS uws){
public DefaultTAPBackupManager(UWS uws) {
super(uws);
}
/**
* Build a default TAP jobs backup manager.
*
*
* @param uws The UWS containing all the jobs to backup.
* @param frequency The backup frequency (in ms ; MUST BE positive and different from 0.
* If negative or 0, the frequency will be automatically set to DEFAULT_FREQUENCY).
*
*
* @see DefaultUWSBackupManager#DefaultUWSBackupManager(UWS, long)
*/
public DefaultTAPBackupManager(UWS uws, long frequency){
public DefaultTAPBackupManager(UWS uws, long frequency) {
super(uws, frequency);
}
/**
* Build a default TAP jobs backup manager.
*
*
* @param uws The UWS containing all the jobs to backup.
* @param byUser Backup mode.
*
*
* @see DefaultUWSBackupManager#DefaultUWSBackupManager(UWS, boolean)
*/
public DefaultTAPBackupManager(UWS uws, boolean byUser) throws UWSException{
public DefaultTAPBackupManager(UWS uws, boolean byUser) throws UWSException {
super(uws, byUser);
}
/**
* Build a default TAP jobs backup manager.
*
*
* @param uws The UWS containing all the jobs to backup.
* @param byUser Backup mode.
* @param frequency The backup frequency (in ms ; MUST BE positive and different from 0.
* If negative or 0, the frequency will be automatically set to DEFAULT_FREQUENCY).
*
*
* @see DefaultUWSBackupManager#DefaultUWSBackupManager(UWS, boolean, long)
*/
public DefaultTAPBackupManager(UWS uws, boolean byUser, long frequency) throws UWSException{
public DefaultTAPBackupManager(UWS uws, boolean byUser, long frequency) throws UWSException {
super(uws, byUser, frequency);
}
@Override
protected JSONObject getJSONJob(UWSJob job, String jlName) throws UWSException, JSONException{
protected JSONObject getJSONJob(UWSJob job, String jlName) throws UWSException, JSONException {
JSONObject jsonJob = Json4Uws.getJson(job);
// Re-Build the parameters map, by separating the uploads and the "normal" parameters:
JSONArray uploads = new JSONArray();
JSONObject params = new JSONObject();
Object val;
for(String name : job.getAdditionalParameters()){
for(String name : job.getAdditionalParameters()) {
// get the raw value:
val = job.getAdditionalParameterValue(name);
// if no value, skip this item:
if (val == null)
continue;
// if an array, build a JSON array of strings:
else if (val.getClass().isArray()){
else if (val.getClass().isArray()) {
JSONArray array = new JSONArray();
for(Object o : (Object[])val){
for(Object o : (Object[])val) {
if (o != null && o instanceof DALIUpload)
array.put(getDALIUploadJson((DALIUpload)o));
else if (o != null)
......@@ -139,7 +139,7 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
}
// Deal with the execution report of the job:
if (job instanceof TAPJob && ((TAPJob)job).getExecReport() != null){
if (job instanceof TAPJob && ((TAPJob)job).getExecReport() != null) {
TAPExecutionReport execReport = ((TAPJob)job).getExecReport();
// Build the JSON representation of the execution report of this job:
......@@ -170,16 +170,16 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
/**
* Get the JSON representation of the given {@link DALIUpload}.
*
*
* @param upl The DALI upload specification to serialize in JSON.
*
*
* @return Its JSON representation.
*
*
* @throws JSONException If there is an error while building the JSON object.
*
*
* @since 2.0
*/
protected JSONObject getDALIUploadJson(final DALIUpload upl) throws JSONException{
protected JSONObject getDALIUploadJson(final DALIUpload upl) throws JSONException {
if (upl == null)
return null;
JSONObject o = new JSONObject();
......@@ -190,48 +190,49 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
}
@Override
protected void restoreOtherJobParams(JSONObject json, UWSJob job) throws UWSException{
protected void restoreOtherJobParams(JSONObject json, UWSJob job) throws UWSException {
// 0. Nothing to do in this function if the job is missing OR if it is not an instance of TAPJob:
if (job == null || !(job instanceof TAPJob))
return;
// 1. Build correctly the TAP UPLOAD parameter (the value of this parameter should be an array of DALIUpload):
if (json != null && json.has(TAPJob.PARAM_PARAMETERS)){
try{
if (json != null && json.has(TAPJob.PARAM_PARAMETERS)) {
try {
// Retrieve the whole list of parameters:
JSONObject params = json.getJSONObject(TAPJob.PARAM_PARAMETERS);
// If there is an UPLOAD parameter, convert the JSON array into a DALIUpload[] and add it to the job:
if (params.has(TAPJob.PARAM_UPLOAD)){
if (params.has(TAPJob.PARAM_UPLOAD)) {
// retrieve the JSON array:
JSONArray uploads = params.getJSONArray(TAPJob.PARAM_UPLOAD);
// for each item of this array, build the corresponding DALIUpload and add it into an ArrayList:
DALIUpload upl;
ArrayList<DALIUpload> lstTAPUploads = new ArrayList<DALIUpload>();
for(int i = 0; i < uploads.length(); i++){
try{
for(int i = 0; i < uploads.length(); i++) {
try {
upl = getDALIUpload(uploads.getJSONObject(i), job);
if (upl != null)
lstTAPUploads.add(upl);
}catch(JSONException je){
} catch(JSONException je) {
getLogger().logUWS(LogLevel.ERROR, uploads.get(i), "RESTORATION", "Incorrect JSON format for a DALIUpload of the job \"" + job.getJobId() + "\": a JSONObject was expected!", null);
}
}
// finally convert the ArrayList into a DALIUpload[] and add it inside the parameters list of the job:
job.addOrUpdateParameter(TAPJob.PARAM_UPLOAD, lstTAPUploads.toArray(new DALIUpload[lstTAPUploads.size()]));
}
}catch(JSONException ex){}
} catch(JSONException ex) {
}
}
// 2. Get the execution report and add it into the given job:
TAPJob tapJob = (TAPJob)job;
Object obj = job.getAdditionalParameterValue("tapexecreport");
if (obj != null){
if (obj instanceof JSONObject){
if (obj != null) {
if (obj instanceof JSONObject) {
JSONObject jsonExecReport = (JSONObject)obj;
TAPExecutionReport execReport = new TAPExecutionReport(job.getJobId(), false, tapJob.getTapParams());
String[] keys = JSONObject.getNames(jsonExecReport);
for(String key : keys){
try{
for(String key : keys) {
try {
if (key.equalsIgnoreCase("success"))
execReport.success = jsonExecReport.getBoolean(key);
else if (key.equalsIgnoreCase("uploadduration"))
......@@ -246,28 +247,28 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
execReport.setTotalDuration(jsonExecReport.getLong(key));
else
getLogger().logUWS(LogLevel.WARNING, obj, "RESTORATION", "The execution report attribute '" + key + "' of the job \"" + job.getJobId() + "\" has been ignored because unknown!", null);
}catch(JSONException je){
} catch(JSONException je) {
getLogger().logUWS(LogLevel.ERROR, obj, "RESTORATION", "Incorrect JSON format for the execution report serialization of the job \"" + job.getJobId() + "\" (attribute: \"" + key + "\")!", je);
}
}
tapJob.setExecReport(execReport);
}else if (!(obj instanceof JSONObject))
} else if (!(obj instanceof JSONObject))
getLogger().logUWS(LogLevel.WARNING, obj, "RESTORATION", "Impossible to restore the execution report of the job \"" + job.getJobId() + "\" because the stored object is not a JSONObject!", null);
}
}
/**
* Restore a {@link DALIUpload} from its JSON representation.
*
*
* @param item {@link JSONObject} representing the {@link DALIUpload} to restore.
* @param job The job which owns this upload.
*
*
* @return The corresponding {@link DALIUpload} or NULL, if an error occurs while converting the JSON.
*
*
* @since 2.0
*/
private DALIUpload getDALIUpload(final JSONObject item, final UWSJob job){
try{
private DALIUpload getDALIUpload(final JSONObject item, final UWSJob job) {
try {
// Get its label:
String label = item.getString("label");
......@@ -275,18 +276,19 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
// Build the DALIUpload object:
/* If the upload spec. IS A FILE, the attribute 'file' should point toward a job parameter
* being an UploadFile. If so, get it and use it to build the DALIUpload: */
if (item.has("file")){
if (item.has("file")) {
Object f = job.getAdditionalParameterValue(item.getString("file"));
if (f == null || !(f instanceof UploadFile))
getLogger().logUWS(LogLevel.ERROR, item, "RESTORATION", "Incorrect JSON format for the DALIUpload labelled \"" + label + "\" of the job \"" + job.getJobId() + "\": \"" + item.getString("file") + "\" is not pointing a job parameter representing a file!", null);
return new DALIUpload(label, (UploadFile)f);
else
return new DALIUpload(label, (UploadFile)f);
}
/* If the upload spec. IS A URI, the attribute 'uri' should contain it
* and should be used to build the DALIUpload: */
else if (item.has("uri")){
try{
else if (item.has("uri")) {
try {
return new DALIUpload(label, new URI(item.getString("uri")), uws.getFileManager());
}catch(URISyntaxException e){
} catch(URISyntaxException e) {
getLogger().logUWS(LogLevel.ERROR, item, "RESTORATION", "Incorrect URI for the DALIUpload labelled \"" + label + "\" of the job \"" + job.getJobId() + "\": \"" + item.getString("uri") + "\"!", null);
}
}
......@@ -294,7 +296,7 @@ public class DefaultTAPBackupManager extends DefaultUWSBackupManager {
else
getLogger().logUWS(LogLevel.ERROR, item, "RESTORATION", "Incorrect JSON format for the DALIUpload labelled \"" + label + "\" of the job \"" + job.getJobId() + "\": missing attribute 'file' or 'uri'!", null);
}catch(JSONException je){
} catch(JSONException je) {
getLogger().logUWS(LogLevel.ERROR, item, "RESTORATION", "Incorrect JSON format for a DALIUpload of the job \"" + job.getJobId() + "\": missing attribute 'label'!", null);
}
......
......@@ -2,21 +2,21 @@ package tap.resource;
/*
* This file is part of TAPLibrary.
*
*
* TAPLibrary 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.
*
*
* TAPLibrary 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 TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
*
* Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
......@@ -42,20 +42,20 @@ import uws.service.log.UWSLog.LogLevel;
/**
* <p>Asynchronous resource of a TAP service.</p>
*
*
* <p>
* Requests sent to this resource are ADQL queries (plus some execution parameters) to execute asynchronously.
* Results and/or errors of the execution are stored on the server side and can be fetched by the user whenever he wants.
* </p>
*
*
* <p>
* This resource is actually another VO service: a UWS (Universal Worker Service pattern).
* That's why all requests sent to this resource are actually forwarded to an instance of {@link UWSService}.
* All the behavior of UWS described by the IVOA is already fully implemented by this implementation.
* </p>
*
*
* <p>This resource is also representing the only jobs' list of this UWS service.</p>
*
*
* <p>The UWS service is created and configured at the creation of this resource. Here are the list of the most important configured elements:</p>
* <ul>
* <li><b>User identification:</b> the user identifier is the same as the one used by the TAP service. It is provided by the given {@link ServiceConnection}.</li>
......@@ -69,10 +69,10 @@ import uws.service.log.UWSLog.LogLevel;
* (except those at the origin of the grave error maybe).</li>
* <li><b>Error logging:</b> the created {@link UWSService} instance is using the same logger as the TAP service. It is also provided by the given {@link ServiceConnection} object at creation.</li>
* </ul>
*
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.0 (04/2015)
*
* @version 2.4 (01/2020)
*
* @see UWSService
*/
public class ASync implements TAPResource {
......@@ -89,14 +89,14 @@ public class ASync implements TAPResource {
/**
* Build an Asynchronous Resource of a TAP service.
*
*
* @param service Description of the TAP service which will own this resource.
*
*
* @throws TAPException If any error occurs while creating a UWS service or its backup manager.
* @throws UWSException If any error occurs while setting a new execution manager to the recent inner UWS service,
* or while restoring a UWS backup.
*/
public ASync(final ServiceConnection service) throws UWSException, TAPException{
public ASync(final ServiceConnection service) throws UWSException, TAPException {
this.service = service;
uws = service.getFactory().createUWS();
......@@ -104,18 +104,18 @@ public class ASync implements TAPResource {
if (uws.getUserIdentifier() == null)
uws.setUserIdentifier(service.getUserIdentifier());
if (uws.getJobList(getName()) == null){
if (uws.getJobList(getName()) == null) {
jobList = new JobList(getName());
uws.addJobList(jobList);
jobList.setExecutionManager(new AsyncExecutionManager(service.getLogger(), service.getNbMaxAsyncJobs()));
}else
} else
jobList = uws.getJobList(getName());
if (uws.getBackupManager() == null)
uws.setBackupManager(service.getFactory().createUWSBackupManager(uws));
UWSBackupManager backupManager = uws.getBackupManager();
if (backupManager != null){
if (backupManager != null) {
backupManager.setEnabled(false);
int[] report = uws.getBackupManager().restoreAll();
String errorMsg = null;
......@@ -128,10 +128,9 @@ public class ASync implements TAPResource {
else
backupManager.setEnabled(true);
if (errorMsg != null){
if (errorMsg != null) {
errorMsg += " => Backup disabled.";
service.getLogger().logTAP(LogLevel.FATAL, null, "ASYNC_INIT", errorMsg, null);
throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, errorMsg);
}
}
}
......@@ -139,49 +138,49 @@ public class ASync implements TAPResource {
/**
* <p>Notify this TAP resource that free DB connection(s) is(are) now available.
* It means that the execution manager should be refreshed in order to execute one or more queued jobs.</p>
*
*
* <p><i>Note:
* This function has no effect if there is no execution manager.
* </i></p>
*/
public void freeConnectionAvailable(){
public void freeConnectionAvailable() {
if (jobList.getExecutionManager() != null)
jobList.getExecutionManager().refresh();
}
@Override
public String getName(){
public String getName() {
return RESOURCE_NAME;
}
@Override
public void setTAPBaseURL(final String baseURL){
public void setTAPBaseURL(final String baseURL) {
;
}
/**
* Get the UWS behind this TAP resource.
*
*
* @return The inner UWS used by this TAP resource.
*/
public final UWSService getUWS(){
public final UWSService getUWS() {
return uws;
}
@Override
public void init(final ServletConfig config) throws ServletException{
public void init(final ServletConfig config) throws ServletException {
;
}
@Override
public void destroy(){
public void destroy() {
if (uws != null)
uws.destroy();
}
@Override
public boolean executeResource(final HttpServletRequest request, final HttpServletResponse response) throws IOException, TAPException{
try{
public boolean executeResource(final HttpServletRequest request, final HttpServletResponse response) throws IOException, TAPException {
try {
// Ensure the service is currently available:
if (!service.isAvailable())
......@@ -190,7 +189,7 @@ public class ASync implements TAPResource {
// Forward the request to the UWS service:
return uws.executeRequest(request, response);
}catch(UWSException ue){
} catch(UWSException ue) {
service.getLogger().logTAP(LogLevel.FATAL, null, null, "Error while executing the /async resource.", ue);
throw new TAPException(ue);
}
......@@ -199,7 +198,7 @@ public class ASync implements TAPResource {
/**
* An execution manager which queues jobs when too many asynchronous jobs are running or
* when no more DB connection is available for the moment.
*
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.0 (02/2015)
* @since 2.0
......@@ -211,17 +210,17 @@ public class ASync implements TAPResource {
/**
* Build a queuing execution manager.
*
*
* @param logger Logger to use.
* @param maxRunningJobs Maximum number of asynchronous jobs that can run in the same time.
*/
public AsyncExecutionManager(UWSLog logger, int maxRunningJobs){
public AsyncExecutionManager(UWSLog logger, int maxRunningJobs) {
super(logger);
nbMaxRunningJobs = (maxRunningJobs <= 0) ? QueuedExecutionManager.NO_QUEUE : maxRunningJobs;
}
@Override
public boolean isReadyForExecution(final UWSJob jobToExecute){
public boolean isReadyForExecution(final UWSJob jobToExecute) {
if (!hasQueue())
return ((TAPJob)jobToExecute).isReadyForExecution();
else
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment