diff --git a/pom.xml b/pom.xml
index 12174752..4759491f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
nl.knaw.dans.validatedansbag.DdValidateDansBagApplication
+ 0.5.1-SNAPSHOT
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/DdValidateDansBagApplication.java b/src/main/java/nl/knaw/dans/validatedansbag/DdValidateDansBagApplication.java
index 773d8f58..cf72965a 100644
--- a/src/main/java/nl/knaw/dans/validatedansbag/DdValidateDansBagApplication.java
+++ b/src/main/java/nl/knaw/dans/validatedansbag/DdValidateDansBagApplication.java
@@ -16,7 +16,6 @@
package nl.knaw.dans.validatedansbag;
-import io.dropwizard.configuration.FileConfigurationSourceProvider;
import io.dropwizard.core.Application;
import io.dropwizard.core.setup.Bootstrap;
import io.dropwizard.core.setup.Environment;
@@ -45,8 +44,9 @@
import nl.knaw.dans.validatedansbag.core.validator.PolygonListValidatorImpl;
import nl.knaw.dans.validatedansbag.health.XmlSchemaHealthCheck;
import nl.knaw.dans.validatedansbag.resources.IllegalArgumentExceptionMapper;
-import nl.knaw.dans.validatedansbag.resources.ValidateOkYamlMessageBodyWriter;
+import nl.knaw.dans.validatedansbag.resources.ValidateLocalDirApiResource;
import nl.knaw.dans.validatedansbag.resources.ValidateResource;
+import nl.knaw.dans.validatedansbag.resources.ValidateZipApiResource;
import nl.knaw.dans.vaultcatalog.client.invoker.ApiClient;
import nl.knaw.dans.vaultcatalog.client.resources.DefaultApi;
@@ -55,7 +55,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
@@ -125,7 +124,8 @@ public void run(final DdValidateDansBagConfiguration configuration, final Enviro
environment.jersey().register(new IllegalArgumentExceptionMapper());
environment.jersey().register(new ValidateResource(ruleEngineService, fileService));
- environment.jersey().register(new ValidateOkYamlMessageBodyWriter());
+ environment.jersey().register(new ValidateZipApiResource(ruleEngineService, fileService));
+ environment.jersey().register(new ValidateLocalDirApiResource(ruleEngineService));
environment.healthChecks().register("xml-schemas", new XmlSchemaHealthCheck(xmlSchemaValidator));
}
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/core/service/FileServiceImpl.java b/src/main/java/nl/knaw/dans/validatedansbag/core/service/FileServiceImpl.java
index 1a90acec..53c6326d 100644
--- a/src/main/java/nl/knaw/dans/validatedansbag/core/service/FileServiceImpl.java
+++ b/src/main/java/nl/knaw/dans/validatedansbag/core/service/FileServiceImpl.java
@@ -32,9 +32,17 @@
public class FileServiceImpl implements FileService {
private final Path baseFolder;
+ private final Path tempFolder;
public FileServiceImpl(Path baseFolder) {
- this.baseFolder = baseFolder;
+ this.baseFolder = baseFolder.normalize().toAbsolutePath();
+
+ try {
+ this.tempFolder = Files.createDirectories(this.baseFolder.resolve("temp"));
+ }
+ catch (IOException e) {
+ throw new RuntimeException("Could not create temp directory", e);
+ }
}
@Override
@@ -84,7 +92,7 @@ public CharBuffer readFileContents(Path path, Charset charset) throws IOExceptio
@Override
public Path extractZipFile(InputStream inputStream) throws IOException {
- var tempPath = Files.createTempDirectory(this.baseFolder, "bag-");
+ var tempPath = Files.createTempDirectory(this.tempFolder, "bag-");
try (var input = new ZipInputStream(inputStream)) {
var entry = input.getNextEntry();
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineService.java b/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineService.java
index 59aeb5ca..53b42a81 100644
--- a/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineService.java
+++ b/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineService.java
@@ -15,6 +15,7 @@
*/
package nl.knaw.dans.validatedansbag.core.service;
+import nl.knaw.dans.validatedansbag.api.ValidateOkDto;
import nl.knaw.dans.validatedansbag.core.engine.DepositType;
import nl.knaw.dans.validatedansbag.core.engine.RuleValidationResult;
@@ -25,4 +26,5 @@ public interface RuleEngineService {
List validateBag(Path path, DepositType depositType) throws Exception;
+ ValidateOkDto validateBag(Path path, DepositType depositType, String bagLocation) throws Exception;
}
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineServiceImpl.java b/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineServiceImpl.java
index d593ee52..be23d1e8 100644
--- a/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineServiceImpl.java
+++ b/src/main/java/nl/knaw/dans/validatedansbag/core/service/RuleEngineServiceImpl.java
@@ -16,6 +16,8 @@
package nl.knaw.dans.validatedansbag.core.service;
import lombok.extern.slf4j.Slf4j;
+import nl.knaw.dans.validatedansbag.api.ValidateOkDto;
+import nl.knaw.dans.validatedansbag.api.ValidateOkRuleViolationsInnerDto;
import nl.knaw.dans.validatedansbag.core.BagNotFoundException;
import nl.knaw.dans.validatedansbag.core.engine.DepositType;
import nl.knaw.dans.validatedansbag.core.engine.NumberedRule;
@@ -25,6 +27,7 @@
import java.nio.file.Path;
import java.util.List;
+import java.util.stream.Collectors;
@Slf4j
public class RuleEngineServiceImpl implements RuleEngineService {
@@ -34,8 +37,8 @@ public class RuleEngineServiceImpl implements RuleEngineService {
private final NumberedRule[] ruleSet;
public RuleEngineServiceImpl(RuleEngine ruleEngine,
- FileService fileService,
- NumberedRule[] ruleSet) {
+ FileService fileService,
+ NumberedRule[] ruleSet) {
this.ruleEngine = ruleEngine;
this.fileService = fileService;
this.ruleSet = ruleSet;
@@ -54,10 +57,58 @@ public List validateBag(Path path, DepositType depositType
return ruleEngine.validateRules(path, this.ruleSet, depositType);
}
+ @Override
+ public ValidateOkDto validateBag(Path path, DepositType depositType, String bagLocation) throws Exception {
+ log.info("Validating bag on path '{}'", path);
+
+ if (!fileService.isReadable(path)) {
+ log.warn("Path {} could not not be found or is not readable", path);
+ throw new BagNotFoundException(String.format("Bag on path '%s' could not be found or read", path));
+ }
+
+ var results = ruleEngine.validateRules(path, this.ruleSet, depositType);
+ var isValid = results.stream().noneMatch(r -> r.getStatus().equals(RuleValidationResult.RuleValidationResultStatus.FAILURE));
+
+ var result = new ValidateOkDto();
+ result.setBagLocation(bagLocation);
+ result.setIsCompliant(isValid);
+ result.setName(path.getFileName().toString());
+ result.setProfileVersion("1.1.0");
+ result.setInformationPackageType(toInfoPackageType(depositType));
+ result.setRuleViolations(results.stream()
+ .filter(r -> r.getStatus().equals(RuleValidationResult.RuleValidationResultStatus.FAILURE))
+ .map(rule -> {
+ var ret = new ValidateOkRuleViolationsInnerDto();
+ ret.setRule(rule.getNumber());
+
+ var message = new StringBuilder();
+
+ if (rule.getErrorMessage() != null) {
+ message.append(rule.getErrorMessage());
+ }
+
+ ret.setViolation(message.toString());
+ return ret;
+ })
+ .collect(Collectors.toList()));
+
+ log.debug("Validation result: {}", result);
+
+ return result;
+ }
+
+ private ValidateOkDto.InformationPackageTypeEnum toInfoPackageType(DepositType value) {
+ if (DepositType.MIGRATION.equals(value)) {
+ return ValidateOkDto.InformationPackageTypeEnum.MIGRATION;
+ }
+ return ValidateOkDto.InformationPackageTypeEnum.DEPOSIT;
+ }
+
public void validateRuleConfiguration() {
try {
this.ruleEngine.validateRuleConfiguration(this.ruleSet);
- } catch (RuleEngineConfigurationException e) {
+ }
+ catch (RuleEngineConfigurationException e) {
throw new RuntimeException("Rule configuration is not valid", e);
}
}
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateLocalDirApiResource.java b/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateLocalDirApiResource.java
new file mode 100644
index 00000000..e9375992
--- /dev/null
+++ b/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateLocalDirApiResource.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 DANS - Data Archiving and Networked Services (info@dans.knaw.nl)
+ *
+ * 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.validatedansbag.resources;
+
+import lombok.AllArgsConstructor;
+import nl.knaw.dans.validatedansbag.api.ValidateCommandDto;
+import nl.knaw.dans.validatedansbag.core.engine.DepositType;
+import nl.knaw.dans.validatedansbag.core.service.RuleEngineService;
+
+import javax.ws.rs.core.Response;
+import java.nio.file.Path;
+
+@AllArgsConstructor
+public class ValidateLocalDirApiResource implements ValidateLocalDirApi {
+ private final RuleEngineService ruleEngineService;
+
+ @Override
+ public Response validateLocalDirPost(ValidateCommandDto validateCommandDto) {
+ try {
+ var result = ruleEngineService.validateBag(Path.of(validateCommandDto.getBagLocation()),
+ DepositType.valueOf(validateCommandDto.getPackageType().toString()),
+ validateCommandDto.getBagLocation());
+ return Response.ok(result).build();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateOkYamlMessageBodyWriter.java b/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateOkYamlMessageBodyWriter.java
deleted file mode 100644
index 25453c8b..00000000
--- a/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateOkYamlMessageBodyWriter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2022 DANS - Data Archiving and Networked Services (info@dans.knaw.nl)
- *
- * 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.validatedansbag.resources;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import nl.knaw.dans.validatedansbag.api.ValidateOkDto;
-
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-
-@Provider
-@Produces(MediaType.TEXT_PLAIN)
-public class ValidateOkYamlMessageBodyWriter implements MessageBodyWriter {
- private final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
-
- @Override
- public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return type == ValidateOkDto.class;
- }
-
- @Override
- public void writeTo(ValidateOkDto ValidateOkDtoResult, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders,
- OutputStream entityStream) throws IOException, WebApplicationException {
- var result = objectMapper.writeValueAsString(ValidateOkDtoResult);
- entityStream.write(result.getBytes(StandardCharsets.UTF_8));
- }
-}
diff --git a/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateZipApiResource.java b/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateZipApiResource.java
new file mode 100644
index 00000000..3089c1d5
--- /dev/null
+++ b/src/main/java/nl/knaw/dans/validatedansbag/resources/ValidateZipApiResource.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 DANS - Data Archiving and Networked Services (info@dans.knaw.nl)
+ *
+ * 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.validatedansbag.resources;
+
+import lombok.AllArgsConstructor;
+import nl.knaw.dans.validatedansbag.core.engine.DepositType;
+import nl.knaw.dans.validatedansbag.core.service.FileService;
+import nl.knaw.dans.validatedansbag.core.service.RuleEngineService;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileInputStream;
+
+@AllArgsConstructor
+public class ValidateZipApiResource implements ValidateZipApi {
+ private final RuleEngineService ruleEngineService;
+ private final FileService fileService;
+
+ @Override
+ public Response validateZipPost(File body) {
+ try (var inputStream = new FileInputStream(body)) {
+ var dir = fileService.extractZipFile(inputStream);
+ var bagDir = fileService.getFirstDirectory(dir);
+ if (bagDir.isEmpty()) {
+ return Response.status(Response.Status.BAD_REQUEST).entity("No bag directory found in zip file").build();
+ }
+ var result = ruleEngineService.validateBag(bagDir.get(), DepositType.DEPOSIT, "ZIP");
+ return Response.ok(result).build();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/test/java/nl/knaw/dans/validatedansbag/resources/ValidateResourceIntegrationTest.java b/src/test/java/nl/knaw/dans/validatedansbag/resources/ValidateResourceIntegrationTest.java
index 860ffef9..5f9c7a22 100644
--- a/src/test/java/nl/knaw/dans/validatedansbag/resources/ValidateResourceIntegrationTest.java
+++ b/src/test/java/nl/knaw/dans/validatedansbag/resources/ValidateResourceIntegrationTest.java
@@ -91,7 +91,6 @@ public boolean isValidLicense(String license) {
static {
EXT = ResourceExtension.builder()
.addProvider(MultiPartFeature.class)
- .addProvider(ValidateOkYamlMessageBodyWriter.class)
.addResource(buildValidateResource())
.build();
}
@@ -367,35 +366,6 @@ void validateFormData_should_not_throw_internal_server_error_on_incomplete_manif
.endsWith("original-metadata.zip] is in the payload directory but isn't listed in any manifest!");
}
- @Test
- void validateZipFile_should_return_a_textual_representation_when_requested() throws Exception {
- var inputStream = Files.newInputStream(Path.of(baseTestFolder, "/zips/invalid-sha1.zip"));
-
- var embargoResultJson = """
- {
- "status": "OK",
- "data": {
- "message": "24"
- }
- }""";
- var maxEmbargoDurationResult = new MockedDataverseResponse(embargoResultJson, DataMessage.class);
- Mockito.when(dataverseService.getMaxEmbargoDurationInMonths())
- .thenReturn(maxEmbargoDurationResult);
-
- var response = EXT.target("/validate")
- .request()
- .header("accept", "text/plain")
- .header("Authorization", basicUsernamePassword("user001", "user001"))
- .post(Entity.entity(inputStream, MediaType.valueOf("application/zip")), String.class);
-
- assertTrue(response.contains("Bag location:"));
- assertTrue(response.contains("Name:"));
- assertTrue(response.contains("Profile version:"));
- assertTrue(response.contains("Information package type:"));
- assertTrue(response.contains("Is compliant:"));
- assertTrue(response.contains("Rule violations:"));
- }
-
@Test
void validateFormData_with_invalid_path_should_return_400_error() {
var data = new ValidateCommandDto();