diff --git a/docs/documentation.adoc b/docs/documentation.adoc index e6fe0300..d362aba5 100644 --- a/docs/documentation.adoc +++ b/docs/documentation.adoc @@ -67,6 +67,7 @@ like this: "sid" : "...", "permission" : "..." } ], + "licenseUri" : "...", "schemaDocumentUri" : "...", "schemaHash" : "...", "locked" : false @@ -81,6 +82,8 @@ At least the following elements are expected to be provided by the user: In addition, ACL may be useful to make schema readable/editable by others. This will be of interest while accessing/updating an existing schema.(if authorization is enabled) +[NOTE] +License URI is optional. It's new since 1.5.0. === Registering a Metadata Schema Document @@ -464,6 +467,7 @@ like this: "sid": "...", "permission": "..." }], + "licenseUri": "...", "metadataDocumentUri": "...", "documentHash": "..." } @@ -479,6 +483,9 @@ In addition, ACL may be useful to make metadata editable by others. (This will b [NOTE] If linked schema is identified by its schemaId the INTERNAL type has to be used. +[NOTE] +License URI is optional. It's new since 1.5.0. + ==== Register/Ingest a Metadata Record with Metadata Document The following example shows the creation of the first metadata record and its metadata only providing mandatory fields mentioned above: @@ -757,6 +764,7 @@ like this: "sid" : "...", "permission" : "..." } ], + "licenseUri" : "...", "schemaDocumentUri" : "...", "schemaHash" : "...", "locked" : false @@ -771,6 +779,9 @@ At least the following elements are expected to be provided by the user: In addition, ACL may be useful to make schema editable by others. (This will be of interest while updating an existing schema) +[NOTE] +License URI is optional. It's new since 1.5.0. + === Registering a Metadata Schema Document The following example shows the creation of the first json schema only providing mandatory fields mentioned above: @@ -1186,6 +1197,7 @@ like this: "sid": "...", "permission": "..." }], + "licenseUri": "...", "metadataDocumentUri": "...", "documentHash": "..." } @@ -1198,6 +1210,9 @@ At least the following elements are expected to be provided by the user: In addition, ACL may be useful to make metadata editable by others. (This will be of interest while updating an existing metadata) +[NOTE] +License URI is optional. It's new since 1.5.0. + ==== Register/Ingest a Metadata Record with Metadata Document The following example shows the creation of the first metadata record and its metadata only providing mandatory fields mentioned above: diff --git a/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataRecord.java b/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataRecord.java index 0f1387b5..dfec5342 100644 --- a/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataRecord.java +++ b/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataRecord.java @@ -77,6 +77,8 @@ public class MetadataRecord implements EtagSupport, Serializable { @NotNull(message = "A list of access control entries for resticting access.") @OneToMany(cascade = jakarta.persistence.CascadeType.ALL, orphanRemoval = true) private final Set acl = new HashSet<>(); + @NotBlank(message = "The uri of the license, e.g. for Apache-2.0 license this would be 'https://spdx.org/licenses/Apache-2.0'.") + private String licenseUri; @NotBlank(message = "The metadata document uri, e.g. pointing to a local file.") private String metadataDocumentUri; @NotBlank(message = "The SHA-1 hash of the associated metadata file. The hash is used for comparison while updating.") diff --git a/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataSchemaRecord.java b/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataSchemaRecord.java index f8793d1d..c06ad45a 100644 --- a/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataSchemaRecord.java +++ b/src/main/java/edu/kit/datamanager/metastore2/domain/MetadataSchemaRecord.java @@ -98,6 +98,8 @@ public enum SCHEMA_TYPE { private Instant lastUpdate; @Transient private final Set acl = new HashSet<>(); + @NotBlank(message = "The uri of the license, e.g. for Apache-2.0 license this would be 'https://spdx.org/licenses/Apache-2.0'.") + private String licenseUri; @NotBlank(message = "The schema document uri, e.g. pointing to a local file.") private String schemaDocumentUri; @NotBlank(message = "The SHA-1 hash of the associated schema file. The hash is used for comparison while synchonization.") diff --git a/src/main/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtil.java b/src/main/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtil.java index 1532ea25..1e1d04bd 100644 --- a/src/main/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtil.java +++ b/src/main/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtil.java @@ -40,6 +40,7 @@ import edu.kit.datamanager.repo.domain.Date; import edu.kit.datamanager.repo.domain.RelatedIdentifier; import edu.kit.datamanager.repo.domain.ResourceType; +import edu.kit.datamanager.repo.domain.Scheme; import edu.kit.datamanager.repo.domain.Title; import edu.kit.datamanager.repo.domain.acl.AclEntry; import edu.kit.datamanager.repo.service.IContentInformationService; @@ -445,6 +446,7 @@ public static DataResource migrateToDataResource(RepoBaseConfiguration applicati dataResource.getTitles().add(Title.factoryTitle(defaultTitle, Title.TYPE.OTHER)); } dataResource.setResourceType(ResourceType.createResourceType(MetadataRecord.RESOURCE_TYPE)); + checkLicense(dataResource, metadataRecord.getLicenseUri()); return dataResource; } @@ -562,6 +564,10 @@ public static MetadataRecord migrateToMetadataRecord(RepoBaseConfiguration appli } } } + // Only one license allowed. So don't worry about size of set. + if (!dataResource.getRights().isEmpty()) { + metadataRecord.setLicenseUri(dataResource.getRights().iterator().next().getSchemeUri()); + } long nano5 = System.nanoTime() / 1000000; LOG.info("Migrate to MetadataRecord, {}, {}, {}, {}, {}, {}", nano1, nano2 - nano1, nano3 - nano1, nano4 - nano1, nano5 - nano1, provideETag); } @@ -622,7 +628,8 @@ public static MetadataSchemaRecord getCurrentInternalSchemaRecord(MetastoreConfi URI finalUri = builder.build().toUri(); try { - returnValue = SimpleServiceClient.create(finalUri.toString()).withBearerToken(guestToken).accept(MetadataSchemaRecord.METADATA_SCHEMA_RECORD_MEDIA_TYPE).getResource(MetadataSchemaRecord.class); + returnValue = SimpleServiceClient.create(finalUri.toString()).withBearerToken(guestToken).accept(MetadataSchemaRecord.METADATA_SCHEMA_RECORD_MEDIA_TYPE).getResource(MetadataSchemaRecord.class + ); success = true; break; } catch (HttpClientErrorException ce) { @@ -672,7 +679,8 @@ public static MetadataSchemaRecord getInternalSchemaRecord(MetastoreConfiguratio URI finalUri = builder.build().toUri(); try { - returnValue = SimpleServiceClient.create(finalUri.toString()).withBearerToken(guestToken).accept(MetadataSchemaRecord.METADATA_SCHEMA_RECORD_MEDIA_TYPE).getResource(MetadataSchemaRecord.class); + returnValue = SimpleServiceClient.create(finalUri.toString()).withBearerToken(guestToken).accept(MetadataSchemaRecord.METADATA_SCHEMA_RECORD_MEDIA_TYPE).getResource(MetadataSchemaRecord.class + ); success = true; break; } catch (HttpClientErrorException ce) { @@ -856,9 +864,10 @@ public static MetadataRecord mergeRecords(MetadataRecord managed, MetadataRecord managed.setRelatedResource(mergeEntry("Updating record->relatedResource", managed.getRelatedResource(), provided.getRelatedResource())); //update schemaId managed.setSchema(mergeEntry("Updating record->schema", managed.getSchema(), provided.getSchema())); - //update schemaVersion managed.setSchemaVersion(mergeEntry("Updating record->schemaVersion", managed.getSchemaVersion(), provided.getSchemaVersion())); + // update licenseUri + managed.setLicenseUri(mergeEntry("Updating record->licenseUri", managed.getLicenseUri(), provided.getLicenseUri(), true)); } else { managed = (managed != null) ? managed : provided; } @@ -1048,7 +1057,29 @@ public static boolean checkAccessRights(Set aclEntries, boolean curren public static final void fixMetadataDocumentUri(MetadataRecord metadataRecord) { String metadataDocumentUri = metadataRecord.getMetadataDocumentUri(); - metadataRecord.setMetadataDocumentUri(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(MetadataControllerImpl.class).getMetadataDocumentById(metadataRecord.getId(), metadataRecord.getRecordVersion(), null, null)).toUri().toString()); + metadataRecord + .setMetadataDocumentUri(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(MetadataControllerImpl.class + ).getMetadataDocumentById(metadataRecord.getId(), metadataRecord.getRecordVersion(), null, null)).toUri().toString()); LOG.trace("Fix metadata document Uri '{}' -> '{}'", metadataDocumentUri, metadataRecord.getMetadataDocumentUri()); } + + public static void checkLicense(DataResource dataResource, String licenseUri) { + if (licenseUri != null) { + Set rights = dataResource.getRights(); + String licenseId = licenseUri.substring(licenseUri.lastIndexOf("/")); + Scheme license = Scheme.factoryScheme(licenseId, licenseUri); + if (rights.isEmpty()) { + rights.add(license); + } else { + // Check if license already exists (only one license allowed) + if (!rights.contains(license)) { + rights.clear(); + rights.add(license); + } + } + } else { + // Remove license + dataResource.getRights().clear(); + } + } } diff --git a/src/main/java/edu/kit/datamanager/metastore2/util/MetadataSchemaRecordUtil.java b/src/main/java/edu/kit/datamanager/metastore2/util/MetadataSchemaRecordUtil.java index 5b27d854..f7c55088 100644 --- a/src/main/java/edu/kit/datamanager/metastore2/util/MetadataSchemaRecordUtil.java +++ b/src/main/java/edu/kit/datamanager/metastore2/util/MetadataSchemaRecordUtil.java @@ -45,6 +45,7 @@ import edu.kit.datamanager.repo.domain.Date; import edu.kit.datamanager.repo.domain.Description; import edu.kit.datamanager.repo.domain.ResourceType; +import edu.kit.datamanager.repo.domain.Scheme; import edu.kit.datamanager.repo.domain.Title; import edu.kit.datamanager.repo.service.IContentInformationService; import edu.kit.datamanager.repo.util.ContentDataUtils; @@ -444,6 +445,7 @@ public static DataResource migrateToDataResource(RepoBaseConfiguration applicati checkDescription(descriptions, metadataSchemaRecord.getLabel(), Description.TYPE.OTHER); checkDescription(descriptions, metadataSchemaRecord.getDefinition(), Description.TYPE.TECHNICAL_INFO); checkDescription(descriptions, metadataSchemaRecord.getComment(), Description.TYPE.ABSTRACT); + MetadataRecordUtil.checkLicense(dataResource, metadataSchemaRecord.getLicenseUri()); return dataResource; } @@ -601,30 +603,34 @@ public static MetadataSchemaRecord migrateToMetadataSchemaRecord(RepoBaseConfigu saveNewSchemaRecord(metadataSchemaRecord); } } - } - long nano7 = System.nanoTime() / 1000000; - // label -> description of type (OTHER) - // description -> description of type (TECHNICAL_INFO) - // comment -> description of type (ABSTRACT) - Iterator iterator = dataResource.getDescriptions().iterator(); - while (iterator.hasNext()) { - Description nextDescription = iterator.next(); - switch (nextDescription.getType()) { - case ABSTRACT: - metadataSchemaRecord.setComment(nextDescription.getDescription()); - break; - case TECHNICAL_INFO: - metadataSchemaRecord.setDefinition(nextDescription.getDescription()); - break; - case OTHER: - metadataSchemaRecord.setLabel(nextDescription.getDescription()); - break; - default: - LOG.trace("Unknown description type: '{}' -> skipped", nextDescription.getType()); + long nano7 = System.nanoTime() / 1000000; + // label -> description of type (OTHER) + // description -> description of type (TECHNICAL_INFO) + // comment -> description of type (ABSTRACT) + Iterator desc_iterator = dataResource.getDescriptions().iterator(); + while (desc_iterator.hasNext()) { + Description nextDescription = desc_iterator.next(); + switch (nextDescription.getType()) { + case ABSTRACT: + metadataSchemaRecord.setComment(nextDescription.getDescription()); + break; + case TECHNICAL_INFO: + metadataSchemaRecord.setDefinition(nextDescription.getDescription()); + break; + case OTHER: + metadataSchemaRecord.setLabel(nextDescription.getDescription()); + break; + default: + LOG.trace("Unknown description type: '{}' -> skipped", nextDescription.getType()); + } + } + // Only one license allowed. So don't worry about size of set. + if (!dataResource.getRights().isEmpty()) { + metadataSchemaRecord.setLicenseUri(dataResource.getRights().iterator().next().getSchemeUri()); + } + if (LOG.isTraceEnabled()) { + LOG.trace("Migrate to schema record, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}", nano1, nano2 - nano1, nano3 - nano1, nano4 - nano1, nano4 - nano1, nano5 - nano1, nano6 - nano1, nano7 - nano1, provideETag); } - } - if (LOG.isTraceEnabled()) { - LOG.trace("Migrate to schema record, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}", nano1, nano2 - nano1, nano3 - nano1, nano4 - nano1, nano4 - nano1, nano5 - nano1, nano6 - nano1, nano7 - nano1, provideETag); } return metadataSchemaRecord; } @@ -916,9 +922,9 @@ public static MetadataSchemaRecord getRecordByIdAndVersion(MetastoreConfiguratio MetadataSchemaRecord result = null; Page dataResource; try { - dataResource = metastoreProperties.getDataResourceService().findAllVersions(recordId, null); + dataResource = metastoreProperties.getDataResourceService().findAllVersions(recordId, null); } catch (ResourceNotFoundException rnfe) { - rnfe.setDetail("Schema document with ID '" + recordId + "' doesn't exist!"); + rnfe.setDetail("Schema document with ID '" + recordId + "' doesn't exist!"); throw rnfe; } long nano2 = System.nanoTime() / 1000000; @@ -930,7 +936,7 @@ public static MetadataSchemaRecord getRecordByIdAndVersion(MetastoreConfiguratio if (findFirst.isPresent()) { result = migrateToMetadataSchemaRecord(metastoreProperties, findFirst.get(), supportEtag); } else { - String message = String.format("Version '%d' of ID '%s' doesn't exist!",version, recordId); + String message = String.format("Version '%d' of ID '%s' doesn't exist!", version, recordId); LOG.error(message); throw new ResourceNotFoundException(message); } @@ -968,6 +974,8 @@ public static MetadataSchemaRecord mergeRecords(MetadataSchemaRecord managed, Me managed.setSchemaId(mergeEntry("Updating record->schema", managed.getSchemaId(), provided.getSchemaId())); //update schemaVersion managed.setSchemaVersion(mergeEntry("Updating record->schemaVersion", managed.getSchemaVersion(), provided.getSchemaVersion())); + // update licenseUri + managed.setLicenseUri(mergeEntry("Updating record->licenseUri", managed.getLicenseUri(), provided.getLicenseUri(), true)); } else { managed = (managed != null) ? managed : provided; } diff --git a/src/test/java/edu/kit/datamanager/metastore2/test/MetadataControllerTest.java b/src/test/java/edu/kit/datamanager/metastore2/test/MetadataControllerTest.java index eac68241..8e99f448 100644 --- a/src/test/java/edu/kit/datamanager/metastore2/test/MetadataControllerTest.java +++ b/src/test/java/edu/kit/datamanager/metastore2/test/MetadataControllerTest.java @@ -114,6 +114,8 @@ public class MetadataControllerTest { private static final String INVALID_SCHEMA = "invalid_dc"; private static final String UNKNOWN_RELATED_RESOURCE = "unknownHResourceId"; private static final String RELATED_RESOURCE_STRING = "anyResourceId"; + private static final String APACHE_2_LICENSE = "https://spdx.org/licenses/Apache-2.0"; + private static final String MIT_LICENSE = "https://spdx.org/licenses/MIT"; private static final ResourceIdentifier RELATED_RESOURCE = ResourceIdentifier.factoryInternalResourceIdentifier(RELATED_RESOURCE_STRING); private static final ResourceIdentifier RELATED_RESOURCE_URL = ResourceIdentifier.factoryUrlResourceIdentifier(RELATED_RESOURCE_STRING); private static final ResourceIdentifier RELATED_RESOURCE_2 = ResourceIdentifier.factoryInternalResourceIdentifier("anyOtherResourceId"); @@ -1599,6 +1601,128 @@ public void testUpdateRecordWithInvalidSetting4Json() throws Exception { CreateSchemaUtil.ingestOrUpdateXmlMetadataDocument(mockMvc, SCHEMA_ID, 1l, "document", null, schemaConfig.getJwtSecret(), true, status().isUnprocessableEntity()); } + @Test + public void testUpdateRecordWithLicense() throws Exception { + String metadataRecordId = createDCMetadataRecord(); + MvcResult result = this.mockMvc.perform(get("/api/v1/metadata/" + metadataRecordId). + header("Accept", MetadataRecord.METADATA_RECORD_MEDIA_TYPE)). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + String etag = result.getResponse().getHeader("ETag"); + String body = result.getResponse().getContentAsString(); + + ObjectMapper mapper = new ObjectMapper(); + MetadataRecord record = mapper.readValue(body, MetadataRecord.class); + record.setLicenseUri(APACHE_2_LICENSE); + MockMultipartFile recordFile = new MockMultipartFile("record", "metadata-record.json", "application/json", mapper.writeValueAsString(record).getBytes()); + MockMultipartFile metadataFile = new MockMultipartFile("document", "metadata.xml", "application/xml", DC_DOCUMENT_VERSION_2.getBytes()); + + result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/api/v1/metadata/" + record.getId()). + file(recordFile). + file(metadataFile). + header("If-Match", etag). + with(putMultipart())). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + +// result = this.mockMvc.perform(put("/api/v1/metadata/dc").header("If-Match", etag).contentType(MetadataRecord.METADATA_RECORD_MEDIA_TYPE).content(mapper.writeValueAsString(record))).andDo(print()).andExpect(status().isOk()).andReturn(); + body = result.getResponse().getContentAsString(); + + MetadataRecord record2 = mapper.readValue(body, MetadataRecord.class); + Assert.assertNotEquals(record.getDocumentHash(), record2.getDocumentHash()); + Assert.assertEquals(record.getCreatedAt(), record2.getCreatedAt()); + Assert.assertEquals(record.getSchema().getIdentifier(), record2.getSchema().getIdentifier()); + Assert.assertEquals((long) record.getRecordVersion(), record2.getRecordVersion() - 1l);// version should be 1 higher + if (record.getAcl() != null) { + Assert.assertTrue(record.getAcl().containsAll(record2.getAcl())); + } + Assert.assertTrue(record.getLastUpdate().isBefore(record2.getLastUpdate())); + Assert.assertNotNull(record2.getLicenseUri()); + Assert.assertTrue(record2.getLicenseUri().equals(APACHE_2_LICENSE)); + // Check for new metadata document. + result = this.mockMvc.perform(get("/api/v1/metadata/" + metadataRecordId)). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + String content = result.getResponse().getContentAsString(); + + String dcMetadata = DC_DOCUMENT_VERSION_2; + + Assert.assertEquals(dcMetadata, content); + + Assert.assertEquals(record.getMetadataDocumentUri().replace("version=1", "version=2"), record2.getMetadataDocumentUri()); + result = this.mockMvc.perform(get("/api/v1/metadata/" + metadataRecordId). + header("Accept", MetadataRecord.METADATA_RECORD_MEDIA_TYPE)). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + etag = result.getResponse().getHeader("ETag"); + body = result.getResponse().getContentAsString(); + + record = mapper.readValue(body, MetadataRecord.class); + record.setLicenseUri(MIT_LICENSE); + recordFile = new MockMultipartFile("record", "metadata-record.json", "application/json", mapper.writeValueAsString(record).getBytes()); + + result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/api/v1/metadata/" + record.getId()). + file(recordFile). + header("If-Match", etag). + with(putMultipart())). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + +// result = this.mockMvc.perform(put("/api/v1/metadata/dc").header("If-Match", etag).contentType(MetadataRecord.METADATA_RECORD_MEDIA_TYPE).content(mapper.writeValueAsString(record))).andDo(print()).andExpect(status().isOk()).andReturn(); + body = result.getResponse().getContentAsString(); + + MetadataRecord record3 = mapper.readValue(body, MetadataRecord.class); + Assert.assertEquals(record2.getDocumentHash(), record3.getDocumentHash()); + Assert.assertEquals(record2.getCreatedAt(), record3.getCreatedAt()); + Assert.assertEquals(record2.getSchema().getIdentifier(), record3.getSchema().getIdentifier()); + Assert.assertEquals((long) record2.getRecordVersion(), (long)record3.getRecordVersion());// version should be the same + if (record.getAcl() != null) { + Assert.assertTrue(record2.getAcl().containsAll(record3.getAcl())); + } + Assert.assertTrue(record2.getLastUpdate().isBefore(record3.getLastUpdate())); + Assert.assertNotNull(record3.getLicenseUri()); + Assert.assertTrue(record3.getLicenseUri().equals(MIT_LICENSE)); + result = this.mockMvc.perform(get("/api/v1/metadata/" + metadataRecordId). + header("Accept", MetadataRecord.METADATA_RECORD_MEDIA_TYPE)). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + etag = result.getResponse().getHeader("ETag"); + body = result.getResponse().getContentAsString(); + + record = mapper.readValue(body, MetadataRecord.class); + record.setLicenseUri(null); + recordFile = new MockMultipartFile("record", "metadata-record.json", "application/json", mapper.writeValueAsString(record).getBytes()); + + result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/api/v1/metadata/" + record.getId()). + file(recordFile). + header("If-Match", etag). + with(putMultipart())). + andDo(print()). + andExpect(status().isOk()). + andReturn(); + +// result = this.mockMvc.perform(put("/api/v1/metadata/dc").header("If-Match", etag).contentType(MetadataRecord.METADATA_RECORD_MEDIA_TYPE).content(mapper.writeValueAsString(record))).andDo(print()).andExpect(status().isOk()).andReturn(); + body = result.getResponse().getContentAsString(); + + MetadataRecord record4 = mapper.readValue(body, MetadataRecord.class); + Assert.assertEquals(record2.getDocumentHash(), record4.getDocumentHash()); + Assert.assertEquals(record2.getCreatedAt(), record4.getCreatedAt()); + Assert.assertEquals(record2.getSchema().getIdentifier(), record4.getSchema().getIdentifier()); + Assert.assertEquals((long) record2.getRecordVersion(), (long)record4.getRecordVersion());// version should be the same + if (record.getAcl() != null) { + Assert.assertTrue(record2.getAcl().containsAll(record4.getAcl())); + } + Assert.assertTrue(record3.getLastUpdate().isBefore(record4.getLastUpdate())); + Assert.assertNull(record4.getLicenseUri()); + + } + @Test public void testDeleteRecordWithoutAuthentication() throws Exception { String metadataRecordId = createDCMetadataRecord(); diff --git a/src/test/java/edu/kit/datamanager/metastore2/test/SchemaRegistryControllerTest.java b/src/test/java/edu/kit/datamanager/metastore2/test/SchemaRegistryControllerTest.java index 748379ba..11ba5db6 100644 --- a/src/test/java/edu/kit/datamanager/metastore2/test/SchemaRegistryControllerTest.java +++ b/src/test/java/edu/kit/datamanager/metastore2/test/SchemaRegistryControllerTest.java @@ -112,8 +112,8 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class SchemaRegistryControllerTest { - private final static String TEMP_DIR_4_ALL = "/tmp/metastore2/schematest/"; - private final static String TEMP_DIR_4_SCHEMAS = TEMP_DIR_4_ALL + "schema/"; + private static final String TEMP_DIR_4_ALL = "/tmp/metastore2/schematest/"; + private static final String TEMP_DIR_4_SCHEMAS = TEMP_DIR_4_ALL + "schema/"; private static final String PID = "anyPID"; private static final ResourceIdentifier.IdentifierType PID_TYPE = ResourceIdentifier.IdentifierType.HANDLE; private static final String SCHEMA_ID = "dc"; @@ -121,9 +121,9 @@ public class SchemaRegistryControllerTest { private static final String LABEL = "any unique label for test"; private static final String DEFINITION = "any unique definition for test"; private static final String COMMENT = "any unique comment for test"; - private final static String KIT_SCHEMA = CreateSchemaUtil.KIT_SCHEMA; - - private final static String KIT_SCHEMA_V2 = "\n" @@ -138,15 +138,15 @@ public class SchemaRegistryControllerTest { + " \n" + " "; - private final static String KIT_DOCUMENT = CreateSchemaUtil.KIT_DOCUMENT; - private final static String INVALID_KIT_DOCUMENT = CreateSchemaUtil.KIT_DOCUMENT_INVALID_1; - private final static String SCHEMA_V1 = CreateSchemaUtil.XML_SCHEMA_V1; - private final static String SCHEMA_V2 = CreateSchemaUtil.XML_SCHEMA_V2; - private final static String SCHEMA_V3 = CreateSchemaUtil.XML_SCHEMA_V3; - private final static String XML_DOCUMENT_V1 = CreateSchemaUtil.XML_DOCUMENT_V1; - private final static String XML_DOCUMENT_V2 = CreateSchemaUtil.XML_DOCUMENT_V2; - private final static String XML_DOCUMENT_V3 = CreateSchemaUtil.XML_DOCUMENT_V3; - private final static String JSON_DOCUMENT = "{\"title\":\"any string\",\"date\": \"2020-10-16\"}"; + private static final String KIT_DOCUMENT = CreateSchemaUtil.KIT_DOCUMENT; + private static final String INVALID_KIT_DOCUMENT = CreateSchemaUtil.KIT_DOCUMENT_INVALID_1; + private static final String SCHEMA_V1 = CreateSchemaUtil.XML_SCHEMA_V1; + private static final String SCHEMA_V2 = CreateSchemaUtil.XML_SCHEMA_V2; + private static final String SCHEMA_V3 = CreateSchemaUtil.XML_SCHEMA_V3; + private static final String XML_DOCUMENT_V1 = CreateSchemaUtil.XML_DOCUMENT_V1; + private static final String XML_DOCUMENT_V2 = CreateSchemaUtil.XML_DOCUMENT_V2; + private static final String XML_DOCUMENT_V3 = CreateSchemaUtil.XML_DOCUMENT_V3; + private static final String JSON_DOCUMENT = "{\"title\":\"any string\",\"date\": \"2020-10-16\"}"; private static final String RELATED_RESOURCE_STRING = "anyResourceId"; private static final ResourceIdentifier RELATED_RESOURCE = ResourceIdentifier.factoryInternalResourceIdentifier(RELATED_RESOURCE_STRING); @@ -1056,6 +1056,8 @@ public void testUpdateRecordAndDocument() throws Exception { body = result.getResponse().getContentAsString(); MetadataSchemaRecord record2 = mapper.readValue(body, MetadataSchemaRecord.class); + Assert.assertNull(record2.getLicenseUri()); + Assert.assertEquals(record.getLicenseUri(), record2.getLicenseUri()); Assert.assertNotEquals(mimeTypeBefore, record2.getMimeType());//mime type was changed by update Assert.assertEquals(record.getCreatedAt(), record2.getCreatedAt()); testForNextVersion(record.getSchemaDocumentUri(), record2.getSchemaDocumentUri()); @@ -1074,6 +1076,86 @@ public void testUpdateRecordAndDocument() throws Exception { Assert.assertEquals(KIT_SCHEMA_V2, content); } + + @Test + public void testUpdateRecordAndDocumentWithLicense() throws Exception { + String schemaId = "updateRecordAndDocumentWithLicense".toLowerCase(Locale.getDefault()); + ingestSchemaRecord(schemaId); + MvcResult result = this.mockMvc.perform(get("/api/v1/schemas/" + schemaId).header("Accept", MetadataSchemaRecord.METADATA_SCHEMA_RECORD_MEDIA_TYPE)).andDo(print()).andExpect(status().isOk()).andReturn(); + String etag = result.getResponse().getHeader("ETag"); + String body = result.getResponse().getContentAsString(); + + ObjectMapper mapper = new ObjectMapper(); + MetadataSchemaRecord record = mapper.readValue(body, MetadataSchemaRecord.class); + String mimeTypeBefore = record.getMimeType(); + record.setMimeType(MediaType.APPLICATION_JSON.toString()); + record.setLicenseUri(APACHE_2_LICENSE); + System.out.println("****************************************************************************************"); + System.out.println("****************************************************************************************"); + System.out.println(mapper.writeValueAsString(record)); + MockMultipartFile recordFile = new MockMultipartFile("record", "metadata-record.json", "application/json", mapper.writeValueAsString(record).getBytes()); + MockMultipartFile schemaFile = new MockMultipartFile("schema", "schema.xsd", "application/xml", KIT_SCHEMA_V2.getBytes()); + + result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/api/v1/schemas/" + schemaId). + file(recordFile). + file(schemaFile). + header("If-Match", etag). + with(putMultipart())). + andDo(print()). + andExpect(status().isOk()). + andExpect(redirectedUrlPattern("http://*:*/**/" + record.getSchemaId() + "?version=*")). + andReturn(); + body = result.getResponse().getContentAsString(); + etag = result.getResponse().getHeader("ETag"); + + MetadataSchemaRecord record2 = mapper.readValue(body, MetadataSchemaRecord.class); + Assert.assertNotNull(record2.getLicenseUri()); + Assert.assertEquals(record.getLicenseUri(), record2.getLicenseUri()); + Assert.assertNotEquals(mimeTypeBefore, record2.getMimeType());//mime type was changed by update + Assert.assertEquals(record.getCreatedAt(), record2.getCreatedAt()); + testForNextVersion(record.getSchemaDocumentUri(), record2.getSchemaDocumentUri()); +// Assert.assertEquals(record.getSchemaDocumentUri().replace("version=1", "version=2"), record2.getSchemaDocumentUri()); + Assert.assertNotEquals(record.getSchemaHash(), record2.getSchemaHash()); + Assert.assertEquals(record.getSchemaId(), record2.getSchemaId()); + Assert.assertEquals((long) record.getSchemaVersion() + 1l, (long) record2.getSchemaVersion());//version is not changing for metadata update + if (record.getAcl() != null) { + Assert.assertTrue(record.getAcl().containsAll(record2.getAcl())); + } + Assert.assertTrue(record.getLastUpdate().isBefore(record2.getLastUpdate())); + // Test also document for update + result = this.mockMvc.perform(get("/api/v1/schemas/" + schemaId)).andDo(print()).andExpect(status().isOk()).andReturn(); + String content = result.getResponse().getContentAsString(); + + Assert.assertEquals(KIT_SCHEMA_V2, content); + // Remove license + record2.setLicenseUri(null); + recordFile = new MockMultipartFile("record", "metadata-record.json", "application/json", mapper.writeValueAsString(record2).getBytes()); + + result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/api/v1/schemas/" + schemaId). + file(recordFile). + header("If-Match", etag). + with(putMultipart())). + andDo(print()). + andExpect(status().isOk()). + andExpect(redirectedUrlPattern("http://*:*/**/" + record.getSchemaId() + "?version=*")). + andReturn(); + body = result.getResponse().getContentAsString(); + + MetadataSchemaRecord record3 = mapper.readValue(body, MetadataSchemaRecord.class); + Assert.assertNull(record3.getLicenseUri()); + Assert.assertEquals(record2.getMimeType(), record3.getMimeType());//mime type was changed by update + Assert.assertEquals(record2.getCreatedAt(), record3.getCreatedAt()); + Assert.assertEquals(record2.getSchemaDocumentUri(), record3.getSchemaDocumentUri()); +// Assert.assertEquals(record.getSchemaDocumentUri().replace("version=1", "version=2"), record2.getSchemaDocumentUri()); + Assert.assertEquals(record2.getSchemaHash(), record3.getSchemaHash()); + Assert.assertEquals(record2.getSchemaId(), record3.getSchemaId()); + Assert.assertEquals((long) record.getSchemaVersion() + 1l, (long) record2.getSchemaVersion());//version is not changing for metadata update + if (record.getAcl() != null) { + Assert.assertTrue(record2.getAcl().containsAll(record3.getAcl())); + } + Assert.assertTrue(record2.getLastUpdate().isBefore(record3.getLastUpdate())); + } + @Test public void testUpdateRecordAndDocumentWithWrongVersion() throws Exception { String schemaId = "updateRecordAndDocumentWithWrongVersion".toLowerCase(Locale.getDefault()); diff --git a/src/test/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtilTest.java b/src/test/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtilTest.java index a5615a96..e8743f91 100644 --- a/src/test/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtilTest.java +++ b/src/test/java/edu/kit/datamanager/metastore2/util/MetadataRecordUtilTest.java @@ -21,6 +21,7 @@ import edu.kit.datamanager.repo.domain.DataResource; import edu.kit.datamanager.repo.domain.Date; import edu.kit.datamanager.repo.domain.RelatedIdentifier; +import edu.kit.datamanager.repo.domain.Scheme; import java.time.Instant; import java.util.function.UnaryOperator; import org.javers.core.Javers; @@ -82,6 +83,7 @@ public class MetadataRecordUtilTest { private final static String TEMP_DIR_4_METADATA = TEMP_DIR_4_ALL + "metadata/"; private static final String METADATA_RECORD_ID = "test_id"; private static final String PID = "anyPID"; + private static final String LICENSE = "https://spdx.org/licenses/Apache-2.0"; private static final String PRINCIPAL = "principal"; private static final String SCHEMA_ID = "my_dc"; private static final String INVALID_SCHEMA = "invalid_dc"; @@ -670,6 +672,7 @@ public void testMigrateToMetadataRecord() { assertEquals("Id should be the same!", result.getId(), dataResource.getId()); assertEquals("Version should be '1'", Long.valueOf(1l), result.getRecordVersion()); assertTrue("ACL should be empty", result.getAcl().isEmpty()); + assertTrue("License should be 'null'", result.getLicenseUri() == null); assertNull("PID should be empty", result.getPid()); assertNull("Create date should be empty!", result.getCreatedAt()); assertNull("Last update date should be empty!", result.getLastUpdate()); @@ -682,6 +685,7 @@ public void testMigrateToMetadataRecord() { assertEquals("Id should be the same!", result.getId(), dataResource.getId()); assertEquals("Version should be '1'", Long.valueOf(1l), result.getRecordVersion()); assertTrue("ACL should be empty", result.getAcl().isEmpty()); + assertTrue("License should be 'null'", result.getLicenseUri() == null); assertNull("PID should be empty", result.getPid()); assertNull("Create date should be empty!", result.getCreatedAt()); assertNull("Last update date should be empty!", result.getLastUpdate()); @@ -693,12 +697,30 @@ public void testMigrateToMetadataRecord() { assertEquals("Id should be the same!", result.getId(), dataResource.getId()); assertEquals("Version should be '1'", Long.valueOf(1l), result.getRecordVersion()); assertTrue("ACL should be empty", result.getAcl().isEmpty()); + assertTrue("License should be 'null'", result.getLicenseUri() == null); assertNull("Create date should be empty!", result.getCreatedAt()); assertNull("Last update date should be empty!", result.getLastUpdate()); // PID should be set assertNotNull("PID shouldn't be NULL", result.getPid()); assertEquals(PID, result.getPid().getIdentifier()); assertEquals(ResourceIdentifier.IdentifierType.UPC, result.getPid().getIdentifierType()); + // Test migration of PID with two alternate identifiers (internal & UPC) + dataResource.getRights().add(Scheme.factoryScheme("test", LICENSE)); + result = MetadataRecordUtil.migrateToMetadataRecord(applicationProperties, dataResource, false); + assertNotNull(result.getId()); + assertEquals("Id should be the same!", result.getId(), dataResource.getId()); + assertEquals("Version should be '1'", Long.valueOf(1l), result.getRecordVersion()); + assertTrue("ACL should be empty", result.getAcl().isEmpty()); + assertNull("Create date should be empty!", result.getCreatedAt()); + assertNull("Last update date should be empty!", result.getLastUpdate()); + // PID should be set + assertNotNull("PID shouldn't be NULL", result.getPid()); + assertEquals(PID, result.getPid().getIdentifier()); + assertEquals(ResourceIdentifier.IdentifierType.UPC, result.getPid().getIdentifierType()); + // License should be set + assertNotNull("License shouldn't be NULL", result.getLicenseUri()); + assertEquals(LICENSE, result.getLicenseUri()); + // Add schemaID, resourceType, relatedIdentifier for schema //@ToDo Make this working again // dataResource.getTitles().add(Title.factoryTitle(SCHEMA_ID));