Skip to content

Commit

Permalink
Comments on PR 309
Browse files Browse the repository at this point in the history
- Add ImporterProviderService.CONTENT_TYPE static strings
- Revert XmlImportMapping changes
- Change SubscribedCatalogueConverter interface to trait
- Use command object validation in SubscribedModelController::federate
- Add dynamic check on type of imported domain in SubscribedModelService::federateSubscribedModel

Also:

- Add migration for replacing DomainExport exportFileType with exportContentType
  • Loading branch information
joe-crawford committed Jun 10, 2022
1 parent 88232b4 commit fe5578a
Show file tree
Hide file tree
Showing 33 changed files with 94 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
UPDATE core.domain_export
SET export_content_type = export_file_type
WHERE export_content_type IS NULL;

ALTER TABLE core.domain_export
ALTER COLUMN export_content_type SET NOT NULL;

ALTER TABLE core.domain_export
DROP COLUMN export_file_type;
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import org.springframework.beans.factory.annotation.Autowired
@CompileStatic
class FolderJsonExporterService extends FolderExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.folder+json'

@Autowired
JsonViewTemplateEngine templateEngine

Expand All @@ -52,7 +54,7 @@ class FolderJsonExporterService extends FolderExporterProviderService implements

@Override
String getContentType() {
'application/mauro.folder+json'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ class ImporterProviderServiceData implements Validateable {
String version

static constraints = {
version nullable: true
version nullable: true, blank: false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import groovy.xml.slurpersupport.NodeChildren
*/
trait XmlImportMapping {

Map<String, Object> convertToMap(NodeChild nodes, List<String> exclude = ['id']) {
Map<String, Object> convertToMap(NodeChild nodes) {
Map<String, Object> map = [:]
if (nodes.children().isEmpty()) {
map[nodes.name()] = nodes.text()
} else {
map = ((NodeChildren) nodes.children()).findAll {!exclude.contains(it.name())}.collectEntries {NodeChild child ->
map = ((NodeChildren) nodes.children()).findAll {it.name() != 'id'}.collectEntries {NodeChild child ->
String name = child.name()
def content = child.text()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ otherwise you could get an error.''',

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.test'
contentType.equalsIgnoreCase('application/mauro.test')
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ otherwise you could get an error.''',

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.test'
contentType.equalsIgnoreCase('application/mauro.test')
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired
*/
class DataFlowJsonExporterService extends DataFlowExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.dataflow+json'

@Autowired
JsonViewTemplateEngine templateEngine

Expand All @@ -43,7 +45,7 @@ class DataFlowJsonExporterService extends DataFlowExporterProviderService implem

@Override
String getContentType() {
'application/mauro.dataflow+json'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired
*/
class DataFlowXmlExporterService extends DataFlowExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.dataflow+xml'

@Autowired
MarkupViewTemplateEngine templateEngine

Expand All @@ -43,7 +45,7 @@ class DataFlowXmlExporterService extends DataFlowExporterProviderService impleme

@Override
String getContentType() {
'application/mauro.dataflow+xml'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.core.traits.provider.importer.JsonImportMapping
import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlow
import uk.ac.ox.softeng.maurodatamapper.dataflow.provider.exporter.DataFlowJsonExporterService
import uk.ac.ox.softeng.maurodatamapper.dataflow.provider.importer.parameter.DataFlowFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand All @@ -42,7 +43,7 @@ class DataFlowJsonImporterService extends DataBindDataFlowImporterProviderServic

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.dataflow+json'
contentType.equalsIgnoreCase(DataFlowJsonExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package uk.ac.ox.softeng.maurodatamapper.dataflow.provider.importer
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.dataflow.DataFlow
import uk.ac.ox.softeng.maurodatamapper.dataflow.provider.exporter.DataFlowXmlExporterService
import uk.ac.ox.softeng.maurodatamapper.dataflow.provider.importer.parameter.DataFlowFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand Down Expand Up @@ -59,7 +60,7 @@ class DataFlowXmlImporterService extends DataBindDataFlowImporterProviderService

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.dataflow+xml'
contentType.equalsIgnoreCase(DataFlowXmlExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired

class DataModelJsonExporterService extends DataModelExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.datamodel+json'

@Autowired
JsonViewTemplateEngine templateEngine

Expand All @@ -49,7 +51,7 @@ class DataModelJsonExporterService extends DataModelExporterProviderService impl

@Override
String getContentType() {
'application/mauro.datamodel+json'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import org.springframework.beans.factory.annotation.Autowired
*/
class DataModelXmlExporterService extends DataModelExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.datamodel+xml'

@Autowired
MarkupViewTemplateEngine templateEngine

Expand All @@ -52,7 +54,7 @@ class DataModelXmlExporterService extends DataModelExporterProviderService imple

@Override
String getContentType() {
'application/mauro.datamodel+xml'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.core.traits.provider.importer.JsonImportMapping
import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel
import uk.ac.ox.softeng.maurodatamapper.datamodel.provider.exporter.DataModelJsonExporterService
import uk.ac.ox.softeng.maurodatamapper.datamodel.provider.importer.parameter.DataModelFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand All @@ -46,7 +47,7 @@ class DataModelJsonImporterService extends DataBindDataModelImporterProviderServ

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.datamodel+json'
contentType.equalsIgnoreCase(DataModelJsonExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.core.traits.provider.importer.XmlImportMapping
import uk.ac.ox.softeng.maurodatamapper.datamodel.DataModel
import uk.ac.ox.softeng.maurodatamapper.datamodel.provider.exporter.DataModelXmlExporterService
import uk.ac.ox.softeng.maurodatamapper.datamodel.provider.importer.parameter.DataModelFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand Down Expand Up @@ -57,7 +58,7 @@ class DataModelXmlImporterService extends DataBindDataModelImporterProviderServi

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.datamodel+xml'
contentType.equalsIgnoreCase(DataModelXmlExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,21 @@ class SubscribedModelController extends EditLoggingController<SubscribedModel> {
def federate(SubscribedModelFederationParams subscribedModelFederationParams) {
if (handleReadOnly()) return

SubscribedModel instance = subscribedModelFederationParams.subscribedModel
if (subscribedModelFederationParams.hasErrors() || !subscribedModelFederationParams.validate()) {
transactionStatus.setRollbackOnly()
respond subscribedModelFederationParams.errors // STATUS CODE 422
return
}

if (!instance) {
return errorResponse(UNPROCESSABLE_ENTITY, 'Subscribed Model parameter is missing')
// Validate nested command object separately
if (subscribedModelFederationParams.importerProviderService &&
(subscribedModelFederationParams.importerProviderService.hasErrors() || !subscribedModelFederationParams.importerProviderService.validate())) {
transactionStatus.setRollbackOnly()
respond subscribedModelFederationParams.importerProviderService.errors // STATUS CODE 422
return
}

SubscribedModel instance = subscribedModelFederationParams.subscribedModel
instance.subscribedCatalogue = subscribedCatalogueService.get(params.subscribedCatalogueId)
instance.createdBy = currentUser.emailAddress

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class SubscribedModel implements MdmDomain, SecurableResource, EditHistoryAware
subscribedCatalogue nullable: false
folderId nullable: false
subscribedModelId nullable: false, unique: 'subscribedCatalogue' // Should prevent subscribing to the same modelId from same catalogue
subscribedModelType nullable: true
subscribedModelType nullable: true, blank: false
lastRead nullable: true
localModelId nullable: true
path nullable: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class SubscribedCatalogueService implements AnonymisableService {
try {
def (Authority subscribedAuthority, List<PublishedModel> publishedModels) = listPublishedModelsWithAuthority(subscribedCatalogue)

// Check that the remote catalogue has a name (Authority label), which is mandatory for both Mauro JSON and Atom XML catalogues
// Check that the publishedModels list exists, however this may be empty
if (!subscribedAuthority.label || publishedModels == null) {
subscribedCatalogue.errors.reject('invalid.subscription.url.response',
[subscribedCatalogue.url].toArray(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiInternalException
import uk.ac.ox.softeng.maurodatamapper.core.authority.Authority
import uk.ac.ox.softeng.maurodatamapper.core.container.Folder
import uk.ac.ox.softeng.maurodatamapper.core.container.FolderService
import uk.ac.ox.softeng.maurodatamapper.core.container.VersionedFolder
import uk.ac.ox.softeng.maurodatamapper.core.facet.VersionLinkType
import uk.ac.ox.softeng.maurodatamapper.core.importer.ImporterService
import uk.ac.ox.softeng.maurodatamapper.core.model.Model
Expand Down Expand Up @@ -188,6 +189,8 @@ class SubscribedModelService implements SecurableResourceService<SubscribedModel
subscribedModel.errors.reject('invalid.subscribedmodel.import',
'Could not import SubscribedModel into local Catalogue')
return subscribedModel.errors
} else if (!Model.isAssignableFrom(model.class) && !VersionedFolder.isAssignableFrom(model.class)) {
throw new ApiInternalException('SMS02', "Domain type ${model.domainType} cannot be imported")
}

log.debug('Importing domain {}, version {} from authority {}', model.label, model.modelVersion, model.authority)
Expand All @@ -200,7 +203,7 @@ class SubscribedModelService implements SecurableResourceService<SubscribedModel
}

if (!model.hasProperty('folder')) {
throw new ApiInternalException('SMS02', "Domain type ${model.domainType} " + 'cannot be imported into a Folder')
throw new ApiInternalException('SMS03', "Domain type ${model.domainType} cannot be imported into a Folder")
}
model.folder = folder

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ import uk.ac.ox.softeng.maurodatamapper.federation.SubscribedCatalogue
import uk.ac.ox.softeng.maurodatamapper.federation.SubscribedCatalogueType
import uk.ac.ox.softeng.maurodatamapper.federation.web.FederationClient

interface SubscribedCatalogueConverter {
trait SubscribedCatalogueConverter {
static final String LINK_RELATIONSHIP_ALTERNATE = 'alternate'

boolean handles(SubscribedCatalogueType type)
abstract boolean handles(SubscribedCatalogueType type)

Tuple2<Authority, List<PublishedModel>> getAuthorityAndPublishedModels(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue)
abstract Tuple2<Authority, List<PublishedModel>> getAuthorityAndPublishedModels(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue)

default Authority getAuthority(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue) {
Authority getAuthority(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue) {
getAuthorityAndPublishedModels(federationClient, subscribedCatalogue).v1
}

default List<PublishedModel> getPublishedModels(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue) {
List<PublishedModel> getPublishedModels(FederationClient federationClient, SubscribedCatalogue subscribedCatalogue) {
getAuthorityAndPublishedModels(federationClient, subscribedCatalogue).v2
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class SubscribedModelFederationParams implements Validateable {
ImporterProviderServiceData importerProviderService

static constraints = {
url nullable: true
contentType nullable: true
url nullable: true, blank: false
contentType nullable: true, blank: false
importerProviderService nullable: true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import org.springframework.beans.factory.annotation.Autowired

class ReferenceDataJsonExporterService extends ReferenceDataModelExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.referencedatamodel+json'

@Autowired
JsonViewTemplateEngine templateEngine

Expand All @@ -40,7 +42,7 @@ class ReferenceDataJsonExporterService extends ReferenceDataModelExporterProvide

@Override
String getContentType() {
'application/mauro.referencedatamodel+json'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import org.springframework.beans.factory.annotation.Autowired

class ReferenceDataXmlExporterService extends ReferenceDataModelExporterProviderService implements TemplateBasedExporter {

public static final CONTENT_TYPE = 'application/mauro.referencedatamodel+xml'

@Autowired
MarkupViewTemplateEngine templateEngine

Expand All @@ -40,7 +42,7 @@ class ReferenceDataXmlExporterService extends ReferenceDataModelExporterProvider

@Override
String getContentType() {
'application/mauro.referencedatamodel+xml'
CONTENT_TYPE
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ReferenceDataCsvImporterService extends ReferenceDataModelImporterProvider

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.referencedatamodel+csv'
contentType.equalsIgnoreCase('application/mauro.referencedatamodel+csv')
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package uk.ac.ox.softeng.maurodatamapper.referencedata.provider.importer
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.referencedata.ReferenceDataModel
import uk.ac.ox.softeng.maurodatamapper.referencedata.provider.exporter.ReferenceDataJsonExporterService
import uk.ac.ox.softeng.maurodatamapper.referencedata.provider.importer.parameter.ReferenceDataModelFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand All @@ -45,7 +46,7 @@ class ReferenceDataJsonImporterService

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.referencedatamodel+json'
contentType.equalsIgnoreCase(ReferenceDataJsonExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiBadRequestException
import uk.ac.ox.softeng.maurodatamapper.api.exception.ApiUnauthorizedException
import uk.ac.ox.softeng.maurodatamapper.core.traits.provider.importer.XmlImportMapping
import uk.ac.ox.softeng.maurodatamapper.referencedata.ReferenceDataModel
import uk.ac.ox.softeng.maurodatamapper.referencedata.provider.exporter.ReferenceDataXmlExporterService
import uk.ac.ox.softeng.maurodatamapper.referencedata.provider.importer.parameter.ReferenceDataModelFileImporterProviderServiceParameters
import uk.ac.ox.softeng.maurodatamapper.security.User

Expand Down Expand Up @@ -51,7 +52,7 @@ class ReferenceDataXmlImporterService

@Override
Boolean handlesContentType(String contentType) {
contentType.toLowerCase() == 'application/mauro.referencedatamodel+xml'
contentType.equalsIgnoreCase(ReferenceDataXmlExporterService.CONTENT_TYPE)
}

@Override
Expand Down
Loading

0 comments on commit fe5578a

Please sign in to comment.