Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conf/docker-aio/run-test-suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ fi

# Please note the "dataverse.test.baseurl" is set to run for "all-in-one" Docker environment.
# TODO: Rather than hard-coding the list of "IT" classes here, add a profile to pom.xml.
mvn test -Dtest=DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT -Ddataverse.test.baseurl=$dvurl
mvn test -Dtest=DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT -Ddataverse.test.baseurl=$dvurl
10 changes: 6 additions & 4 deletions src/main/java/edu/harvard/iq/dataverse/api/Access.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public DownloadInstance datafile(@PathParam("fileId") String fileId, @QueryParam
if (df.isTabularData()) {
String originalMimeType = df.getDataTable().getOriginalFileFormat();
dInfo.addServiceAvailable(new OptionalAccessService("original", originalMimeType, "format=original","Saved original (" + originalMimeType + ")"));

dInfo.addServiceAvailable(new OptionalAccessService("tabular", "text/tab-separated-values", "format=tab", "Tabular file in native format"));
dInfo.addServiceAvailable(new OptionalAccessService("R", "application/x-rlang-transport", "format=RData", "Data in R format"));
dInfo.addServiceAvailable(new OptionalAccessService("preprocessed", "application/json", "format=prep", "Preprocessed data in JSON"));
dInfo.addServiceAvailable(new OptionalAccessService("subset", "text/tab-separated-values", "variables=<LIST>", "Column-wise Subsetting"));
Expand All @@ -321,7 +321,7 @@ public DownloadInstance datafile(@PathParam("fileId") String fileId, @QueryParam
logger.fine("is download service supported? key=" + key + ", value=" + value);
// The loop goes through all query params (e.g. including key, gbrecs, persistentId, etc. )
// So we need to identify when a service is being called and then let checkIfServiceSupportedAndSetConverter see if the required one exists
if (key.equals("imageThumb") || key.equals("format") || key.equals("variables")) {
if (key.equals("imageThumb") || key.equals("format") || key.equals("variables") || key.equals("noVarHeader")) {
serviceRequested = true;
//Only need to check if this key is associated with a service
if (downloadInstance.checkIfServiceSupportedAndSetConverter(key, value)) {
Expand Down Expand Up @@ -371,6 +371,8 @@ public DownloadInstance datafile(@PathParam("fileId") String fileId, @QueryParam
serviceFound = true;
break;
}
} else {

}
}
if (serviceRequested && !serviceFound) {
Expand All @@ -379,9 +381,9 @@ public DownloadInstance datafile(@PathParam("fileId") String fileId, @QueryParam
// a ServiceNotAvailableException. However, since the returns are all files of
// some sort, it seems reasonable, and more standard, to just return
// a NotFoundException.
throw new NotFoundException();
throw new NotFoundException("datafile access error: requested optional service (image scaling, format conversion, etc.) is not supported on this datafile.");
} // Else - the file itself was requested or we have the info needed to invoke the service and get the derived info
logger.warning("Returning download instance");
logger.fine("Returning download instance");
/*
* Provide some browser-friendly headers: (?)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.RedirectionException;
import javax.ws.rs.ServiceUnavailableException;

/**
*
Expand Down Expand Up @@ -222,7 +222,10 @@ public void writeTo(DownloadInstance di, Class<?> clazz, Type type, Annotation[]


if (storageIO == null) {
throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
//throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
// 404/not found may be a better return code option here
// (similarly to what the Access API returns when a thumbnail is requested on a text file, etc.)
throw new NotFoundException("datafile access error: requested optional service (image scaling, format conversion, etc.) could not be performed on this datafile.");
}
} else {
if (storageIO instanceof S3AccessIO && !(dataFile.isTabularData()) && isRedirectToS3()) {
Expand All @@ -241,7 +244,7 @@ public void writeTo(DownloadInstance di, Class<?> clazz, Type type, Annotation[]
}

if (redirect_url_str == null) {
throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
throw new WebApplicationException(new ServiceUnavailableException());
}

logger.fine("Data Access API: direct S3 url: "+redirect_url_str);
Expand Down Expand Up @@ -271,7 +274,7 @@ public void writeTo(DownloadInstance di, Class<?> clazz, Type type, Annotation[]
logger.fine("Issuing redirect to the file location on S3.");
throw new RedirectionException(response);
}
throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
throw new WebApplicationException(new ServiceUnavailableException());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package edu.harvard.iq.dataverse.api.errorhandlers;

import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ServiceUnavailableException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
* Produces custom 503 messages for the API.
* @author michael
*/
@Provider
public class ServiceUnavailableExceptionHandler implements ExceptionMapper<ServiceUnavailableException>{

@Context
HttpServletRequest request;

@Override
public Response toResponse(ServiceUnavailableException ex){
String uri = request.getRequestURI();
String exMessage = ex.getMessage();
String outputMessage;
if (exMessage != null && exMessage.toLowerCase().startsWith("datafile")) {
outputMessage = exMessage;
} else {
outputMessage = "Requested service or method not available on the requested object";
}
return Response.status(503)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 503)
.add("message", "'" + uri + "' " + outputMessage)
.build())
.type("application/json").build();


}

}

17 changes: 14 additions & 3 deletions src/test/java/edu/harvard/iq/dataverse/api/AccessIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
import static org.junit.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;

/**
*
Expand Down Expand Up @@ -172,17 +178,22 @@ public void testDownloadSingleFile() {
Response anonDownloadConverted = UtilIT.downloadFile(tabFile1Id);
// ... and download the same tabular data file, but without the variable name header added:
Response anonDownloadTabularNoHeader = UtilIT.downloadTabularFileNoVarHeader(tabFile1Id);
// ... and download the same tabular file, this time requesting the "format=tab" explicitly:
Response anonDownloadTabularWithFormatName = UtilIT.downloadTabularFile(tabFile1Id);
assertEquals(OK.getStatusCode(), anonDownloadOriginal.getStatusCode());
assertEquals(OK.getStatusCode(), anonDownloadConverted.getStatusCode());
assertEquals(OK.getStatusCode(), anonDownloadTabularNoHeader.getStatusCode());
assertEquals(OK.getStatusCode(), anonDownloadTabularWithFormatName.getStatusCode());
int origSizeAnon = anonDownloadOriginal.getBody().asByteArray().length;
int convertSizeAnon = anonDownloadConverted.getBody().asByteArray().length;
int tabularSizeNoVarHeader = anonDownloadTabularNoHeader.getBody().asByteArray().length;
int tabularSizeWithFormatName = anonDownloadTabularWithFormatName.getBody().asByteArray().length;
System.out.println("origSize: "+origSizeAnon + " | convertSize: " + convertSizeAnon + " | convertNoHeaderSize: " + tabularSizeNoVarHeader);

assertEquals(origSizeAnon, tabFile1SizeOriginal);
assertEquals(convertSizeAnon, tabFile1SizeConvertedWithVarHeader);
assertEquals(tabularSizeNoVarHeader, tabFile1SizeConverted);
assertEquals(tabFile1SizeOriginal, origSizeAnon);
assertEquals(tabFile1SizeConvertedWithVarHeader, convertSizeAnon);
assertEquals(tabFile1SizeConverted, tabularSizeNoVarHeader);
assertEquals(tabFile1SizeConvertedWithVarHeader, tabularSizeWithFormatName);

//Not logged in restricted
Response anonDownloadOriginalRestricted = UtilIT.downloadFileOriginal(tabFile3IdRestricted);
Expand Down
6 changes: 6 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,12 @@ static Response downloadFile(Integer fileId, String apiToken) {
//.header(API_TOKEN_HTTP_HEADER, apiToken)
.get("/api/access/datafile/" + fileId + "?key=" + apiToken);
}

static Response downloadTabularFile(Integer fileId) {
return given()
// this downloads a tabular file, explicitly requesting the format by name
.get("/api/access/datafile/" + fileId + "?format=tab");
}

static Response downloadFileOriginal(Integer fileId) {
return given()
Expand Down