Skip to content

Commit

Permalink
Merge pull request #52 from janvanmansum/DD-1575
Browse files Browse the repository at this point in the history
DD-1575 validate dataset files
  • Loading branch information
janvanmansum authored Aug 23, 2024
2 parents ae1911d + a1590ad commit 9f05fef
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.lib.dataverse.example;

import lombok.extern.slf4j.Slf4j;
import nl.knaw.dans.lib.dataverse.DataverseResponseWithoutEnvelope;
import nl.knaw.dans.lib.dataverse.ExampleBase;
import nl.knaw.dans.lib.dataverse.model.DatasetFileValidationResultList;

@Slf4j
public class AdminValidateDatasetFiles extends ExampleBase {

public static void main(String[] args) throws Exception {
var id = args[0];
DataverseResponseWithoutEnvelope<DatasetFileValidationResultList> r;
// If id is parseable as a number, it is assumed to be a dataset id.
try {
r = client.admin().validateDatasetFiles(Integer.parseInt(id));
} catch (NumberFormatException e) {
r = client.admin().validateDatasetFiles(id);
}
log.info(r.getBodyAsJson().toPrettyString());
for (var result : r.getBodyAsObject().getDataFiles()) {
log.info("File: {}", result.getDatafileId());
log.info(" Storage Identifier: {}", result.getStorageIdentifier());
log.info(" Status: {}", result.getStatus());
}
}
}
22 changes: 22 additions & 0 deletions lib/src/main/java/nl/knaw/dans/lib/dataverse/AdminApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import nl.knaw.dans.lib.dataverse.model.DataMessage;
import nl.knaw.dans.lib.dataverse.model.DatasetFileValidationResultList;
import nl.knaw.dans.lib.dataverse.model.user.AuthenticatedUser;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -79,4 +81,24 @@ public DataverseHttpResponse<DataMessage> getDatabaseSetting(String key) throws
return httpClientWrapper.get(path, DataMessage.class);
}

public DataverseHttpResponseWithoutEnvelope<DatasetFileValidationResultList> validateDatasetFiles(int dbId) throws IOException, DataverseException {
return validateDatasetFiles(Integer.toString(dbId), false);
}

public DataverseHttpResponseWithoutEnvelope<DatasetFileValidationResultList> validateDatasetFiles(String pid) throws IOException, DataverseException {
return validateDatasetFiles(pid, true);
}

public DataverseHttpResponseWithoutEnvelope<DatasetFileValidationResultList> validateDatasetFiles(String id, boolean isPersistentId) throws IOException, DataverseException {
Path path = buildPath(targetBase, "validate/dataset/files");
var queryParameters = new HashMap<String, List<String>>();
if (isPersistentId) {
path = path.resolve(":persistentId");
queryParameters.put("persistentId", List.of(id));
} else {
path = path.resolve(id);
}
return httpClientWrapper.getWithoutEnvelope(path, queryParameters, new HashMap<>(), DatasetFileValidationResultList.class);
}

}
5 changes: 0 additions & 5 deletions lib/src/main/java/nl/knaw/dans/lib/dataverse/DatasetApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@
*/
@Slf4j
public class DatasetApi extends AbstractTargetedApi {

DatasetApi(HttpClientWrapper httpClientWrapper, String id, boolean isPersistentId) {
this(httpClientWrapper, id, isPersistentId, null);
}

@Override
public String toString() {
return format("DatasetApi(id=''{0}, isPersistentId={1})", id, isPersistentId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.lib.dataverse;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.apache.hc.core5.http.HttpResponse;

import java.io.IOException;

public class DataverseHttpResponseWithoutEnvelope<D> extends DataverseResponseWithoutEnvelope<D> {
private final HttpResponse httpResponse;

DataverseHttpResponseWithoutEnvelope(DispatchResult dispatchResult, ObjectMapper customMapper, Class<?>... dataClass) throws IOException {
super(dispatchResult.getBody(), customMapper, dataClass);
this.httpResponse = dispatchResult.getResponse();
}

public HttpResponse getHttpResponse() {
return httpResponse;
}
}
45 changes: 11 additions & 34 deletions lib/src/main/java/nl/knaw/dans/lib/dataverse/DataverseResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,61 +15,38 @@
*/
package nl.knaw.dans.lib.dataverse;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;
import nl.knaw.dans.lib.dataverse.model.DataverseEnvelope;

import java.io.IOException;

/**
* Response from Dataverse.
* Response from Dataverse, wrapped in a {@link nl.knaw.dans.lib.dataverse.model.DataverseEnvelope}.
*
* @param <D> the type of the data of the response message envelope, one of the classes in {@link nl.knaw.dans.lib.dataverse.model}
*/

@Slf4j
public class DataverseResponse<D> {
private final ObjectMapper mapper;

private final String bodyText;
private final JavaType dataType;

public class DataverseResponse<D> extends DataverseResponseWithoutEnvelope<DataverseEnvelope<D>> {
protected DataverseResponse(String bodyText, ObjectMapper mapper, Class<?>... dataClass) {
this.bodyText = bodyText;
this.mapper = mapper;
TypeFactory typeFactory = mapper.getTypeFactory();

switch (dataClass.length) {
case 0:
throw new IllegalArgumentException("No parameter type given");
case 1:
this.dataType = typeFactory.constructParametricType(DataverseEnvelope.class, dataClass[0]);
break;
case 2:
JavaType inner = typeFactory.constructParametricType(dataClass[0], dataClass[1]);
this.dataType = typeFactory.constructParametricType(DataverseEnvelope.class, inner);
break;
default:
throw new IllegalArgumentException("Currently no more than one nested parameter type supported");
}
super(bodyText, mapper, wrapInEnvelope(dataClass));
}

// Must be static, otherwise compiler complains about passing result into 'this()' call
private static JavaType constuctJavaTypeForContainerClass(Class<?> containerClass, Class<?> elementClass, ObjectMapper mapper) {
TypeFactory typeFactory = mapper.getTypeFactory();
JavaType inner = typeFactory.constructParametricType(containerClass, elementClass);
return typeFactory.constructParametricType(DataverseEnvelope.class, inner);
private static Class<?>[] wrapInEnvelope(Class<?>... otherClasses) {
Class<?>[] combined = new Class<?>[otherClasses.length + 1];
combined[0] = DataverseEnvelope.class;
System.arraycopy(otherClasses, 0, combined, 1, otherClasses.length);
return combined;
}

/**
* @return A dataverse envelope
* @throws com.fasterxml.jackson.core.JsonParseException if body cannot be processed properly as JSON
*/
public DataverseEnvelope<D> getEnvelope() throws IOException {
return mapper.readValue(bodyText, dataType);
return super.getBodyAsObject();
}

/**
Expand All @@ -85,13 +62,13 @@ public D getData() throws IOException {
* @throws com.fasterxml.jackson.core.JsonParseException if body cannot be processed properly as JSON
*/
public JsonNode getEnvelopeAsJson() throws IOException {
return mapper.readTree(bodyText);
return super.getBodyAsJson();
}

/**
* @return the body as a String
*/
public String getEnvelopeAsString() {
return bodyText;
return super.getBodyAsString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2021 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.lib.dataverse;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/**
* Response from Dataverse that is <em>not</em> wrapped in an envelope. Normally, Dataverse responses are wrapped in an
* envelope that contains metadata about the response, such as the status code and the message. In some cases, however,
* the response is not wrapped in an envelope. This class is used to handle such responses.
*
* @param <B> the type of the data of the response body
*/

@Slf4j
public class DataverseResponseWithoutEnvelope<B> {
private final ObjectMapper mapper;

private final String bodyText;
private final JavaType dataType;

protected DataverseResponseWithoutEnvelope(String bodyText, ObjectMapper mapper, Class<?>... dataClass) {
this.bodyText = bodyText;
this.mapper = mapper;
TypeFactory typeFactory = mapper.getTypeFactory();
switch (dataClass.length) {
case 0:
throw new IllegalArgumentException("No parameter type given");
case 1:
this.dataType = typeFactory.constructType(dataClass[0]);
break;
case 2:
this.dataType = typeFactory.constructParametricType(dataClass[0], dataClass[1]);
break;
case 3:
JavaType nested = typeFactory.constructParametricType(dataClass[1], dataClass[2]);
this.dataType = typeFactory.constructParametricType(dataClass[0], nested);
break;
default:
throw new IllegalArgumentException("Currently no more than two nested parameter types supported");
}
}


/**
* @return the body as bean of type D
* @throws com.fasterxml.jackson.core.JsonParseException if body cannot be processed properly as JSON
*/
public B getBodyAsObject() throws IOException {
return mapper.readValue(bodyText, dataType);
}

/**
* @return the body as a JsonNode
* @throws com.fasterxml.jackson.core.JsonParseException if body cannot be processed properly as JSON
*/
public JsonNode getBodyAsJson() throws IOException {
return mapper.readTree(bodyText);
}

/**
* @return the body as a String
*/
public String getBodyAsString() {
return bodyText;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ public <D> DataverseHttpResponse<D> get(Path subPath, Map<String, List<String>>
return wrap(dispatch(get), outputClass);
}

public <D> DataverseHttpResponseWithoutEnvelope<D> getWithoutEnvelope(Path subPath, Map<String, List<String>> parameters, Map<String, String> headers, Class<?>... outputClass)
throws IOException, DataverseException {
var get = new HttpGet(buildURi(subPath, parameters));
headers.forEach(get::setHeader);
return wrapWithoutEnvelope(dispatch(get), outputClass);
}

public <T> T get(Path subPath, Map<String, List<String>> parameters, Map<String, String> headers, HttpClientResponseHandler<T> handler) throws IOException, DataverseException {
var get = new HttpGet(buildURi(subPath, parameters));
headers.forEach(get::setHeader);
Expand Down Expand Up @@ -219,6 +226,10 @@ private <D> DataverseHttpResponse<D> wrap(DispatchResult result, Class<?>... dat
return new DataverseHttpResponse<>(result, mapper, dataClass);
}

private <D> DataverseHttpResponseWithoutEnvelope<D> wrapWithoutEnvelope(DispatchResult result, Class<?>... dataClass) throws IOException {
return new DataverseHttpResponseWithoutEnvelope<>(result, mapper, dataClass);
}

private DispatchResult dispatch(HttpRequest request) throws IOException, DataverseException {
Optional.ofNullable(config.getApiToken()).ifPresent(token -> setApiTokenHeader(request, token));
return dispatch(request, response -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2021 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.lib.dataverse.model;

import lombok.Data;

@Data
public class DatasetFileValidationResult {
private int datafileId;
private String storageIdentifier;
private String status;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2021 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.lib.dataverse.model;

import lombok.Data;

import java.util.List;

@Data
public class DatasetFileValidationResultList {
private List<DatasetFileValidationResult> dataFiles;
}

0 comments on commit 9f05fef

Please sign in to comment.